jsonmon icon indicating copy to clipboard operation
jsonmon copied to clipboard

Windows

Open tooolbox opened this issue 9 years ago • 15 comments

This seems like pretty much exactly what I need: highly configurable, super-lightweight alerting system written in Go.

Do you know how much effort it would take to get this thing working on Windows?

tooolbox avatar Oct 05 '16 02:10 tooolbox

There are two stoppers for Windows:

  1. we use /bin/sh to launch shell checks (code)
  2. we use /usr/sbin/sendmail for mail notifications (code)

What would you suggest to use on Windows instead of these Unix commands? The sendmail one worries me more than the shell.

My thoughts are that probably we need either Cygwin or native Powershell + SMTP delivery configuration.

chillum avatar Oct 05 '16 09:10 chillum

And the third stopper is logs. We send them to stderr and they're picked with systemd. Not sure if that will work with Windows, probably we need to direct them to the Event Log.

chillum avatar Oct 05 '16 09:10 chillum

Hm, okay. Seems like the shell checks could be done somewhat like this:

package main

import(
    "fmt"
    "os/exec"
)

func main(){    
    c := exec.Command("cmd", "/C", "del", "D:\\a.txt")

    if err := c.Run(); err != nil { 
        fmt.Println("Error: ", err)
    }   
}

