...

Source file src/edge-infra.dev/pkg/edge/rollouts/plan.go

Documentation: edge-infra.dev/pkg/edge/rollouts

     1  package rollouts
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  )
     8  
     9  // RolloutPlan is the configuration, or a "template" to create rollouts from. It is a named object, eg my-rollout-plan, that
    10  // can be re-used with different inputs. For example, there may be a rollout plan for upgrading the version of Edge on clusters
    11  // in phases, from dev to staging, then to production. That type of plan could be reused for upgrading workloads or O/S versions
    12  // as well
    13  type RolloutPlan struct {
    14  	ID          string
    15  	Name        string
    16  	Description string
    17  
    18  	Initial       []NodeKey
    19  	Nodes         NodeMap
    20  	Edges         []RolloutGraphEdge
    21  	Configuration json.RawMessage
    22  
    23  	// GraphConfigration ...
    24  	// make note about how it can be stored in sql in a jsonb
    25  	// GraphConfiguration json.RawMessage
    26  }
    27  
    28  // RolloutPlanJSON is the intermediate format used to implement custom json unmarshaling
    29  type RolloutPlanJSON struct {
    30  	ID          string             `json:"id,omitempty"`
    31  	Name        string             `json:"name"`
    32  	Description string             `json:"description"`
    33  	Initial     []NodeKey          `json:"initial"`
    34  	Nodes       []BaseNodeJSON     `json:"nodes"`
    35  	Edges       []RolloutGraphEdge `json:"edges"`
    36  }
    37  
    38  func (p *RolloutPlan) UnmarshalJSON(data []byte) error {
    39  	// Unmarshal raw json payload into intermediate type
    40  	planJSON := &RolloutPlanJSON{}
    41  	err := json.Unmarshal(data, planJSON)
    42  	if err != nil {
    43  		return fmt.Errorf("failed to unmarshal rollout graph payload: %v", err)
    44  	}
    45  
    46  	// ID
    47  	p.ID = planJSON.ID
    48  
    49  	// Name
    50  	p.Name = planJSON.Name
    51  
    52  	// Description
    53  	p.Description = planJSON.Description
    54  
    55  	// Nodes. Unmarshal nodes into concrete types
    56  	p.Nodes = make(map[NodeKey]RolloutGraphNode, len(planJSON.Nodes))
    57  	for _, n := range planJSON.Nodes {
    58  		node, err := UnmarshalRolloutGraphNode(n)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		p.Nodes[node.GetKey()] = node
    63  	}
    64  
    65  	// Edges. Unmarshal and update node connections based on edges
    66  	p.Edges = make([]RolloutGraphEdge, len(planJSON.Edges))
    67  	for i, edge := range planJSON.Edges {
    68  		// For each edge, create links between the respective nodes
    69  		p.Edges[i] = RolloutGraphEdge{To: edge.To, From: edge.From}
    70  		toNode, found := p.Nodes[edge.To]
    71  		if !found {
    72  			return fmt.Errorf("node key %s was stated in edge but not in nodes", edge.To)
    73  		}
    74  		fromNode, found := p.Nodes[edge.From]
    75  		if !found {
    76  			return fmt.Errorf("node key %s was stated in edge but not in nodes", edge.From)
    77  		}
    78  		toNode.AddDependency(fromNode)
    79  		fromNode.AddNext(toNode)
    80  	}
    81  
    82  	// Initial. Copy all current node keys
    83  	p.Initial = planJSON.Initial
    84  
    85  	return nil
    86  }
    87  
    88  func (p *RolloutPlan) MarshalJSON() ([]byte, error) {
    89  	// Nodes. Convert all nodes to serializable types
    90  	nodes := make([]BaseNodeJSON, len(p.Nodes))
    91  	i := 0
    92  	for _, node := range p.Nodes {
    93  		data, err := json.Marshal(node)
    94  		if err != nil {
    95  			return nil, fmt.Errorf("failed to marshal node: %v", err)
    96  		}
    97  		baseNodeJSON := BaseNodeJSON{
    98  			// Seems to be necessary for pointer types, eg *TargetGroup -> TargetGroup. If this is a hassle to maintain
    99  			// or causes issues, a GetType func could be added to the node interface and implemented by each node type
   100  			NodeType: reflect.Indirect(reflect.ValueOf(node)).Type().Name(),
   101  			Data:     data,
   102  		}
   103  		nodes[i] = baseNodeJSON
   104  		i++
   105  	}
   106  
   107  	// Edges. Rote copying
   108  	edges := make([]RolloutGraphEdge, len(p.Edges))
   109  	copy(edges, p.Edges)
   110  
   111  	jsonData := &RolloutGraphJSON{
   112  		Nodes: nodes,
   113  		Edges: edges,
   114  	}
   115  
   116  	return json.Marshal(jsonData)
   117  }
   118  
   119  func NewRolloutPlanFromJSON(data json.RawMessage) (RolloutPlan, error) {
   120  	plan := &RolloutPlan{}
   121  	err := json.Unmarshal(data, plan)
   122  	if err != nil {
   123  		return *plan, err
   124  	}
   125  	return *plan, nil
   126  }
   127  

View as plain text