github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/ansible/event_stream.go (about) 1 package ansible 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 8 "github.com/apprenda/kismatic/pkg/util" 9 ) 10 11 // EventStream reads JSON lines from the incoming stream, and convert them 12 // into a stream of events. 13 func EventStream(in io.Reader) <-chan Event { 14 lr := util.NewLineReader(in, 64*1024) 15 out := make(chan Event) 16 go func() { 17 var line []byte 18 var err error 19 for { 20 line, err = lr.Read() 21 if err != nil { // we are done with the stream 22 break 23 } 24 event, err := eventFromJSONLine(line) 25 if err != nil { 26 // handle this error? Maybe have an outErr channel 27 continue 28 } 29 out <- event 30 } 31 if err != io.EOF { 32 fmt.Printf("Error reading ansible event stream: %v", err) 33 } 34 // Close the channel, as the stream is done 35 close(out) 36 }() 37 return out 38 } 39 40 // eventEnvelope contains event data for a specific event type 41 type eventEnvelope struct { 42 Type string `json:"eventType"` 43 Data interface{} `json:"eventData"` 44 } 45 46 func eventFromJSONLine(line []byte) (Event, error) { 47 // Unmarshal the event type, but defer unmarshaling the data 48 var data json.RawMessage 49 env := &eventEnvelope{ 50 Data: &data, 51 } 52 if err := json.Unmarshal(line, env); err != nil { 53 return nil, fmt.Errorf("error parsing event: %v\nline was:\n%s\n", err, string(line)) 54 } 55 56 // Unmarshal the data according to the event type 57 switch env.Type { 58 case "PLAYBOOK_START": 59 e := &PlaybookStartEvent{} 60 if err := json.Unmarshal(data, e); err != nil { 61 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 62 } 63 return e, nil 64 case "PLAYBOOK_END": 65 e := &PlaybookEndEvent{} 66 if err := json.Unmarshal(data, e); err != nil { 67 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 68 } 69 return e, nil 70 case "PLAY_START": 71 e := &PlayStartEvent{} 72 if err := json.Unmarshal(data, e); err != nil { 73 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 74 } 75 return e, nil 76 case "TASK_START": 77 e := &TaskStartEvent{} 78 if err := json.Unmarshal(data, e); err != nil { 79 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 80 } 81 return e, nil 82 case "HANDLER_TASK_START": 83 e := &HandlerTaskStartEvent{} 84 if err := json.Unmarshal(data, e); err != nil { 85 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 86 } 87 return e, nil 88 case "RUNNER_OK": 89 e := &RunnerOKEvent{} 90 if err := json.Unmarshal(data, e); err != nil { 91 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 92 } 93 return e, nil 94 case "RUNNER_ITEM_OK": 95 e := &RunnerItemOKEvent{} 96 if err := json.Unmarshal(data, e); err != nil { 97 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 98 } 99 return e, nil 100 case "RUNNER_ITEM_FAILED": 101 e := &RunnerItemFailedEvent{} 102 if err := json.Unmarshal(data, e); err != nil { 103 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 104 } 105 return e, nil 106 case "RUNNER_ITEM_RETRY": 107 e := &RunnerItemRetryEvent{} 108 if err := json.Unmarshal(data, e); err != nil { 109 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 110 } 111 return e, nil 112 case "RUNNER_FAILED": 113 e := &RunnerFailedEvent{} 114 if err := json.Unmarshal(data, e); err != nil { 115 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 116 } 117 return e, nil 118 case "RUNNER_SKIPPED": 119 e := &RunnerSkippedEvent{} 120 if err := json.Unmarshal(data, e); err != nil { 121 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 122 } 123 return e, nil 124 case "RUNNER_UNREACHABLE": 125 e := &RunnerUnreachableEvent{} 126 if err := json.Unmarshal(data, e); err != nil { 127 return nil, fmt.Errorf("error reading event data: %v\nline was:\n%s\n", err, string(line)) 128 } 129 return e, nil 130 default: 131 return nil, fmt.Errorf("unhandled ansible event type %q", env.Type) 132 } 133 }