(From here: http://stackoverflow.com/a/13013520/700471)

So you could check for a Windows OS and use cmd instead of /bin/sh basically. Although frankly...cygwin is kinda tempting because I'd rather write bash scripts than batch scripts. But I'd also rather avoid a hard dependency, perhaps we could add cmd to the config, so you can choose between the two based on if you have cygwin installed or not?

On the mailings, there's a number of ways of doing that from the command-line on Windows, as you say involving PowerShell in some cases other 3rd-party tools. I'd be tempted to pull in gophermail or some similar Go package to just hit the server directly. This would be reasonable, right? sendmail is essentially serving that same purpose, formatting an email and sending it to postfix on localhost:25?

For logs, there's NSSM which allows you to set up any binary as a service on Windows, and handles redirecting stdout and stderr to log files, including log rotation. Not sure if that fits the bill for you or not.

tooolbox avatar Oct 05 '16 17:10 tooolbox

  1. Regarding /usr/sbin/sendmail. Actually it's the same Postfix in your case, but not a TCP, but a CLI interface. Will look into gophermail, thanks.
  2. I don't think, I want NSSM as only option. Go has Windows event log built-in, we can just use that on Windows without complicating the system further. It would be nice to add syslog for macOS as well, but that's low priority as for now.
  3. I can easily make shell checks to use sh from $PATH, not /bin/sh. Would that help you as a Cygwin user? That is: is sh normally in your $PATH? (I don't use Cygwin, so I don't know if that's a common case)

chillum avatar Oct 05 '16 18:10 chillum

As for gophermail. It seems like the standard library is OK for our needs.

chillum avatar Oct 05 '16 18:10 chillum

I'm not sure what we should do with the environment variables configuration on Windows. That is: it's common for Unix systems to set up env. variables for a daemon, but I don't know if that's common on Windows. Or on Windows the way to go is to create a .bat file and to register it as a service?

chillum avatar Oct 05 '16 19:10 chillum

  1. Okay, so sendmail is a CLI interface to Postfix, I get it.
  2. I confess ignorance when it comes to many Windows things, so I'll trust you on the event log. I guess the logging is not a problem, then?
  3. When I'm dev'ing on Windows I use Babun which is zsh or bash basically, and in that environment I do have sh in my path. But if you're just running a binary as a service or something, there's no sh in your path by default. Then again, I'm sure it could be added.

What makes you want to avoid gophermail? If I were going to write the code, I'd definitely rather use that than the std lib.

I'm mostly OSX and Linux. My recent experience with Windows has been compiling binaries in Go and then using NSSM to turn them into a service. (Apparently it is hellish to add all of the hooks that are needed on a program to make it into a legitimate windows service, so NSSM shortcuts that for you.) NSSM lets you specify arguments and environment variables, but I don't know the true "Windows way".

tooolbox avatar Oct 05 '16 19:10 tooolbox

Yes, logging is pretty trivial.

What benefits does gophermail provide over the stdlib?

chillum avatar Oct 05 '16 20:10 chillum

Sorry, I think I was thinking of gomail but, in any case, it's just API differences. Would you rather do this-ish with gomail:

m := gomail.NewMessage()
m.SetHeader("From", "[email protected]")
m.SetHeader("To", "[email protected]", "[email protected]")
m.SetAddressHeader("Cc", "[email protected]", "Dan")
m.SetHeader("Subject", "Hello!")
m.SetBody("text/html", "Hello <b>Bob</b> and <i>Cora</i>!")
m.Attach("/home/Alex/lolcat.jpg")

d := gomail.NewDialer("smtp.example.com", 587, "user", "123456")

// Send the email to Bob, Cora and Dan.
if err := d.DialAndSend(m); err != nil {
    panic(err)
}

Or this-ish with stdlib:

func send(body string) {
    from := "[email protected]"
    pass := "..."
    to := "[email protected]"

    msg := "From: " + from + "\n" +
        "To: " + to + "\n" +
        "Subject: Hello there\n\n" +
        body

    err := smtp.SendMail("smtp.gmail.com:587",
        smtp.PlainAuth("", from, pass, "smtp.gmail.com"),
        from, []string{to}, []byte(msg))

    if err != nil {
        log.Printf("smtp error: %s", err)
        return
    }
}

Honestly, now that I look at it, stdlib is probably fine because we don't exactly need HTML bodies, attachments and these sorts of things.

tooolbox avatar Oct 05 '16 20:10 tooolbox

One note is that if you email within Go it is more flexible (you don't need a local postfix install, you can use whatever mail server is available) but you also need to take auth into account in terms of configuration. Username & pass, PlainAuth or potentially something else. I have an implementation of LoginAuth (such as for an Exchange server) which I can contribute.

I feel like this might overall increase the complexity of the default configuration, but not sure of a better way to make it work on Windows without requiring the implementor to write a custom notification plugin.

tooolbox avatar Oct 05 '16 20:10 tooolbox

Now the only thing left is the actual SMTP code.

I did some experiments and would like to stick with the env. variables as for configuration. MAIL_HOST, MAIL_PORT, MAIL_USER, MAIL_PASS, maybe something else. I don't think I have a preference whether we should use an external dependency or not.

If you want to contribute the SMTP code, I will review it. Or will write it myself, but that's not going to be very fast.

chillum avatar Oct 06 '16 19:10 chillum

Great progress!

Agreed on the env. variables. I will try to write the SMTP code today or tomorrow. To be clear, this will become the default for mail-sending from jsonmon, correct? We can probably provide a sample sendmail notification plugin for people who have a local postfix install.

tooolbox avatar Oct 06 '16 20:10 tooolbox

I would like not to break old configurations. But if the default will be sending to localhost:25 without authentication, we shouldn't break anyone.

Leaving the sendmail together with SMTP seems like complicating the code, so I agree that we probably should remove sendmail CLI invocation if we have SMTP.

We should also default the sender to user.Username (without domain) to keep the maximum compatibility (CLI invocation does this automatically). And I think that's it.

chillum avatar Oct 06 '16 21:10 chillum

I have a question (I don't use Windows myself). Is there around some Windows mail server that's free, light, easy to install and configure, that will start at boot and will listen at 127.0.0.1:25 for messages to relay?

chillum avatar Jun 01 '17 10:06 chillum

recently tested myself and found one more problem with Windows (besides SMTP), it affects non-English language packs.

let's take ping command. on non-English language pack it returns data not in Unicode, but in CP866.

both Event Log and terminal output look like: Failed: ping -c 1 192.168.6.1 ������ �����饭. ��� ��ࠬ���� -c �ॡ����� �ࠢ� ��������������. exit status 1

also it seems like Event Log needs more work (like proper event IDs or multiline handling).

chillum avatar Apr 12 '19 21:04 chillum