github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_run_log_driver_syslog_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "os" 22 "runtime" 23 "strconv" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/containerd/nerdctl/pkg/rootlessutil" 29 "github.com/containerd/nerdctl/pkg/testutil" 30 "github.com/containerd/nerdctl/pkg/testutil/testca" 31 "github.com/containerd/nerdctl/pkg/testutil/testsyslog" 32 syslog "github.com/yuchanns/srslog" 33 ) 34 35 func runSyslogTest(t *testing.T, networks []string, syslogFacilities map[string]syslog.Priority, fmtValidFuncs map[string]func(string, string, string, string, syslog.Priority, bool) error) { 36 if runtime.GOOS == "windows" { 37 t.Skip("syslog container logging is not officially supported on Windows") 38 } 39 40 base := testutil.NewBase(t) 41 base.Cmd("pull", testutil.CommonImage).AssertOK() 42 hostname, err := os.Hostname() 43 if err != nil { 44 t.Fatalf("Error retrieving hostname") 45 } 46 ca := testca.New(base.T) 47 cert := ca.NewCert("127.0.0.1") 48 t.Cleanup(func() { 49 cert.Close() 50 ca.Close() 51 }) 52 rI := 0 53 for _, network := range networks { 54 for rFK, rFV := range syslogFacilities { 55 fPriV := rFV 56 // test both string and number facility 57 for _, fPriK := range []string{rFK, strconv.Itoa(int(fPriV) >> 3)} { 58 for fmtK, fmtValidFunc := range fmtValidFuncs { 59 fmtKT := "empty" 60 if fmtK != "" { 61 fmtKT = fmtK 62 } 63 subTestName := fmt.Sprintf("%s_%s_%s", strings.ReplaceAll(network, "+", "_"), fPriK, fmtKT) 64 i := rI 65 rI++ 66 t.Run(subTestName, func(t *testing.T) { 67 tID := testutil.Identifier(t) 68 tag := tID + "_syslog_driver" 69 msg := "hello, " + tID + "_syslog_driver" 70 if !testsyslog.TestableNetwork(network) { 71 if rootlessutil.IsRootless() { 72 t.Skipf("skipping on %s/%s; '%s' for rootless containers are not supported", runtime.GOOS, runtime.GOARCH, network) 73 } 74 t.Skipf("skipping on %s/%s; '%s' is not supported", runtime.GOOS, runtime.GOARCH, network) 75 } 76 testContainerName := fmt.Sprintf("%s-%d-%s", tID, i, fPriK) 77 done := make(chan string) 78 addr, closer := testsyslog.StartServer(network, "", done, cert) 79 args := []string{ 80 "run", 81 "-d", 82 "--name", 83 testContainerName, 84 "--restart=no", 85 "--log-driver=syslog", 86 "--log-opt=syslog-facility=" + fPriK, 87 "--log-opt=tag=" + tag, 88 "--log-opt=syslog-format=" + fmtK, 89 "--log-opt=syslog-address=" + fmt.Sprintf("%s://%s", network, addr), 90 } 91 if network == "tcp+tls" { 92 args = append(args, 93 "--log-opt=syslog-tls-cert="+cert.CertPath, 94 "--log-opt=syslog-tls-key="+cert.KeyPath, 95 "--log-opt=syslog-tls-ca-cert="+ca.CertPath, 96 ) 97 } 98 args = append(args, testutil.CommonImage, "echo", msg) 99 base.Cmd(args...).AssertOK() 100 t.Cleanup(func() { 101 base.Cmd("rm", "-f", testContainerName).AssertOK() 102 }) 103 defer closer.Close() 104 defer close(done) 105 select { 106 case rcvd := <-done: 107 if err := fmtValidFunc(rcvd, msg, tag, hostname, fPriV, network == "tcp+tls"); err != nil { 108 t.Error(err) 109 } 110 case <-time.Tick(time.Second * 3): 111 t.Errorf("timeout with %s", subTestName) 112 } 113 }) 114 } 115 } 116 } 117 } 118 } 119 120 func TestSyslogNetwork(t *testing.T) { 121 var syslogFacilities = map[string]syslog.Priority{ 122 "user": syslog.LOG_USER, 123 } 124 125 networks := []string{ 126 "udp", 127 "tcp", 128 "tcp+tls", 129 "unix", 130 "unixgram", 131 } 132 fmtValidFuncs := map[string]func(string, string, string, string, syslog.Priority, bool) error{ 133 "rfc5424": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isTLS bool) error { 134 var parsedHostname, timestamp string 135 var length, version, pid int 136 if !isTLS { 137 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 138 if n, err := fmt.Sscanf(rcvd, exp, &version, ×tamp, &parsedHostname, &pid); n != 4 || err != nil || hostname != parsedHostname { 139 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 140 } 141 } else { 142 exp := "%d " + fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 143 if n, err := fmt.Sscanf(rcvd, exp, &length, &version, ×tamp, &parsedHostname, &pid); n != 5 || err != nil || hostname != parsedHostname { 144 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 145 } 146 } 147 return nil 148 }, 149 } 150 runSyslogTest(t, networks, syslogFacilities, fmtValidFuncs) 151 } 152 153 func TestSyslogFacilities(t *testing.T) { 154 var syslogFacilities = map[string]syslog.Priority{ 155 "kern": syslog.LOG_KERN, 156 "user": syslog.LOG_USER, 157 "mail": syslog.LOG_MAIL, 158 "daemon": syslog.LOG_DAEMON, 159 "auth": syslog.LOG_AUTH, 160 "syslog": syslog.LOG_SYSLOG, 161 "lpr": syslog.LOG_LPR, 162 "news": syslog.LOG_NEWS, 163 "uucp": syslog.LOG_UUCP, 164 "cron": syslog.LOG_CRON, 165 "authpriv": syslog.LOG_AUTHPRIV, 166 "ftp": syslog.LOG_FTP, 167 "local0": syslog.LOG_LOCAL0, 168 "local1": syslog.LOG_LOCAL1, 169 "local2": syslog.LOG_LOCAL2, 170 "local3": syslog.LOG_LOCAL3, 171 "local4": syslog.LOG_LOCAL4, 172 "local5": syslog.LOG_LOCAL5, 173 "local6": syslog.LOG_LOCAL6, 174 "local7": syslog.LOG_LOCAL7, 175 } 176 177 networks := []string{"unix"} 178 fmtValidFuncs := map[string]func(string, string, string, string, syslog.Priority, bool) error{ 179 "rfc5424": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isTLS bool) error { 180 var parsedHostname, timestamp string 181 var length, version, pid int 182 if !isTLS { 183 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 184 if n, err := fmt.Sscanf(rcvd, exp, &version, ×tamp, &parsedHostname, &pid); n != 4 || err != nil || hostname != parsedHostname { 185 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 186 } 187 } else { 188 exp := "%d " + fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 189 if n, err := fmt.Sscanf(rcvd, exp, &length, &version, ×tamp, &parsedHostname, &pid); n != 5 || err != nil || hostname != parsedHostname { 190 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 191 } 192 } 193 return nil 194 }, 195 } 196 runSyslogTest(t, networks, syslogFacilities, fmtValidFuncs) 197 } 198 199 func TestSyslogFormat(t *testing.T) { 200 var syslogFacilities = map[string]syslog.Priority{ 201 "user": syslog.LOG_USER, 202 } 203 204 networks := []string{"unix"} 205 fmtValidFuncs := map[string]func(string, string, string, string, syslog.Priority, bool) error{ 206 "": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isSTLS bool) error { 207 var mon, day, hrs string 208 var pid int 209 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%s %s %s " + tag + "[%d]: " + msg + "\n" 210 if n, err := fmt.Sscanf(rcvd, exp, &mon, &day, &hrs, &pid); n != 4 || err != nil { 211 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 212 } 213 return nil 214 }, 215 "rfc3164": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isTLS bool) error { 216 var parsedHostname, mon, day, hrs string 217 var pid int 218 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%s %s %s %s " + tag + "[%d]: " + msg + "\n" 219 if n, err := fmt.Sscanf(rcvd, exp, &mon, &day, &hrs, &parsedHostname, &pid); n != 5 || err != nil || hostname != parsedHostname { 220 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 221 } 222 return nil 223 }, 224 "rfc5424": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isTLS bool) error { 225 var parsedHostname, timestamp string 226 var length, version, pid int 227 if !isTLS { 228 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 229 if n, err := fmt.Sscanf(rcvd, exp, &version, ×tamp, &parsedHostname, &pid); n != 4 || err != nil || hostname != parsedHostname { 230 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 231 } 232 } else { 233 exp := "%d " + fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 234 if n, err := fmt.Sscanf(rcvd, exp, &length, &version, ×tamp, &parsedHostname, &pid); n != 5 || err != nil || hostname != parsedHostname { 235 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 236 } 237 } 238 return nil 239 }, 240 "rfc5424micro": func(rcvd, msg, tag, hostname string, pri syslog.Priority, isTLS bool) error { 241 var parsedHostname, timestamp string 242 var length, version, pid int 243 if !isTLS { 244 exp := fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 245 if n, err := fmt.Sscanf(rcvd, exp, &version, ×tamp, &parsedHostname, &pid); n != 4 || err != nil || hostname != parsedHostname { 246 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 247 } 248 } else { 249 exp := "%d " + fmt.Sprintf("<%d>", pri|syslog.LOG_INFO) + "%d %s %s " + tag + " %d " + tag + " - " + msg + "\n" 250 if n, err := fmt.Sscanf(rcvd, exp, &length, &version, ×tamp, &parsedHostname, &pid); n != 5 || err != nil || hostname != parsedHostname { 251 return fmt.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, exp, n, err) 252 } 253 } 254 return nil 255 }, 256 } 257 runSyslogTest(t, networks, syslogFacilities, fmtValidFuncs) 258 }