go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/node_utils.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kvscheduler
    16  
    17  import (
    18  	"google.golang.org/protobuf/proto"
    19  
    20  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    21  	"go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/graph"
    22  	"go.ligato.io/vpp-agent/v3/plugins/kvscheduler/internal/utils"
    23  	"go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler"
    24  )
    25  
    26  func nodeToKVPairWithMetadata(node graph.Node) kvs.KVWithMetadata {
    27  	return kvs.KVWithMetadata{
    28  		Key:      node.GetKey(),
    29  		Value:    node.GetValue(),
    30  		Metadata: node.GetMetadata(),
    31  		Origin:   getNodeOrigin(node),
    32  	}
    33  }
    34  
    35  func nodesToKVPairsWithMetadata(nodes []graph.Node) (kvPairs []kvs.KVWithMetadata) {
    36  	for _, node := range nodes {
    37  		kvPairs = append(kvPairs, nodeToKVPairWithMetadata(node))
    38  	}
    39  	return kvPairs
    40  }
    41  
    42  // constructTargets builds targets for the graph based on derived values and dependencies.
    43  func constructTargets(deps []kvs.Dependency, derives []kvs.KeyValuePair) (targets []graph.RelationTargetDef) {
    44  	targets = make([]graph.RelationTargetDef, 0, len(deps)+len(derives))
    45  	for _, dep := range deps {
    46  		target := graph.RelationTargetDef{
    47  			Relation: DependencyRelation,
    48  			Label:    dep.Label,
    49  			Key:      dep.Key,
    50  			Selector: graph.TargetSelector{
    51  				KeyPrefixes: dep.AnyOf.KeyPrefixes,
    52  				KeySelector: dep.AnyOf.KeySelector,
    53  			},
    54  		}
    55  		targets = append(targets, target)
    56  	}
    57  
    58  	for _, derived := range derives {
    59  		target := graph.RelationTargetDef{
    60  			Relation: DerivesRelation,
    61  			Label:    derived.Key,
    62  			Key:      derived.Key,
    63  		}
    64  		targets = append(targets, target)
    65  	}
    66  
    67  	return targets
    68  }
    69  
    70  // equalValueDetails compares value state details for equality.
    71  func equalValueDetails(details1, details2 []string) bool {
    72  	if len(details1) != len(details2) {
    73  		return false
    74  	}
    75  	for _, d1 := range details1 {
    76  		found := false
    77  		for _, d2 := range details2 {
    78  			if d1 == d2 {
    79  				found = true
    80  				break
    81  			}
    82  		}
    83  		if !found {
    84  			return false
    85  		}
    86  	}
    87  	return true
    88  }
    89  
    90  // getValueDetails returns further details about the value state.
    91  func getValueDetails(node graph.Node) (details []string) {
    92  	state := getNodeState(node)
    93  	_, err := getNodeError(node)
    94  	if state == kvscheduler.ValueState_INVALID {
    95  		if ivErr, isIVErr := err.(*kvs.InvalidValueError); isIVErr {
    96  			details = ivErr.GetInvalidFields()
    97  			return
    98  		}
    99  	}
   100  	if state == kvscheduler.ValueState_PENDING {
   101  		for _, targets := range node.GetTargets(DependencyRelation) {
   102  			satisfied := false
   103  			for _, target := range targets.Nodes {
   104  				if isNodeAvailable(target) {
   105  					satisfied = true
   106  				}
   107  			}
   108  			if !satisfied {
   109  				details = append(details, targets.Label)
   110  			}
   111  		}
   112  	}
   113  	return details
   114  }
   115  
   116  // getValueStatus reads the value status from the corresponding node.
   117  func getValueStatus(node graph.Node, key string) *kvscheduler.BaseValueStatus {
   118  	status := &kvscheduler.BaseValueStatus{
   119  		Value: &kvscheduler.ValueStatus{
   120  			Key: key,
   121  		},
   122  	}
   123  
   124  	status.Value.State = getNodeState(node)
   125  	if status.Value.State == kvscheduler.ValueState_NONEXISTENT {
   126  		// nothing else to get for non-existent value
   127  		return status
   128  	}
   129  	_, err := getNodeError(node)
   130  	if err != nil {
   131  		status.Value.Error = err.Error()
   132  	}
   133  	status.Value.LastOperation = getNodeLastOperation(node)
   134  	status.Value.State = getNodeState(node)
   135  	status.Value.Details = getValueDetails(node)
   136  
   137  	// derived nodes
   138  	if !isNodeDerived(node) {
   139  		for _, derivedNode := range getDerivedNodes(node) {
   140  			derValStatus := getValueStatus(derivedNode, derivedNode.GetKey())
   141  			status.DerivedValues = append(status.DerivedValues, derValStatus.Value)
   142  		}
   143  	}
   144  
   145  	return status
   146  }
   147  
   148  // functions returns selectors selecting non-derived NB values.
   149  func nbBaseValsSelectors() []graph.FlagSelector {
   150  	return []graph.FlagSelector{
   151  		graph.WithoutFlags(&DerivedFlag{}),
   152  		graph.WithoutFlags(&ValueStateFlag{kvscheduler.ValueState_OBTAINED}),
   153  	}
   154  }
   155  
   156  // functions returns selectors selecting non-derived SB values.
   157  func sbBaseValsSelectors() []graph.FlagSelector {
   158  	return []graph.FlagSelector{
   159  		graph.WithoutFlags(&DerivedFlag{}),
   160  		graph.WithFlags(&ValueStateFlag{kvscheduler.ValueState_OBTAINED}),
   161  	}
   162  }
   163  
   164  // function returns selectors selecting non-derived values belonging to the given
   165  // descriptor.
   166  func descrValsSelectors(descriptor string, onlyAvailable bool) []graph.FlagSelector {
   167  	descrSel := graph.WithFlags(&DescriptorFlag{descriptor})
   168  	baseSel := graph.WithoutFlags(&DerivedFlag{})
   169  	if onlyAvailable {
   170  		return []graph.FlagSelector{
   171  			descrSel, baseSel, graph.WithoutFlags(&UnavailValueFlag{}),
   172  		}
   173  	}
   174  	return []graph.FlagSelector{descrSel, baseSel}
   175  }
   176  
   177  // getNodeState returns state stored in the ValueState flag.
   178  func getNodeState(node graph.Node) kvscheduler.ValueState {
   179  	if node != nil {
   180  		flag := node.GetFlag(ValueStateFlagIndex)
   181  		if flag != nil {
   182  			return flag.(*ValueStateFlag).valueState
   183  		}
   184  	}
   185  	return kvscheduler.ValueState_NONEXISTENT
   186  }
   187  
   188  func valueStateToOrigin(state kvscheduler.ValueState) kvs.ValueOrigin {
   189  	switch state {
   190  	case kvscheduler.ValueState_NONEXISTENT:
   191  		return kvs.UnknownOrigin
   192  	case kvscheduler.ValueState_OBTAINED:
   193  		return kvs.FromSB
   194  	}
   195  	return kvs.FromNB
   196  }
   197  
   198  // getNodeOrigin returns node origin based on the value state.
   199  func getNodeOrigin(node graph.Node) kvs.ValueOrigin {
   200  	state := getNodeState(node)
   201  	return valueStateToOrigin(state)
   202  }
   203  
   204  // getNodeError returns node error stored in Error flag.
   205  func getNodeError(node graph.Node) (retriable bool, err error) {
   206  	if node != nil {
   207  		errorFlag := node.GetFlag(ErrorFlagIndex)
   208  		if errorFlag != nil {
   209  			flag := errorFlag.(*ErrorFlag)
   210  			return flag.retriable, flag.err
   211  		}
   212  	}
   213  	return false, nil
   214  }
   215  
   216  // getNodeErrorString returns node error stored in Error flag as string.
   217  func getNodeErrorString(node graph.Node) string {
   218  	_, err := getNodeError(node)
   219  	if err == nil {
   220  		return ""
   221  	}
   222  	return err.Error()
   223  }
   224  
   225  // getNodeLastUpdate returns info about the last update for a given node, stored in LastUpdate flag.
   226  func getNodeLastUpdate(node graph.Node) *LastUpdateFlag {
   227  	if node == nil {
   228  		return nil
   229  	}
   230  	flag := node.GetFlag(LastUpdateFlagIndex)
   231  	if flag == nil {
   232  		return nil
   233  	}
   234  	return flag.(*LastUpdateFlag)
   235  }
   236  
   237  // getNodeLastAppliedValue return the last applied value for the given node
   238  func getNodeLastAppliedValue(node graph.Node) proto.Message {
   239  	lastUpdate := getNodeLastUpdate(node)
   240  	if lastUpdate == nil {
   241  		return nil
   242  	}
   243  	return lastUpdate.value
   244  }
   245  
   246  // getNodeLastOperation returns last operation executed over the given node.
   247  func getNodeLastOperation(node graph.Node) kvscheduler.TxnOperation {
   248  	if node != nil && getNodeState(node) != kvscheduler.ValueState_OBTAINED {
   249  		lastUpdate := getNodeLastUpdate(node)
   250  		if lastUpdate != nil {
   251  			return lastUpdate.txnOp
   252  		}
   253  	}
   254  	return kvscheduler.TxnOperation_UNDEFINED
   255  }
   256  
   257  func isNodeDerived(node graph.Node) bool {
   258  	return node.GetFlag(DerivedFlagIndex) != nil
   259  }
   260  
   261  func getNodeBaseKey(node graph.Node) string {
   262  	flag := node.GetFlag(DerivedFlagIndex)
   263  	if flag == nil {
   264  		return node.GetKey()
   265  	}
   266  	return flag.(*DerivedFlag).baseKey
   267  }
   268  
   269  // isNodePending checks whether the node is available for dependency resolution.
   270  func isNodeAvailable(node graph.Node) bool {
   271  	if node == nil {
   272  		return false
   273  	}
   274  	return node.GetFlag(UnavailValueFlagIndex) == nil
   275  }
   276  
   277  // isNodeReady return true if the given node has all dependencies satisfied.
   278  // Recursive calls are needed to handle circular dependencies - nodes of a strongly
   279  // connected component are treated as if they were squashed into one.
   280  func isNodeReady(node graph.Node) bool {
   281  	if getNodeOrigin(node) == kvs.FromSB {
   282  		// for SB values dependencies are not checked
   283  		return true
   284  	}
   285  	ready, _ := isNodeReadyRec(node, 0, make(map[string]int), false)
   286  	return ready
   287  }
   288  
   289  // isNodeReadyRec is a recursive call from within isNodeReady.
   290  // visited = map{ key -> depth }
   291  func isNodeReadyRec(node graph.Node, depth int, visited map[string]int, checkSCC bool) (ready bool, cycleDepth int) {
   292  	if targetDepth, wasVisited := visited[node.GetKey()]; wasVisited {
   293  		return true, targetDepth
   294  	}
   295  	cycleDepth = depth
   296  	visited[node.GetKey()] = depth
   297  	defer delete(visited, node.GetKey())
   298  
   299  	ready = true // for zero dependencies
   300  	var satisfiedLabel bool
   301  	cb := func(target graph.Node, label string) (skipLabel, abort bool) {
   302  		if target == nil { // end of the available targets for this label
   303  			if !satisfiedLabel {
   304  				ready = false
   305  				abort = true
   306  				return
   307  			}
   308  			satisfiedLabel = false // clear for the next label
   309  			return
   310  		}
   311  
   312  		if getNodeState(target) == kvscheduler.ValueState_REMOVED {
   313  			// do not consider values that are (being) removed
   314  			return
   315  		}
   316  
   317  		if isNodeAvailable(target) {
   318  			satisfiedLabel = true
   319  			if !checkSCC {
   320  				skipLabel = true
   321  				return
   322  			}
   323  		}
   324  
   325  		// test if node is inside a strongly-connected component (treated as one node)
   326  		targetReady, targetCycleDepth := isNodeReadyRec(target, depth+1, visited, true)
   327  		if targetReady && targetCycleDepth <= depth {
   328  			// this node is reachable from the target
   329  			satisfiedLabel = true
   330  			if targetCycleDepth < cycleDepth {
   331  				// update how far back in the branch this node can reach following dependencies
   332  				cycleDepth = targetCycleDepth
   333  			}
   334  		}
   335  		return
   336  	}
   337  
   338  	node.IterTargets(DependencyRelation, cb)
   339  	return
   340  }
   341  
   342  func canNodeHaveMetadata(node graph.Node) bool {
   343  	return !isNodeDerived(node)
   344  }
   345  
   346  func getDerivedNodes(node graph.Node) (derived []graph.Node) {
   347  	for _, derivedNodes := range node.GetTargets(DerivesRelation) {
   348  		derived = append(derived, derivedNodes.Nodes...)
   349  	}
   350  	return derived
   351  }
   352  
   353  func getDerivedKeys(node graph.Node) utils.KeySet {
   354  	set := utils.NewSliceBasedKeySet()
   355  	for _, derived := range getDerivedNodes(node) {
   356  		set.Add(derived.GetKey())
   357  	}
   358  	return set
   359  }