summaryrefslogtreecommitdiffstats
path: root/msb2pilot
diff options
context:
space:
mode:
Diffstat (limited to 'msb2pilot')
-rw-r--r--msb2pilot/src/msb2pilot/pilot/controller.go11
-rw-r--r--msb2pilot/src/msb2pilot/pilot/controller_test.go193
-rw-r--r--msb2pilot/src/msb2pilot/pilot/msb.go258
-rw-r--r--msb2pilot/src/msb2pilot/pilot/msb_test.go171
4 files changed, 428 insertions, 205 deletions
diff --git a/msb2pilot/src/msb2pilot/pilot/controller.go b/msb2pilot/src/msb2pilot/pilot/controller.go
index f0cf87d..bc79cc5 100644
--- a/msb2pilot/src/msb2pilot/pilot/controller.go
+++ b/msb2pilot/src/msb2pilot/pilot/controller.go
@@ -41,7 +41,7 @@ const (
[{}, {}] is error. {} {} is right
*/
func ParseParam(input string) ([]model.Config, error) {
- configs, _, err := crd.ParseInputs(input)
+ configs, _, err := crd.ParseInputsWithoutValidation(input)
return configs, err
}
@@ -66,12 +66,15 @@ func init() {
updateK8sAddress(configPath)
var err error
- client, err = crd.NewClient(configPath, model.ConfigDescriptor{
- model.RouteRule,
- model.DestinationPolicy,
+ client, err = crd.NewClient(configPath, "", model.ConfigDescriptor{
+ model.VirtualService,
model.DestinationRule,
}, "")
+ if err = client.RegisterResources(); err != nil {
+ log.Log.Error("failed to register custom resources.", err)
+ }
+
if err != nil {
log.Log.Error("fail to init crd", err)
}
diff --git a/msb2pilot/src/msb2pilot/pilot/controller_test.go b/msb2pilot/src/msb2pilot/pilot/controller_test.go
index d7fe7d9..3c01b44 100644
--- a/msb2pilot/src/msb2pilot/pilot/controller_test.go
+++ b/msb2pilot/src/msb2pilot/pilot/controller_test.go
@@ -13,14 +13,16 @@ package pilot
import (
"fmt"
- "msb2pilot/models"
- "os"
- "reflect"
+
+ // "fmt"
+ // "msb2pilot/models"
+ // "os"
+ // "reflect"
"testing"
)
func TestList(t *testing.T) {
- res, err := List("routerules", "default")
+ res, err := List("virtualservice", "default")
if err != nil {
t.Errorf("List() => got %v", err)
} else {
@@ -28,39 +30,162 @@ func TestList(t *testing.T) {
}
}
-func TestUpdateK8sAddress(t *testing.T) {
- cases := []struct {
- path, addr, want, err string
- }{
- {
- path: "k8s.yml222",
- addr: "filenoteexisttest",
- want: "",
- err: "*os.PathError",
- },
- {
- path: configPath,
- addr: "",
- want: "",
- err: "",
- },
+//func TestParseParam(t *testing.T) {
+// cases := []struct {
+// in string
+// }{
+// // {
+// // in: `{
+// //"apiVersion": "networking.istio.io/v1alpha3",
+// //"kind": "VirtualService",
+// //"metadata": {"name": "default-apigateway"},
+// //"spec": {"hosts":["apigateway"],"http":[{
+// //"match":{"uri": {"prefix": "/portaladmin"}},
+// //"rewrite": {"uri": "/portaladmin"},
+// //"route": [{"destination": {"host": "portaladmin"}}]
+// //},{
+// //"match":{"uri": {"prefix": "/pm_mgt/v1"}},
+// //"rewrite": {"uri": "/pm_mgt/v1"},
+// //"route": [{"destination": {"host": "pm_mgt"}}]
+// //}]}
+// //}`,
+// // },
+// {
+// in: `{
+//"apiVersion": "networking.istio.io/v1alpha3",
+//"kind": "VirtualService",
+//"metadata": {"name": "default-apigateway"},
+//"spec": {"destination":{"service":"reviews.service.consul"},"http":[{
+//"match":{"uri": {"prefix": "/portaladmin"}},
+//"rewrite": {"uri": "/portaladmin"},
+//}]}
+//}`,
+// },
+// {
+// in: `{
+//"apiVersion": "networking.istio.io/v1alpha3",
+//"kind": "VirtualService",
+//"metadata": {"name": "default-apigateway"},
+//"spec": {"hosts":["test"],"http":[]}
+//}`,
+// },
+// }
+
+// for _, cas := range cases {
+// res, err := ParseParam(cas.in)
+// if err != nil {
+// t.Errorf("ParseParam() => got %v", err)
+// } else {
+// fmt.Print(res)
+// }
+// }
+//}
+
+func TestCreate(t *testing.T) {
+ str := `
{
- path: configPath,
- addr: "k8stest",
- want: "k8stest",
- err: "",
- },
+ "apiVersion": "networking.istio.io/v1alpha3",
+ "kind": "VirtualService",
+ "metadata":{
+ "name": "reviews"},
+ "spec":{
+ "hosts":["reviews.service.consul"],
+ "http":[{
+ "match":[{"uri": {"prefix": "/pm_mgt/v1"}}],
+ "rewrite": {"uri": "/portaladmin"},
+ "route":[{
+ "destination":{
+ "host": "reviews.service.consul",
+ "subset": "v3"
+ }}]
+ }]
+ }
+ }
+ `
+
+ config, exist := Get("virtualservice", "default", "reviews")
+ if exist {
+ Delete("virtualservice", "default", "reviews")
+ }
+ configs, err := ParseParam(str)
+ if err != nil {
+ t.Errorf("ParseParam() => got %v", err)
+ } else {
+ fmt.Println(configs)
}
- oldEnv := os.Getenv(models.EnvK8sAddress)
- for _, cas := range cases {
- os.Unsetenv(models.EnvK8sAddress)
- os.Setenv(models.EnvK8sAddress, cas.addr)
+ res, err := Create(&configs[0])
+ if err != nil {
+ t.Errorf("Create() => got %v", err)
+ } else {
+ fmt.Println(res)
+ }
- got, err := updateK8sAddress(cas.path)
- if got != cas.want || (err != nil && reflect.TypeOf(err).String() != cas.err) {
- t.Errorf("updateK8sAddress(%s, %s) => got %s %v, want %s", cas.path, cas.addr, got, reflect.TypeOf(err), cas.want)
- }
+ if exist {
+ Create(config)
}
- os.Setenv(models.EnvK8sAddress, oldEnv)
}
+
+//func TestParseParam(t *testing.T) {
+// str := `
+// {
+// "apiVersion": "networking.istio.io/v1alpha3",
+// "kind": "VirtualService",
+// "metadata":{
+// "name": "reviews"},
+// "spec":{
+// "hosts":["reviews.service.consul"],
+// "http":[{
+// "route":[{
+// "destination":{
+// "host": "reviews.service.consul",
+// "subset": "v3"
+// }}]
+// }]
+// }
+// }
+// `
+// res, err := ParseParam(str)
+// if err != nil {
+// t.Errorf("ParseParam() => got %v", err)
+// } else {
+// fmt.Println(res)
+// }
+//}
+
+//func TestUpdateK8sAddress(t *testing.T) {
+// cases := []struct {
+// path, addr, want, err string
+// }{
+// {
+// path: "k8s.yml222",
+// addr: "filenoteexisttest",
+// want: "",
+// err: "*os.PathError",
+// },
+// {
+// path: configPath,
+// addr: "",
+// want: "",
+// err: "",
+// },
+// {
+// path: configPath,
+// addr: "k8stest",
+// want: "k8stest",
+// err: "",
+// },
+// }
+
+// oldEnv := os.Getenv(models.EnvK8sAddress)
+// for _, cas := range cases {
+// os.Unsetenv(models.EnvK8sAddress)
+// os.Setenv(models.EnvK8sAddress, cas.addr)
+
+// got, err := updateK8sAddress(cas.path)
+// if got != cas.want || (err != nil && reflect.TypeOf(err).String() != cas.err) {
+// t.Errorf("updateK8sAddress(%s, %s) => got %s %v, want %s", cas.path, cas.addr, got, reflect.TypeOf(err), cas.want)
+// }
+// }
+// os.Setenv(models.EnvK8sAddress, oldEnv)
+//}
diff --git a/msb2pilot/src/msb2pilot/pilot/msb.go b/msb2pilot/src/msb2pilot/pilot/msb.go
index fb87d08..875715e 100644
--- a/msb2pilot/src/msb2pilot/pilot/msb.go
+++ b/msb2pilot/src/msb2pilot/pilot/msb.go
@@ -17,8 +17,6 @@ import (
"msb2pilot/models"
"msb2pilot/msb"
"os"
- "regexp"
- "strings"
istioModel "istio.io/istio/pilot/pkg/model"
)
@@ -28,64 +26,59 @@ var (
)
const (
- routerulePrefix = "msbcustom."
+ defaultVirtualService = "default-apigateway"
)
func SyncMsbData(newServices []*models.MsbService) {
- if len(cachedServices) == 0 {
- deleteAllMsbRules()
- }
log.Log.Debug("sync msb rewrite rule to pilot")
- createServices, updateServices, deleteServices := compareServices(cachedServices, newServices)
-
- saveService(OperationCreate, createServices)
- saveService(OperationUpdate, updateServices)
- saveService(OperationDelete, deleteServices)
- cachedServices = newServices
-}
-
-func saveService(operation Operation, services []*models.MsbService) {
- if len(services) == 0 {
- log.Log.Debug("0 services need to %s. \n", operation)
+ serviceUpdated := isUpdated(cachedServices, newServices)
+ if !serviceUpdated { // no service updated
return
}
- configs, err := parseServiceToConfig(services)
- if err != nil {
- log.Log.Error("param parse error", err)
- return
- }
- fails := Save(operation, configs)
- log.Log.Debug("%d services %d rules need to %s, %d fails. \n", len(services), len(configs), operation, len(fails))
-}
+ log.Log.Debug("service updated")
-func deleteAllMsbRules() {
- log.Log.Informational("delete all msb rules")
- configs, err := List("routerules", "")
+ apiGateway := os.Getenv(models.EnvApiGatewayName)
+ publishServices := getPublishServiceMap()
+ virtueServiceString := parseServiceToConfig(apiGateway, newServices, publishServices)
+ log.Log.Debug(virtueServiceString)
+ configs, err := ParseParam(virtueServiceString)
if err != nil {
- log.Log.Error("fail to load rule list", err)
+ log.Log.Error("param parse error", err)
return
}
- deleteList := msbRuleFilter(configs)
- failed := Save(OperationDelete, deleteList)
- log.Log.Debug("deleteAllMsbRules total %d rules, fail %d", len(configs), len(failed))
+ updateVirtualService(newServices, configs)
}
-func msbRuleFilter(configs []istioModel.Config) []istioModel.Config {
- res := make([]istioModel.Config, 0, len(configs))
-
- for _, config := range configs {
- if strings.HasPrefix(config.Name, routerulePrefix) {
- res = append(res, config)
+func updateVirtualService(newServices []*models.MsbService, configs []istioModel.Config) {
+ // if virtualservice exist, then delete it
+ config, exist := Get("virtualservice", "default", defaultVirtualService)
+ if exist {
+ log.Log.Informational("default virtual is: %v", config)
+ err := Delete("virtualservice", "default", defaultVirtualService)
+ if err != nil {
+ log.Log.Debug("failed to delete virture service %v \n", err)
+ return
}
}
- return res
+ if len(newServices) == 0 {
+ cachedServices = newServices
+ return
+ }
+
+ fails := Save(OperationCreate, configs)
+ if len(fails) != 0 {
+ log.Log.Debug("failed to create virture service %v \n", fails)
+ return
+ } else {
+ cachedServices = newServices
+ }
}
-func compareServices(oldServices, newServices []*models.MsbService) (createServices, updateServices, deleteServices []*models.MsbService) {
+func isUpdated(oldServices, newServices []*models.MsbService) bool {
oldServiceMap := toServiceMap(oldServices)
newServiceMap := toServiceMap(newServices)
@@ -93,21 +86,22 @@ func compareServices(oldServices, newServices []*models.MsbService) (createServi
if oldService, exist := oldServiceMap[key]; exist {
// service exist: check whether need to update
if oldService.ModifyIndex != newService.ModifyIndex {
- updateServices = append(updateServices, newService)
+ // service updated
+ return true
}
} else {
- // service not exist: add
- createServices = append(createServices, newService)
+ // old service not exist: add
+ return true
}
delete(oldServiceMap, key)
}
- for _, service := range oldServiceMap {
- deleteServices = append(deleteServices, service)
+ if len(oldServiceMap) != 0 { // some service has been deleted
+ return true
}
- return
+ return false
}
func toServiceMap(services []*models.MsbService) map[string]*models.MsbService {
@@ -120,20 +114,39 @@ func toServiceMap(services []*models.MsbService) map[string]*models.MsbService {
return serviceMap
}
-func parseServiceToConfig(services []*models.MsbService) ([]istioModel.Config, error) {
- publishServices := getPublishServiceMap()
- apiGateway := os.Getenv(models.EnvApiGatewayName)
+func parseServiceToConfig(host string, services []*models.MsbService, publishServices map[string]*models.PublishService) string {
+ httpRoutes := getAllHttpRoute(services, publishServices)
+
+ rule := `{
+"apiVersion": "networking.istio.io/v1alpha3",
+"kind": "VirtualService",
+"metadata": {"name": "` + defaultVirtualService + `"},
+"spec": {"hosts":["` + host + `"],"http":[` + httpRoutes + `]}
+}`
+
+ return rule
+}
+
+func getAllHttpRoute(services []*models.MsbService, publishServices map[string]*models.PublishService) string {
var buf bytes.Buffer
+ hasPre := false
for _, service := range services {
if publishService, exist := publishServices[getPublishServiceKey(service)]; exist {
if service.ConsulLabels.BaseInfo != nil {
- rule := createRouteRule(apiGateway, publishService.PublishUrl, service.ServiceName, service.ConsulLabels.BaseInfo.Url)
+ if hasPre {
+ buf.WriteString(",")
+ }
+
+ rule := createHttpRoute(publishService.PublishUrl, service.ServiceName, service.ConsulLabels.BaseInfo.Url)
buf.WriteString(rule)
+
+ hasPre = true
}
}
}
- return ParseParam(buf.String())
+
+ return buf.String()
}
func getPublishServiceKey(svc *models.MsbService) string {
@@ -163,51 +176,118 @@ func getPublishServiceMap() map[string]*models.PublishService {
return res
}
-func createRouteRule(sourceService, sourcePath, targetService, targetPath string) string {
+//func createRouteRule(sourceService, sourcePath, targetService, targetPath string) string {
+// if sourcePath == "" {
+// sourcePath = "/"
+// }
+// if targetPath == "" {
+// targetPath = "/"
+// }
+// // rule name must consist of lower case alphanuberic charactoers, '-' or '.'. and must start and end with an alphanumberic charactore
+// r := regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*")
+// strs := r.FindAllString(targetService, -1)
+// name := routerulePrefix + strings.Join(strs, "")
+// name = strings.ToLower(name)
+
+// rule := `{
+//"apiVersion": "config.istio.io/v1alpha2",
+//"kind": "RouteRule",
+//"metadata": {
+// "name": "` + name + `"
+//},
+//"spec": {
+// "destination":{
+// "name":"` + sourceService + `"
+// },
+// "match":{
+// "request":{
+// "headers": {
+// "uri": {
+// "prefix": "` + sourcePath + `"
+// }
+// }
+// }
+// },
+// "rewrite": {
+// "uri": "` + targetPath + `"
+// },
+// "route":[
+// {
+// "destination":{
+// "name":"` + targetService + `"
+// }
+// }
+// ]
+//}
+//}
+
+//`
+// return rule
+//}
+
+//func createRouteRule(sourceService, sourcePath, targetService, targetPath string) string {
+// if sourcePath == "" {
+// sourcePath = "/"
+// }
+// if targetPath == "" {
+// targetPath = "/"
+// }
+
+// rule := `
+//apiVersion: networking.istio.io/v1alpha3
+//kind: VirtualService
+//metadata:
+// name: default-apigateway
+//spec:
+// hosts:
+// - reviews
+// http:
+// - match:
+// - headers:
+// end-user:
+// exact: jason
+// route:
+// - destination:
+// host: reviews
+// - route:
+// - destination:
+// host: reviews
+// `
+// return rule
+//}
+
+func createHttpRoute(sourcePath, targetHost, targetPath string) string {
+ // - match:
+ // - uri:
+ // prefix: /ratings
+ // rewrite:
+ // uri: /v1/bookRatings
+ // route:
+ // - destination:
+ // host: ratings.prod.svc.cluster.local
+ // subset: v1
+
if sourcePath == "" {
sourcePath = "/"
}
if targetPath == "" {
targetPath = "/"
}
- // rule name must consist of lower case alphanuberic charactoers, '-' or '.'. and must start and end with an alphanumberic charactore
- r := regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*")
- strs := r.FindAllString(targetService, -1)
- name := routerulePrefix + strings.Join(strs, "")
- name = strings.ToLower(name)
- rule := `{
-"apiVersion": "config.istio.io/v1alpha2",
-"kind": "RouteRule",
-"metadata": {
- "name": "` + name + `"
-},
-"spec": {
- "destination":{
- "name":"` + sourceService + `"
- },
- "match":{
- "request":{
- "headers": {
- "uri": {
- "prefix": "` + sourcePath + `"
- }
- }
- }
- },
- "rewrite": {
- "uri": "` + targetPath + `"
- },
- "route":[
- {
- "destination":{
- "name":"` + targetService + `"
- }
- }
- ]
-}
+ httpRoute := `{
+"match":[{"uri": {"prefix": "` + sourcePath + `"}}],
+"rewrite": {"uri": "` + targetPath + `"},
+"route": [` + createDestinationWeight(targetHost) + `]
+}`
+
+ return httpRoute
}
-`
- return rule
+func createDestinationWeight(targetHost string) string {
+ // destination:
+ // host: reviews.prod.svc.cluster.local
+ // subset: v2
+ // weight: 25
+
+ return `{"destination": {"host": "` + targetHost + `"}}`
}
diff --git a/msb2pilot/src/msb2pilot/pilot/msb_test.go b/msb2pilot/src/msb2pilot/pilot/msb_test.go
index e3cf7ad..ca5e84f 100644
--- a/msb2pilot/src/msb2pilot/pilot/msb_test.go
+++ b/msb2pilot/src/msb2pilot/pilot/msb_test.go
@@ -12,97 +12,112 @@
package pilot
import (
+ "msb2pilot/models"
"testing"
)
-func TestCreateRouteRule(t *testing.T) {
+func TestParseServiceToConfig(t *testing.T) {
cases := []struct {
- sService, sPath, tService, tPath, want string
+ services []*models.MsbService
+ publishServices map[string]*models.PublishService
+ want string
}{
- { // success demo
- sService: "sservice",
- sPath: "/",
- tService: "tservice",
- tPath: "/",
+ {
+ services: []*models.MsbService{},
+ publishServices: map[string]*models.PublishService{},
want: `{
-"apiVersion": "config.istio.io/v1alpha2",
-"kind": "RouteRule",
-"metadata": {
- "name": "msbcustom.tservice"
-},
-"spec": {
- "destination":{
- "name":"sservice"
- },
- "match":{
- "request":{
- "headers": {
- "uri": {
- "prefix": "/"
- }
- }
- }
- },
- "rewrite": {
- "uri": "/"
- },
- "route":[
- {
- "destination":{
- "name":"tservice"
- }
- }
- ]
-}
-}
-
-`,
+"apiVersion": "networking.istio.io/v1alpha3",
+"kind": "VirtualService",
+"metadata": {"name": "default-apigateway"},
+"spec": {"hosts":["tService"],"http":[]}
+}`,
},
- { // rule name must consist of lower case alphanuberic charactoers, '-' or '.'. and must start and end with an alphanumberic charactore
- sService: "sservice",
- sPath: "/",
- tService: "123ABCrule-name.test~!@#$%^&*()_+321",
- tPath: "/",
+ {
+ services: []*models.MsbService{
+ &models.MsbService{
+ ConsulLabels: &models.ConsulLabels{
+ NameSpace: &models.NameSpace{
+ NameSpace: "service1namespace",
+ },
+ BaseInfo: &models.BaseInfo{
+ Version: "service1v1",
+ Url: "service1url",
+ },
+ },
+ ServiceName: "service1",
+ },
+ &models.MsbService{
+ ConsulLabels: &models.ConsulLabels{
+ NameSpace: &models.NameSpace{
+ NameSpace: "service2namespace",
+ },
+ BaseInfo: &models.BaseInfo{
+ Version: "service2v2",
+ Url: "service2url",
+ },
+ },
+ ServiceName: "service2",
+ },
+ },
+ publishServices: map[string]*models.PublishService{
+ "service1service1v1service1namespace": &models.PublishService{
+ ServiceName: "service1",
+ Version: "service1v1",
+ NameSpace: "service1namespace",
+ PublishUrl: "service1publishurl",
+ },
+ "service2service2v2service2namespace": &models.PublishService{
+ ServiceName: "service2",
+ Version: "service2v2",
+ NameSpace: "service2namespace",
+ PublishUrl: "service2publihurl",
+ },
+ },
want: `{
-"apiVersion": "config.istio.io/v1alpha2",
-"kind": "RouteRule",
-"metadata": {
- "name": "msbcustom.123rule-name.test321"
-},
-"spec": {
- "destination":{
- "name":"sservice"
- },
- "match":{
- "request":{
- "headers": {
- "uri": {
- "prefix": "/"
- }
- }
- }
- },
- "rewrite": {
- "uri": "/"
- },
- "route":[
- {
- "destination":{
- "name":"123ABCrule-name.test~!@#$%^&*()_+321"
- }
- }
- ]
-}
-}
-
-`,
+"apiVersion": "networking.istio.io/v1alpha3",
+"kind": "VirtualService",
+"metadata": {"name": "default-apigateway"},
+"spec": {"hosts":["tService"],"http":[{
+"match":{"uri": {"prefix": "service1publishurl"}},
+"rewrite": {"uri": "service1url"},
+"route": [{"destination": {"host": "service1"}}]
+},{
+"match":{"uri": {"prefix": "service2publihurl"}},
+"rewrite": {"uri": "service2url"},
+"route": [{"destination": {"host": "service2"}}]
+}]}
+}`,
},
}
for _, cas := range cases {
- got := createRouteRule(cas.sService, cas.sPath, cas.tService, cas.tPath)
+ got := parseServiceToConfig("tService", cas.services, cas.publishServices)
if got != cas.want {
- t.Errorf("createRouteRule(%s, %s, %s, %s) => got %s, want %s", cas.sService, cas.sPath, cas.tService, cas.tPath, got, cas.want)
+ t.Errorf("parseServiceToConfig() => got %s, want %s", got, cas.want)
}
}
}
+
+//func TestCreateHttpRoute(t *testing.T) {
+// cases := []struct {
+// sPath, tService, tPath, want string
+// }{
+// { // success demo
+// sPath: "/",
+// tService: "tService",
+// tPath: "/",
+// want: `{
+//"match":{"uri": {"prefix": "/"}},
+//"rewrite": {"uri": "/"},
+//"route": [{"destination": {"host": "tService"}}]
+//}`,
+// },
+// }
+
+// for _, cas := range cases {
+// got := createHttpRoute(cas.sPath, cas.tService, cas.tPath)
+// if got != cas.want {
+// t.Errorf("createHttpRoute(%s, %s, %s) => got %s, want %s", cas.sPath, cas.tService, cas.tPath, got, cas.want)
+// }
+// }
+//}