github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/cmd/ocsplunk/main.go (about) 1 // Copyright (c) 2017 Arista Networks, Inc. 2 // Use of this source code is governed by the Apache License 2.0 3 // that can be found in the COPYING file. 4 5 package main 6 7 import ( 8 "context" 9 "crypto/tls" 10 "flag" 11 "fmt" 12 "net/http" 13 "os" 14 "strings" 15 "time" 16 17 "github.com/aristanetworks/goarista/gnmi" 18 19 "github.com/aristanetworks/glog" 20 hec "github.com/aristanetworks/splunk-hec-go" 21 pb "github.com/openconfig/gnmi/proto/gnmi" 22 "golang.org/x/sync/errgroup" 23 ) 24 25 func exitWithError(s string) { 26 fmt.Fprintln(os.Stderr, s) 27 os.Exit(1) 28 } 29 30 func main() { 31 // gNMI options 32 cfg := &gnmi.Config{} 33 flag.StringVar(&cfg.Addr, "addr", "localhost", "gNMI gRPC server `address`") 34 flag.StringVar(&cfg.CAFile, "cafile", "", "Path to server TLS certificate file") 35 flag.StringVar(&cfg.CertFile, "certfile", "", "Path to client TLS certificate file") 36 flag.StringVar(&cfg.KeyFile, "keyfile", "", "Path to client TLS private key file") 37 flag.StringVar(&cfg.Username, "username", "", "Username to authenticate with") 38 flag.StringVar(&cfg.Password, "password", "", "Password to authenticate with") 39 flag.BoolVar(&cfg.TLS, "tls", false, "Enable TLS") 40 flag.StringVar(&cfg.TLSMinVersion, "tls-min-version", "", 41 fmt.Sprintf("Set minimum TLS version for connection (%s)", gnmi.TLSVersions)) 42 flag.StringVar(&cfg.TLSMaxVersion, "tls-max-version", "", 43 fmt.Sprintf("Set maximum TLS version for connection (%s)", gnmi.TLSVersions)) 44 subscribePaths := flag.String("paths", "/", "Comma-separated list of paths to subscribe to") 45 46 // Splunk options 47 splunkURLs := flag.String("splunkurls", "https://localhost:8088", 48 "Comma-separated list of URLs of the Splunk servers") 49 splunkToken := flag.String("splunktoken", "", "Token to connect to the Splunk servers") 50 splunkIndex := flag.String("splunkindex", "", "Index for the data in Splunk") 51 52 flag.Parse() 53 54 // gNMI connection 55 ctx := gnmi.NewContext(context.Background(), cfg) 56 // Store the address without the port so it can be used as the host in the Splunk event. 57 addr := cfg.Addr 58 client, err := gnmi.Dial(cfg) 59 if err != nil { 60 glog.Fatal(err) 61 } 62 63 // Splunk connection 64 urls := strings.Split(*splunkURLs, ",") 65 cluster := hec.NewCluster(urls, *splunkToken) 66 cluster.SetHTTPClient(&http.Client{ 67 Transport: &http.Transport{ 68 // TODO: add flags for TLS 69 TLSClientConfig: &tls.Config{ 70 // TODO: add flag to enable TLS 71 InsecureSkipVerify: true, 72 }, 73 }, 74 }) 75 76 // gNMI subscription 77 respChan := make(chan *pb.SubscribeResponse) 78 paths := strings.Split(*subscribePaths, ",") 79 subscribeOptions := &gnmi.SubscribeOptions{ 80 Mode: "stream", 81 StreamMode: "target_defined", 82 Paths: gnmi.SplitPaths(paths), 83 } 84 var g errgroup.Group 85 g.Go(func() error { return gnmi.SubscribeErr(ctx, client, subscribeOptions, respChan) }) 86 87 // Forward subscribe responses to Splunk 88 for resp := range respChan { 89 // We got a subscribe response 90 response := resp.GetResponse() 91 update, ok := response.(*pb.SubscribeResponse_Update) 92 if !ok { 93 continue 94 } 95 96 // Convert the response into a map[string]interface{} 97 notification, err := gnmi.NotificationToMap(update.Update) 98 if err != nil { 99 exitWithError(err.Error()) 100 } 101 102 // Build the Splunk event 103 path := notification["path"].(string) 104 delete(notification, "path") 105 timestamp := notification["timestamp"].(int64) 106 delete(notification, "timestamp") 107 // Should this be configurable? 108 sourceType := "openconfig" 109 event := &hec.Event{ 110 Host: &addr, 111 Index: splunkIndex, 112 Source: &path, 113 SourceType: &sourceType, 114 Event: notification, 115 } 116 event.SetTime(time.Unix(timestamp/1e9, timestamp%1e9)) 117 118 // Write the event to Splunk 119 if err := cluster.WriteEvent(event); err != nil { 120 exitWithError("failed to write event: " + err.Error()) 121 } 122 123 } 124 if err := g.Wait(); err != nil { 125 exitWithError(err.Error()) 126 } 127 }