github.com/ves/terraform@v0.8.0-beta2/dag/marshal.go (about) 1 package dag 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "log" 8 "reflect" 9 "sort" 10 "strconv" 11 ) 12 13 // the marshal* structs are for serialization of the graph data. 14 type marshalGraph struct { 15 // Type is always "Graph", for identification as a top level object in the 16 // JSON stream. 17 Type string 18 19 // Each marshal structure requires a unique ID so that it can be referenced 20 // by other structures. 21 ID string `json:",omitempty"` 22 23 // Human readable name for this graph. 24 Name string `json:",omitempty"` 25 26 // Arbitrary attributes that can be added to the output. 27 Attrs map[string]string `json:",omitempty"` 28 29 // List of graph vertices, sorted by ID. 30 Vertices []*marshalVertex `json:",omitempty"` 31 32 // List of edges, sorted by Source ID. 33 Edges []*marshalEdge `json:",omitempty"` 34 35 // Any number of subgraphs. A subgraph itself is considered a vertex, and 36 // may be referenced by either end of an edge. 37 Subgraphs []*marshalGraph `json:",omitempty"` 38 39 // Any lists of vertices that are included in cycles. 40 Cycles [][]*marshalVertex `json:",omitempty"` 41 } 42 43 // The add, remove, connect, removeEdge methods mirror the basic Graph 44 // manipulations to reconstruct a marshalGraph from a debug log. 45 func (g *marshalGraph) add(v *marshalVertex) { 46 g.Vertices = append(g.Vertices, v) 47 sort.Sort(vertices(g.Vertices)) 48 } 49 50 func (g *marshalGraph) remove(v *marshalVertex) { 51 for i, existing := range g.Vertices { 52 if v.ID == existing.ID { 53 g.Vertices = append(g.Vertices[:i], g.Vertices[i+1:]...) 54 return 55 } 56 } 57 } 58 59 func (g *marshalGraph) connect(e *marshalEdge) { 60 g.Edges = append(g.Edges, e) 61 sort.Sort(edges(g.Edges)) 62 } 63 64 func (g *marshalGraph) removeEdge(e *marshalEdge) { 65 for i, existing := range g.Edges { 66 if e.Source == existing.Source && e.Target == existing.Target { 67 g.Edges = append(g.Edges[:i], g.Edges[i+1:]...) 68 return 69 } 70 } 71 } 72 73 func (g *marshalGraph) vertexByID(id string) *marshalVertex { 74 for _, v := range g.Vertices { 75 if id == v.ID { 76 return v 77 } 78 } 79 return nil 80 } 81 82 type marshalVertex struct { 83 // Unique ID, used to reference this vertex from other structures. 84 ID string 85 86 // Human readable name 87 Name string `json:",omitempty"` 88 89 Attrs map[string]string `json:",omitempty"` 90 91 // This is to help transition from the old Dot interfaces. We record if the 92 // node was a GraphNodeDotter here, so we know if it should be included in the 93 // dot output 94 graphNodeDotter bool 95 } 96 97 func newMarshalVertex(v Vertex) *marshalVertex { 98 return &marshalVertex{ 99 ID: marshalVertexID(v), 100 Name: VertexName(v), 101 Attrs: make(map[string]string), 102 graphNodeDotter: isDotter(v), 103 } 104 } 105 106 func isDotter(v Vertex) bool { 107 dn, isDotter := v.(GraphNodeDotter) 108 dotOpts := &DotOpts{ 109 Verbose: true, 110 DrawCycles: true, 111 } 112 if isDotter && dn.DotNode("fake", dotOpts) == nil { 113 isDotter = false 114 } 115 return isDotter 116 } 117 118 // vertices is a sort.Interface implementation for sorting vertices by ID 119 type vertices []*marshalVertex 120 121 func (v vertices) Less(i, j int) bool { return v[i].Name < v[j].Name } 122 func (v vertices) Len() int { return len(v) } 123 func (v vertices) Swap(i, j int) { v[i], v[j] = v[j], v[i] } 124 125 type marshalEdge struct { 126 // Human readable name 127 Name string 128 129 // Source and Target Vertices by ID 130 Source string 131 Target string 132 133 Attrs map[string]string `json:",omitempty"` 134 } 135 136 func newMarshalEdge(e Edge) *marshalEdge { 137 return &marshalEdge{ 138 Name: fmt.Sprintf("%s|%s", VertexName(e.Source()), VertexName(e.Target())), 139 Source: marshalVertexID(e.Source()), 140 Target: marshalVertexID(e.Target()), 141 Attrs: make(map[string]string), 142 } 143 } 144 145 // edges is a sort.Interface implementation for sorting edges by Source ID 146 type edges []*marshalEdge 147 148 func (e edges) Less(i, j int) bool { return e[i].Name < e[j].Name } 149 func (e edges) Len() int { return len(e) } 150 func (e edges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } 151 152 // build a marshalGraph structure from a *Graph 153 func newMarshalGraph(name string, g *Graph) *marshalGraph { 154 mg := &marshalGraph{ 155 Type: "Graph", 156 Name: name, 157 Attrs: make(map[string]string), 158 } 159 160 for _, v := range g.Vertices() { 161 id := marshalVertexID(v) 162 if sg, ok := marshalSubgrapher(v); ok { 163 smg := newMarshalGraph(VertexName(v), sg) 164 smg.ID = id 165 mg.Subgraphs = append(mg.Subgraphs, smg) 166 } 167 168 mv := newMarshalVertex(v) 169 mg.Vertices = append(mg.Vertices, mv) 170 } 171 172 sort.Sort(vertices(mg.Vertices)) 173 174 for _, e := range g.Edges() { 175 mg.Edges = append(mg.Edges, newMarshalEdge(e)) 176 } 177 178 sort.Sort(edges(mg.Edges)) 179 180 for _, c := range (&AcyclicGraph{*g}).Cycles() { 181 var cycle []*marshalVertex 182 for _, v := range c { 183 mv := newMarshalVertex(v) 184 cycle = append(cycle, mv) 185 } 186 mg.Cycles = append(mg.Cycles, cycle) 187 } 188 189 return mg 190 } 191 192 // Attempt to return a unique ID for any vertex. 193 func marshalVertexID(v Vertex) string { 194 val := reflect.ValueOf(v) 195 switch val.Kind() { 196 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: 197 return strconv.Itoa(int(val.Pointer())) 198 case reflect.Interface: 199 return strconv.Itoa(int(val.InterfaceData()[1])) 200 } 201 202 if v, ok := v.(Hashable); ok { 203 h := v.Hashcode() 204 if h, ok := h.(string); ok { 205 return h 206 } 207 } 208 209 // fallback to a name, which we hope is unique. 210 return VertexName(v) 211 212 // we could try harder by attempting to read the arbitrary value from the 213 // interface, but we shouldn't get here from terraform right now. 214 } 215 216 // check for a Subgrapher, and return the underlying *Graph. 217 func marshalSubgrapher(v Vertex) (*Graph, bool) { 218 sg, ok := v.(Subgrapher) 219 if !ok { 220 return nil, false 221 } 222 223 switch g := sg.Subgraph().DirectedGraph().(type) { 224 case *Graph: 225 return g, true 226 case *AcyclicGraph: 227 return &g.Graph, true 228 } 229 230 return nil, false 231 } 232 233 // The DebugOperationEnd func type provides a way to call an End function via a 234 // method call, allowing for the chaining of methods in a defer statement. 235 type DebugOperationEnd func(string) 236 237 // End calls function e with the info parameter, marking the end of this 238 // operation in the logs. 239 func (e DebugOperationEnd) End(info string) { e(info) } 240 241 // encoder provides methods to write debug data to an io.Writer, and is a noop 242 // when no writer is present 243 type encoder struct { 244 w io.Writer 245 } 246 247 // Encode is analogous to json.Encoder.Encode 248 func (e *encoder) Encode(i interface{}) { 249 if e == nil || e.w == nil { 250 return 251 } 252 253 js, err := json.Marshal(i) 254 if err != nil { 255 log.Println("[ERROR] dag:", err) 256 return 257 } 258 js = append(js, '\n') 259 260 _, err = e.w.Write(js) 261 if err != nil { 262 log.Println("[ERROR] dag:", err) 263 return 264 } 265 } 266 267 func (e *encoder) Add(v Vertex) { 268 e.Encode(marshalTransform{ 269 Type: "Transform", 270 AddVertex: newMarshalVertex(v), 271 }) 272 } 273 274 // Remove records the removal of Vertex v. 275 func (e *encoder) Remove(v Vertex) { 276 e.Encode(marshalTransform{ 277 Type: "Transform", 278 RemoveVertex: newMarshalVertex(v), 279 }) 280 } 281 282 func (e *encoder) Connect(edge Edge) { 283 e.Encode(marshalTransform{ 284 Type: "Transform", 285 AddEdge: newMarshalEdge(edge), 286 }) 287 } 288 289 func (e *encoder) RemoveEdge(edge Edge) { 290 e.Encode(marshalTransform{ 291 Type: "Transform", 292 RemoveEdge: newMarshalEdge(edge), 293 }) 294 } 295 296 // BeginOperation marks the start of set of graph transformations, and returns 297 // an EndDebugOperation func to be called once the opration is complete. 298 func (e *encoder) BeginOperation(op string, info string) DebugOperationEnd { 299 if e == nil { 300 return func(string) {} 301 } 302 303 e.Encode(marshalOperation{ 304 Type: "Operation", 305 Begin: op, 306 Info: info, 307 }) 308 309 return func(info string) { 310 e.Encode(marshalOperation{ 311 Type: "Operation", 312 End: op, 313 Info: info, 314 }) 315 } 316 } 317 318 // structure for recording graph transformations 319 type marshalTransform struct { 320 // Type: "Transform" 321 Type string 322 AddEdge *marshalEdge `json:",omitempty"` 323 RemoveEdge *marshalEdge `json:",omitempty"` 324 AddVertex *marshalVertex `json:",omitempty"` 325 RemoveVertex *marshalVertex `json:",omitempty"` 326 } 327 328 func (t marshalTransform) Transform(g *marshalGraph) { 329 switch { 330 case t.AddEdge != nil: 331 g.connect(t.AddEdge) 332 case t.RemoveEdge != nil: 333 g.removeEdge(t.RemoveEdge) 334 case t.AddVertex != nil: 335 g.add(t.AddVertex) 336 case t.RemoveVertex != nil: 337 g.remove(t.RemoveVertex) 338 } 339 } 340 341 // this structure allows us to decode any object in the json stream for 342 // inspection, then re-decode it into a proper struct if needed. 343 type streamDecode struct { 344 Type string 345 Map map[string]interface{} 346 JSON []byte 347 } 348 349 func (s *streamDecode) UnmarshalJSON(d []byte) error { 350 s.JSON = d 351 err := json.Unmarshal(d, &s.Map) 352 if err != nil { 353 return err 354 } 355 356 if t, ok := s.Map["Type"]; ok { 357 s.Type, _ = t.(string) 358 } 359 return nil 360 } 361 362 // structure for recording the beginning and end of any multi-step 363 // transformations. These are informational, and not required to reproduce the 364 // graph state. 365 type marshalOperation struct { 366 Type string 367 Begin string `json:",omitempty"` 368 End string `json:",omitempty"` 369 Info string `json:",omitempty"` 370 } 371 372 // decodeGraph decodes a marshalGraph from an encoded graph stream. 373 func decodeGraph(r io.Reader) (*marshalGraph, error) { 374 dec := json.NewDecoder(r) 375 376 // a stream should always start with a graph 377 g := &marshalGraph{} 378 379 err := dec.Decode(g) 380 if err != nil { 381 return nil, err 382 } 383 384 // now replay any operations that occurred on the original graph 385 for dec.More() { 386 s := &streamDecode{} 387 err := dec.Decode(s) 388 if err != nil { 389 return g, err 390 } 391 392 // the only Type we're concerned with here is Transform to complete the 393 // Graph 394 if s.Type != "Transform" { 395 continue 396 } 397 398 t := &marshalTransform{} 399 err = json.Unmarshal(s.JSON, t) 400 if err != nil { 401 return g, err 402 } 403 t.Transform(g) 404 } 405 return g, nil 406 } 407 408 // *DebugInfo structs allow encoding arbitrary information about the graph in 409 // the logs. 410 type vertexDebugInfo struct { 411 Type string 412 Vertex *marshalVertex 413 Info string 414 } 415 416 func newVertexDebugInfo(v Vertex, info string) *vertexDebugInfo { 417 return &vertexDebugInfo{ 418 Type: "VertexDebugInfo", 419 Vertex: newMarshalVertex(v), 420 Info: info, 421 } 422 } 423 424 type edgeDebugInfo struct { 425 Type string 426 Edge *marshalEdge 427 Info string 428 } 429 430 func newEdgeDebugInfo(e Edge, info string) *edgeDebugInfo { 431 return &edgeDebugInfo{ 432 Type: "EdgeDebugInfo", 433 Edge: newMarshalEdge(e), 434 Info: info, 435 } 436 }