diff --git a/CHANGELOG.md b/CHANGELOG.md index ac382a583..cceb498ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# Release 0.25.3 + +* Enhancement: Add cost and precedence to host.v1 and host.v2 config types. This allows router-embedded tunnelers the ability to handle HA failover scenarios. +* Bug fix: Router link listener type was only inferred from the adverise address, not the bind address + # Release 0.25.2 ## Deprecations diff --git a/go.mod b/go.mod index d5f31b50d..896bf97de 100644 --- a/go.mod +++ b/go.mod @@ -35,19 +35,19 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/michaelquigley/pfxlog v0.6.3 - github.com/openziti/channel v0.18.14 - github.com/openziti/foundation v0.17.8 - github.com/openziti/sdk-golang v0.16.20 + github.com/openziti/channel v0.18.17 + github.com/openziti/foundation v0.17.12 + github.com/openziti/sdk-golang v0.16.27 github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 github.com/russross/blackfriday v1.5.2 github.com/shirou/gopsutil v2.21.11+incompatible github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.3.0 + github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.10.0 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.1 github.com/valyala/fasttemplate v1.2.1 go.etcd.io/bbolt v1.3.6 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd @@ -123,7 +123,7 @@ require ( github.com/mdlayher/netlink v1.6.0 // indirect github.com/mdlayher/socket v0.1.1 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/miekg/dns v1.1.46 // indirect + github.com/miekg/dns v1.1.47 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect @@ -154,11 +154,11 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect go.mongodb.org/mongo-driver v1.8.3 // indirect go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 // indirect - golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/image v0.0.0-20191206065243-da761ea9ff43 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect + golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.7 // indirect @@ -173,7 +173,7 @@ require ( require ( github.com/jedib0t/go-pretty/v6 v6.2.4 - github.com/openziti/edge v0.21.127 - github.com/openziti/fabric v0.17.62 + github.com/openziti/edge v0.21.139 + github.com/openziti/fabric v0.17.68 github.com/rivo/uniseg v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 308145830..077c746b0 100644 --- a/go.sum +++ b/go.sum @@ -752,8 +752,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.46 h1:uzwpxRtSVxtcIZmz/4Uz6/Rn7G11DvsaslXoy5LxQio= -github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.47 h1:J9bWiXbqMbnZPcY8Qi2E3EWIBsIm6MZzzJB9VRg5gL8= +github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -820,18 +820,22 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openziti/channel v0.18.14 h1:MS6Wfo0BklKI/IQ/HQl+wKJBw9rPimTSSqFIeBcsHGQ= -github.com/openziti/channel v0.18.14/go.mod h1:F370DYbKEKpIEhRaZVbEK6xN+pirSZx4qnwbObQAV2I= +github.com/openziti/channel v0.18.17 h1:0nZz9WMmxGnySE5yg8IeBY20yjO/YPFurP1qNt2wryE= +github.com/openziti/channel v0.18.17/go.mod h1:seDAqUKIl6J5vmHWlk042WkAzyY9qaPKr2DJc2DMpHE= github.com/openziti/dilithium v0.3.3 h1:PLgQ6PMNLSTzCFbX/h98cmudgz/cU6TmjdSv5NAPD8k= github.com/openziti/dilithium v0.3.3/go.mod h1:vsCjI2AU/hon9e+dLhUFbCNGesJDj2ASgkySOcpmvjo= -github.com/openziti/edge v0.21.127 h1:4Z2AlmSjMgw/a0PQt4aYuVIURW0nQVwnR0mSvgyVZcc= -github.com/openziti/edge v0.21.127/go.mod h1:NIOrmA5yEhdTbmARyPm4DOrdpWiaB33OVpJVj4PkEDY= -github.com/openziti/fabric v0.17.62 h1:V1Eavso4AvMSCMXJYtEATu5NQ9Dtpu3s3OYZt+SuVwY= -github.com/openziti/fabric v0.17.62/go.mod h1:8oBcmWriG/nTGF/+8pkv1oAKQY97XXG4ptns8dUTMr4= -github.com/openziti/foundation v0.17.8 h1:vlX6yQHrs5Tcp39xHylJhzohTDOZ6d/VrVlQahw7GBo= +github.com/openziti/edge v0.21.139 h1:ilQIWWfej9f6AMnNcRpsjn99PV2eAGBWetMRbTCJ9V0= +github.com/openziti/edge v0.21.139/go.mod h1:iQ3vlNek4vqsekcmE1i8qcGi90r/myYdoUsQzkZrZ64= +github.com/openziti/fabric v0.17.67/go.mod h1:NpU40k5h8KoWMwBRT6w1t/pzl8J4f9fc1bMdG6ZQevQ= +github.com/openziti/fabric v0.17.68 h1:2aC6b7krnkqaLxOF5mzr8CZ8wV202subup4espv9WeY= +github.com/openziti/fabric v0.17.68/go.mod h1:3coRsWdb4jkFSYtMZh5NlTlgBw7y5oL3D8lky5eGmEQ= github.com/openziti/foundation v0.17.8/go.mod h1:dTaJgdO5OqnKpV+0OPHpnTnqfPpqNGbhJv8O6pMot6o= -github.com/openziti/sdk-golang v0.16.20 h1:AtSaD0Do5HgkDWFR0dLUVpiOpky2WAh6cf78hcG30jk= -github.com/openziti/sdk-golang v0.16.20/go.mod h1:uQ90QCehBrfO/xmpnWGVr3Jj65BMUrvGPH4I0gRl0og= +github.com/openziti/foundation v0.17.11/go.mod h1:2wUj+Kcvi8RsgP2wvPtmMLmk0OtIKD+3IVQj2pGZCrs= +github.com/openziti/foundation v0.17.12 h1:buMTGTgrBlkr7Yv0pqTEJGvyZVg0Tp9gC02cqu3jhSI= +github.com/openziti/foundation v0.17.12/go.mod h1:YT8EFUtJMS4qBN2j0KnVyKR0gUmGy4i8tLCETC3pM5A= +github.com/openziti/sdk-golang v0.16.26/go.mod h1:Ay1QKaARofijMSjkkPzlu6jIadmWmc+w5ZGQgvIM7cQ= +github.com/openziti/sdk-golang v0.16.27 h1:1ZdK5jmmqVWDjW8UzEDwIVA9mbbU3YP4iam+7xU9ZYI= +github.com/openziti/sdk-golang v0.16.27/go.mod h1:bAjupBbh1GKyuNvJaWcn/8RLKIN/0WCNpRIfx9FMzn0= github.com/oracle/oci-go-sdk v24.2.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231 h1:fa50YL1pzKW+1SsBnJDOHppJN9stOEwS+CRWyUtyYGU= @@ -976,8 +980,9 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1000,8 +1005,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -1132,8 +1138,9 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1382,8 +1389,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= diff --git a/quickstart/docker/blue.nw.attach.sh b/quickstart/docker/blue.nw.attach.sh new file mode 100644 index 000000000..49f34a3ad --- /dev/null +++ b/quickstart/docker/blue.nw.attach.sh @@ -0,0 +1 @@ +docker run --cap-add=NET_ADMIN --device /dev/net/tun --name ziti-tunneler-blue --user root --network docker_zitiblue -v docker_ziti-fs:/openziti --rm -it openziti/quickstart /bin/bash diff --git a/quickstart/docker/docker-compose.yml b/quickstart/docker/docker-compose.yml index 0ae6989c7..227e6099e 100644 --- a/quickstart/docker/docker-compose.yml +++ b/quickstart/docker/docker-compose.yml @@ -102,7 +102,11 @@ services: ports: - "80:8000" networks: - - zitiblue + zitiblue: + aliases: + - web-test-blue + - web-test.blue + - web.test.blue ziti-console: image: openziti/zac diff --git a/quickstart/docker/red.nw.attach.sh b/quickstart/docker/red.nw.attach.sh new file mode 100644 index 000000000..bdc82a7b0 --- /dev/null +++ b/quickstart/docker/red.nw.attach.sh @@ -0,0 +1 @@ +docker run --cap-add=NET_ADMIN --device /dev/net/tun --name ziti-tunneler-red --user root --network docker_zitired -v docker_ziti-fs:/openziti --rm -it openziti/quickstart /bin/bash diff --git a/ziti-controller/subcmd/root.go b/ziti-controller/subcmd/root.go index 261f0140a..6b46ca25e 100644 --- a/ziti-controller/subcmd/root.go +++ b/ziti-controller/subcmd/root.go @@ -21,6 +21,8 @@ import ( "github.com/michaelquigley/pfxlog" edgeSubCmd "github.com/openziti/edge/controller/subcmd" "github.com/openziti/ziti/common/version" + "github.com/openziti/ziti/ziti/cmd/ziti/constants" + "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -52,6 +54,7 @@ var root = &cobra.Command{ default: // let logrus do its own thing } + util.LogReleaseVersionCheck(constants.ZITI_CONTROLLER) }, } diff --git a/ziti-router/subcmd/root.go b/ziti-router/subcmd/root.go index a1ef7b59b..1b57f1488 100644 --- a/ziti-router/subcmd/root.go +++ b/ziti-router/subcmd/root.go @@ -19,6 +19,8 @@ package subcmd import ( "fmt" "github.com/michaelquigley/pfxlog" + "github.com/openziti/ziti/ziti/cmd/ziti/constants" + "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -49,6 +51,7 @@ var root = &cobra.Command{ default: // let logrus do its own thing } + util.LogReleaseVersionCheck(constants.ZITI_ROUTER) }, } diff --git a/ziti-tunnel/cmd/ziti-tunnel/subcmd/root.go b/ziti-tunnel/cmd/ziti-tunnel/subcmd/root.go index c9e21d834..12371c288 100644 --- a/ziti-tunnel/cmd/ziti-tunnel/subcmd/root.go +++ b/ziti-tunnel/cmd/ziti-tunnel/subcmd/root.go @@ -27,6 +27,8 @@ import ( "github.com/openziti/sdk-golang/ziti/config" "github.com/openziti/ziti/common/enrollment" "github.com/openziti/ziti/common/version" + "github.com/openziti/ziti/ziti/cmd/ziti/constants" + "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "os" @@ -90,6 +92,7 @@ func rootPreRun(cmd *cobra.Command, _ []string) { default: // let logrus do its own thing } + util.LogReleaseVersionCheck(constants.ZITI_TUNNEL) } func rootPostRun(cmd *cobra.Command, _ []string) { diff --git a/ziti/cmd/ziti/cmd/config_templates/environment.yml b/ziti/cmd/ziti/cmd/config_templates/environment.yml index 69be5476b..2b402a7e5 100644 --- a/ziti/cmd/ziti/cmd/config_templates/environment.yml +++ b/ziti/cmd/ziti/cmd/config_templates/environment.yml @@ -1,46 +1,6 @@ -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiHomeVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiHomeVarName }}={{ .ZitiHome }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlNameVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlNameVarName }}={{ .Controller.Name }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlPortVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlPortVarName }}={{ .Controller.Port }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeRouterRawNameVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeRouterRawNameVarName }}={{ .Router.Edge.Hostname }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeRouterPortVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeRouterPortVarName }}={{ .Router.Edge.Port }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlListenerAddressVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlListenerAddressVarName }}={{ .Controller.ListenerAddress }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlAdvertisedAddressVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlAdvertisedAddressVarName }}={{ .Controller.AdvertisedAddress }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlIdentityCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlIdentityCertVarName }}={{ .Controller.Edge.IdentityCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlIdentityServerCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlIdentityServerCertVarName }}={{ .Controller.Edge.IdentityServerCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlIdentityKeyVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlIdentityKeyVarName }}={{ .Controller.Edge.IdentityKey }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlIdentityCAVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlIdentityCAVarName }}={{ .Controller.Edge.IdentityCA }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlIdentityCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlIdentityCertVarName }}={{ .Controller.IdentityCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlIdentityServerCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlIdentityServerCertVarName }}={{ .Controller.IdentityServerCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlIdentityKeyVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlIdentityKeyVarName }}={{ .Controller.IdentityKey }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiCtrlIdentityCAVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiCtrlIdentityCAVarName }}={{ .Controller.IdentityCA }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiRouterIdentityCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiRouterIdentityCertVarName }}={{ .Router.IdentityCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiRouterIdentityServerCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiRouterIdentityServerCertVarName }}={{ .Router.IdentityServerCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiRouterIdentityKeyVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiRouterIdentityKeyVarName }}={{ .Router.IdentityKey }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiRouterIdentityCAVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiRouterIdentityCAVarName }}={{ .Router.IdentityCA }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiSigningCertVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiSigningCertVarName }}={{ .Controller.Edge.ZitiSigningCert }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiSigningKeyVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiSigningKeyVarName }}={{ .Controller.Edge.ZitiSigningKey }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlListenerHostPortVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlListenerHostPortVarName }}={{ .Controller.Edge.ListenerHostPort }} -{{ if eq .OS "windows" }}Rem {{ else }}# {{ end }}{{ .ZitiEdgeCtrlAdvertisedHostPortVarDescription }} -{{ if eq .OS "windows" }}SET{{ else }}export{{ end }} {{ .ZitiEdgeCtrlAdvertisedHostPortVarName }}={{ .Controller.Edge.AdvertisedHostPort }} \ No newline at end of file +{{ $commentPrefix := .OSCommentPrefix }} +{{ $varDeclare := .OSVarDeclare }} +{{- range .EnvVars}} +{{ $commentPrefix }} {{ .Description }} +{{ $varDeclare }} {{ .Name }}={{ .Value }} +{{- end }} \ No newline at end of file diff --git a/ziti/cmd/ziti/cmd/create_config.go b/ziti/cmd/ziti/cmd/create_config.go index 584aee725..82358ae24 100644 --- a/ziti/cmd/ziti/cmd/create_config.go +++ b/ziti/cmd/ziti/cmd/create_config.go @@ -83,6 +83,7 @@ type ControllerTemplateValues struct { } type EdgeControllerValues struct { + AdvertisedPort string ZitiSigningCert string ZitiSigningKey string @@ -236,6 +237,10 @@ func (data *ConfigTemplateValues) populateEnvVars() { zitiEdgeCtrlAdvertisedHostPort, err := cmdhelper.GetZitiEdgeCtrlAdvertisedHostPort() handleVariableError(err, constants.ZitiEdgeCtrlAdvertisedHostPortVarName) + // Get Ziti Edge Controller Advertised Port + zitiEdgeCtrlAdvertisedPort, err := cmdhelper.GetZitiEdgeCtrlAdvertisedPort() + handleVariableError(err, constants.ZitiEdgeCtrlAdvertisedPortVarName) + data.ZitiHome = zitiHome data.Hostname = hostname data.Controller.Name = zitiCtrlHostname @@ -245,6 +250,7 @@ func (data *ConfigTemplateValues) populateEnvVars() { data.Controller.Edge.ListenerHostPort = zitiEdgeCtrlListenerHostPort data.Controller.Edge.AdvertisedHostPort = zitiEdgeCtrlAdvertisedHostPort data.Router.Edge.Port = zitiEdgeRouterPort + data.Controller.Edge.AdvertisedPort = zitiEdgeCtrlAdvertisedPort } func (data *ConfigTemplateValues) populateDefaults() { diff --git a/ziti/cmd/ziti/cmd/create_config_controller.go b/ziti/cmd/ziti/cmd/create_config_controller.go index 693b82749..2e5cc10dc 100644 --- a/ziti/cmd/ziti/cmd/create_config_controller.go +++ b/ziti/cmd/ziti/cmd/create_config_controller.go @@ -139,7 +139,6 @@ func (options *CreateConfigControllerOptions) run(data *ConfigTemplateValues) er // Check if the path exists, fail if it doesn't basePath := filepath.Dir(options.Output) + "/" if _, err := os.Stat(filepath.Dir(basePath)); os.IsNotExist(err) { - logrus.Fatalf("Provided path: [%s] does not exist\n", basePath) return err } diff --git a/ziti/cmd/ziti/cmd/create_config_controller_test.go b/ziti/cmd/ziti/cmd/create_config_controller_test.go new file mode 100644 index 000000000..c8dcbd0df --- /dev/null +++ b/ziti/cmd/ziti/cmd/create_config_controller_test.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func TestControllerOutputPathDoesNotExist(t *testing.T) { + expectedErrorMsg := "stat /IDoNotExist: no such file or directory" + + // Create the options with both flags set to true + options := &CreateConfigControllerOptions{} + options.Output = "/IDoNotExist/MyController.yaml" + + err := options.run(&ConfigTemplateValues{}) + + assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) +} + +func TestCreateConfigControllerTemplateValues(t *testing.T) { + expectedNonEmptyStringFields := []string{".Controller.Name", ".ZitiHome", ".Controller.IdentityCert", ".Controller.IdentityServerCert", ".Controller.IdentityKey", ".Controller.IdentityCA", ".Controller.ListenerAddress", ".Controller.Port", ".Controller.Edge.AdvertisedHostPort", ".Controller.Edge.ZitiSigningCert", ".Controller.Edge.ZitiSigningKey", ".Controller.Edge.ListenerHostPort", ".Controller.Edge.IdentityCA", ".Controller.Edge.IdentityKey", ".Controller.Edge.IdentityServerCert", ".Controller.Edge.IdentityCert", ".Controller.WebListener.MinTLSVersion", ".Controller.WebListener.MaxTLSVersion"} + expectedNonEmptyStringValues := []*string{&data.Controller.Name, &data.ZitiHome, &data.Controller.IdentityCert, &data.Controller.IdentityServerCert, &data.Controller.IdentityKey, &data.Controller.IdentityCA, &data.Controller.ListenerAddress, &data.Controller.Port, &data.Controller.Edge.AdvertisedHostPort, &data.Controller.Edge.ZitiSigningCert, &data.Controller.Edge.ZitiSigningKey, &data.Controller.Edge.ListenerHostPort, &data.Controller.Edge.IdentityCA, &data.Controller.Edge.IdentityKey, &data.Controller.Edge.IdentityServerCert, &data.Controller.Edge.IdentityCert, &data.Controller.WebListener.MinTLSVersion, &data.Controller.WebListener.MaxTLSVersion} + expectedNonEmptyTimeFields := []string{".Controller.HealthCheck.Interval", ".Controller.HealthCheck.Timeout", ".Controller.HealthCheck.InitialDelay", ".Controller.Edge.APISessionTimeout", ".Controller.EdgeIdentityDuration", ".Controller.EdgeRouterDuration", ".Controller.WebListener.IdleTimeout", ".Controller.WebListener.ReadTimeout", ".Controller.WebListener.WriteTimeout"} + expectedNonEmptyTimeValues := []*time.Duration{&data.Controller.HealthCheck.Interval, &data.Controller.HealthCheck.Timeout, &data.Controller.HealthCheck.InitialDelay, &data.Controller.Edge.APISessionTimeout, &data.Controller.EdgeIdentityDuration, &data.Controller.EdgeRouterDuration, &data.Controller.WebListener.IdleTimeout, &data.Controller.WebListener.ReadTimeout, &data.Controller.WebListener.WriteTimeout} + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + // Check that the expected string template values are not blank + for field, value := range expectedNonEmptyStringValues { + assert.NotEqualf(t, "", *value, expectedNonEmptyStringFields[field]+" should be a non-blank value") + } + + // Check that the expected time.Duration template values are not zero + for field, value := range expectedNonEmptyTimeValues { + assert.NotZero(t, *value, expectedNonEmptyTimeFields[field]+" should be a non-zero value") + } +} + +// Edge Ctrl Listener address and port should use default values if env vars are not set +func TestDefaultListenerAddress(t *testing.T) { + expectedListenerAddress := "0.0.0.0:1280" + + // Make sure the related env vars are unset + _ = os.Unsetenv("ZITI_EDGE_CONTROLLER_PORT") + _ = os.Unsetenv("ZITI_CTRL_EDGE_LISTENER_HOST_PORT") + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + assert.Equal(t, expectedListenerAddress, data.Controller.Edge.ListenerHostPort) +} + +// Edge Ctrl Listener port should use ZITI_EDGE_CONTROLLER_PORT if it is set +func TestListenerAddressWhenEdgeCtrlPortAndListenerHostPortNotSet(t *testing.T) { + myPort := "1234" + expectedListenerAddress := "0.0.0.0:" + myPort + + // Make sure the related env vars are unset + _ = os.Unsetenv("ZITI_CTRL_EDGE_LISTENER_HOST_PORT") + + // Set the edge controller port + _ = os.Setenv("ZITI_EDGE_CONTROLLER_PORT", myPort) + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + assert.Equal(t, expectedListenerAddress, data.Controller.Edge.ListenerHostPort) +} + +// Edge Ctrl Listener address and port should always use ZITI_EDGE_CTRL_LISTENER_HOST_PORT value if it is set +func TestListenerAddressWhenEdgeCtrlPortAndListenerHostPortSet(t *testing.T) { + myPort := "1234" + expectedListenerAddress := "0.0.0.0:4321" // Expecting a different port even when edge ctrl port is set + + // Set a custom value for the host and port + _ = os.Setenv("ZITI_CTRL_EDGE_LISTENER_HOST_PORT", expectedListenerAddress) + + // Set the edge controller port (this should not show up in the end resulting listener address) + _ = os.Setenv("ZITI_EDGE_CONTROLLER_PORT", myPort) + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + assert.Equal(t, expectedListenerAddress, data.Controller.Edge.ListenerHostPort) +} + +// Edge Ctrl Advertised Port should update the edge ctrl port to the default when ZITI_EDGE_CONTROLLER_PORT is not set +func TestDefaultEdgeCtrlAdvertisedPort(t *testing.T) { + expectedPort := "1280" // Expecting the default port of 1280 + + // Set a custom value for the host and port + _ = os.Unsetenv("ZITI_EDGE_CONTROLLER_PORT") + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + assert.Equal(t, expectedPort, data.Controller.Edge.AdvertisedPort) +} + +// Edge Ctrl Advertised Port should update the edge ctrl port to the custom value when ZITI_EDGE_CONTROLLER_PORT is set +func TestEdgeCtrlAdvertisedPortValueWhenSet(t *testing.T) { + expectedPort := "1234" // Setting a custom port which is not the default value + + // Set a custom value for the host and port + _ = os.Setenv("ZITI_EDGE_CONTROLLER_PORT", expectedPort) + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigController() + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + assert.Equal(t, expectedPort, data.Controller.Edge.AdvertisedPort) +} diff --git a/ziti/cmd/ziti/cmd/create_config_environment.go b/ziti/cmd/ziti/cmd/create_config_environment.go index 9a71f5a3e..6ffbe220a 100644 --- a/ziti/cmd/ziti/cmd/create_config_environment.go +++ b/ziti/cmd/ziti/cmd/create_config_environment.go @@ -32,56 +32,16 @@ import ( "text/template" ) -type EnvVariableMetaData struct { - OS string - ZitiHomeVarName string - ZitiCtrlNameVarName string - ZitiCtrlPortVarName string - ZitiEdgeRouterRawNameVarName string - ZitiEdgeRouterPortVarName string - ZitiEdgeCtrlIdentityCertVarName string - ZitiEdgeCtrlIdentityServerCertVarName string - ZitiEdgeCtrlIdentityKeyVarName string - ZitiEdgeCtrlIdentityCAVarName string - ZitiCtrlIdentityCertVarName string - ZitiCtrlIdentityServerCertVarName string - ZitiCtrlIdentityKeyVarName string - ZitiCtrlIdentityCAVarName string - ZitiSigningCertVarName string - ZitiSigningKeyVarName string - ZitiCtrlMgmtListenerHostPortVarName string - ZitiEdgeCtrlListenerHostPortVarName string - ZitiEdgeCtrlAdvertisedHostPortVarName string - ZitiRouterIdentityCertVarName string - ZitiRouterIdentityServerCertVarName string - ZitiRouterIdentityKeyVarName string - ZitiRouterIdentityCAVarName string - ZitiCtrlListenerAddressVarName string - ZitiCtrlAdvertisedAddressVarName string - ZitiHomeVarDescription string - ZitiCtrlNameVarDescription string - ZitiEdgeRouterRawNameVarDescription string - ZitiEdgeRouterPortVarDescription string - ZitiEdgeCtrlIdentityCertVarDescription string - ZitiEdgeCtrlIdentityServerCertVarDescription string - ZitiEdgeCtrlIdentityKeyVarDescription string - ZitiEdgeCtrlIdentityCAVarDescription string - ZitiCtrlIdentityCertVarDescription string - ZitiCtrlIdentityServerCertVarDescription string - ZitiCtrlIdentityKeyVarDescription string - ZitiCtrlIdentityCAVarDescription string - ZitiSigningCertVarDescription string - ZitiSigningKeyVarDescription string - ZitiCtrlPortVarDescription string - ZitiCtrlListenerAddressVarDescription string - ZitiCtrlAdvertisedAddressVarDescription string - ZitiCtrlMgmtListenerHostPortVarDescription string - ZitiEdgeCtrlListenerHostPortVarDescription string - ZitiEdgeCtrlAdvertisedHostPortVarDescription string - ZitiRouterIdentityCertVarDescription string - ZitiRouterIdentityServerCertVarDescription string - ZitiRouterIdentityKeyVarDescription string - ZitiRouterIdentityCAVarDescription string +type EnvVariableTemplateData struct { + OSCommentPrefix string + OSVarDeclare string + EnvVars []EnvVar +} + +type EnvVar struct { + Name string + Description string + Value string } var ( @@ -101,69 +61,19 @@ var ( //go:embed config_templates/environment.yml var environmentConfigTemplate string +var environmentOptions *CreateConfigEnvironmentOptions + // CreateConfigEnvironmentOptions the options for the create environment command type CreateConfigEnvironmentOptions struct { CreateConfigOptions - ConfigTemplateValues - EnvVariableMetaData + EnvVariableTemplateData output string } // NewCmdCreateConfigEnvironment creates a command object for the "environment" command func NewCmdCreateConfigEnvironment() *cobra.Command { - environmentOptions := &CreateConfigEnvironmentOptions{ - ConfigTemplateValues: *data, - EnvVariableMetaData: EnvVariableMetaData{ - OS: "Stuff", - ZitiHomeVarName: constants.ZitiHomeVarName, - ZitiHomeVarDescription: constants.ZitiHomeVarDescription, - ZitiCtrlNameVarName: constants.ZitiCtrlNameVarName, - ZitiCtrlNameVarDescription: constants.ZitiCtrlNameVarDescription, - ZitiCtrlPortVarName: constants.ZitiCtrlPortVarName, - ZitiCtrlPortVarDescription: constants.ZitiCtrlPortVarDescription, - ZitiEdgeRouterRawNameVarName: constants.ZitiEdgeRouterRawNameVarName, - ZitiEdgeRouterRawNameVarDescription: constants.ZitiEdgeRouterRawNameVarDescription, - ZitiEdgeRouterPortVarName: constants.ZitiEdgeRouterPortVarName, - ZitiEdgeRouterPortVarDescription: constants.ZitiEdgeRouterPortVarDescription, - ZitiEdgeCtrlIdentityCertVarName: constants.ZitiEdgeCtrlIdentityCertVarName, - ZitiEdgeCtrlIdentityCertVarDescription: constants.ZitiEdgeCtrlIdentityCertVarDescription, - ZitiEdgeCtrlIdentityServerCertVarName: constants.ZitiEdgeCtrlIdentityServerCertVarName, - ZitiEdgeCtrlIdentityServerCertVarDescription: constants.ZitiEdgeCtrlIdentityServerCertVarDescription, - ZitiEdgeCtrlIdentityKeyVarName: constants.ZitiEdgeCtrlIdentityKeyVarName, - ZitiEdgeCtrlIdentityKeyVarDescription: constants.ZitiEdgeCtrlIdentityKeyVarDescription, - ZitiEdgeCtrlIdentityCAVarName: constants.ZitiEdgeCtrlIdentityCAVarName, - ZitiEdgeCtrlIdentityCAVarDescription: constants.ZitiEdgeCtrlIdentityCAVarDescription, - ZitiCtrlIdentityCertVarName: constants.ZitiCtrlIdentityCertVarName, - ZitiCtrlIdentityCertVarDescription: constants.ZitiCtrlIdentityCertVarDescription, - ZitiCtrlIdentityServerCertVarName: constants.ZitiCtrlIdentityServerCertVarName, - ZitiCtrlIdentityServerCertVarDescription: constants.ZitiCtrlIdentityServerCertVarDescription, - ZitiCtrlIdentityKeyVarName: constants.ZitiCtrlIdentityKeyVarName, - ZitiCtrlIdentityKeyVarDescription: constants.ZitiCtrlIdentityKeyVarDescription, - ZitiCtrlIdentityCAVarName: constants.ZitiCtrlIdentityCAVarName, - ZitiCtrlIdentityCAVarDescription: constants.ZitiCtrlIdentityCAVarDescription, - ZitiSigningCertVarName: constants.ZitiSigningCertVarName, - ZitiSigningCertVarDescription: constants.ZitiSigningCertVarDescription, - ZitiSigningKeyVarName: constants.ZitiSigningKeyVarName, - ZitiSigningKeyVarDescription: constants.ZitiSigningKeyVarDescription, - ZitiRouterIdentityCertVarName: constants.ZitiRouterIdentityCertVarName, - ZitiRouterIdentityCertVarDescription: constants.ZitiRouterIdentityCertVarDescription, - ZitiRouterIdentityServerCertVarName: constants.ZitiRouterIdentityServerCertVarName, - ZitiRouterIdentityServerCertVarDescription: constants.ZitiRouterIdentityServerCertVarDescription, - ZitiRouterIdentityKeyVarName: constants.ZitiRouterIdentityKeyVarName, - ZitiRouterIdentityKeyVarDescription: constants.ZitiRouterIdentityKeyVarDescription, - ZitiRouterIdentityCAVarName: constants.ZitiRouterIdentityCAVarName, - ZitiRouterIdentityCAVarDescription: constants.ZitiRouterIdentityCAVarDescription, - ZitiCtrlListenerAddressVarName: constants.ZitiCtrlListenerAddressVarName, - ZitiCtrlListenerAddressVarDescription: constants.ZitiCtrlListenerAddressVarDescription, - ZitiCtrlAdvertisedAddressVarName: constants.ZitiCtrlAdvertisedAddressVarName, - ZitiCtrlAdvertisedAddressVarDescription: constants.ZitiCtrlAdvertisedAddressVarDescription, - ZitiEdgeCtrlListenerHostPortVarName: constants.ZitiEdgeCtrlListenerHostPortVarName, - ZitiEdgeCtrlListenerHostPortVarDescription: constants.ZitiEdgeCtrlListenerHostPortVarDescription, - ZitiEdgeCtrlAdvertisedHostPortVarName: constants.ZitiEdgeCtrlAdvertisedHostPortVarName, - ZitiEdgeCtrlAdvertisedHostPortVarDescription: constants.ZitiEdgeCtrlAdvertisedHostPortVarDescription, - }, - } + environmentOptions = &CreateConfigEnvironmentOptions{} cmd := &cobra.Command{ Use: "environment", @@ -174,10 +84,50 @@ func NewCmdCreateConfigEnvironment() *cobra.Command { PreRun: func(cmd *cobra.Command, args []string) { data.populateEnvVars() data.populateDefaults() + // Set router identities + SetZitiRouterIdentity(&data.Router, validateRouterName("")) + // Set up other identity info + SetControllerIdentity(&data.Controller) + SetEdgeConfig(&data.Controller) + SetWebConfig(&data.Controller) + + environmentOptions.EnvVars = []EnvVar{ + {constants.ZitiHomeVarName, constants.ZitiHomeVarDescription, data.ZitiHome}, + {constants.ZitiCtrlNameVarName, constants.ZitiCtrlNameVarDescription, data.Controller.Name}, + {constants.ZitiCtrlPortVarName, constants.ZitiCtrlPortVarDescription, data.Controller.Port}, + {constants.ZitiEdgeRouterRawNameVarName, constants.ZitiEdgeRouterRawNameVarDescription, data.Router.Edge.Hostname}, + {constants.ZitiEdgeRouterPortVarName, constants.ZitiEdgeRouterPortVarDescription, data.Router.Edge.Port}, + {constants.ZitiEdgeCtrlIdentityCertVarName, constants.ZitiEdgeCtrlIdentityCertVarDescription, data.Controller.Edge.IdentityCert}, + {constants.ZitiEdgeCtrlIdentityServerCertVarName, constants.ZitiEdgeCtrlIdentityServerCertVarDescription, data.Controller.Edge.IdentityServerCert}, + {constants.ZitiEdgeCtrlIdentityKeyVarName, constants.ZitiEdgeCtrlIdentityKeyVarDescription, data.Controller.Edge.IdentityKey}, + {constants.ZitiEdgeCtrlIdentityCAVarName, constants.ZitiEdgeCtrlIdentityCAVarDescription, data.Controller.Edge.IdentityCA}, + {constants.ZitiCtrlIdentityCertVarName, constants.ZitiCtrlIdentityCertVarDescription, data.Controller.IdentityCert}, + {constants.ZitiCtrlIdentityServerCertVarName, constants.ZitiCtrlIdentityServerCertVarDescription, data.Controller.IdentityServerCert}, + {constants.ZitiCtrlIdentityKeyVarName, constants.ZitiCtrlIdentityKeyVarDescription, data.Controller.IdentityKey}, + {constants.ZitiCtrlIdentityCAVarName, constants.ZitiCtrlIdentityCAVarDescription, data.Controller.IdentityCA}, + {constants.ZitiSigningCertVarName, constants.ZitiSigningCertVarDescription, data.Controller.Edge.ZitiSigningCert}, + {constants.ZitiSigningKeyVarName, constants.ZitiSigningKeyVarDescription, data.Controller.Edge.ZitiSigningKey}, + {constants.ZitiRouterIdentityCertVarName, constants.ZitiRouterIdentityCertVarDescription, data.Router.IdentityCert}, + {constants.ZitiRouterIdentityServerCertVarName, constants.ZitiRouterIdentityServerCertVarDescription, data.Router.IdentityServerCert}, + {constants.ZitiRouterIdentityKeyVarName, constants.ZitiRouterIdentityKeyVarDescription, data.Router.IdentityKey}, + {constants.ZitiRouterIdentityCAVarName, constants.ZitiRouterIdentityCAVarDescription, data.Router.IdentityCA}, + {constants.ZitiCtrlListenerAddressVarName, constants.ZitiCtrlListenerAddressVarDescription, data.Controller.ListenerAddress}, + {constants.ZitiCtrlAdvertisedAddressVarName, constants.ZitiCtrlAdvertisedAddressVarDescription, data.Controller.AdvertisedAddress}, + {constants.ZitiEdgeCtrlListenerHostPortVarName, constants.ZitiEdgeCtrlListenerHostPortVarDescription, data.Controller.Edge.ListenerHostPort}, + {constants.ZitiEdgeCtrlAdvertisedHostPortVarName, constants.ZitiEdgeCtrlAdvertisedHostPortVarDescription, data.Controller.Edge.AdvertisedHostPort}, + {constants.ZitiEdgeCtrlAdvertisedPortVarName, constants.ZitiEdgeCtrlAdvertisedPortVarDescription, data.Controller.Edge.AdvertisedPort}, + } // Setup logging var logOut *os.File - environmentOptions.OS = runtime.GOOS + // Figure out the correct comment prefix and variable declaration command + if runtime.GOOS == "windows" { + environmentOptions.OSCommentPrefix = "rem" + environmentOptions.OSVarDeclare = "SET" + } else { + environmentOptions.OSCommentPrefix = "#" + environmentOptions.OSVarDeclare = "export" + } if environmentOptions.Verbose { logrus.SetLevel(logrus.DebugLevel) // Only print log to stdout if not printing config to stdout @@ -225,6 +175,7 @@ func NewCmdCreateConfigEnvironment() *cobra.Command { "%-36s %-50s %s\n"+ "%-36s %-50s %s\n"+ "%-36s %-50s %s\n"+ + "%-36s %-50s %s\n"+ "%-36s %-50s %s", constants.ZitiHomeVarName, constants.ZitiHomeVarDescription, data.ZitiHome, constants.ZitiCtrlPortVarName, constants.ZitiCtrlPortVarDescription, data.Controller.Port, @@ -233,6 +184,7 @@ func NewCmdCreateConfigEnvironment() *cobra.Command { constants.ZitiCtrlListenerAddressVarName, constants.ZitiCtrlListenerAddressVarDescription, data.Controller.ListenerAddress, constants.ZitiEdgeCtrlListenerHostPortVarName, constants.ZitiEdgeCtrlListenerHostPortVarDescription, data.Controller.Edge.ListenerHostPort, constants.ZitiEdgeCtrlAdvertisedHostPortVarName, constants.ZitiEdgeCtrlAdvertisedHostPortVarDescription, data.Controller.Edge.AdvertisedHostPort, + constants.ZitiEdgeCtrlAdvertisedPortVarName, constants.ZitiEdgeCtrlAdvertisedPortVarDescription, data.Controller.Edge.AdvertisedPort, constants.ZitiEdgeRouterRawNameVarName, constants.ZitiEdgeRouterRawNameVarDescription, data.Router.Edge.Hostname, constants.ZitiEdgeRouterPortVarName, constants.ZitiEdgeRouterPortVarDescription, data.Router.Edge.Port, constants.ZitiRouterIdentityCertVarName, constants.ZitiRouterIdentityCertVarDescription, data.Router.IdentityCert, diff --git a/ziti/cmd/ziti/cmd/create_config_router.go b/ziti/cmd/ziti/cmd/create_config_router.go index 3fc7044b3..b0d9684f9 100644 --- a/ziti/cmd/ziti/cmd/create_config_router.go +++ b/ziti/cmd/ziti/cmd/create_config_router.go @@ -65,7 +65,7 @@ func NewCmdCreateConfigRouter() *cobra.Command { data.populateDefaults() // Update router data with options passed in - data.Router.Name = routerOptions.RouterName + data.Router.Name = validateRouterName(routerOptions.RouterName) SetZitiRouterIdentity(&data.Router, data.Router.Name) }, Run: func(cmd *cobra.Command, args []string) { diff --git a/ziti/cmd/ziti/cmd/create_config_router_common.go b/ziti/cmd/ziti/cmd/create_config_router_common.go index 4a2d35b3b..8ac190ee4 100644 --- a/ziti/cmd/ziti/cmd/create_config_router_common.go +++ b/ziti/cmd/ziti/cmd/create_config_router_common.go @@ -64,3 +64,12 @@ func SetZitiRouterIdentityCA(r *RouterTemplateValues, routerName string) { } r.IdentityCA = cmdhelper.NormalizePath(val) } + +func validateRouterName(name string) string { + // Currently, only worry about router name if it's blank + if name == "" { + hostname, _ := os.Hostname() + return hostname + } + return name +} diff --git a/ziti/cmd/ziti/cmd/create_config_router_edge.go b/ziti/cmd/ziti/cmd/create_config_router_edge.go index f6262514b..dc6ce81e6 100644 --- a/ziti/cmd/ziti/cmd/create_config_router_edge.go +++ b/ziti/cmd/ziti/cmd/create_config_router_edge.go @@ -93,8 +93,7 @@ func (options *CreateConfigRouterOptions) addEdgeFlags(cmd *cobra.Command) { func (options *CreateConfigRouterOptions) runEdgeRouter(data *ConfigTemplateValues) error { // Ensure private and wss are not both used if options.IsPrivate && options.WssEnabled { - logrus.Fatal("Flags for private and wss configs are mutually exclusive. You must choose private or wss, not both") - return errors.New("Flags for private and wss configs are mutually exclusive.") + return errors.New("Flags for private and wss configs are mutually exclusive. You must choose private or wss, not both") } tmpl, err := template.New("edge-router-config").Parse(routerConfigEdgeTemplate) @@ -107,7 +106,6 @@ func (options *CreateConfigRouterOptions) runEdgeRouter(data *ConfigTemplateValu // Check if the path exists, fail if it doesn't basePath := filepath.Dir(options.Output) + "/" if _, err := os.Stat(filepath.Dir(basePath)); os.IsNotExist(err) { - logrus.Fatalf("Provided path: [%s] does not exist\n", basePath) return err } diff --git a/ziti/cmd/ziti/cmd/create_config_router_fabric.go b/ziti/cmd/ziti/cmd/create_config_router_fabric.go index cdf376ff3..457fb8a31 100644 --- a/ziti/cmd/ziti/cmd/create_config_router_fabric.go +++ b/ziti/cmd/ziti/cmd/create_config_router_fabric.go @@ -90,7 +90,6 @@ func (options *CreateConfigRouterOptions) runFabricRouter(data *ConfigTemplateVa // Check if the path exists, fail if it doesn't basePath := filepath.Dir(options.Output) + "/" if _, err := os.Stat(filepath.Dir(basePath)); os.IsNotExist(err) { - logrus.Fatalf("Provided path: [%s] does not exist\n", basePath) return err } diff --git a/ziti/cmd/ziti/cmd/create_config_router_test.go b/ziti/cmd/ziti/cmd/create_config_router_test.go new file mode 100644 index 000000000..55075883b --- /dev/null +++ b/ziti/cmd/ziti/cmd/create_config_router_test.go @@ -0,0 +1,318 @@ +package cmd + +import ( + "github.com/openziti/ziti/ziti/cmd/ziti/constants" + "github.com/stretchr/testify/assert" + "os" + "testing" + "time" +) + +func clearOptionsAndTemplateData() { + routerOptions = CreateConfigRouterOptions{} + data = &ConfigTemplateValues{} +} + +func TestBlankEdgeRouterNameBecomesHostname(t *testing.T) { + hostname, _ := os.Hostname() + blank := "" + + // Setup options with blank router name + clearOptionsAndTemplateData() + routerOptions.Output = defaultOutput + routerOptions.RouterName = blank + + // Check that template values is a blank name + assert.Equal(t, blank, data.Router.Name, "Mismatch router name, expected %s but got %s", "", hostname) + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigRouter() + cmd.SetArgs([]string{"edge", "--routerName", blank}) + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + // Check that the blank name was replaced with hostname in the template values + assert.Equal(t, hostname, data.Router.Name, "Mismatch router name, expected %s but got %s", "", hostname) + +} + +func TestBlankFabricRouterNameBecomesHostname(t *testing.T) { + hostname, _ := os.Hostname() + blank := "" + + // Create the options with empty router name + clearOptionsAndTemplateData() + routerOptions.Output = defaultOutput + routerOptions.RouterName = blank + + // Check that template values is a blank name + assert.Equal(t, blank, data.Router.Name, "Mismatch router name, expected %s but got %s", "", hostname) + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigRouter() + cmd.SetArgs([]string{"fabric", "--routerName", blank}) + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + // Check that the blank name was replaced with hostname in the template values + assert.Equal(t, hostname, data.Router.Name, "Mismatch router name, expected %s but got %s", "", hostname) + +} + +func TestEdgeRouterCannotBeWSSAndPrivate(t *testing.T) { + expectedErrorMsg := "Flags for private and wss configs are mutually exclusive. You must choose private or wss, not both" + + // Create the options with both flags set to true + clearOptionsAndTemplateData() + routerOptions.Output = defaultOutput + routerOptions.IsPrivate = true + routerOptions.WssEnabled = true + + err := routerOptions.runEdgeRouter(&ConfigTemplateValues{}) + + assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) +} + +func TestEdgeRouterOutputPathDoesNotExist(t *testing.T) { + expectedErrorMsg := "stat /IDoNotExist: no such file or directory" + + // Set the router options + clearOptionsAndTemplateData() + routerOptions.RouterName = "MyEdgeRouter" + routerOptions.Output = "/IDoNotExist/MyEdgeRouter.yaml" + + err := routerOptions.runEdgeRouter(&ConfigTemplateValues{}) + + assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) +} + +func TestFabricRouterOutputPathDoesNotExist(t *testing.T) { + expectedErrorMsg := "stat /IDoNotExist: no such file or directory" + + // Set the router options + clearOptionsAndTemplateData() + routerOptions.RouterName = "MyFabricRouter" + routerOptions.Output = "/IDoNotExist/MyFabricRouter.yaml" + + err := routerOptions.runFabricRouter(&ConfigTemplateValues{}) + + assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) +} + +func TestSetZitiRouterIdentityCertDefault(t *testing.T) { + // Ensure env variable is not set + _ = os.Setenv(constants.ZitiRouterIdentityCertVarName, "") + + routerName := "RouterTest" + expectedDefault := workingDir + "/" + routerName + ".cert" + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityCert(rtv, routerName) + + // Check that the default is used + assert.Equal(t, expectedDefault, rtv.IdentityCert) +} + +func TestSetZitiRouterIdentityCertCustom(t *testing.T) { + expectedCustom := "My/Custom/Path/for/PKI/RouterTest.cert" + // Set the env variable which is used to populate this value + _ = os.Setenv(constants.ZitiRouterIdentityCertVarName, expectedCustom) + + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityCert(rtv, "Irrelevant") + + // Check that the custom value is used + assert.Equal(t, expectedCustom, rtv.IdentityCert) +} + +func TestSetZitiRouterIdentityServerCertDefault(t *testing.T) { + // Ensure env variable is not set + _ = os.Setenv(constants.ZitiRouterIdentityServerCertVarName, "") + + routerName := "RouterTest" + expectedDefault := workingDir + "/" + routerName + ".server.chain.cert" + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityServerCert(rtv, routerName) + + // Check that the default is used + assert.Equal(t, expectedDefault, rtv.IdentityServerCert) +} + +func TestSetZitiRouterIdentityServerCertCustom(t *testing.T) { + expectedCustom := "My/Custom/Path/for/PKI/RouterTest.server.chain.cert" + // Set the env variable which is used to populate this value + _ = os.Setenv(constants.ZitiRouterIdentityServerCertVarName, expectedCustom) + + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityServerCert(rtv, "Irrelevant") + + // Check that the custom value is used + assert.Equal(t, expectedCustom, rtv.IdentityServerCert) +} + +func TestSetZitiRouterIdentityKeyCertDefault(t *testing.T) { + // Ensure env variable is not set + _ = os.Setenv(constants.ZitiRouterIdentityKeyVarDescription, "") + + routerName := "RouterTest" + expectedDefault := workingDir + "/" + routerName + ".key" + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityKey(rtv, routerName) + + // Check that the default is used + assert.Equal(t, expectedDefault, rtv.IdentityKey) +} + +func TestSetZitiRouterIdentityKeyCustom(t *testing.T) { + expectedCustom := "My/Custom/Path/for/PKI/RouterTest.key" + // Set the env variable which is used to populate this value + _ = os.Setenv(constants.ZitiRouterIdentityKeyVarName, expectedCustom) + + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityKey(rtv, "Irrelevant") + + // Check that the custom value is used + assert.Equal(t, expectedCustom, rtv.IdentityKey) +} + +func TestSetZitiRouterIdentityKeyCADefault(t *testing.T) { + // Ensure env variable is not set + _ = os.Setenv(constants.ZitiRouterIdentityCAVarName, "") + + routerName := "RouterTest" + expectedDefault := workingDir + "/" + routerName + ".cas" + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityCA(rtv, routerName) + + // Check that the default is used + assert.Equal(t, expectedDefault, rtv.IdentityCA) +} + +func TestSetZitiRouterIdentityCACustom(t *testing.T) { + expectedCustom := "My/Custom/Path/for/PKI/RouterTest.cas" + // Set the env variable which is used to populate this value + _ = os.Setenv(constants.ZitiRouterIdentityCAVarName, expectedCustom) + + rtv := &RouterTemplateValues{} + SetZitiRouterIdentityCA(rtv, "Irrelevant") + + // Check that the custom value is used + assert.Equal(t, expectedCustom, rtv.IdentityCA) +} + +func TestSetZitiRouterIdentitySetsAllIdentitiesAndEdgeRouterRawName(t *testing.T) { + // Setup + expectedRawName := "MyEdgeRouterRawName" + blank := "" + rtv := &RouterTemplateValues{} + + // Check that they're all currently blank + assert.Equal(t, blank, rtv.Edge.Hostname) + assert.Equal(t, blank, rtv.IdentityCert) + assert.Equal(t, blank, rtv.IdentityServerCert) + assert.Equal(t, blank, rtv.IdentityKey) + assert.Equal(t, blank, rtv.IdentityCA) + + // Set the env variable + _ = os.Setenv(constants.ZitiEdgeRouterRawNameVarName, expectedRawName) + + SetZitiRouterIdentity(rtv, expectedRawName) + + // Check that the value matches + assert.Equal(t, expectedRawName, rtv.Edge.Hostname) + assert.NotEqualf(t, blank, rtv.IdentityCert, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityServerCert, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityKey, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityCA, "Router.IdentityCert expected to have a value, instead it was blank") +} + +func TestSetZitiRouterIdentitySetsAllIdentitiesAndEdgeRouterRawNameToHostWhenBlank(t *testing.T) { + // Setup + expectedRawName, _ := os.Hostname() + blank := "" + rtv := &RouterTemplateValues{} + + // Check that they're all currently blank + assert.Equal(t, blank, rtv.Edge.Hostname) + assert.Equal(t, blank, rtv.IdentityCert) + assert.Equal(t, blank, rtv.IdentityServerCert) + assert.Equal(t, blank, rtv.IdentityKey) + assert.Equal(t, blank, rtv.IdentityCA) + + // Set the env variable to an empty value + _ = os.Setenv(constants.ZitiEdgeRouterRawNameVarName, "") + + SetZitiRouterIdentity(rtv, expectedRawName) + + // Check that the value matches + assert.Equal(t, expectedRawName, rtv.Edge.Hostname) + assert.NotEqualf(t, blank, rtv.IdentityCert, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityServerCert, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityKey, "Router.IdentityCert expected to have a value, instead it was blank") + assert.NotEqualf(t, blank, rtv.IdentityCA, "Router.IdentityCert expected to have a value, instead it was blank") +} + +func TestExecuteCreateConfigRouterEdgeHasNonBlankTemplateValues(t *testing.T) { + routerName := "MyEdgeRouter" + expectedNonEmptyStringFields := []string{".ZitiHome", ".Hostname", ".Router.Name", ".Router.IdentityCert", ".Router.IdentityServerCert", ".Router.IdentityKey", ".Router.IdentityCA", ".Router.Edge.Hostname", ".Router.Edge.Port"} + expectedNonEmptyStringValues := []*string{&data.ZitiHome, &data.Hostname, &data.Router.Name, &data.Router.IdentityCert, &data.Router.IdentityServerCert, &data.Router.IdentityKey, &data.Router.IdentityCA, &data.Router.Edge.Hostname, &data.Router.Edge.Port} + expectedNonEmptyIntFields := []string{".Router.Listener.BindPort", ".Router.Listener.OutQueueSize", ".Router.Wss.ReadBufferSize", ".Router.Wss.WriteBufferSize", ".Router.Forwarder.XgressDialQueueLength", ".Router.Forwarder.XgressDialWorkerCount", ".Router.Forwarder.LinkDialQueueLength", ".Router.Forwarder.LinkDialWorkerCount"} + expectedNonEmptyIntValues := []*int{&data.Router.Listener.BindPort, &data.Router.Listener.OutQueueSize, &data.Router.Wss.ReadBufferSize, &data.Router.Wss.WriteBufferSize, &data.Router.Forwarder.XgressDialQueueLength, &data.Router.Forwarder.XgressDialWorkerCount, &data.Router.Forwarder.LinkDialQueueLength, &data.Router.Forwarder.LinkDialWorkerCount} + expectedNonEmptyTimeFields := []string{".Router.Listener.ConnectTimeout", "Router.Listener.GetSessionTimeout", ".Router.Wss.WriteTimeout", ".Router.Wss.ReadTimeout", ".Router.Wss.IdleTimeout", ".Router.Wss.PongTimeout", ".Router.Wss.PingInterval", ".Router.Wss.HandshakeTimeout", ".Router.Forwarder.LatencyProbeInterval"} + expectedNonEmptyTimeValues := []*time.Duration{&data.Router.Listener.ConnectTimeout, &data.Router.Listener.GetSessionTimeout, &data.Router.Wss.WriteTimeout, &data.Router.Wss.ReadTimeout, &data.Router.Wss.IdleTimeout, &data.Router.Wss.PongTimeout, &data.Router.Wss.PingInterval, &data.Router.Wss.HandshakeTimeout, &data.Router.Forwarder.LatencyProbeInterval} + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigRouter() + cmd.SetArgs([]string{"edge", "--routerName", routerName}) + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + // Check that the expected string template values are not blank + for field, value := range expectedNonEmptyStringValues { + assert.NotEqualf(t, "", *value, expectedNonEmptyStringFields[field]+" should be a non-blank value") + } + + // Check that the expected int template values are not zero + for field, value := range expectedNonEmptyIntValues { + assert.NotZero(t, *value, expectedNonEmptyIntFields[field]+" should be a non-zero value") + } + + // Check that the expected time.Duration template values are not zero + for field, value := range expectedNonEmptyTimeValues { + assert.NotZero(t, *value, expectedNonEmptyTimeFields[field]+" should be a non-zero value") + } +} + +func TestExecuteCreateConfigRouterFabricHasNonBlankTemplateValues(t *testing.T) { + routerName := "MyFabricRouter" + expectedNonEmptyStringFields := []string{".ZitiHome", ".Hostname", ".Router.Name", ".Router.IdentityCert", ".Router.IdentityServerCert", ".Router.IdentityKey", ".Router.IdentityCA", ".Router.Edge.Hostname", ".Router.Edge.Port"} + expectedNonEmptyStringValues := []*string{&data.ZitiHome, &data.Hostname, &data.Router.Name, &data.Router.IdentityCert, &data.Router.IdentityServerCert, &data.Router.IdentityKey, &data.Router.IdentityCA, &data.Router.Edge.Hostname, &data.Router.Edge.Port} + expectedNonEmptyIntFields := []string{".Router.Listener.BindPort", ".Router.Listener.OutQueueSize", ".Router.Wss.ReadBufferSize", ".Router.Wss.WriteBufferSize", ".Router.Forwarder.XgressDialQueueLength", ".Router.Forwarder.XgressDialWorkerCount", ".Router.Forwarder.LinkDialQueueLength", ".Router.Forwarder.LinkDialWorkerCount"} + expectedNonEmptyIntValues := []*int{&data.Router.Listener.BindPort, &data.Router.Listener.OutQueueSize, &data.Router.Wss.ReadBufferSize, &data.Router.Wss.WriteBufferSize, &data.Router.Forwarder.XgressDialQueueLength, &data.Router.Forwarder.XgressDialWorkerCount, &data.Router.Forwarder.LinkDialQueueLength, &data.Router.Forwarder.LinkDialWorkerCount} + expectedNonEmptyTimeFields := []string{".Router.Listener.ConnectTimeout", "Router.Listener.GetSessionTimeout", ".Router.Wss.WriteTimeout", ".Router.Wss.ReadTimeout", ".Router.Wss.IdleTimeout", ".Router.Wss.PongTimeout", ".Router.Wss.PingInterval", ".Router.Wss.HandshakeTimeout", ".Router.Forwarder.LatencyProbeInterval"} + expectedNonEmptyTimeValues := []*time.Duration{&data.Router.Listener.ConnectTimeout, &data.Router.Listener.GetSessionTimeout, &data.Router.Wss.WriteTimeout, &data.Router.Wss.ReadTimeout, &data.Router.Wss.IdleTimeout, &data.Router.Wss.PongTimeout, &data.Router.Wss.PingInterval, &data.Router.Wss.HandshakeTimeout, &data.Router.Forwarder.LatencyProbeInterval} + + // Create and run the CLI command (capture output, otherwise config prints to stdout instead of test results) + cmd := NewCmdCreateConfigRouter() + cmd.SetArgs([]string{"fabric", "--routerName", routerName}) + _ = captureOutput(func() { + _ = cmd.Execute() + }) + + // Check that the expected string template values are not blank + for field, value := range expectedNonEmptyStringValues { + assert.NotEqualf(t, "", *value, expectedNonEmptyStringFields[field]+" should be a non-blank value") + } + + // Check that the expected int template values are not zero + for field, value := range expectedNonEmptyIntValues { + assert.NotZero(t, *value, expectedNonEmptyIntFields[field]+" should be a non-zero value") + } + + // Check that the expected time.Duration template values are not zero + for field, value := range expectedNonEmptyTimeValues { + assert.NotZero(t, *value, expectedNonEmptyTimeFields[field]+" should be a non-zero value") + } +} diff --git a/ziti/cmd/ziti/cmd/create_config_test.go b/ziti/cmd/ziti/cmd/create_config_test.go new file mode 100644 index 000000000..03e9f56c1 --- /dev/null +++ b/ziti/cmd/ziti/cmd/create_config_test.go @@ -0,0 +1,230 @@ +package cmd + +import ( + "bytes" + "fmt" + "github.com/stretchr/testify/assert" + "io" + "os" + "strings" + "testing" +) + +func getZitiEnvironmentVariables() []string { + return []string{ + "ZITI_HOME", + "ZITI_CONTROLLER_NAME", + "ZITI_CTRL_PORT", + "ZITI_EDGE_ROUTER_RAWNAME", + "ZITI_EDGE_ROUTER_PORT", + "ZITI_EDGE_CTRL_IDENTITY_CERT", + "ZITI_EDGE_CTRL_IDENTITY_SERVER_CERT", + "ZITI_EDGE_CTRL_IDENTITY_KEY", + "ZITI_EDGE_CTRL_IDENTITY_CA", + "ZITI_CTRL_IDENTITY_CERT", + "ZITI_CTRL_IDENTITY_SERVER_CERT", + "ZITI_CTRL_IDENTITY_KEY", + "ZITI_CTRL_IDENTITY_CA", + "ZITI_SIGNING_CERT", + "ZITI_SIGNING_KEY", + "ZITI_ROUTER_IDENTITY_CERT", + "ZITI_ROUTER_IDENTITY_SERVER_CERT", + "ZITI_ROUTER_IDENTITY_KEY", + "ZITI_ROUTER_IDENTITY_CA", + "ZITI_CTRL_LISTENER_ADDRESS", + "ZITI_CTRL_ADVERTISED_ADDRESS", + "ZITI_CTRL_EDGE_LISTENER_HOST_PORT", + "ZITI_EDGE_CTRL_ADVERTISED_HOST_PORT", + } +} + +// Test that all ZITI_* variables are included in the values for output +func TestNoUnknownOutputEnvVariablesExist(t *testing.T) { + // Get the list of ZITI_* environment variables + allEnvVars := getZitiEnvironmentVariables() + + // Create a config environment command which will populate the env variable metadata + NewCmdCreateConfigEnvironment() + + // Run the environment options command and capture stdout + cmd := NewCmdCreateConfigEnvironment() + cmd.SetArgs([]string{"-o", "stdout"}) + output := captureOutput(func() { + _ = cmd.Execute() + }) + + // Split the output on newlines + lines := strings.Split(output, "\n") + // Check that every known environment variable is represented in the env file output + prefix := "ZITI_" + var unknownValues []string + for _, line := range lines { + // Only look at lines with a ZITI_* env var + if !strings.Contains(line, prefix) { + continue + } + // Strip out the variable name and see if it's a known value + start := strings.Index(line, prefix) + end := strings.Index(line, "=") + if end < 0 { + // If there's no assignment, assume a variable name was referenced in a comment and ignore + continue + } + envVar := strings.TrimSpace(line[start:end]) + if !contains(allEnvVars, envVar) { + unknownValues = append(unknownValues, envVar) + } + } + + assert.Zero(t, len(unknownValues)) + for _, value := range unknownValues { + fmt.Printf("The variable %s was found in env command output but was not expected.\n -If this is a new variable, add it to the ZITI env variables list in create_config_test.\n -If this variable was removed, remove the variable from the env command output.\n", value) + } +} + +// Test that all known ZITI_* variables are included in the env file +func TestAllKnownEnvVariablesAreFoundInOutput(t *testing.T) { + // Get the list of ZITI_* environment variables + allEnvVars := getZitiEnvironmentVariables() + + // Create a config environment command which will populate the env variable metadata + NewCmdCreateConfigEnvironment() + + // Run the environment options command and capture stdout + cmd := NewCmdCreateConfigEnvironment() + cmd.SetArgs([]string{"-o", "stdout"}) + output := captureOutput(func() { + _ = cmd.Execute() + }) + + // Split the output on newlines + lines := strings.Split(output, "\n") + // Check that every known environment variable is represented in the env file output + var unfoundVariables []string + for _, variable := range allEnvVars { + found := false + for _, line := range lines { + // Check if the line contains an assignment for this env variable + assignment := variable + "=" + if strings.Contains(line, assignment) { + found = true + break + } + } + if !found { + unfoundVariables = append(unfoundVariables, variable) + } + } + + assert.Zero(t, len(unfoundVariables)) + for _, value := range unfoundVariables { + fmt.Printf("The variable %s was expected in env command output but was not found.\n -If this is variable was removed, remove it from the ZITI env variables list in create_config_test.\n -If this is a new variable, add it to the env command output.\n", value) + } +} + +// Test that all known ZITI_* variables are included in the help output +func TestAllKnownEnvVariablesAreFoundInHelpOutput(t *testing.T) { + // Get the list of ZITI_* environment variables + allEnvVars := getZitiEnvironmentVariables() + + // Create a config environment command which will populate the env variable metadata + NewCmdCreateConfigEnvironment() + + // Run the environment options command and capture stdout from help + cmd := NewCmdCreateConfigEnvironment() + cmd.SetArgs([]string{"-h"}) + output := captureOutput(func() { + _ = cmd.Execute() + }) + + // Split the output on newlines + lines := strings.Split(output, "\n") + // Check that every known environment variable is represented in the help output + var unfoundVariables []string + for _, variable := range allEnvVars { + found := false + for _, line := range lines { + // Check if the line contains an assignment for this env variable + if strings.HasPrefix(line, variable) { + found = true + break + } + } + if !found { + unfoundVariables = append(unfoundVariables, variable) + } + } + + assert.Zero(t, len(unfoundVariables)) + for _, value := range unfoundVariables { + fmt.Printf("The variable %s was expected in env command's help output but was not found.\n -If this is variable was removed, remove it from the ZITI env variables list in create_config_test.\n -If this is a new variable, add it to the env command's help output.\n", value) + } +} + +// Test that all ZITI_* variables are included in the values for help output +func TestNoUnknownHelpEnvVariablesExist(t *testing.T) { + // Get the list of ZITI_* environment variables + allEnvVars := getZitiEnvironmentVariables() + + // Create a config environment command which will populate the env variable metadata + NewCmdCreateConfigEnvironment() + + // Run the environment options command and capture stdout from help + cmd := NewCmdCreateConfigEnvironment() + cmd.SetArgs([]string{"-h"}) + output := captureOutput(func() { + _ = cmd.Execute() + }) + + // Split the output on newlines + lines := strings.Split(output, "\n") + // Check that every known environment variable is represented in the env file output + prefix := "ZITI_" + var unknownValues []string + for _, line := range lines { + // Only look at lines with a ZITI_* env var + if !strings.HasPrefix(line, prefix) { + continue + } + // Strip out the variable name and see if it's a known value + start := strings.Index(line, prefix) + end := strings.Index(line, " ") + if end < 0 { + // If there's no assignment, assume a variable name was referenced in a comment and ignore + continue + } + envVar := strings.TrimSpace(line[start:end]) + if !contains(allEnvVars, envVar) { + unknownValues = append(unknownValues, envVar) + } + } + + assert.Zero(t, len(unknownValues)) + for _, value := range unknownValues { + fmt.Printf("The variable %s was found in env command's help output but was not expected.\n -If this is a new variable, add it to the ZITI env variables list in create_config_test.\n -If this variable was removed, remove the variable from the env command's help output.\n", value) + } +} + +func contains(s []string, str string) bool { + for _, v := range s { + if v == str { + return true + } + } + + return false +} + +func captureOutput(function func()) string { + var buffer bytes.Buffer + oldStdOut := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + function() + + _ = w.Close() + os.Stdout = oldStdOut + _, _ = io.Copy(&buffer, r) + return buffer.String() +} diff --git a/ziti/cmd/ziti/cmd/helpers/env_helpers.go b/ziti/cmd/ziti/cmd/helpers/env_helpers.go index 2d74d8050..c6aa83cb2 100644 --- a/ziti/cmd/ziti/cmd/helpers/env_helpers.go +++ b/ziti/cmd/ziti/cmd/helpers/env_helpers.go @@ -75,27 +75,36 @@ func GetZitiCtrlAdvertisedAddress() (string, error) { } } - return getValueOrSetAndGetDefault(constants.ZitiCtrlAdvertisedAddressVarName, hostname, false) + return getValueOrSetAndGetDefault(constants.ZitiCtrlAdvertisedAddressVarName, hostname) } func GetZitiCtrlPort() (string, error) { - return getValueOrSetAndGetDefault(constants.ZitiCtrlPortVarName, constants.DefaultZitiControllerPort, false) + return getValueOrSetAndGetDefault(constants.ZitiCtrlPortVarName, constants.DefaultZitiControllerPort) } func GetZitiCtrlListenerAddress() (string, error) { - return getValueOrSetAndGetDefault(constants.ZitiCtrlListenerAddressVarName, constants.DefaultZitiControllerListenerAddress, false) + return getValueOrSetAndGetDefault(constants.ZitiCtrlListenerAddressVarName, constants.DefaultZitiControllerListenerAddress) } func GetZitiCtrlName() (string, error) { - return getValueOrSetAndGetDefault(constants.ZitiCtrlNameVarName, constants.DefaultZitiControllerName, false) + return getValueOrSetAndGetDefault(constants.ZitiCtrlNameVarName, constants.DefaultZitiControllerName) } func GetZitiEdgeRouterPort() (string, error) { - return getValueOrSetAndGetDefault(constants.ZitiEdgeRouterPortVarName, constants.DefaultZitiEdgeRouterPort, false) + return getValueOrSetAndGetDefault(constants.ZitiEdgeRouterPortVarName, constants.DefaultZitiEdgeRouterPort) } func GetZitiEdgeCtrlListenerHostPort() (string, error) { - return getValueOrSetAndGetDefault(constants.ZitiEdgeCtrlListenerHostPortVarName, constants.DefaultZitiEdgeListenerHostPort, false) + // Get the edge controller port to use as the default + edgeCtrlPort, err := GetZitiEdgeCtrlAdvertisedPort() + if err != nil { + err := errors.Wrap(err, "Unable to get "+constants.ZitiEdgeCtrlAdvertisedPortVarName) + if err != nil { + return "", err + } + } + + return getValueOrSetAndGetDefault(constants.ZitiEdgeCtrlListenerHostPortVarName, constants.DefaultZitiEdgeListenerHost+":"+edgeCtrlPort) } func GetZitiEdgeCtrlAdvertisedHostPort() (string, error) { @@ -107,17 +116,26 @@ func GetZitiEdgeCtrlAdvertisedHostPort() (string, error) { } } - return getValueOrSetAndGetDefault(constants.ZitiEdgeCtrlAdvertisedHostPortVarName, hostname+":"+constants.DefaultZitiEdgeAPIPort, false) + port, err := GetZitiEdgeCtrlAdvertisedPort() + if err != nil { + err := errors.Wrap(err, "Unable to get "+constants.ZitiEdgeCtrlAdvertisedPortVarName) + if err != nil { + return "", err + } + } + + return getValueOrSetAndGetDefault(constants.ZitiEdgeCtrlAdvertisedHostPortVarName, hostname+":"+port) } -func getValueOrSetAndGetDefault(envVarName string, defaultValue string, forceDefault bool) (string, error) { - retVal := "" - if !forceDefault { - // Get path from env variable - retVal = os.Getenv(envVarName) - if retVal != "" { - return retVal, nil - } +func GetZitiEdgeCtrlAdvertisedPort() (string, error) { + return getValueOrSetAndGetDefault(constants.ZitiEdgeCtrlAdvertisedPortVarName, constants.DefaultZitiEdgeAPIPort) +} + +func getValueOrSetAndGetDefault(envVarName string, defaultValue string) (string, error) { + // Get path from env variable + retVal := os.Getenv(envVarName) + if retVal != "" { + return retVal, nil } err := os.Setenv(envVarName, defaultValue) diff --git a/ziti/cmd/ziti/cmd/helpers/helpers_test.go b/ziti/cmd/ziti/cmd/helpers/helpers_test.go new file mode 100644 index 000000000..2919aabb2 --- /dev/null +++ b/ziti/cmd/ziti/cmd/helpers/helpers_test.go @@ -0,0 +1,303 @@ +package helpers + +import ( + "github.com/stretchr/testify/assert" + "os" + "strings" + "testing" +) + +func TestHomeDirHasNoWindowsSlashes(t *testing.T) { + + value := HomeDir() + + assert.Zero(t, strings.Count(value, "\\")) + +} + +func TestWorkingDirHasNoWindowsSlashes(t *testing.T) { + value, _ := WorkingDir() + + assert.Zero(t, strings.Count(value, "\\")) +} + +func TestGetZitiHomeWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_HOME" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + wd, _ := os.Getwd() + expectedValue := NormalizePath(wd) + + // Check that the value matches + actualValue, _ := GetZitiHome() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiHomeWhenSet(t *testing.T) { + // Setup + varName := "ZITI_HOME" + expectedValue := "/path/to/ziti/home" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiHome() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiHomeWhenSetWithWindowsSlashes(t *testing.T) { + // Setup + varName := "ZITI_HOME" + expectedValue := "/path/to/ziti/home" + + // Set the env variable using windows backslash + _ = os.Setenv(varName, strings.ReplaceAll(expectedValue, "/", "\\")) + + // Check that the value matches + actualValue, _ := GetZitiHome() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiCtrlAdvertisedAddressWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_CTRL_ADVERTISED_ADDRESS" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue, _ := os.Hostname() + + // Check that the value matches + actualValue, _ := GetZitiCtrlAdvertisedAddress() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiCtrlAdvertisedAddressWhenSet(t *testing.T) { + // Setup + varName := "ZITI_CTRL_ADVERTISED_ADDRESS" + expectedValue := "localhost" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiCtrlAdvertisedAddress() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiCtrlPortWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_CTRL_PORT" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue := "6262" + + // Check that the value matches + actualValue, _ := GetZitiCtrlPort() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiCtrlPortWhenSet(t *testing.T) { + // Setup + varName := "ZITI_CTRL_PORT" + expectedValue := "1234" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiCtrlPort() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiCtrlListenerAddressWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_CTRL_LISTENER_ADDRESS" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue := "0.0.0.0" + + // Check that the value matches + actualValue, _ := GetZitiCtrlListenerAddress() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiCtrlListenerAddressWhenSet(t *testing.T) { + // Setup + varName := "ZITI_CTRL_LISTENER_ADDRESS" + expectedValue := "localhost" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiCtrlListenerAddress() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiCtrlNameWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_CONTROLLER_NAME" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue := "controller" + + // Check that the value matches + actualValue, _ := GetZitiCtrlName() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiCtrlNameWhenSet(t *testing.T) { + // Setup + varName := "ZITI_CONTROLLER_NAME" + expectedValue := "MyController" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiCtrlName() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiEdgeRouterPortWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_EDGE_ROUTER_PORT" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue := "3022" + + // Check that the value matches + actualValue, _ := GetZitiEdgeRouterPort() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiEdgeRouterPortWhenSet(t *testing.T) { + // Setup + varName := "ZITI_EDGE_ROUTER_PORT" + expectedValue := "4321" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiEdgeRouterPort() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiEdgeCtrlListenerHostPortWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_CTRL_EDGE_LISTENER_HOST_PORT" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + expectedValue := "0.0.0.0:1280" + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlListenerHostPort() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiEdgeCtrlListenerHostPortWhenSet(t *testing.T) { + // Setup + varName := "ZITI_CTRL_EDGE_LISTENER_HOST_PORT" + expectedValue := "localhost:1234" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlListenerHostPort() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiEdgeCtrlAdvertisedHostPortWhenUnset(t *testing.T) { + // Setup + varName := "ZITI_EDGE_CTRL_ADVERTISED_HOST_PORT" + + // Ensure the variable is unset + _ = os.Unsetenv(varName) + hostname, _ := os.Hostname() + expectedValue := hostname + ":1280" + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlAdvertisedHostPort() + assert.Equal(t, expectedValue, actualValue) + + // The env variable should be populated with the expected value + envValue := os.Getenv(varName) + assert.Equal(t, expectedValue, envValue) +} + +func TestGetZitiEdgeCtrlAdvertisedHostPortWhenSet(t *testing.T) { + // Setup + varName := "ZITI_EDGE_CTRL_ADVERTISED_HOST_PORT" + expectedValue := "localhost:4321" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlAdvertisedHostPort() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiEdgeCtrlPortWhenNotSet(t *testing.T) { + // Setup + varName := "ZITI_EDGE_CONTROLLER_PORT" + expectedValue := "1280" + + // Be sure the var is unset + _ = os.Unsetenv(varName) + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlAdvertisedPort() + assert.Equal(t, expectedValue, actualValue) +} + +func TestGetZitiEdgeCtrlPortWhenSet(t *testing.T) { + // Setup + varName := "ZITI_EDGE_CONTROLLER_PORT" + expectedValue := "1234" + + // Set the env variable + _ = os.Setenv(varName, expectedValue) + + // Check that the value matches + actualValue, _ := GetZitiEdgeCtrlAdvertisedPort() + assert.Equal(t, expectedValue, actualValue) +} diff --git a/ziti/cmd/ziti/constants/constants.go b/ziti/cmd/ziti/constants/constants.go index b206e84a3..4d6e1b552 100644 --- a/ziti/cmd/ziti/constants/constants.go +++ b/ziti/cmd/ziti/constants/constants.go @@ -44,7 +44,7 @@ const ( DefaultZitiControllerName = "controller" DefaultZitiEdgeAPIPort = "1280" - DefaultZitiEdgeListenerHostPort = "0.0.0.0:1280" + DefaultZitiEdgeListenerHost = "0.0.0.0" DefaultZitiControllerListenerAddress = "0.0.0.0" DefaultZitiControllerPort = "6262" ) @@ -97,4 +97,6 @@ const ( ZitiEdgeCtrlListenerHostPortVarDescription = "Host and port of the Ziti Edge Controller Listener" ZitiEdgeCtrlAdvertisedHostPortVarName = "ZITI_EDGE_CTRL_ADVERTISED_HOST_PORT" ZitiEdgeCtrlAdvertisedHostPortVarDescription = "Host and port of the Ziti Edge Controller API" + ZitiEdgeCtrlAdvertisedPortVarName = "ZITI_EDGE_CONTROLLER_PORT" + ZitiEdgeCtrlAdvertisedPortVarDescription = "The advertised port of the edge controller" ) diff --git a/ziti/cmd/ziti/util/updates.go b/ziti/cmd/ziti/util/updates.go new file mode 100644 index 000000000..e5ce2e029 --- /dev/null +++ b/ziti/cmd/ziti/util/updates.go @@ -0,0 +1,83 @@ +/* + Copyright NetFoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "fmt" + "os" + + "github.com/fatih/color" + + "github.com/blang/semver" + "github.com/michaelquigley/pfxlog" + "github.com/openziti/ziti/common/version" + "github.com/openziti/ziti/ziti/cmd/ziti/constants" +) + +func LogReleaseVersionCheck(ziti_component string) { + logger := pfxlog.Logger() + developmentSemver, _ := semver.Parse("0.0.0") + latestGithubRelease, err := GetLatestGitHubReleaseVersion(false, constants.ZITI) + if err != nil { + logger.Debugf("failed to find latest GitHub version with error: %s", err) + return // soft-fail version check if GitHub API is unavailable + } + // compose current build's semver as version string and semver object + currentBuildVersion := version.GetVersion() + currentBuildSemver, err := semver.ParseTolerant(currentBuildVersion) // ParseTolerant trims leading "v" + if err != nil { + logger.Warnln("failed to parse current build version as semver: '%s' with error: %s", version.GetVersion(), err) + return + } + // ignore non-release builds and current release build + if currentBuildSemver.EQ(developmentSemver) { + logger.Debugf( + "this build of %s is unreleased v%s", + ziti_component, + developmentSemver, + ) + } else if latestGithubRelease.GT(currentBuildSemver) { + yellow := color.New(color.FgYellow).SprintFunc() + green := color.New(color.FgGreen).SprintFunc() + fmt.Fprintf(os.Stderr, + ` +********************************************************************************* + +An update with %s is available for %s %s from +https://github.com/openziti/%s/releases/latest/ + +********************************************************************************* +`, + green("v"+latestGithubRelease.String()), + ziti_component, + yellow("v"+currentBuildSemver.String()), + constants.ZITI, + ) + logger.Debugf( + "this v%s build of %s is superseded by v%s", + currentBuildSemver, + ziti_component, + latestGithubRelease, + ) + } else if latestGithubRelease.EQ(currentBuildSemver) { + logger.Debugf( + "this build of %s is the latest release v%s", + ziti_component, + currentBuildSemver, + ) + } +}