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  }