From 4a1b25d200409438a47e591b67bf76205fbb06ff Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Fri, 19 Jan 2024 10:40:20 -0500 Subject: [PATCH 1/7] Adding logic to find certs/included files in NATS config for file watcher Deps updates --- cmd/nats-server-config-reloader/main.go | 10 +- go.mod | 60 ++++---- go.sum | 128 +++++++++--------- pkg/natsreloader/natsreloader.go | 124 +++++++++++++++-- .../natsreloadertest/natsreloader_test.go | 8 +- 5 files changed, 219 insertions(+), 111 deletions(-) diff --git a/cmd/nats-server-config-reloader/main.go b/cmd/nats-server-config-reloader/main.go index 5745f812..5d9b7978 100644 --- a/cmd/nats-server-config-reloader/main.go +++ b/cmd/nats-server-config-reloader/main.go @@ -42,9 +42,9 @@ func main() { // Help and version var ( - showHelp bool - showVersion bool - fileSet StringSet + showHelp bool + showVersion bool + fileSet StringSet customSignal int ) @@ -64,9 +64,9 @@ func main() { fs.Parse(os.Args[1:]) - nconfig.ConfigFiles = fileSet + nconfig.WatchedFiles = fileSet if len(fileSet) == 0 { - nconfig.ConfigFiles = []string{"/etc/nats-config/gnatsd.conf"} + nconfig.WatchedFiles = []string{"/etc/nats-config/gnatsd.conf"} } nconfig.Signal = syscall.Signal(customSignal) diff --git a/go.mod b/go.mod index d0921bd3..2b0c5b74 100644 --- a/go.mod +++ b/go.mod @@ -1,30 +1,30 @@ module github.com/nats-io/nack -go 1.20 +go 1.21 require ( - github.com/fsnotify/fsnotify v1.6.0 + github.com/fsnotify/fsnotify v1.7.0 github.com/nats-io/jsm.go v0.1.0 - github.com/nats-io/nats-server/v2 v2.10.0 - github.com/nats-io/nats.go v1.30.0 + github.com/nats-io/nats-server/v2 v2.10.9 + github.com/nats-io/nats.go v1.32.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 - golang.org/x/sync v0.1.0 - k8s.io/api v0.28.2 - k8s.io/apimachinery v0.28.2 - k8s.io/client-go v0.28.2 - k8s.io/code-generator v0.28.2 - k8s.io/klog/v2 v2.100.1 - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 + golang.org/x/sync v0.6.0 + k8s.io/api v0.29.1 + k8s.io/apimachinery v0.29.1 + k8s.io/client-go v0.29.1 + k8s.io/code-generator v0.29.1 + k8s.io/klog/v2 v2.120.1 + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 ) require ( github.com/antonmedv/expr v1.15.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -32,41 +32,41 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nats-io/jwt/v2 v2.5.2 // indirect - github.com/nats-io/nkeys v0.4.5 // indirect + github.com/nats-io/jwt/v2 v2.5.3 // indirect + github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.8.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index bc071373..e37bb900 100644 --- a/go.sum +++ b/go.sum @@ -6,16 +6,15 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -23,6 +22,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -35,13 +35,15 @@ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvR github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= @@ -52,11 +54,12 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -74,23 +77,26 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/jsm.go v0.1.0 h1:H2gYCee/iyBDjUftPOr5fEPWAcG/+fyVl89IWiy6AC4= github.com/nats-io/jsm.go v0.1.0/go.mod h1:snnYORje42cEDCX5QygzeoVA2KiWVbiIJbLfGIvXW08= -github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU= -github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI= -github.com/nats-io/nats-server/v2 v2.10.0 h1:rcU++Hzo+wARxtJugrV3J5z5iGdHeVG8tT8Chb3bKDg= -github.com/nats-io/nats-server/v2 v2.10.0/go.mod h1:3PMvMSu2cuK0J9YInRLWdFpFsswKKGUS77zVSAudRto= -github.com/nats-io/nats.go v1.30.0 h1:bj/rVsRCrFXxmm9mJiDhb74UKl2HhKpDwKRBtvCjZjc= -github.com/nats-io/nats.go v1.30.0/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM= -github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk= -github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= +github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo= +github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4= +github.com/nats-io/nats-server/v2 v2.10.9 h1:VEW43Zz+p+9lARtiPM9ctd6ckun+92ZT2T17HWtwiFI= +github.com/nats-io/nats-server/v2 v2.10.9/go.mod h1:oorGiV9j3BOLLO3ejQe+U7pfAGyPo+ppD7rpgNF6KTQ= +github.com/nats-io/nats.go v1.32.0 h1:Bx9BZS+aXYlxW08k8Gd3yR2s73pV5XSoAQUyp1Kwvp0= +github.com/nats-io/nats.go v1.32.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -110,51 +116,49 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -163,8 +167,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -177,27 +181,27 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/code-generator v0.28.2 h1:u47guga1rCWLnEnffF09p+cqj8B20oHOLoQ1lb1HGtQ= -k8s.io/code-generator v0.28.2/go.mod h1:ueeSJZJ61NHBa0ccWLey6mwawum25vX61nRZ6WOzN9A= -k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= -k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= +k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= +k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= +k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A= +k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks= +k8s.io/code-generator v0.29.1 h1:8ba8BdtSmAVHgAMpzThb/fuyQeTRtN7NtN7VjMcDLew= +k8s.io/code-generator v0.29.1/go.mod h1:FwFi3C9jCrmbPjekhaCYcYG1n07CYiW1+PAPCockaos= +k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= +k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/natsreloader/natsreloader.go b/pkg/natsreloader/natsreloader.go index e1c048bc..0eba35d0 100644 --- a/pkg/natsreloader/natsreloader.go +++ b/pkg/natsreloader/natsreloader.go @@ -23,6 +23,7 @@ import ( "math/rand" "os" "path/filepath" + "regexp" "sort" "strconv" "syscall" @@ -36,7 +37,7 @@ const errorFmt = "Error: %s\n" // Config represents the configuration of the reloader. type Config struct { PidFile string - ConfigFiles []string + WatchedFiles []string MaxRetries int RetryWaitSecs int Signal os.Signal @@ -186,7 +187,7 @@ func handleEvents(configWatcher *fsnotify.Watcher, event fsnotify.Event, lastCon } } -func handleDeletedFiles(deletedFiles []string, configWatcher *fsnotify.Watcher, lastConfigAppliedCache map[string][]byte) ([]string, []string) { +func handleDeletedFiles(deletedFiles []string, configWatcher *fsnotify.Watcher, lastConfigAppliedCache map[string][]byte) ([]string, []string) { if len(deletedFiles) > 0 { log.Printf("Tracking files %v", deletedFiles) } @@ -213,23 +214,36 @@ func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) { return nil, nil, err } + watchedFiles := make([]string, 0) + + for _, c := range r.WatchedFiles { + childFiles, err := getServerFiles(c) + if err != nil { + return nil, nil, err + } + + watchedFiles = append(watchedFiles, childFiles...) + } + + r.WatchedFiles = append(r.WatchedFiles, watchedFiles...) + // Follow configuration updates in the directory where // the config file is located and trigger reload when // it is either recreated or written into. - for i := range r.ConfigFiles { + for i := range r.WatchedFiles { // Ensure our paths are canonical - r.ConfigFiles[i], _ = filepath.Abs(r.ConfigFiles[i]) + r.WatchedFiles[i], _ = filepath.Abs(r.WatchedFiles[i]) } - r.ConfigFiles = removeDuplicateStrings(r.ConfigFiles) + r.WatchedFiles = removeDuplicateStrings(r.WatchedFiles) // Follow configuration file updates and trigger reload when // it is either recreated or written into. - for i := range r.ConfigFiles { + for i := range r.WatchedFiles { // Watch files individually for https://github.com/kubernetes/kubernetes/issues/112677 - if err := configWatcher.Add(r.ConfigFiles[i]); err != nil { + if err := configWatcher.Add(r.WatchedFiles[i]); err != nil { _ = configWatcher.Close() return nil, nil, err } - log.Printf("Watching file: %v", r.ConfigFiles[i]) + log.Printf("Watching file: %v", r.WatchedFiles[i]) } // lastConfigAppliedCache is the last config update @@ -238,7 +252,7 @@ func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) { // Preload config hashes, so we know their digests // up front and avoid potentially reloading when unnecessary. - for _, configFile := range r.ConfigFiles { + for _, configFile := range r.WatchedFiles { digest, err := getFileDigest(configFile) if err != nil { _ = configWatcher.Close() @@ -251,7 +265,7 @@ func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) { if len(lastConfigAppliedCache) == 0 { log.Printf("Error: no watched config files cached; input spec was: %#v", - r.ConfigFiles) + r.WatchedFiles) } return configWatcher, lastConfigAppliedCache, nil } @@ -374,3 +388,93 @@ func retryJitter(base time.Duration) time.Duration { offset := rand.Float64()*0.2 - 0.1 return time.Duration(b + offset) } + +func getServerFiles(configFile string) ([]string, error) { + filePaths, err := getIncludePaths(configFile, make(map[string]interface{})) + if err != nil { + return nil, err + } + + certPaths, err := getCertPaths(filePaths) + if err != nil { + return nil, err + } + + filePaths = append(filePaths, certPaths...) + sort.Strings(filePaths) + + return filePaths, nil +} + +func getIncludePaths(configFile string, checked map[string]interface{}) ([]string, error) { + if _, ok := checked[configFile]; ok { + return []string{}, nil + } + + configFile, err := filepath.Abs(configFile) + if err != nil { + return nil, err + } + + // Add the current config file to the list and mark it as checked + filePaths := []string{configFile} + checked[configFile] = nil + + parentDirectory := filepath.Dir(configFile) + includeRegex := regexp.MustCompile(`(?m)^\s*include\s+([^\n]*)`) + + content, err := os.ReadFile(configFile) + if err != nil { + return nil, err + } + + includeMatches := includeRegex.FindAllStringSubmatch(string(content), -1) + for _, match := range includeMatches { + // Include filepaths in NATS config are always relative + fullyQualifiedPath := filepath.Join(parentDirectory, match[1]) + fullyQualifiedPath = filepath.Clean(fullyQualifiedPath) + + if _, err := os.Stat(fullyQualifiedPath); os.IsNotExist(err) { + return nil, fmt.Errorf("%s does not exist", fullyQualifiedPath) + } + + // Recursive call to make sure we catch any nested includes + // Using map[string]interface{} as a set to avoid loops + includePaths, err := getIncludePaths(fullyQualifiedPath, checked) + if err != nil { + return nil, err + } + + filePaths = append(filePaths, includePaths...) + } + + return filePaths, nil +} + +func getCertPaths(configPaths []string) ([]string, error) { + certPaths := []string{} + certRegex := regexp.MustCompile(`(?m)^\s*(cert_file|key_file|ca_file)\s*:\s*"?([^"\n]*)"?`) + + for _, configPath := range configPaths { + content, err := os.ReadFile(configPath) + if err != nil { + return nil, err + } + + certMatches := certRegex.FindAllStringSubmatch(string(content), -1) + for _, match := range certMatches { + fullyQualifiedPath, err := filepath.Abs(match[2]) + if err != nil { + return nil, err + } + + if _, err := os.Stat(fullyQualifiedPath); os.IsNotExist(err) { + return nil, fmt.Errorf("%s does not exist", fullyQualifiedPath) + } + + certPaths = append(certPaths, fullyQualifiedPath) + } + } + + return certPaths, nil +} diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloadertest/natsreloader_test.go index 7bd9755d..5877b08e 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloadertest/natsreloader_test.go @@ -48,9 +48,9 @@ func TestReloader(t *testing.T) { // Create tempfile with contents, then update it nconfig := &natsreloader.Config{ - PidFile: pidfile.Name(), - ConfigFiles: []string{}, - Signal: syscall.SIGHUP, + PidFile: pidfile.Name(), + WatchedFiles: []string{}, + Signal: syscall.SIGHUP, } var configFiles []*os.File @@ -65,7 +65,7 @@ func TestReloader(t *testing.T) { t.Fatal(err) } configFiles = append(configFiles, configFile) - nconfig.ConfigFiles = append(nconfig.ConfigFiles, configFile.Name()) + nconfig.WatchedFiles = append(nconfig.WatchedFiles, configFile.Name()) } r, err := natsreloader.NewReloader(nconfig) From bee9f0987e015dcf99dd4542e8f0542515c0b8bf Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Fri, 19 Jan 2024 14:27:34 -0500 Subject: [PATCH 2/7] Add test for filewatcher logic --- .../natsreloadertest/natsreloader_test.go | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloadertest/natsreloader_test.go index 5877b08e..e027858e 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloadertest/natsreloader_test.go @@ -17,8 +17,12 @@ import ( "context" "errors" "fmt" + "io/fs" "os" "os/signal" + "path/filepath" + "sort" + "strings" "sync" "syscall" "testing" @@ -27,6 +31,40 @@ import ( "github.com/nats-io/nack/pkg/natsreloader" ) +const ( + testConfig_0 = ` +jetstream { + store_dir: data/jetstream + max_mem: 10G + max_file: 10G +} +operator: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiI3Sk1aNEQ0RE1WU1hGWDRYWExCTVVITjY1MjdaQlhaV0dZUUtBQVk0TVRQQTZOSEdHS1NBIiwiaWF0IjoxNjgyNTAzMzg4LCJpc3MiOiJPQ1hXU0tWNU5UTUxCUjI0NlZaQ0laSzVZRlBVTVNPVjZVWk5JNDRPTFVVUUlCNkE0VU1RWE1USiIsIm5hbWUiOiJuYXRzLXRlc3QtMDEiLCJzdWIiOiJPQ1hXU0tWNU5UTUxCUjI0NlZaQ0laSzVZRlBVTVNPVjZVWk5JNDRPTFVVUUlCNkE0VU1RWE1USiIsIm5hdHMiOnsic2lnbmluZ19rZXlzIjpbIk9DS1oyNkpJUDdCN1BHQk43QTdEVEVHVk9NUlNHNE5XVFZURjdPQ0pOSVdRS0xZT0YzWDJBTlFKIl0sImFjY291bnRfc2VydmVyX3VybCI6Im5hdHM6Ly9sb2NhbGhvc3Q6NDIyMiIsIm9wZXJhdG9yX3NlcnZpY2VfdXJscyI6WyJuYXRzOi8vbG9jYWxob3N0OjQyMjIiXSwic3lzdGVtX2FjY291bnQiOiJBQk5ITEY2NVlEWkxGWUlIUVVVU0pXWlZSUVc0UE8zVFFRT0VTNlA3WTRUQ1BQWVVTNkhIVzJFUyIsInR5cGUiOiJvcGVyYXRvciIsInZlcnNpb24iOjJ9fQ.LjVkEnA3Fg3F20cPZm5FShZQKWPiU4pLdhh2s0cj_zhxA88wXgNfUo_SPs59JE97qvpR7AOWksP5dzxMZJ2iBQ +# System Account named SYS +system_account: ABNHLF65YDZLFYIHQUUSJWZVRQW4PO3TQQOES6P7Y4TCPPYUS6HHW2ES + +resolver { + type: full + dir: './' +} + +jetstream { + store_dir: data/jetstream + max_mem: 10G + max_file: 10G +} + +include ./testConfig_1.conf` + + testConfig_1 = `include ./testConfig_2.conf` + + testConfig_2 = ` +tls: { + cert_file: "./test.pem" + key_file: "./testkey.pem" +} +` +) + var configContents = `port = 2222` var newConfigContents = `port = 2222 someOtherThing = "bar" @@ -134,3 +172,121 @@ func TestReloader(t *testing.T) { t.Fatalf("Wrong number of signals received. Expected: %v, got: %v", expected, got) } } + +func TestFileFinder(t *testing.T) { + directory, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + confFile := filepath.Join(directory, "testConfig_0.conf") + err = writeFile(testConfig_0, confFile) + defer os.Remove(confFile) + if err != nil { + t.Fatal(err) + } + confFile = filepath.Join(directory, "testConfig_1.conf") + err = writeFile(testConfig_1, confFile) + defer os.Remove(confFile) + if err != nil { + t.Fatal(err) + } + confFile = filepath.Join(directory, "testConfig_2.conf") + err = writeFile(testConfig_2, confFile) + defer os.Remove(confFile) + if err != nil { + t.Fatal(err) + } + confFile = filepath.Join(directory, "test.pem") + err = writeFile("test", confFile) + defer os.Remove(confFile) + if err != nil { + t.Fatal(err) + } + confFile = filepath.Join(directory, "testkey.pem") + err = writeFile("test", confFile) + defer os.Remove(confFile) + if err != nil { + t.Fatal(err) + } + + pid := os.Getpid() + pidFile := filepath.Join(directory, "nats.pid") + err = writeFile(fmt.Sprintf("%d", pid), pidFile) + if err != nil { + t.Fatal(err) + } + defer os.Remove(pidFile) + + nconfig := &natsreloader.Config{ + PidFile: pidFile, + WatchedFiles: []string{filepath.Join(directory, "testConfig_0.conf")}, + Signal: syscall.SIGHUP, + } + + r, err := natsreloader.NewReloader(nconfig) + if err != nil { + t.Fatal(err) + } + + ctx, cancel := context.WithCancel(context.Background()) + + go func() { + err = r.Run(ctx) + if err != nil { + t.Error(err) + } + }() + + time.Sleep(time.Second) + + expectedWatchedFiles := []string{ + "/testConfig_0.conf", + "/testConfig_1.conf", + "/testConfig_2.conf", + "/test.pem", + "/testkey.pem", + } + + watchedFiles := r.WatchedFiles + + sort.Strings(expectedWatchedFiles) + sort.Strings(watchedFiles) + + if len(watchedFiles) > len(expectedWatchedFiles) { + t.Fatal("Unexpected number of watched files") + } + + for i, e := range expectedWatchedFiles { + f := strings.TrimPrefix(watchedFiles[i], directory) + if f != e { + t.Fatal("Expected watched file list does not match") + } + + } + + cancel() +} + +func writeFile(content, path string) error { + parentDirectory := filepath.Dir(path) + if _, err := os.Stat(parentDirectory); errors.Is(err, fs.ErrNotExist) { + err = os.MkdirAll(parentDirectory, 0o755) + if err != nil { + return err + } + } + + file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0o644) + if err != nil { + return err + } + defer file.Close() + + _, err = file.WriteString(content) + if err != nil { + return err + } + + return nil +} From fe6ef2f6f8afb316ebcfc0838019d7a40c008304 Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Mon, 22 Jan 2024 12:36:25 -0500 Subject: [PATCH 3/7] Fix race in test --- pkg/natsreloader/natsreloadertest/natsreloader_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloadertest/natsreloader_test.go index e027858e..1f01f61f 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloadertest/natsreloader_test.go @@ -240,6 +240,8 @@ func TestFileFinder(t *testing.T) { time.Sleep(time.Second) + cancel() + expectedWatchedFiles := []string{ "/testConfig_0.conf", "/testConfig_1.conf", @@ -264,8 +266,6 @@ func TestFileFinder(t *testing.T) { } } - - cancel() } func writeFile(content, path string) error { From c0422b17337b45309f0232a3024ca7d599db19e5 Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Wed, 24 Jan 2024 15:00:38 -0500 Subject: [PATCH 4/7] Renaming gnatsd files to nats. Adding config file extension check --- cmd/nats-server-config-reloader/main.go | 6 +++--- pkg/natsreloader/natsreloader.go | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/nats-server-config-reloader/main.go b/cmd/nats-server-config-reloader/main.go index 5d9b7978..be9c5fde 100644 --- a/cmd/nats-server-config-reloader/main.go +++ b/cmd/nats-server-config-reloader/main.go @@ -54,8 +54,8 @@ func main() { fs.BoolVar(&showVersion, "v", false, "Show version") fs.BoolVar(&showVersion, "version", false, "Show version") - fs.StringVar(&nconfig.PidFile, "P", "/var/run/nats/gnatsd.pid", "NATS Server Pid File") - fs.StringVar(&nconfig.PidFile, "pid", "/var/run/nats/gnatsd.pid", "NATS Server Pid File") + fs.StringVar(&nconfig.PidFile, "P", "/var/run/nats/nats.pid", "NATS Server Pid File") + fs.StringVar(&nconfig.PidFile, "pid", "/var/run/nats/nats.pid", "NATS Server Pid File") fs.Var(&fileSet, "c", "NATS Server Config File (may be repeated to specify more than one)") fs.Var(&fileSet, "config", "NATS Server Config File (may be repeated to specify more than one)") fs.IntVar(&nconfig.MaxRetries, "max-retries", 30, "Max attempts to trigger reload") @@ -66,7 +66,7 @@ func main() { nconfig.WatchedFiles = fileSet if len(fileSet) == 0 { - nconfig.WatchedFiles = []string{"/etc/nats-config/gnatsd.conf"} + nconfig.WatchedFiles = []string{"/etc/nats-config/nats.conf"} } nconfig.Signal = syscall.Signal(customSignal) diff --git a/pkg/natsreloader/natsreloader.go b/pkg/natsreloader/natsreloader.go index 0eba35d0..2d93bcaf 100644 --- a/pkg/natsreloader/natsreloader.go +++ b/pkg/natsreloader/natsreloader.go @@ -26,6 +26,7 @@ import ( "regexp" "sort" "strconv" + "strings" "syscall" "time" @@ -217,6 +218,10 @@ func (r *Reloader) init() (*fsnotify.Watcher, map[string][]byte, error) { watchedFiles := make([]string, 0) for _, c := range r.WatchedFiles { + // Only try to parse config files + if !strings.HasSuffix(c, ".conf") { + continue + } childFiles, err := getServerFiles(c) if err != nil { return nil, nil, err From 44412c570a6f7ce50cf030a1c47c6c1931db857d Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Thu, 25 Jan 2024 00:49:50 -0500 Subject: [PATCH 5/7] Handle quoted includes --- pkg/natsreloader/natsreloader.go | 2 +- pkg/natsreloader/natsreloadertest/natsreloader_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/natsreloader/natsreloader.go b/pkg/natsreloader/natsreloader.go index 2d93bcaf..a09ef58c 100644 --- a/pkg/natsreloader/natsreloader.go +++ b/pkg/natsreloader/natsreloader.go @@ -426,7 +426,7 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin checked[configFile] = nil parentDirectory := filepath.Dir(configFile) - includeRegex := regexp.MustCompile(`(?m)^\s*include\s+([^\n]*)`) + includeRegex := regexp.MustCompile(`(?m)^\s*include\s+['"]?([^'"\n]*)`) content, err := os.ReadFile(configFile) if err != nil { diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloadertest/natsreloader_test.go index 1f01f61f..a61936e3 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloadertest/natsreloader_test.go @@ -53,7 +53,7 @@ jetstream { max_file: 10G } -include ./testConfig_1.conf` +include './testConfig_1.conf'` testConfig_1 = `include ./testConfig_2.conf` From 8ee50b06392bd1cb48908e241cc59e3c05419e51 Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Thu, 25 Jan 2024 18:27:16 -0500 Subject: [PATCH 6/7] Update regex to handle quotes and variables --- pkg/natsreloader/natsreloader.go | 24 +++- .../natsreloader_test.go | 105 ++++++++++++++++-- 2 files changed, 118 insertions(+), 11 deletions(-) rename pkg/natsreloader/{natsreloadertest => }/natsreloader_test.go (75%) diff --git a/pkg/natsreloader/natsreloader.go b/pkg/natsreloader/natsreloader.go index a09ef58c..39a3559b 100644 --- a/pkg/natsreloader/natsreloader.go +++ b/pkg/natsreloader/natsreloader.go @@ -426,7 +426,7 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin checked[configFile] = nil parentDirectory := filepath.Dir(configFile) - includeRegex := regexp.MustCompile(`(?m)^\s*include\s+['"]?([^'"\n]*)`) + includeRegex := regexp.MustCompile(`(?m)^\s*include\s+(['"]?[^'";\n]*)`) content, err := os.ReadFile(configFile) if err != nil { @@ -435,8 +435,16 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin includeMatches := includeRegex.FindAllStringSubmatch(string(content), -1) for _, match := range includeMatches { + matchStr := match[1] + if strings.HasPrefix(matchStr, "$") { + continue + } + + matchStr = strings.TrimPrefix(matchStr, "'") + matchStr = strings.TrimPrefix(matchStr, "\"") + // Include filepaths in NATS config are always relative - fullyQualifiedPath := filepath.Join(parentDirectory, match[1]) + fullyQualifiedPath := filepath.Join(parentDirectory, matchStr) fullyQualifiedPath = filepath.Clean(fullyQualifiedPath) if _, err := os.Stat(fullyQualifiedPath); os.IsNotExist(err) { @@ -458,7 +466,7 @@ func getIncludePaths(configFile string, checked map[string]interface{}) ([]strin func getCertPaths(configPaths []string) ([]string, error) { certPaths := []string{} - certRegex := regexp.MustCompile(`(?m)^\s*(cert_file|key_file|ca_file)\s*:\s*"?([^"\n]*)"?`) + certRegex := regexp.MustCompile(`(?m)^\s*(cert_file|key_file|ca_file)\s*:\s*(['"]?[^'";\n]*)"?`) for _, configPath := range configPaths { content, err := os.ReadFile(configPath) @@ -468,7 +476,15 @@ func getCertPaths(configPaths []string) ([]string, error) { certMatches := certRegex.FindAllStringSubmatch(string(content), -1) for _, match := range certMatches { - fullyQualifiedPath, err := filepath.Abs(match[2]) + matchStr := match[2] + if strings.HasPrefix(matchStr, "$") { + continue + } + + matchStr = strings.TrimPrefix(matchStr, "'") + matchStr = strings.TrimPrefix(matchStr, "\"") + + fullyQualifiedPath, err := filepath.Abs(matchStr) if err != nil { return nil, err } diff --git a/pkg/natsreloader/natsreloadertest/natsreloader_test.go b/pkg/natsreloader/natsreloader_test.go similarity index 75% rename from pkg/natsreloader/natsreloadertest/natsreloader_test.go rename to pkg/natsreloader/natsreloader_test.go index a61936e3..d57b4422 100644 --- a/pkg/natsreloader/natsreloadertest/natsreloader_test.go +++ b/pkg/natsreloader/natsreloader_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package natsreloadertest +package natsreloader import ( "context" @@ -27,8 +27,6 @@ import ( "syscall" "testing" "time" - - "github.com/nats-io/nack/pkg/natsreloader" ) const ( @@ -62,6 +60,31 @@ tls: { cert_file: "./test.pem" key_file: "./testkey.pem" } +` + includeTest_0 = ` +include nats_0.conf +include nats_1.conf; // semicolon terminated +include "nats_2.conf" // quoted +include "nats_3.conf"; // quoted and semicolon terminated +include 'nats_4.conf' // are single quotes valid in nats conf? if so also need this +include 'nats_5.conf'; // are single quotes valid in nats conf? if so also need this +include $NATS; // ignore, this is a variable. let's not worry about variable interpolation +include "$NATS_6.conf" // don't ignore, this is a string not a variable +include includeTest_1.conf +` + includeTest_1 = ` +tls: { + cert_file: ./nats_0.pem + key_file: 'nats_0.key' +} +tls: { + cert_file: "./nats_1.pem" + key_file: $test +} +tls: { + cert_file: "$nats_2.pem"; + key_file: 'nats_1.key'; +} ` ) @@ -85,7 +108,7 @@ func TestReloader(t *testing.T) { defer os.Remove(pidfile.Name()) // Create tempfile with contents, then update it - nconfig := &natsreloader.Config{ + nconfig := &Config{ PidFile: pidfile.Name(), WatchedFiles: []string{}, Signal: syscall.SIGHUP, @@ -106,7 +129,7 @@ func TestReloader(t *testing.T) { nconfig.WatchedFiles = append(nconfig.WatchedFiles, configFile.Name()) } - r, err := natsreloader.NewReloader(nconfig) + r, err := NewReloader(nconfig) if err != nil { t.Fatal(err) } @@ -173,6 +196,74 @@ func TestReloader(t *testing.T) { } } +func TestInclude(t *testing.T) { + directory, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + dummyFiles := []string{ + "nats_0.conf", + "nats_1.conf", + "nats_2.conf", + "nats_3.conf", + "nats_4.conf", + "nats_5.conf", + "$NATS_6.conf", + "nats_0.pem", + "nats_1.pem", + "$nats_2.pem", + "nats_0.key", + "nats_1.key", + } + + for _, f := range dummyFiles { + p := filepath.Join(directory, f) + err = writeFile("", p) + defer os.Remove(p) + if err != nil { + t.Fatal(err) + } + } + + includeTestConf_0 := filepath.Join(directory, "includeTest_0.conf") + err = writeFile(includeTest_0, includeTestConf_0) + defer os.Remove(includeTestConf_0) + if err != nil { + t.Fatal(err) + } + + includeTestConf_1 := filepath.Join(directory, "includeTest_1.conf") + err = writeFile(includeTest_1, includeTestConf_1) + defer os.Remove(includeTestConf_1) + if err != nil { + t.Fatal(err) + } + + includes, err := getServerFiles("includeTest_0.conf") + if err != nil { + t.Fatal(err) + } + + includePaths := make([]string, 0) + for _, p := range includes { + includePaths = append(includePaths, filepath.Base(p)) + } + + dummyFiles = append(dummyFiles, "includeTest_0.conf") + dummyFiles = append(dummyFiles, "includeTest_1.conf") + + sort.Strings(dummyFiles) + sort.Strings(includePaths) + + for i, p := range dummyFiles { + if p != includePaths[i] { + t.Fatal("Expected include paths do not match") + } + } + +} + func TestFileFinder(t *testing.T) { directory, err := os.Getwd() if err != nil { @@ -218,13 +309,13 @@ func TestFileFinder(t *testing.T) { } defer os.Remove(pidFile) - nconfig := &natsreloader.Config{ + nconfig := &Config{ PidFile: pidFile, WatchedFiles: []string{filepath.Join(directory, "testConfig_0.conf")}, Signal: syscall.SIGHUP, } - r, err := natsreloader.NewReloader(nconfig) + r, err := NewReloader(nconfig) if err != nil { t.Fatal(err) } From 7fe8585ed46dc3f399067c8b8759fb8035402df1 Mon Sep 17 00:00:00 2001 From: Samuel Attwood Date: Thu, 25 Jan 2024 19:06:08 -0500 Subject: [PATCH 7/7] Fix comments --- pkg/natsreloader/natsreloader_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/natsreloader/natsreloader_test.go b/pkg/natsreloader/natsreloader_test.go index d57b4422..1e05edee 100644 --- a/pkg/natsreloader/natsreloader_test.go +++ b/pkg/natsreloader/natsreloader_test.go @@ -64,12 +64,12 @@ tls: { includeTest_0 = ` include nats_0.conf include nats_1.conf; // semicolon terminated -include "nats_2.conf" // quoted -include "nats_3.conf"; // quoted and semicolon terminated -include 'nats_4.conf' // are single quotes valid in nats conf? if so also need this -include 'nats_5.conf'; // are single quotes valid in nats conf? if so also need this -include $NATS; // ignore, this is a variable. let's not worry about variable interpolation -include "$NATS_6.conf" // don't ignore, this is a string not a variable +include "nats_2.conf" // double-quoted +include "nats_3.conf"; // double-quoted and semicolon terminated +include 'nats_4.conf' // single-quoted +include 'nats_5.conf'; // single-quoted and semicolon terminated +include $NATS; // ignore variable +include "$NATS_6.conf" // filename starting with $ include includeTest_1.conf ` includeTest_1 = `