You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ze...@apache.org on 2019/08/22 04:35:06 UTC
[servicecomb-service-center] branch master updated: Add new
servicecenter plugin supported eureka
This is an automated email from the ASF dual-hosted git repository.
zenlin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-service-center.git
The following commit(s) were added to refs/heads/master by this push:
new 11eed33 Add new servicecenter plugin supported eureka
new dad8f29 Merge pull request #574 from zenlint/syncer-eureka
11eed33 is described below
commit 11eed33811468dfa9bb4a46f7b8fbeec13f024f5
Author: Zen Lin <li...@huawei.com>
AuthorDate: Thu Aug 22 11:11:24 2019 +0800
Add new servicecenter plugin supported eureka
---
syncer/cmd/daemon.go | 3 +
syncer/config/config.go | 1 +
syncer/plugins/eureka/eureka.go | 113 ++++++++++++++++
syncer/plugins/eureka/instance.go | 108 +++++++++++++++
syncer/plugins/eureka/service.go | 38 ++++++
syncer/plugins/eureka/transform.go | 218 ++++++++++++++++++++++++++++++
syncer/plugins/eureka/type.go | 155 +++++++++++++++++++++
syncer/plugins/servicecenter/transform.go | 6 +-
8 files changed, 641 insertions(+), 1 deletion(-)
diff --git a/syncer/cmd/daemon.go b/syncer/cmd/daemon.go
index dde9836..70b65da 100644
--- a/syncer/cmd/daemon.go
+++ b/syncer/cmd/daemon.go
@@ -61,6 +61,9 @@ func init() {
syncerCmd.Flags().IntVar(&conf.ClusterPort, "cluster-port", conf.ClusterPort,
"port to communicate between cluster members")
+
+ syncerCmd.Flags().StringVar(&conf.ServicecenterPlugin, "sc-plugin", conf.ServicecenterPlugin,
+ "plugin name of servicecenter")
}
// runSyncer Runs the Syncer service.
diff --git a/syncer/config/config.go b/syncer/config/config.go
index b194d45..723eab8 100644
--- a/syncer/config/config.go
+++ b/syncer/config/config.go
@@ -25,6 +25,7 @@ import (
"github.com/apache/servicecomb-service-center/pkg/log"
"github.com/apache/servicecomb-service-center/syncer/etcd"
"github.com/apache/servicecomb-service-center/syncer/pkg/utils"
+ _ "github.com/apache/servicecomb-service-center/syncer/plugins/eureka"
"github.com/apache/servicecomb-service-center/syncer/plugins/servicecenter"
"github.com/apache/servicecomb-service-center/syncer/serf"
)
diff --git a/syncer/plugins/eureka/eureka.go b/syncer/plugins/eureka/eureka.go
new file mode 100644
index 0000000..71039e2
--- /dev/null
+++ b/syncer/plugins/eureka/eureka.go
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package eureka
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/apache/servicecomb-service-center/pkg/client/sc"
+ "github.com/apache/servicecomb-service-center/pkg/util"
+ "github.com/apache/servicecomb-service-center/syncer/plugins"
+ pb "github.com/apache/servicecomb-service-center/syncer/proto"
+)
+
+const (
+ PluginName = "eureka"
+
+ apiApplications = "/apps"
+)
+
+func init() {
+ // Register self as a repository plugin
+ plugins.RegisterPlugin(&plugins.Plugin{
+ Kind: plugins.PluginServicecenter,
+ Name: PluginName,
+ New: New,
+ })
+}
+
+type adaptor struct{}
+
+func New() plugins.PluginInstance {
+ return &adaptor{}
+}
+
+// New repository with endpoints
+func (*adaptor) New(endpoints []string) (plugins.Servicecenter, error) {
+ cfg := sc.Config{Endpoints: endpoints}
+ client, err := sc.NewLBClient(cfg.Endpoints, cfg.Merge())
+ if err != nil {
+ return nil, err
+ }
+ return &Client{LBClient: client, Cfg: cfg}, nil
+}
+
+type Client struct {
+ *sc.LBClient
+ Cfg sc.Config
+}
+
+// GetAll get and transform eureka data to SyncData
+func (c *Client) GetAll(ctx context.Context) (*pb.SyncData, error) {
+ method := http.MethodGet
+ headers := c.CommonHeaders(method)
+ resp, err := c.RestDoWithContext(ctx, method, apiApplications, headers, nil)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.StatusCode != http.StatusOK {
+ return nil, c.toError(body)
+ }
+
+ data := &eurekaData{}
+ err = json.Unmarshal(body, data)
+ if err != nil {
+ return nil, err
+ }
+
+ return toSyncData(data), nil
+}
+
+// CommonHeaders Set the common header of the request
+func (c *Client) CommonHeaders(method string) http.Header {
+ var headers = make(http.Header)
+ if len(c.Cfg.Token) > 0 {
+ headers.Set("X-Auth-Token", c.Cfg.Token)
+ }
+ headers.Set("Accept", " application/json")
+ headers.Set("Content-Type", "application/json")
+ if method == http.MethodPut {
+ headers.Set("x-netflix-discovery-replication", "true")
+ }
+ return headers
+}
+
+// toError response body to error
+func (c *Client) toError(body []byte) error {
+ return errors.New(util.BytesToStringWithNoCopy(body))
+}
diff --git a/syncer/plugins/eureka/instance.go b/syncer/plugins/eureka/instance.go
new file mode 100644
index 0000000..4e4806c
--- /dev/null
+++ b/syncer/plugins/eureka/instance.go
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package eureka
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+
+ pb "github.com/apache/servicecomb-service-center/syncer/proto"
+)
+
+const (
+ apiInstances = "/apps/%s"
+ apiInstance = "/apps/%s/%s"
+)
+
+// RegisterInstance register instance to servicecenter
+func (c *Client) RegisterInstance(ctx context.Context, domainProject, serviceId string, syncInstance *pb.SyncInstance) (string, error) {
+ instance := toInstance(serviceId, syncInstance)
+ method := http.MethodPost
+ headers := c.CommonHeaders(method)
+ body, err := json.Marshal(&InstanceRequest{Instance: instance})
+ if err != nil {
+ return "", err
+ }
+
+ apiURL := fmt.Sprintf(apiInstances, serviceId)
+ resp, err := c.RestDoWithContext(ctx, method, apiURL, headers, body)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ body, err = ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return "", err
+ }
+ if resp.StatusCode != http.StatusNoContent {
+ return "", c.toError(body)
+ }
+
+ return instance.InstanceId, nil
+}
+
+// UnregisterInstance unregister instance from servicecenter
+func (c *Client) UnregisterInstance(ctx context.Context, domainProject, serviceId, instanceId string) error {
+ method := http.MethodDelete
+ headers := c.CommonHeaders(method)
+
+ apiURL := fmt.Sprintf(apiInstance, serviceId, instanceId)
+ resp, err := c.RestDoWithContext(ctx, method, apiURL, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+
+ if resp.StatusCode != http.StatusOK {
+ return c.toError(body)
+ }
+
+ return nil
+}
+
+// Heartbeat sends heartbeat to servicecenter
+func (c *Client) Heartbeat(ctx context.Context, domainProject, serviceId, instanceId string) error {
+ method := http.MethodPut
+ headers := c.CommonHeaders(method)
+ apiURL := fmt.Sprintf(apiInstance, serviceId, instanceId) + "?" + url.Values{"status": {UP}}.Encode()
+ resp, err := c.RestDoWithContext(ctx, method, apiURL, headers, nil)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+
+ if resp.StatusCode != http.StatusOK {
+ return c.toError(body)
+ }
+
+ return nil
+}
diff --git a/syncer/plugins/eureka/service.go b/syncer/plugins/eureka/service.go
new file mode 100644
index 0000000..69c17c2
--- /dev/null
+++ b/syncer/plugins/eureka/service.go
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package eureka
+
+import (
+ "context"
+
+ pb "github.com/apache/servicecomb-service-center/syncer/proto"
+)
+
+// CreateService Eureka's application is created with instance and does not need to be processed here.
+func (c *Client) CreateService(ctx context.Context, domainProject string, syncService *pb.SyncService) (string, error) {
+ return syncService.Name, nil
+}
+
+// DeleteService Eureka's application is created with instance and does not need to be processed here.
+func (c *Client) DeleteService(ctx context.Context, domainProject, serviceId string) error {
+ return nil
+}
+
+// ServiceExistence Eureka's application is created with instance and does not need to be processed here.
+func (c *Client) ServiceExistence(ctx context.Context, domainProject string, syncService *pb.SyncService) (string, error) {
+ return syncService.Name, nil
+}
diff --git a/syncer/plugins/eureka/transform.go b/syncer/plugins/eureka/transform.go
new file mode 100644
index 0000000..686dbef
--- /dev/null
+++ b/syncer/plugins/eureka/transform.go
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package eureka
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+
+ "github.com/apache/servicecomb-service-center/pkg/log"
+ pb "github.com/apache/servicecomb-service-center/syncer/proto"
+)
+
+const (
+ eurekaInstanceFormat = "%s:%s:%d"
+
+ defaultApp = "eureka"
+
+ // The name is limited to "Netflix" or "Amazon" or "MyOwn"
+ // by the enumeration type in the interface of eureka
+ // "com.netflix.appinfo.DataCenterInfo".
+ // Here, "MyOwn" is used as the default.
+ defaultDataCenterInfoName = "MyOwn"
+
+ // Class is used the static variable "MY_DATA_CENTER_INFO_TYPE_MARKER"
+ // defined in eureka "com.netflix.discovery.converters.jackson",
+ // that is kept for backward compatibility
+ defaultDataCenterInfoClass = "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"
+)
+
+// toSyncData transform eureka service cache to SyncData
+func toSyncData(eureka *eurekaData) (data *pb.SyncData) {
+ apps := eureka.APPS.Applications
+ data = &pb.SyncData{
+ Services: make([]*pb.SyncService, 0, len(apps)),
+ Instances: make([]*pb.SyncInstance, 0, 10),
+ }
+
+ for _, app := range apps {
+ service := toSyncService(app)
+
+ instances := toSyncInstances(service.ServiceId, app.Instances)
+ if len(instances) == 0 {
+ continue
+ }
+
+ data.Services = append(data.Services, service)
+ data.Instances = append(data.Instances, instances...)
+ }
+ return
+}
+
+// toSyncService transform eureka application to SyncService
+func toSyncService(app *Application) (service *pb.SyncService) {
+ appName := strings.ToLower(app.Name)
+ service = &pb.SyncService{
+ ServiceId: appName,
+ Name: appName,
+ App: defaultApp,
+ Version: "0.0.1",
+ DomainProject: "default/default",
+ Status: pb.SyncService_UP,
+ PluginName: PluginName,
+ }
+ return
+}
+
+// toSyncInstances transform eureka instances to SyncInstances
+func toSyncInstances(serviceID string, instances []*Instance) []*pb.SyncInstance {
+ instList := make([]*pb.SyncInstance, 0, len(instances))
+ for _, inst := range instances {
+ if inst.Status != UP {
+ continue
+ }
+
+ instList = append(instList, toSyncInstance(serviceID, inst))
+ }
+ return instList
+}
+
+// toSyncInstance transform eureka instance to SyncInstance
+func toSyncInstance(serviceID string, instance *Instance) (syncInstance *pb.SyncInstance) {
+ syncInstance = &pb.SyncInstance{
+ InstanceId: instance.InstanceId,
+ ServiceId: serviceID,
+ Endpoints: make([]string, 0, 2),
+ HostName: instance.HostName,
+ PluginName: PluginName,
+ Version: "latest",
+ }
+
+ switch instance.Status {
+ case UP:
+ syncInstance.Status = pb.SyncInstance_UP
+ case DOWN:
+ syncInstance.Status = pb.SyncInstance_DOWN
+ case STARTING:
+ syncInstance.Status = pb.SyncInstance_STARTING
+ case OUTOFSERVICE:
+ syncInstance.Status = pb.SyncInstance_OUTOFSERVICE
+ default:
+ syncInstance.Status = pb.SyncInstance_UNKNOWN
+ }
+
+ if instance.Port.Enabled.Bool() {
+ syncInstance.Endpoints = append(syncInstance.Endpoints, fmt.Sprintf("http://%s:%d", instance.IPAddr, instance.Port.Port))
+ }
+
+ if instance.SecurePort.Enabled.Bool() {
+ syncInstance.Endpoints = append(syncInstance.Endpoints, fmt.Sprintf("https://%s:%d", instance.IPAddr, instance.SecurePort.Port))
+ }
+
+ if instance.HealthCheckUrl != "" {
+ syncInstance.HealthCheck = &pb.HealthCheck{
+ Interval: 30,
+ Times: 3,
+ Url: instance.HealthCheckUrl,
+ }
+ }
+
+ expansion, err := json.Marshal(instance)
+ if err != nil {
+ log.Errorf(err, "transform sc service to syncer service failed: %s", err)
+ return
+ }
+ syncInstance.Expansion = expansion
+ return
+}
+
+// toInstance transform SyncInstance to eureka instance
+func toInstance(serviceID string, syncInstance *pb.SyncInstance) (instance *Instance) {
+ instance = &Instance{}
+ if syncInstance.PluginName == PluginName && syncInstance.Expansion != nil {
+ err := json.Unmarshal(syncInstance.Expansion, instance)
+ if err == nil {
+ return
+ }
+ log.Errorf(err, "proto unmarshal %s instance, instanceID = %s, content = %v failed",
+ PluginName, syncInstance.InstanceId, syncInstance.Expansion)
+ }
+ instance.InstanceId = syncInstance.InstanceId
+ instance.APP = serviceID
+ instance.Status = pb.SyncInstance_Status_name[int32(syncInstance.Status)]
+ instance.OverriddenStatus = UNKNOWN
+ instance.DataCenterInfo = &DataCenterInfo{
+ Name: defaultDataCenterInfoName,
+ Class: defaultDataCenterInfoClass,
+ }
+
+ instance.Metadata = &MetaData{
+ Map: map[string]string{"instanceId": syncInstance.InstanceId},
+ }
+
+ ipAddr := ""
+ for _, ep := range syncInstance.Endpoints {
+ addr, err := url.Parse(ep)
+ if err != nil {
+ log.Error("parse the endpoint of eureka`s instance failed", err)
+ continue
+ }
+ hostname := addr.Hostname()
+ if ipAddr != "" || ipAddr != hostname {
+ log.Error("eureka`s ipAddr must be unique in endpoints", err)
+ }
+ ipAddr = hostname
+
+ port := &Port{}
+ port.Port, err = strconv.Atoi(addr.Port())
+ if err != nil {
+ log.Error("Illegal value of port", err)
+ continue
+ }
+ port.Enabled.Set(true)
+
+ switch addr.Scheme {
+ case "http":
+ instance.Port = port
+ instance.VipAddress = serviceID
+ case "https":
+ instance.SecurePort = port
+ instance.SecureVipAddress = ep
+ }
+ }
+ log.Error(ipAddr,errors.New("sc to eureka hostname failed"))
+ instance.IPAddr = ipAddr
+ instance.HostName = ipAddr
+
+ if syncInstance.HealthCheck != nil {
+ instance.HealthCheckUrl = syncInstance.HealthCheck.Url
+ }
+
+ instArr := strings.Split(syncInstance.InstanceId, ":")
+ if len(instArr) != 3 {
+ if instance.Port != nil && instance.Port.Enabled.Bool() {
+ instance.InstanceId = fmt.Sprintf(eurekaInstanceFormat, ipAddr, instance.APP, instance.Port.Port)
+ } else if instance.SecurePort != nil && instance.SecurePort.Enabled.Bool() {
+ instance.InstanceId = fmt.Sprintf(eurekaInstanceFormat, ipAddr, instance.APP, instance.SecurePort.Port)
+ }
+ }
+ return
+}
diff --git a/syncer/plugins/eureka/type.go b/syncer/plugins/eureka/type.go
new file mode 100644
index 0000000..3388165
--- /dev/null
+++ b/syncer/plugins/eureka/type.go
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package eureka
+
+import (
+ "encoding/json"
+ "strconv"
+)
+
+const (
+ UNKNOWN = "UNKNOWN"
+ UP = "UP"
+ DOWN = "DOWN"
+ STARTING = "STARTING"
+ OUTOFSERVICE = "OUTOFSERVICE"
+)
+
+type eurekaData struct {
+ APPS *Applications `json:"applications"`
+}
+
+type Applications struct {
+ VersionsDelta string `json:"versions__delta"`
+ AppsHashcode string `json:"apps__hashcode"`
+ Applications []*Application `json:"application,omitempty"`
+}
+
+type Application struct {
+ Name string `json:"name"`
+ Instances []*Instance `json:"instance"`
+}
+
+type InstanceRequest struct {
+ Instance *Instance `json:"instance"`
+}
+
+type Instance struct {
+ InstanceId string `json:"instanceId"`
+ HostName string `json:"hostName"`
+ APP string `json:"app"`
+ IPAddr string `json:"ipAddr"`
+ Status string `json:"status"`
+ OverriddenStatus string `json:"overriddenStatus,omitempty"`
+ Port *Port `json:"port,omitempty"`
+ SecurePort *Port `json:"securePort,omitempty"`
+ CountryId int `json:"countryId,omitempty"`
+ DataCenterInfo *DataCenterInfo `json:"dataCenterInfo"`
+ LeaseInfo *LeaseInfo `json:"leaseInfo,omitempty"`
+ Metadata *MetaData `json:"metadata,omitempty"`
+ HomePageUrl string `json:"homePageUrl,omitempty"`
+ StatusPageUrl string `json:"statusPageUrl,omitempty"`
+ HealthCheckUrl string `json:"healthCheckUrl,omitempty"`
+ VipAddress string `json:"vipAddress,omitempty"`
+ SecureVipAddress string `json:"secureVipAddress,omitempty"`
+ IsCoordinatingDiscoveryServer BoolString `json:"isCoordinatingDiscoveryServer,omitempty"`
+ LastUpdatedTimestamp string `json:"lastUpdatedTimestamp,omitempty"`
+ LastDirtyTimestamp string `json:"lastDirtyTimestamp,omitempty"`
+ ActionType string `json:"actionType,omitempty"`
+}
+
+type DataCenterInfo struct {
+ Name string `json:"name"`
+ Class string `json:"@class"`
+ Metadata *DataCenterMetadata `json:"metadata,omitempty"`
+}
+
+type DataCenterMetadata struct {
+ AmiLaunchIndex string `json:"ami-launch-index,omitempty"`
+ LocalHostname string `json:"local-hostname,omitempty"`
+ AvailabilityZone string `json:"availability-zone,omitempty"`
+ InstanceId string `json:"instance-id,omitempty"`
+ PublicIpv4 string `json:"public-ipv4,omitempty"`
+ PublicHostname string `json:"public-hostname,omitempty"`
+ AmiManifestPath string `json:"ami-manifest-path,omitempty"`
+ LocalIpv4 string `json:"local-ipv4,omitempty"`
+ Hostname string `json:"hostname,omitempty"`
+ AmiId string `json:"ami-id,omitempty"`
+ InstanceType string `json:"instance-type,omitempty"`
+}
+
+type LeaseInfo struct {
+ RenewalIntervalInSecs int `json:"renewalIntervalInSecs,omitempty"`
+ DurationInSecs int `json:"durationInSecs,omitempty"`
+ RegistrationTimestamp int `json:"registrationTimestamp,omitempty"`
+ LastRenewalTimestamp int `json:"lastRenewalTimestamp,omitempty"`
+ EvictionDurationInSecs uint `json:"evictionDurationInSecs,omitempty"`
+ EvictionTimestamp int `json:"evictionTimestamp,omitempty"`
+ ServiceUpTimestamp int `json:"serviceUpTimestamp,omitempty"`
+}
+
+type Port struct {
+ Port int `json:"$"`
+ Enabled BoolString `json:"@enabled"`
+}
+
+type MetaData struct {
+ Map map[string]string
+ Class string
+}
+
+func (s *MetaData) MarshalJSON() ([]byte, error) {
+ newMap := make(map[string]string)
+ for key, value := range s.Map {
+ newMap[key] = value
+ }
+ if s.Class != "" {
+ newMap["@class"] = s.Class
+ }
+ return json.Marshal(&newMap)
+}
+
+func (s *MetaData) UnmarshalJSON(data []byte) error {
+ newMap := make(map[string]string)
+ err := json.Unmarshal(data, &newMap)
+ if err != nil {
+ return err
+ }
+
+ s.Map = newMap
+ if val, ok := s.Map["@class"]; ok {
+ s.Class = val
+ delete(s.Map, "@class")
+ }
+ return nil
+}
+
+type BoolString string
+
+func (b *BoolString) Set(value bool) {
+ str := strconv.FormatBool(value)
+ *b = BoolString(str)
+}
+
+func (b BoolString) Bool() bool {
+ enabled, err := strconv.ParseBool(string(b))
+ if err != nil {
+ return false
+ }
+ return enabled
+}
diff --git a/syncer/plugins/servicecenter/transform.go b/syncer/plugins/servicecenter/transform.go
index e028d1c..071e547 100644
--- a/syncer/plugins/servicecenter/transform.go
+++ b/syncer/plugins/servicecenter/transform.go
@@ -206,12 +206,16 @@ func toInstance(syncInstance *pb.SyncInstance) (instance *scpb.MicroServiceInsta
endpoint = strings.Replace(ep, "http://", "rest://", 1)
case "https":
endpoint = strings.Replace(ep, "https://", "rest://", 1) + "?sslEnabled=true"
+ case "rest":
+ endpoint = ep
+
}
instance.Endpoints = append(instance.Endpoints, endpoint)
}
- if syncInstance.HealthCheck != nil {
+ if syncInstance.HealthCheck != nil && syncInstance.HealthCheck.Mode != pb.HealthCheck_UNKNOWN {
instance.HealthCheck = &scpb.HealthCheck{
+ Mode: pb.HealthCheck_Modes_name[int32(syncInstance.HealthCheck.Mode)],
Port: syncInstance.HealthCheck.Port,
Interval: syncInstance.HealthCheck.Interval,
Times: syncInstance.HealthCheck.Times,