Просмотр исходного кода

ClusterRoleBinding & RoleBinding SpecRel with roleRef and subjects

sunguroku 5 лет назад
Родитель
Сommit
12515909ba
2 измененных файлов с 73 добавлено и 8 удалено
  1. 7 4
      internal/helm/grapher/object.go
  2. 66 4
      internal/helm/grapher/relation.go

+ 7 - 4
internal/helm/grapher/object.go

@@ -5,6 +5,7 @@ type Object struct {
 	ID        int
 	Kind      string
 	Name      string
+	Namespace string
 	RawYAML   map[string]interface{}
 	Relations Relations
 }
@@ -17,13 +18,15 @@ func ParseObjs(objs []map[string]interface{}) []Object {
 	for i, obj := range objs {
 		kind := getField(obj, "kind").(string)
 		name := getField(obj, "metadata", "name").(string)
+		namespace := getField(obj, "metadata", "namespace").(string)
 
 		// First add the object that appears on the YAML
 		parsedObj := Object{
-			ID:      i,
-			Kind:    kind,
-			Name:    name,
-			RawYAML: obj,
+			ID:        i,
+			Kind:      kind,
+			Name:      name,
+			Namespace: namespace,
+			RawYAML:   obj,
 			Relations: Relations{
 				ControlRels: []ControlRel{},
 				LabelRels:   []LabelRel{},

+ 66 - 4
internal/helm/grapher/relation.go

@@ -24,6 +24,11 @@ type LabelRel struct {
 	Relation
 }
 
+// SpecRel connects objects via various spec properties.
+type SpecRel struct {
+	Relation
+}
+
 // ParsedObjs has methods GetControlRel and GetLabelRel that updates its objects array.
 type ParsedObjs struct {
 	Objects []Object
@@ -33,6 +38,7 @@ type ParsedObjs struct {
 type Relations struct {
 	ControlRels []ControlRel
 	LabelRels   []LabelRel
+	SpecRels    []SpecRel
 }
 
 // MatchLabel is used to match Equality label selector.
@@ -78,10 +84,11 @@ func (parsed *ParsedObjs) GetControlRel() {
 					}
 
 					pod := Object{
-						ID:      cid,
-						Kind:    "Pod",
-						Name:    obj.Name + "-" + strconv.Itoa(j), // tentative name pre-deploy
-						RawYAML: template,
+						ID:        cid,
+						Kind:      "Pod",
+						Name:      obj.Name + "-" + strconv.Itoa(j), // tentative name pre-deploy
+						Namespace: obj.Namespace,
+						RawYAML:   template,
 						Relations: Relations{
 							ControlRels: []ControlRel{
 								crel,
@@ -156,6 +163,61 @@ 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 {
+		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)
+			}
+			parsed.Objects[i].Relations.SpecRels = rels
+		}
+	}
+}
+
+// SpecRel helpers
+func (parsed *ParsedObjs) findRBACTargets(parentID int, yaml map[string]interface{}) []int {
+	roleRef := getField(yaml, "roleRef")
+	subjects := getField(yaml, "subjects")
+	rules := append(subjects.([]interface{}), roleRef)
+	targets := []int{}
+	for i, o := range parsed.Objects {
+		for _, r := range rules {
+			tr := r.(map[string]interface{})
+
+			newrel := SpecRel{
+				Relation{
+					Source: parentID,
+					Target: o.ID,
+				},
+			}
+
+			// first consider case of targets added via subjects, which are namespace scoped.
+			if tr["namespace"] != nil && o.Kind == tr["kind"] &&
+				o.Name == tr["name"] && o.Namespace == tr["namespace"] {
+
+				// Add bidirectional link from children as well.
+				parsed.Objects[i].Relations.SpecRels = append(parsed.Objects[i].Relations.SpecRels, newrel)
+				targets = append(targets, o.ID)
+
+			} else if tr["namespace"] == nil && o.Kind == tr["kind"] && o.Name == tr["name"] {
+				parsed.Objects[i].Relations.SpecRels = append(parsed.Objects[i].Relations.SpecRels, newrel)
+				targets = append(targets, o.ID)
+			}
+		}
+	}
+	return targets
+}
+
 func addMatchLabels(matchLabels []MatchLabel, ml map[string]interface{}) []MatchLabel {
 	for k, v := range ml {
 		matchLabels = append(matchLabels, MatchLabel{