Bläddra i källkod

basic spec relations

sunguroku 5 år sedan
förälder
incheckning
534d44b7f4

+ 71 - 11
internal/helm/grapher/relation.go

@@ -166,25 +166,85 @@ func (parsed *ParsedObjs) GetLabelRel() {
 // GetSpecRel draws relationships between two objects that are tied via various fields in their spec.
 func (parsed *ParsedObjs) GetSpecRel() {
 	for i, o := range parsed.Objects {
+		tid := []int{}
 		switch o.Kind {
 		case "ClusterRoleBinding", "RoleBinding":
-			tid := parsed.findRBACTargets(o.ID, o.RawYAML)
-			rels := o.Relations.SpecRels
-			for _, id := range tid {
-				newrel := SpecRel{
-					Relation{
-						Source: o.ID,
-						Target: id,
-					},
-				}
-				rels = append(rels, newrel)
+			tid = parsed.findRBACTargets(o.ID, o.RawYAML)
+		case "Ingress":
+			// service and resource are mutually exclusive backend types.
+			kind := "Service"
+			name := getField(o.RawYAML, "spec", "rules", "http", "paths", "backend", "service", "name")
+			if name == nil {
+				name = getField(o.RawYAML, "spec", "rules", "http", "paths", "backend", "resource", "name")
+				kind = getField(o.RawYAML, "spec", "rules", "http", "paths", "backend", "resource", "kind").(string)
+			}
+			tid = parsed.findObjectByNameAndKind(o.ID, name.(string), kind)
+		case "StatefulSet":
+			serviceName := getField(o.RawYAML, "spec", "serviceName").(string)
+			tid = append(tid, parsed.findObjectByNameAndKind(o.ID, serviceName, "Service")...)
+		case "Pod":
+			volume := getField(o.RawYAML, "spec", "volumes")
+			imageSecrets := getField(o.RawYAML, "spec", "ImagePullSecrets")
+			serviceAccount := getField(o.RawYAML, "spec", "serviceaccountname")
+
+			tid = append(tid, parsed.findObjectByNameAndKind(o.ID, imageSecrets, "Secret")...)
+			tid = append(tid, parsed.findObjectByNameAndKind(o.ID, serviceAccount, "ServiceAccount")...)
+
+			for _, v := range volume.([]interface{}) {
+				vt := v.(map[string]interface{})
+				configMap := getField(vt, "configMap", "name")
+				pvc := getField(vt, "persistentVolumeClaim", "claimName")
+				secret := getField(vt, "secret", "secretName")
+
+				tid = append(tid, parsed.findObjectByNameAndKind(o.ID, configMap.(string), "ConfigMap")...)
+				tid = append(tid, parsed.findObjectByNameAndKind(o.ID, pvc.(string), "PersistentVolumeClaim")...)
+				tid = append(tid, parsed.findObjectByNameAndKind(o.ID, secret.(string), "Secret")...)
+			}
+		}
+
+		// Add edges to parent
+		rels := o.Relations.SpecRels
+		for _, id := range tid {
+			newrel := SpecRel{
+				Relation{
+					Source: o.ID,
+					Target: id,
+				},
 			}
-			parsed.Objects[i].Relations.SpecRels = rels
+			rels = append(rels, newrel)
 		}
+		parsed.Objects[i].Relations.SpecRels = rels
+
 	}
 }
 
 // SpecRel helpers
+func (parsed *ParsedObjs) findObjectByNameAndKind(parentID int, name interface{}, kind string) []int {
+	targets := []int{}
+
+	if name == nil {
+		return targets
+	}
+
+	name = name.(string)
+	for i, o := range parsed.Objects {
+		newrel := SpecRel{
+			Relation{
+				Source: parentID,
+				Target: o.ID,
+			},
+		}
+
+		if o.Name == name && o.Kind == kind {
+			// Add bidirectional link from children as well.
+			parsed.Objects[i].Relations.SpecRels = append(parsed.Objects[i].Relations.SpecRels, newrel)
+			targets = append(targets, o.ID)
+			return targets
+		}
+	}
+	return targets
+}
+
 func (parsed *ParsedObjs) findRBACTargets(parentID int, yaml map[string]interface{}) []int {
 	roleRef := getField(yaml, "roleRef")
 	subjects := getField(yaml, "subjects")

+ 52 - 0
internal/helm/grapher/relation_test.go

@@ -224,3 +224,55 @@ func TestLabelRels(t *testing.T) {
 
 	}
 }
+
+func TestSpecRels(t *testing.T) {
+	ts := []test{
+		test{
+			Expected: expControlRels1,
+			FilePath: "./test_yaml/cassandra.yaml",
+		},
+	}
+
+	for _, r := range ts {
+		// Load in yaml from test files
+		file, err := ioutil.ReadFile(r.FilePath)
+
+		if err != nil {
+			t.Errorf("Error reading file %s", r.FilePath)
+		}
+
+		yamlArr := grapher.ImportMultiDocYAML(file)
+		objects := grapher.ParseObjs(yamlArr)
+		parsed := grapher.ParsedObjs{
+			Objects: objects,
+		}
+
+		parsed.GetControlRel()
+		parsed.GetSpecRel()
+
+		t.Errorf("ok")
+
+		// for i, o := range parsed.Objects {
+		// 	e := r.Expected[i]
+		// 	if len(e.Relations.LabelRels) != len(o.Relations.LabelRels) {
+		// 		t.Errorf("Number of LabelRel differs for %s of type %s. Expected %d. Got %d",
+		// 			e.Name, e.Kind, len(e.Relations.LabelRels), len(o.Relations.LabelRels))
+		// 	}
+
+		// 	for j, rrel := range o.Relations.LabelRels {
+		// 		expRrel := e.Relations.LabelRels[j]
+
+		// 		if expRrel.Relation.Source != rrel.Relation.Source {
+		// 			t.Errorf("Source in ControlRel differs for %s of type %s. Expected %d. Got %d",
+		// 				o.Name, o.Kind, expRrel.Relation.Source, rrel.Relation.Source)
+		// 		}
+
+		// 		if expRrel.Relation.Target != rrel.Relation.Target {
+		// 			t.Errorf("Target in ControlRel differs for %s of type %s. Expected %d. Got %d",
+		// 				o.Name, o.Kind, expRrel.Relation.Target, rrel.Relation.Target)
+		// 		}
+		// 	}
+		// }
+
+	}
+}

+ 3 - 0
internal/helm/grapher/test_yaml/cassandra.yaml

@@ -219,6 +219,9 @@ spec:
               mountPath: /bitnami/cassandra
             
       volumes:
+      - name: config-volume
+        configMap:
+          name: config-example
   volumeClaimTemplates:
     - metadata:
         name: data