summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--msb2pilot/src/msb2pilot/conf/consul.yml2
-rw-r--r--msb2pilot/src/msb2pilot/consul/controller.go98
-rw-r--r--msb2pilot/src/msb2pilot/consul/controller_test.go89
-rw-r--r--msb2pilot/src/msb2pilot/consul/monitor.go78
-rw-r--r--msb2pilot/src/msb2pilot/log/log_test.go10
-rw-r--r--msb2pilot/src/msb2pilot/main.go17
-rw-r--r--msb2pilot/src/msb2pilot/models/config.go16
-rw-r--r--msb2pilot/src/msb2pilot/models/conversion.go117
-rw-r--r--msb2pilot/src/msb2pilot/models/conversion_test.go115
-rw-r--r--msb2pilot/src/msb2pilot/models/msb.go65
-rw-r--r--msb2pilot/src/msb2pilot/util/common.go1
11 files changed, 602 insertions, 6 deletions
diff --git a/msb2pilot/src/msb2pilot/conf/consul.yml b/msb2pilot/src/msb2pilot/conf/consul.yml
new file mode 100644
index 0000000..3c30cba
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/conf/consul.yml
@@ -0,0 +1,2 @@
+# consul api address, default to be http://localhost:8500
+address: http://127.0.0.1:8500
diff --git a/msb2pilot/src/msb2pilot/consul/controller.go b/msb2pilot/src/msb2pilot/consul/controller.go
new file mode 100644
index 0000000..b6e798f
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/consul/controller.go
@@ -0,0 +1,98 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package consul
+
+import (
+ "msb2pilot/log"
+ "msb2pilot/models"
+ "msb2pilot/util"
+ "os"
+ "path/filepath"
+
+ "github.com/hashicorp/consul/api"
+)
+
+var client *api.Client
+var consulAddress string
+
+var (
+ cfgFilePath = filepath.Join(util.GetCfgPath(), "consul.yml")
+)
+
+const (
+ defaultAddress = "http://localhost:8500"
+)
+
+func init() {
+ consulAddress = getConsulAddress(cfgFilePath)
+
+ conf := api.DefaultConfig()
+ conf.Address = consulAddress
+ var err error
+ client, err = api.NewClient(conf)
+
+ if err != nil {
+ log.Log.Error("failed to init consul client", err)
+ }
+}
+
+func getConsulAddress(path string) string {
+ res := os.Getenv(models.EnvConsulAddress)
+ if res != "" {
+ return res
+ }
+
+ cfg, err := loadCfgInfo(path)
+ if err != nil {
+ log.Log.Error("load consul config info error", err)
+ return defaultAddress
+ } else {
+ if addr, exist := cfg["address"]; exist {
+ return addr.(string)
+ } else {
+ return defaultAddress
+ }
+ }
+}
+
+func loadCfgInfo(path string) (map[interface{}]interface{}, error) {
+ log.Log.Informational("consul config path is:" + path)
+ cfg, err := util.Read(path)
+ if err != nil {
+ return nil, err
+ }
+
+ result := make(map[interface{}]interface{})
+ err = util.UnmarshalYaml(cfg, result)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+
+func GetServices() (map[string][]string, error) {
+ data, _, err := client.Catalog().Services(nil)
+
+ if err != nil {
+ return nil, err
+ }
+ return data, nil
+}
+
+func GetInstances(serviceName string) ([]*api.CatalogService, error) {
+ endpoints, _, err := client.Catalog().Service(serviceName, "", nil)
+ if err != nil {
+ log.Log.Error("can not get endpoints of ", serviceName)
+ return nil, err
+ }
+ return endpoints, nil
+}
diff --git a/msb2pilot/src/msb2pilot/consul/controller_test.go b/msb2pilot/src/msb2pilot/consul/controller_test.go
new file mode 100644
index 0000000..a6569bd
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/consul/controller_test.go
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package consul
+
+import (
+ "msb2pilot/models"
+ "os"
+ "testing"
+)
+
+func TestSetConsulAddress(t *testing.T) {
+ cases := []struct {
+ env, path, want string
+ }{
+ {
+ env: "testEnv",
+ path: "",
+ want: `testEnv`,
+ },
+ {
+ env: "",
+ path: cfgFilePath,
+ want: `http://127.0.0.1:8500`,
+ },
+ {
+ env: "testEnvWithPath",
+ path: cfgFilePath,
+ want: `testEnvWithPath`,
+ },
+ {
+ env: "",
+ path: ``,
+ want: `http://localhost:8500`,
+ },
+ {
+ env: "",
+ path: `controller.go`,
+ want: `http://localhost:8500`,
+ },
+ }
+
+ oldEnv := os.Getenv(models.EnvConsulAddress)
+
+ for _, cas := range cases {
+ os.Setenv(models.EnvConsulAddress, cas.env)
+
+ res := getConsulAddress(cas.path)
+ if res != cas.want {
+ t.Errorf("getConsulAddress() => want %s, got %s", cas.want, res)
+ }
+ }
+
+ os.Setenv(models.EnvConsulAddress, oldEnv)
+}
+
+func TestLoadCfgInfo(t *testing.T) {
+ cases := []struct {
+ path, status string
+ }{
+ {
+ path: cfgFilePath,
+ status: `success`,
+ },
+ {
+ path: ``,
+ status: `path is empty`,
+ },
+ {
+ path: `controller.go`,
+ status: `yaml format error`,
+ },
+ }
+
+ for _, cas := range cases {
+ _, err := loadCfgInfo(cas.path)
+ if (cas.status == "success" && err != nil) || (cas.status != "success" && err == nil) {
+ t.Errorf("loadCfgInfo() => want %s, got %v", cas.status, err)
+ }
+ }
+}
diff --git a/msb2pilot/src/msb2pilot/consul/monitor.go b/msb2pilot/src/msb2pilot/consul/monitor.go
new file mode 100644
index 0000000..c3adde4
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/consul/monitor.go
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package consul
+
+import (
+ "msb2pilot/log"
+ "msb2pilot/models"
+ "time"
+
+ "github.com/hashicorp/consul/api"
+)
+
+type Monitor interface {
+ Start(<-chan struct{})
+}
+
+type ServiceHandler func(newServices []*models.MsbService)
+
+type consulMonitor struct {
+ discovery *api.Client
+ period time.Duration
+ serviceHandler ServiceHandler
+}
+
+func NewConsulMonitor(client *api.Client, period time.Duration, serviceHandler ServiceHandler) Monitor {
+ return &consulMonitor{
+ discovery: client,
+ period: period,
+ serviceHandler: serviceHandler,
+ }
+}
+
+func (this *consulMonitor) Start(stop <-chan struct{}) {
+ this.run(stop)
+}
+
+func (this *consulMonitor) run(stop <-chan struct{}) {
+ ticker := time.NewTicker(this.period)
+ for {
+ select {
+ case <-stop:
+ ticker.Stop()
+ return
+ case <-ticker.C:
+ this.updateServiceRecord()
+ }
+ }
+
+}
+
+func (this *consulMonitor) updateServiceRecord() {
+ data, err := GetServices()
+ if err != nil {
+ log.Log.Error("failed to get services from consul", err)
+ return
+ }
+
+ newRecords := make([]*models.MsbService, 0, len(data))
+ for name := range data {
+ endpoints, err := GetInstances(name)
+ if err != nil {
+ log.Log.Error("failed to get service instance of "+name, err)
+ continue
+ }
+ newRecords = append(newRecords, models.ConvertService(endpoints))
+ }
+
+ this.serviceHandler(newRecords)
+}
diff --git a/msb2pilot/src/msb2pilot/log/log_test.go b/msb2pilot/src/msb2pilot/log/log_test.go
index 816e10f..9ed192a 100644
--- a/msb2pilot/src/msb2pilot/log/log_test.go
+++ b/msb2pilot/src/msb2pilot/log/log_test.go
@@ -12,14 +12,13 @@
package log
import (
- "apiroute/util"
+ "msb2pilot/util"
"os"
"strings"
"testing"
)
func TestCheckLogDir(t *testing.T) {
- pathSep := string(os.PathSeparator)
cases := []struct {
path string
exist bool
@@ -33,7 +32,7 @@ func TestCheckLogDir(t *testing.T) {
exist: false,
},
{
- path: `.` + pathSep + `test` + pathSep + `test.log`,
+ path: `.` + util.PathSep + `test` + util.PathSep + `test.log`,
exist: true,
},
}
@@ -41,7 +40,7 @@ func TestCheckLogDir(t *testing.T) {
for _, cas := range cases {
checkLogDir(cas.path)
- index := strings.LastIndex(cas.path, pathSep)
+ index := strings.LastIndex(cas.path, util.PathSep)
if cas.exist && !util.FileExists(cas.path[0:index]) {
t.Errorf("checkLogDir() => dir not exist, want %s", cas.path)
}
@@ -52,13 +51,12 @@ func TestCheckLogDir(t *testing.T) {
}
func TestLoadCustom(t *testing.T) {
- pathSep := string(os.PathSeparator)
cases := []struct {
path string
want string
}{
{
- path: `..` + pathSep + "conf" + pathSep + cfgFileName,
+ path: `..` + util.PathSep + "conf" + util.PathSep + cfgFileName,
want: "success",
},
{
diff --git a/msb2pilot/src/msb2pilot/main.go b/msb2pilot/src/msb2pilot/main.go
index c19000a..7ed762c 100644
--- a/msb2pilot/src/msb2pilot/main.go
+++ b/msb2pilot/src/msb2pilot/main.go
@@ -12,13 +12,30 @@
package main
import (
+ "fmt"
+ "msb2pilot/consul"
"msb2pilot/log"
+ "msb2pilot/models"
_ "msb2pilot/routers"
+ "time"
"github.com/astaxie/beego"
)
func main() {
log.Log.Informational("**************** init msb2pilot ************************")
+ // start sync msb data
+ go syncConsulData()
+
beego.Run()
}
+
+func syncConsulData() {
+ stop := make(chan struct{})
+ monitor := consul.NewConsulMonitor(nil, 20*time.Second, syncMsbData)
+ monitor.Start(stop)
+}
+
+func syncMsbData(newServices []*models.MsbService) {
+ fmt.Println(len(newServices), "services updated", time.Now())
+}
diff --git a/msb2pilot/src/msb2pilot/models/config.go b/msb2pilot/src/msb2pilot/models/config.go
new file mode 100644
index 0000000..7f34514
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/models/config.go
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package models
+
+const (
+ EnvConsulAddress = "ConsulAddress" //http://localhost:8500
+)
diff --git a/msb2pilot/src/msb2pilot/models/conversion.go b/msb2pilot/src/msb2pilot/models/conversion.go
new file mode 100644
index 0000000..144d05b
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/models/conversion.go
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package models
+
+import (
+ "encoding/json"
+ "msb2pilot/log"
+ "strings"
+
+ "github.com/hashicorp/consul/api"
+)
+
+func ConvertService(endpoints []*api.CatalogService) *MsbService {
+ if len(endpoints) == 0 {
+ return nil
+ }
+
+ endpoint := endpoints[0]
+ service := &MsbService{
+ ServiceName: endpoint.ServiceName,
+ ModifyIndex: endpoint.ModifyIndex,
+ ConsulLabels: &ConsulLabels{},
+ }
+
+ convertMsbLabels(service.ConsulLabels, endpoint.ServiceTags)
+ return service
+}
+
+func convertBaseInfo(baseString string) (baseInfo *BaseInfo, err error) {
+ baseInfo = new(BaseInfo)
+ err = json.Unmarshal([]byte(baseString), baseInfo)
+
+ return
+}
+
+func convertNameSpace(ns string) (nameSpace *NameSpace, err error) {
+ nameSpace = new(NameSpace)
+ err = json.Unmarshal([]byte(ns), nameSpace)
+ return
+}
+
+func LoadMsbServiceFromMap(services map[string][]string) []*MsbService {
+ result := make([]*MsbService, 0, len(services))
+
+ for k, v := range services {
+ service := &MsbService{
+ ServiceName: k,
+ ConsulLabels: new(ConsulLabels),
+ }
+ convertMsbLabels(service.ConsulLabels, v)
+ result = append(result, service)
+ }
+ return result
+}
+
+func ConsulService2MsbService(consulService *api.CatalogService) *MsbService {
+ msbService := &MsbService{
+ ServiceName: consulService.ServiceName,
+ ServiceAddress: consulService.ServiceAddress,
+ ServicePort: consulService.ServicePort,
+ ConsulLabels: new(ConsulLabels),
+ }
+
+ convertMsbLabels(msbService.ConsulLabels, consulService.ServiceTags)
+
+ return msbService
+}
+
+func convertMsbLabel(label, labelstr string) interface{} {
+ var result interface{}
+ var err error
+
+ labelPrefix := "\"" + label + "\":"
+
+ if strings.HasPrefix(labelstr, labelPrefix) {
+ kvp := strings.Split(labelstr, labelPrefix)
+ value := kvp[1]
+
+ switch label {
+ case "base":
+ result, err = convertBaseInfo(value)
+ case "ns":
+ result, err = convertNameSpace(value)
+ }
+
+ if err != nil {
+ log.Log.Error("parse msb label error", err)
+ return nil
+ }
+
+ return result
+ }
+
+ return nil
+}
+func convertMsbLabels(consulLabels *ConsulLabels, labels []string) {
+ for _, label := range labels {
+ baseInfo := convertMsbLabel("base", label)
+ if baseInfo != nil {
+ consulLabels.BaseInfo = baseInfo.(*BaseInfo)
+ }
+
+ ns := convertMsbLabel("ns", label)
+ if ns != nil {
+ consulLabels.NameSpace = ns.(*NameSpace)
+ }
+ }
+}
diff --git a/msb2pilot/src/msb2pilot/models/conversion_test.go b/msb2pilot/src/msb2pilot/models/conversion_test.go
new file mode 100644
index 0000000..212e994
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/models/conversion_test.go
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package models
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestConvertBaseInfo(t *testing.T) {
+ cases := []struct{ in, want string }{
+ {
+ in: `{"enable_ssl":"true", "version":"v1","protocol":"REST","publish_port":"28012|28013","url":"/api/itm-pmadaptor/v1","is_manual":"false","visualRange":"0","appversion":"v1.18.20.04"}`,
+ want: `v1`,
+ },
+ {
+ in: `{"enable_ssl":"true", "version":"v2","protocol":"UI", "status":"1", "url":"/api/itm-pmadaptor/v1","is_manual":"false"}`,
+ want: `v2`,
+ },
+ {
+ in: `{"others":"other"}`,
+ want: ``,
+ },
+ {
+ in: ``,
+ want: ``,
+ },
+ }
+
+ for _, cas := range cases {
+ got, _ := convertBaseInfo(cas.in)
+ if got.Version != cas.want {
+ t.Errorf("convertBaseInfo(%s) => got %s, want %s", cas.in, got.AppVersion, cas.want)
+ }
+ }
+
+}
+
+func TestConvertNameSpace(t *testing.T) {
+ cases := []struct{ in, want string }{
+ {
+ in: `{"namespace":"test"}`,
+ want: `test`,
+ },
+ {
+ in: `{"namespace":"testwithother", "others":"other"}`,
+ want: `testwithother`,
+ },
+ {
+ in: `{"others":"other"}`,
+ want: ``,
+ },
+ {
+ in: ``,
+ want: ``,
+ },
+ }
+
+ for _, cas := range cases {
+ got, _ := convertNameSpace(cas.in)
+ if got.NameSpace != cas.want {
+ t.Errorf("convertNameSpace(%s) => got %s, want %s", cas.in, got.NameSpace, cas.want)
+ }
+ }
+
+}
+
+func TestConvertMsbLabel(t *testing.T) {
+ cases := []struct{ label, in, want string }{
+ {
+ label: "base",
+ in: `"base":{"enable_ssl":"true", "version":"v1","protocol":"REST","publish_port":"28012|28013","url":"/api/itm-pmadaptor/v1","is_manual":"false","visualRange":"0","appversion":"v1.18.20.04"}`,
+ want: `*models.BaseInfo`,
+ },
+ {
+ label: "ns",
+ in: `"ns":{"namespace":"test"}`,
+ want: `*models.NameSpace`,
+ },
+ {
+ label: "others",
+ in: `{"others":"other"}`,
+ want: ``,
+ },
+ {
+ label: "",
+ in: ``,
+ want: ``,
+ },
+ }
+
+ for _, cas := range cases {
+ got := convertMsbLabel(cas.label, cas.in)
+
+ if got == nil {
+ if cas.want != "" {
+ t.Errorf("convertMsbLabel(%s, %s) => got nil, want %s", cas.label, cas.in, cas.want)
+ }
+ } else {
+ if reflect.TypeOf(got).String() != cas.want {
+ t.Errorf("convertMsbLabel(%s, %s) => got %v, want %s", cas.label, cas.in, reflect.TypeOf(got), cas.want)
+ }
+ }
+ }
+
+}
diff --git a/msb2pilot/src/msb2pilot/models/msb.go b/msb2pilot/src/msb2pilot/models/msb.go
new file mode 100644
index 0000000..09418e7
--- /dev/null
+++ b/msb2pilot/src/msb2pilot/models/msb.go
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2018 ZTE Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * ZTE - initial Project
+ */
+package models
+
+type Protocol string
+
+const (
+ Protocol_UI Protocol = "UI"
+ Protocol_REST Protocol = "REST"
+ Protocol_HTTP Protocol = "HTTP"
+ Protocol_MQ Protocol = "MQ"
+ Protocol_FTP Protocol = "FTP"
+ Protocol_SNMP Protocol = "SNMP"
+ Protocol_TCP Protocol = "TCP"
+ Protocol_UDP Protocol = "UDP"
+)
+
+type BaseInfo struct {
+ Path string `json:"path",omitempty`
+ VisualRange string `json:"visualRange"`
+ AppVersion string `json:"appversion"`
+ PublishPort string `json:"publish_port"`
+ EnableSSL string `json:"enable_ssl",omitempty`
+ IsManual string `json:"is_manual"`
+ Protocol Protocol `json:"protocol"`
+ ServiceStatus string `json:"status,omitempty"`
+ Version string `json:"version"`
+ Url string `json:"url"`
+}
+
+type NameSpace struct {
+ NameSpace string `json:"namespace"`
+}
+
+type ConsulLabels struct {
+ NameSpace *NameSpace
+ BaseInfo *BaseInfo
+}
+
+type MsbService struct {
+ ConsulLabels *ConsulLabels
+ ServiceName string
+ ServiceAddress string
+ ServicePort int
+ ModifyIndex uint64
+}
+
+type PublishService struct {
+ ServiceName string `json:"serviceName"`
+ Version string `json:"version",omitempty`
+ PublishPort string `json:"publish_port",omitempty`
+ Protocol string `json:"protocol",omitempty`
+ NameSpace string `json:"namespace",omitempty`
+ PublishUrl string `json:"publish_url",omitempty`
+ PublishProtocol string `json:"publish_protocol",omitempty`
+}
diff --git a/msb2pilot/src/msb2pilot/util/common.go b/msb2pilot/src/msb2pilot/util/common.go
index 1bb10df..d46bb6f 100644
--- a/msb2pilot/src/msb2pilot/util/common.go
+++ b/msb2pilot/src/msb2pilot/util/common.go
@@ -19,6 +19,7 @@ import (
const (
ConfigPath = "conf"
+ PathSep = string(os.PathSeparator)
)
func GetCfgPath() string {