commit b50075083e382213b25a505b9e12ec78010d8e32 Author: Nathan Coad Date: Wed Mar 12 19:43:25 2025 +1100 first commit diff --git a/.drone.sh b/.drone.sh new file mode 100644 index 0000000..10f9de1 --- /dev/null +++ b/.drone.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +export now=$(TZ=Australia/Sydney date '+%Y%m%d-%H%M%S') +echo $now +echo "build commences" +go build -ldflags "-X main.sha1ver=`git rev-parse HEAD` -X main.buildTime=$now" -o go-snow +echo "build complete" +sha256sum go-snow > go-snow_checksum.txt +ls -lah \ No newline at end of file diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..98d4a4f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,29 @@ +kind: pipeline +type: docker +name: default + +# Docs at https://docs.drone.io/pipeline/exec/overview/ +# Also see https://github.com/harness/drone-cli/blob/master/.drone.yml + +steps: +- name: build + image: golang + commands: + - sh ./.drone.sh + +# https://github.com/hypervtechnics/drone-sftp +- name: dell-sftp-deploy + image: hypervtechnics/drone-sftp + settings: + host: deft.dell.com + username: + from_secret: DELLFTP_USER + password: + from_secret: DELLFTP_PASS + port: 22 + source: ./ + filter: go-snow* + clean: false + target: / + overwrite: true + verbose: true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24c746a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +log.txt +go-snow* \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7e1ab4b --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module go-snow + +go 1.24.1 + +require github.com/launchdarkly/go-ntlm-proxy-auth v1.0.1 + +require ( + github.com/launchdarkly/go-ntlmssp v1.0.1 // indirect + golang.org/x/crypto v0.36.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cefb998 --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +github.com/launchdarkly/go-ntlm-proxy-auth v1.0.1 h1:Iz5cg9mB/0vt5llZE+J0iGQ5+O/U8CWuRUUR7Ou8eNM= +github.com/launchdarkly/go-ntlm-proxy-auth v1.0.1/go.mod h1:hKWfH/hga5oslM2mRkDZi+14u2h1dFsmgbvSM9qF8pk= +github.com/launchdarkly/go-ntlmssp v1.0.1 h1:snB77118TQvf9tfHrkSyrIop/UX5e5VD2D2mv7Kh3wE= +github.com/launchdarkly/go-ntlmssp v1.0.1/go.mod h1:/cq3t2JyALD7GdVF5BEWcEuGlIGa44FZ4v4CVk7vuCY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e1a4fe8 --- /dev/null +++ b/main.go @@ -0,0 +1,197 @@ +package main + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "flag" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "runtime" + "time" +) + +type Incident struct { + AppID string `json:"app_id"` + Resource string `json:"resource"` + Node string `json:"node"` + ShortDescription string `json:"short_description"` + MetricName string `json:"metric_name"` + MessageKey string `json:"message_key"` + MetricValue string `json:"metric_value"` + Source string `json:"source"` + Description string `json:"description"` + EventClass string `json:"event_class"` + Severity int `json:"severity"` + Type string `json:"type"` + AssignmentGroup string `json:"assignment_group"` + Environment string `json:"environment"` +} + +// ValidAuthMethods defines the allowed authentication methods. +//var ValidAuthMethods = []string{"no-auth", "basic", "ntlm"} + +var ( + sha1ver string // sha1 revision used to build the program + buildTime string // when the executable was built +) + +/* +// ValidateAuthMethod checks if the provided auth method is valid. +func ValidateAuthMethod(authMethod string) error { + for _, validMethod := range ValidAuthMethods { + if authMethod == validMethod { + return nil + } + } + return errors.New("invalid authentication method: " + authMethod) +} +*/ + +func prettyPrint(args ...interface{}) { + var caller string + + timeNow := time.Now().Format("01-02-2006 15:04:05") + prefix := fmt.Sprintf("[%s] %s -- ", "PrettyPrint", timeNow) + _, fileName, fileLine, ok := runtime.Caller(1) + + if ok { + caller = fmt.Sprintf("%s:%d", fileName, fileLine) + } else { + caller = "" + } + + log.Printf("\n%s%s\n", prefix, caller) + + if len(args) == 2 { + label := args[0] + value := args[1] + + s, _ := json.MarshalIndent(value, "", "\t") + fmt.Printf("%s%s: %s\n", prefix, label, string(s)) + } else { + s, _ := json.MarshalIndent(args, "", "\t") + log.Printf("%s%s\n", prefix, string(s)) + } +} + +func main() { + // Command line flags for the vCenter connection + snowURL := flag.String("url", "https://server.domain.example/api/global/em/inbound_event", "The URL of the SNOW endpoint") + snowUser := flag.String("user", "username", "The username to use when authenticating to SNOW") + snowPass := flag.String("password", "password", "The password to use when authenticating to SNOW") + proxyURL := flag.String("p-url", "", "The URL of the SNOW endpoint, including protocol and port. Eg http://proxy.domain.example:8080") + + // proxyUser := flag.String("p-user", "", "The username to use when authenticating to the proxy") + // proxyPass := flag.String("p-pass", "", "The password to use when authenticating to the proxy") + // proxyDomain := flag.String("p-domain", "", "The domain to use when authenticating to the proxy with NTLM authentication") + payload := flag.String("payload", "{}", "The JSON formatted payload to send to SNOW") + + flag.Parse() + + // Print logs to file + f, err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Fatalf("error opening file: %v", err) + } + defer f.Close() + log.SetOutput(f) + + //log.Printf("Starting execution. Built on %s from sha1 %s\n", buildTime, sha1ver) + + /* + if err := ValidateAuthMethod(*proxyType); err != nil { + log.Fatalf("error validating auth method '%s': %s\n", *proxyType, err) + } else { + fmt.Println("Valid auth method:", *proxyType) + } + */ + + // Validate the incoming payload + var incident Incident + if err := json.Unmarshal([]byte(*payload), &incident); err != nil { + fmt.Printf("Error unmarshaling JSON: %s\n", err) + os.Exit(1) + } else { + prettyPrint(incident) + } + + // Configure proxy transport + var transport http.RoundTripper = http.DefaultTransport + if *proxyURL != "" { + proxy, err := url.Parse(*proxyURL) + if err != nil { + fmt.Println("Invalid proxy URL:", err) + return + } + + // Base transport with proxy + // baseTransport := &http.Transport{Proxy: http.ProxyURL(proxy)} + transport = &http.Transport{Proxy: http.ProxyURL(proxy)} + + /* + // If NTLM credentials are provided, wrap the transport + if *proxyUser != "" && *proxyPass != "" { + // create a dialer + dialer := &net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + } + + // wrap dial context with NTLM + ntlmDialContext := ntlm.NewNTLMProxyDialContext(dialer, *proxy, *proxyUser, *proxyPass, *proxyDomain, nil) + + transport = &http.Transport{ + Proxy: nil, // !!! IMPORTANT, do not set proxy here !!! + DialContext: ntlmDialContext, + } + } else { + transport = baseTransport + } + */ + } + + // Create HTTP client with custom transport + client := &http.Client{ + Transport: transport, + } + + // Create the request + req, err := http.NewRequest("POST", *snowURL, bytes.NewBuffer([]byte(*payload))) + if err != nil { + log.Println("Error creating request:", err) + return + } + + // Set headers + req.Header.Set("Content-Type", "application/json") + + // Add Basic Authentication for target URL + if *snowUser != "" && *snowPass != "" { + basicAuth := base64.StdEncoding.EncodeToString([]byte(*snowUser + ":" + *snowPass)) + req.Header.Set("Authorization", "Basic "+basicAuth) + } + + // Send the request + resp, err := client.Do(req) + if err != nil { + log.Println("Error sending request:", err) + return + } + defer resp.Body.Close() + + // Read response + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Println("Error reading response:", err) + return + } + + // Print response + log.Println("Response Status:", resp.Status) + fmt.Println(string(body)) +}