Merge remote-tracking branch 'origin/master' into problame/replication_refactor

This commit is contained in:
Christian Schwarz 2019-03-16 14:48:01 +01:00
commit da3ba50a2c
7 changed files with 95 additions and 9 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/pkg/errors"
"github.com/zrepl/yaml-config"
"io/ioutil"
"log/syslog"
"os"
"reflect"
"regexp"
@ -38,7 +39,7 @@ func (j JobEnum) Name() string {
case *PullJob: name = v.Name
case *SourceJob: name = v.Name
default:
panic(fmt.Sprintf("unknownn job type %T", v))
panic(fmt.Sprintf("unknown job type %T", v))
}
return name
}
@ -289,6 +290,7 @@ type StdoutLoggingOutlet struct {
type SyslogLoggingOutlet struct {
LoggingOutletCommon `yaml:",inline"`
Facility *SyslogFacility `yaml:"facility,optional,fromdefaults"`
RetryInterval time.Duration `yaml:"retry_interval,positive,default=10s"`
}
@ -315,6 +317,14 @@ type PrometheusMonitoring struct {
Listen string `yaml:"listen"`
}
type SyslogFacility syslog.Priority
func (f *SyslogFacility) SetDefault() {
*f = SyslogFacility(syslog.LOG_LOCAL0)
}
var _ yaml.Defaulter = (*SyslogFacility)(nil)
type GlobalControl struct {
SockPath string `yaml:"sockpath,default=/var/run/zrepl/control"`
}
@ -420,6 +430,40 @@ func (t *MonitoringEnum) UnmarshalYAML(u func(interface{}, bool) error) (err err
return
}
func (t *SyslogFacility) UnmarshalYAML(u func(interface{}, bool) error) (err error) {
var s string
if err := u(&s, true); err != nil {
return err
}
var level syslog.Priority
switch s {
case "kern": level = syslog.LOG_KERN
case "user": level = syslog.LOG_USER
case "mail": level = syslog.LOG_MAIL
case "daemon": level = syslog.LOG_DAEMON
case "auth": level = syslog.LOG_AUTH
case "syslog": level = syslog.LOG_SYSLOG
case "lpr": level = syslog.LOG_LPR
case "news": level = syslog.LOG_NEWS
case "uucp": level = syslog.LOG_UUCP
case "cron": level = syslog.LOG_CRON
case "authpriv": level = syslog.LOG_AUTHPRIV
case "ftp": level = syslog.LOG_FTP
case "local0": level = syslog.LOG_LOCAL0
case "local1": level = syslog.LOG_LOCAL1
case "local2": level = syslog.LOG_LOCAL2
case "local3": level = syslog.LOG_LOCAL3
case "local4": level = syslog.LOG_LOCAL4
case "local5": level = syslog.LOG_LOCAL5
case "local6": level = syslog.LOG_LOCAL6
case "local7": level = syslog.LOG_LOCAL7
default:
return fmt.Errorf("invalid syslog level: %q", s)
}
*t = SyslogFacility(level)
return nil
}
var ConfigFileDefaultLocations = []string{
"/etc/zrepl/zrepl.yml",
"/usr/local/etc/zrepl/zrepl.yml",

View File

@ -1,9 +1,11 @@
package config
import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zrepl/yaml-config"
"log/syslog"
"testing"
)
@ -72,6 +74,36 @@ global:
assert.Equal(t, ":9091", conf.Global.Monitoring[0].Ret.(*PrometheusMonitoring).Listen)
}
func TestSyslogLoggingOutletFacility(t *testing.T) {
type SyslogFacilityPriority struct {
Facility string
Priority syslog.Priority
}
syslogFacilitiesPriorities := []SyslogFacilityPriority{
{"", syslog.LOG_LOCAL0}, // default
{"kern", syslog.LOG_KERN}, {"daemon", syslog.LOG_DAEMON}, {"auth", syslog.LOG_AUTH},
{"syslog", syslog.LOG_SYSLOG}, {"lpr", syslog.LOG_LPR}, {"news", syslog.LOG_NEWS},
{"uucp", syslog.LOG_UUCP}, {"cron", syslog.LOG_CRON}, {"authpriv", syslog.LOG_AUTHPRIV},
{"ftp", syslog.LOG_FTP}, {"local0", syslog.LOG_LOCAL0}, {"local1", syslog.LOG_LOCAL1},
{"local2", syslog.LOG_LOCAL2}, {"local3", syslog.LOG_LOCAL3}, {"local4", syslog.LOG_LOCAL4},
{"local5", syslog.LOG_LOCAL5}, {"local6", syslog.LOG_LOCAL6}, {"local7", syslog.LOG_LOCAL7},
}
for _, sFP := range syslogFacilitiesPriorities {
logcfg := fmt.Sprintf(`
global:
logging:
- type: syslog
level: info
format: human
facility: %s
`, sFP.Facility)
conf := testValidGlobalSection(t, logcfg)
assert.Equal(t, 1, len(*conf.Global.Logging))
assert.True(t, SyslogFacility(sFP.Priority) == *(*conf.Global.Logging)[0].Ret.(*SyslogLoggingOutlet).Facility)
}
}
func TestLoggingOutletEnumList_SetDefaults(t *testing.T) {
e := &LoggingOutletEnumList{}
var i yaml.Defaulter = e

View File

@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"log/syslog"
"os"
"github.com/mattn/go-isatty"
@ -222,6 +223,7 @@ func parseSyslogOutlet(in *config.SyslogLoggingOutlet, formatter EntryFormatter)
out = &SyslogOutlet{}
out.Formatter = formatter
out.Formatter.SetMetadataFlags(MetadataNone)
out.Facility = syslog.Priority(*in.Facility)
out.RetryInterval = in.RetryInterval
return out, nil
}

