Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows #13

Open
tooolbox opened this issue Oct 5, 2016 · 15 comments
Open

Windows #13

tooolbox opened this issue Oct 5, 2016 · 15 comments

Comments

@tooolbox
Copy link

tooolbox commented Oct 5, 2016

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?

@chillum
Copy link
Owner

chillum commented Oct 5, 2016

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
Copy link
Owner

chillum commented Oct 5, 2016

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.

@tooolbox
Copy link
Author

tooolbox commented Oct 5, 2016

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.

@chillum
Copy link
Owner

chillum commented Oct 5, 2016

  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
Copy link
Owner

chillum commented Oct 5, 2016

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

@chillum
Copy link
Owner

chillum commented Oct 5, 2016

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?

@tooolbox
Copy link
Author

tooolbox commented Oct 5, 2016

  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".

@chillum
Copy link
Owner

chillum commented Oct 5, 2016

Yes, logging is pretty trivial.

What benefits does gophermail provide over the stdlib?

chillum added a commit that referenced this issue Oct 5, 2016
@tooolbox
Copy link
Author

tooolbox commented Oct 5, 2016

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", "alex@example.com")
m.SetHeader("To", "bob@example.com", "cora@example.com")
m.SetAddressHeader("Cc", "dan@example.com", "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 := "...@gmail.com"
    pass := "..."
    to := "foobarbazz@mailinator.com"

    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
Copy link
Author

tooolbox commented Oct 5, 2016

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.

@chillum
Copy link
Owner

chillum commented Oct 6, 2016

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.

@tooolbox
Copy link
Author

tooolbox commented Oct 6, 2016

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.

@chillum
Copy link
Owner

chillum commented Oct 6, 2016

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
Copy link
Owner

chillum commented Jun 1, 2017

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 chillum changed the title Windows SMTP support (was: Windows) Nov 5, 2017
@chillum chillum changed the title SMTP support (was: Windows) Windows Apr 12, 2019
@chillum
Copy link
Owner

chillum commented Apr 12, 2019

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants