Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KIALI-619 Add route rule appender #179

Merged
merged 1 commit into from Apr 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions graph/appender/circuit_breaker.go
Expand Up @@ -22,17 +22,17 @@ func (a CircuitBreakerAppender) AppendGraph(trees *[]tree.ServiceNode, namespace

func applyCircuitBreakers(n *tree.ServiceNode, namespaceName string, istioClient *kubernetes.IstioClient) {
// determine if there is a circuit breaker on this node
istioDetails, err := istioClient.GetIstioDetails(namespaceName, strings.Split(n.Name, ".")[0])
destinationPolicies, err := istioClient.GetDestinationPolicies(namespaceName, strings.Split(n.Name, ".")[0])
if err == nil {
if istioDetails.DestinationPolicies != nil {
if destinationPolicies != nil {
dps := make(models.DestinationPolicies, 0)
dps.Parse(istioDetails.DestinationPolicies)
dps.Parse(destinationPolicies)
for _, dp := range dps {
if dp.CircuitBreaker != nil {
if d, ok := dp.Destination.(map[string]interface{}); ok {
if labels, ok2 := d["labels"].(map[string]interface{}); ok2 {
if labels["version"] == n.Version {
n.Metadata["isCircuitBreaker"] = "true"
n.Metadata["hasCircuitBreaker"] = "true"
break // no need to keep going, we know it has at least one CB policy
}
}
Expand All @@ -42,7 +42,7 @@ func applyCircuitBreakers(n *tree.ServiceNode, namespaceName string, istioClient
}
} else {
log.Warningf("Cannot determine if service [%v:%v] has circuit breakers: %v", namespaceName, n.Name, err)
n.Metadata["isCircuitBreaker"] = "unknown"
n.Metadata["hasCircuitBreaker"] = "unknown"
}

for _, child := range n.Children {
Expand Down
54 changes: 54 additions & 0 deletions graph/appender/route_rule.go
@@ -0,0 +1,54 @@
package appender

import (
"strings"

"github.com/kiali/kiali/graph/tree"
"github.com/kiali/kiali/kubernetes"
"github.com/kiali/kiali/log"
"github.com/kiali/kiali/services/models"
)

type RouteRuleAppender struct{}

func (a RouteRuleAppender) AppendGraph(trees *[]tree.ServiceNode, namespaceName string) {
istioClient, err := kubernetes.NewClient()
checkError(err)

for _, tree := range *trees {
applyRouteRules(&tree, namespaceName, istioClient)
}
}

func applyRouteRules(n *tree.ServiceNode, namespaceName string, istioClient *kubernetes.IstioClient) {
// determine if there is a route rule on this node
routeRules, err := istioClient.GetRouteRules(namespaceName, strings.Split(n.Name, ".")[0])
if err == nil {
if routeRules != nil {
rrs := make(models.RouteRules, 0)
rrs.Parse(routeRules)
Found:
for _, rr := range rrs {
if routeMaps, ok := rr.Route.([]interface{}); ok {
for _, routeMap := range routeMaps {
if rm, ok2 := routeMap.(map[string]interface{}); ok2 {
if labels, ok3 := rm["labels"].(map[string]interface{}); ok3 {
if labels["version"] == n.Version {
n.Metadata["hasRouteRule"] = "true"
break Found // no need to keep going, we know it has at least one RouteRule
}
}
}
}
}
}
}
} else {
log.Warningf("Cannot determine if service [%v:%v] has route rules: %v", namespaceName, n.Name, err)
n.Metadata["hasRouteRule"] = "unknown"
}

for _, child := range n.Children {
applyRouteRules(child, namespaceName, istioClient)
}
}
34 changes: 20 additions & 14 deletions graph/cytoscape/cytoscape.go
Expand Up @@ -30,17 +30,18 @@ type NodeData struct {
Parent string `json:"parent,omitempty"` // Compound Node parent ID

// App Fields (not required by Cytoscape)
Service string `json:"service"`
Version string `json:"version,omitempty"`
Rate string `json:"rate,omitempty"` // edge aggregate
Rate3xx string `json:"rate3XX,omitempty"` // edge aggregate
Rate4xx string `json:"rate4XX,omitempty"` // edge aggregate
Rate5xx string `json:"rate5XX,omitempty"` // edge aggregate
IsCircuitBreaker string `json:"isCircuitBreaker,omitempty"` // true | false | unknown
IsGroup string `json:"isGroup,omitempty"` // set to the grouping type, current values: [ 'version' ]
IsRoot string `json:"isRoot,omitempty"` // true | false
IsSelfInvoke string `json:"isSelfInvoke,omitempty"` // rate of selfInvoke
IsUnused string `json:"isUnused,omitempty"` // true | false
Service string `json:"service"`
Version string `json:"version,omitempty"`
Rate string `json:"rate,omitempty"` // edge aggregate
Rate3xx string `json:"rate3XX,omitempty"` // edge aggregate
Rate4xx string `json:"rate4XX,omitempty"` // edge aggregate
Rate5xx string `json:"rate5XX,omitempty"` // edge aggregate
RateSelfInvoke string `json:"rateSelfInvoke,omitempty"` // rate of selfInvoke
HasCircuitBreaker string `json:"hasCB,omitempty"` // true | false | unknown
HasRouteRule string `json:"hasRR,omitempty"` // true | false | unknown
IsGroup string `json:"isGroup,omitempty"` // set to the grouping type, current values: [ 'version' ]
IsRoot string `json:"isRoot,omitempty"` // true | false
IsUnused string `json:"isUnused,omitempty"` // true | false
}

type EdgeData struct {
Expand Down Expand Up @@ -157,8 +158,13 @@ func walk(sn *tree.ServiceNode, nodes *[]*NodeWrapper, edges *[]*EdgeWrapper, pa
}

// node may have a circuit breaker
if cb, ok := sn.Metadata["isCircuitBreaker"]; ok {
nd.IsCircuitBreaker = cb.(string)
if cb, ok := sn.Metadata["hasCircuitBreaker"]; ok {
nd.HasCircuitBreaker = cb.(string)
}

// node may have a route rule
if cb, ok := sn.Metadata["hasRouteRule"]; ok {
nd.HasRouteRule = cb.(string)
}

nw := NodeWrapper{
Expand All @@ -171,7 +177,7 @@ func walk(sn *tree.ServiceNode, nodes *[]*NodeWrapper, edges *[]*EdgeWrapper, pa
//TODO If we can find a graph layout that handles loop edges well then
// we can go back to allowing these but for now, flag the node text
if parentNodeId == nd.Id {
nd.IsSelfInvoke = fmt.Sprintf("%.3f", sn.Metadata["rate"].(float64))
nd.RateSelfInvoke = fmt.Sprintf("%.3f", sn.Metadata["rate"].(float64))
} else {
edgeId := fmt.Sprintf("e%v", *edgeIdSequence)
*edgeIdSequence++
Expand Down
3 changes: 3 additions & 0 deletions graph/options/options.go
Expand Up @@ -93,5 +93,8 @@ func parseAppenders(params url.Values) []appender.Appender {
if csl == all || strings.Contains(csl, "circuit_breaker") {
appenders = append(appenders, appender.CircuitBreakerAppender{})
}
if csl == all || strings.Contains(csl, "route_rule") {
appenders = append(appenders, appender.RouteRuleAppender{})
}
return appenders
}
3 changes: 0 additions & 3 deletions handlers/graph.go
Expand Up @@ -159,7 +159,6 @@ func buildNamespaceTree(sn *tree.ServiceNode, start time.Time, seenNodes map[str
i := 0
for k, d := range destinations {
s := strings.Split(k, " ")
// d["link_prom_graph"] = linkPromGraph(client.Address(), o.Metric, s[0], s[1])
child := tree.NewServiceNode(s[0], s[1])
child.Parent = sn
child.Metadata = d
Expand Down Expand Up @@ -246,7 +245,6 @@ func buildServiceTrees(o options.Options, client *prometheus.Client) (trees []tr
rootService := string(sourceSvc)
rootVersion := string(sourceVer)
md := make(map[string]interface{})
// md["link_prom_graph"] = linkPromGraph(client.Address(), o.Metric, rootService, rootVersion)

root := tree.NewServiceNode(rootService, rootVersion)
root.Parent = nil
Expand Down Expand Up @@ -291,7 +289,6 @@ func buildServiceSubtree(sn *tree.ServiceNode, destinationSvc string, queryTime
i := 0
for k, d := range destinations {
s := strings.Split(k, " ")
// d["link_prom_graph"] = linkPromGraph(client.Address(), o.Metric, s[0], s[1])
child := tree.NewServiceNode(s[0], s[1])
child.Parent = sn
child.Metadata = d
Expand Down
6 changes: 3 additions & 3 deletions handlers/testdata/test_namespace_graph.expected
Expand Up @@ -27,7 +27,7 @@
"service": "productpage.istio-system.svc.cluster.local",
"version": "v1",
"rate": "150.000",
"isSelfInvoke": "20.000"
"rateSelfInvoke": "20.000"
}
},
{
Expand Down Expand Up @@ -61,7 +61,7 @@
"service": "reviews.istio-system.svc.cluster.local",
"version": "v2",
"rate": "20.000",
"isSelfInvoke": "20.000"
"rateSelfInvoke": "20.000"
}
},
{
Expand All @@ -71,7 +71,7 @@
"service": "reviews.istio-system.svc.cluster.local",
"version": "v3",
"rate": "20.000",
"isSelfInvoke": "20.000"
"rateSelfInvoke": "20.000"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions handlers/testdata/test_service_graph.expected
Expand Up @@ -40,7 +40,7 @@
"service": "reviews.istio-system.svc.cluster.local",
"version": "v2",
"rate": "20.000",
"isSelfInvoke": "20.000"
"rateSelfInvoke": "20.000"
}
},
{
Expand All @@ -50,7 +50,7 @@
"service": "reviews.istio-system.svc.cluster.local",
"version": "v3",
"rate": "20.000",
"isSelfInvoke": "20.000"
"rateSelfInvoke": "20.000"
}
}
],
Expand Down
16 changes: 8 additions & 8 deletions kubernetes/istio_details_service.go
Expand Up @@ -17,22 +17,22 @@ func (in *IstioClient) GetIstioDetails(namespace string, serviceName string) (*I

go func() {
defer wg.Done()
routeRules, routeRulesErr = in.getRouteRules(namespace, serviceName)
routeRules, routeRulesErr = in.GetRouteRules(namespace, serviceName)
}()

go func() {
defer wg.Done()
destinationPolicies, destinationPoliciesErr = in.getDestinationPolicies(namespace, serviceName)
destinationPolicies, destinationPoliciesErr = in.GetDestinationPolicies(namespace, serviceName)
}()

go func() {
defer wg.Done()
virtualServices, virtualServicesErr = in.getVirtualServices(namespace, serviceName)
virtualServices, virtualServicesErr = in.GetVirtualServices(namespace, serviceName)
}()

go func() {
defer wg.Done()
destinationRules, destinationRulesErr = in.getDestinationRules(namespace, serviceName)
destinationRules, destinationRulesErr = in.GetDestinationRules(namespace, serviceName)
}()

wg.Wait()
Expand Down Expand Up @@ -62,7 +62,7 @@ func (in *IstioClient) GetIstioDetails(namespace string, serviceName string) (*I
return &istioDetails, nil
}

func (in *IstioClient) getRouteRules(namespace string, serviceName string) ([]IstioObject, error) {
func (in *IstioClient) GetRouteRules(namespace string, serviceName string) ([]IstioObject, error) {
result, err := in.istioConfigApi.Get().Namespace(namespace).Resource(routeRules).Do().Get()
if err != nil {
return nil, err
Expand All @@ -86,7 +86,7 @@ func (in *IstioClient) getRouteRules(namespace string, serviceName string) ([]Is
return routerRules, nil
}

func (in *IstioClient) getDestinationPolicies(namespace string, serviceName string) ([]IstioObject, error) {
func (in *IstioClient) GetDestinationPolicies(namespace string, serviceName string) ([]IstioObject, error) {
result, err := in.istioConfigApi.Get().Namespace(namespace).Resource(destinationPolicies).Do().Get()
if err != nil {
return nil, err
Expand All @@ -110,7 +110,7 @@ func (in *IstioClient) getDestinationPolicies(namespace string, serviceName stri
return destinationPolicies, nil
}

func (in *IstioClient) getVirtualServices(namespace string, serviceName string) ([]IstioObject, error) {
func (in *IstioClient) GetVirtualServices(namespace string, serviceName string) ([]IstioObject, error) {
result, err := in.istioNetworkingApi.Get().Namespace(namespace).Resource(virtualServices).Do().Get()
if err != nil {
return nil, err
Expand Down Expand Up @@ -138,7 +138,7 @@ func (in *IstioClient) getVirtualServices(namespace string, serviceName string)
return virtualServices, nil
}

func (in *IstioClient) getDestinationRules(namespace string, serviceName string) ([]IstioObject, error) {
func (in *IstioClient) GetDestinationRules(namespace string, serviceName string) ([]IstioObject, error) {
result, err := in.istioNetworkingApi.Get().Namespace(namespace).Resource(destinationRules).Do().Get()
if err != nil {
return nil, err
Expand Down