View File

@ -124,6 +124,7 @@ func (h *TCPOutlet) WriteEntry(e logger.Entry) error {
type SyslogOutlet struct {
Formatter EntryFormatter
RetryInterval time.Duration
Facility syslog.Priority
writer *syslog.Writer
lastConnectAttempt time.Time
}
@ -142,7 +143,7 @@ func (o *SyslogOutlet) WriteEntry(entry logger.Entry) error {
if now.Sub(o.lastConnectAttempt) < o.RetryInterval {
return nil // not an error toward logger
}
o.writer, err = syslog.New(syslog.LOG_LOCAL0, "zrepl")
o.writer, err = syslog.New(o.Facility, "zrepl")
o.lastConnectAttempt = time.Now()
if err != nil {
o.writer = nil

View File

@ -147,6 +147,8 @@ Can only be specified once.
- minimum :ref:`log level <logging-levels>`
* - ``format``
- output :ref:`format <logging-formats>`
* - ``facility``
- Which syslog facility to use (default = ``local0``)
* - ``retry_interval``
- Interval between reconnection attempts to syslog (default = 0)

View File

@ -76,6 +76,7 @@ Connect
The ``tls`` transport uses TCP + TLS with client authentication using client certificates.
The client identity is the common name (CN) presented in the client certificate.
It is recommended to set up a dedicated CA infrastructure for this transport, e.g. using OpenVPN's `EasyRSA <https://github.com/OpenVPN/easy-rsa>`_.
For a simple 2-machine setup, see the :ref:`instructions below<transport-tcp+tlsclientauth-2machineopenssl>`.
@ -85,6 +86,10 @@ Since Go binaries are statically linked, you or your distribution need to recomp
All file paths are resolved relative to the zrepl daemon's working directory.
Specify absolute paths if you are unsure what directory that is (or find out from your init system).
If intermediate CAs are used, the **full chain** must be present in either in the ``ca`` file or the individual ``cert`` files.
Regardless, the client's certificate must be first in the ``cert`` file, with each following certificate directly certifying the one preceding it (see `TLS's specification <https://tools.ietf.org/html/rfc5246#section-7.4.2>`_).
This is the common default when using a CA management tool.
Serve
~~~~~
@ -96,9 +101,9 @@ Serve
serve:
type: tls
listen: ":8888"
ca: /etc/zrepl/ca.crt
cert: /etc/zrepl/prod.crt
key: /etc/zrepl/prod.key
ca: /etc/zrepl/ca.crt
cert: /etc/zrepl/prod.fullchain
key: /etc/zrepl/prod.key
client_cns:
- "laptop1"
- "homeserver"
@ -116,8 +121,8 @@ Connect
connect:
type: tls
address: "server1.foo.bar:8888"
ca: /etc/zrepl/ca.crt
cert: /etc/zrepl/backupserver.crt
ca: /etc/zrepl/ca.crt
cert: /etc/zrepl/backupserver.fullchain
key: /etc/zrepl/backupserver.key
server_cn: "server1"
dial_timeout: # optional, default 10s

View File

@ -83,8 +83,8 @@ func (l *ClientAuthListener) Accept() (tcpConn *net.TCPConn, tlsConn *tls.Conn,
tlsConn.SetDeadline(time.Time{})
peerCerts = tlsConn.ConnectionState().PeerCertificates
if len(peerCerts) != 1 {
err = errors.New("unexpected number of certificates presented by TLS client")
if len(peerCerts) < 1 {
err = errors.New("client must present full RFC5246:7.4.2 TLS client certificate chain")
goto CloseAndErr
}
cn = peerCerts[0].Subject.CommonName