diff --git a/CHANGELOG.md b/CHANGELOG.md index aa7272dcf..621858f57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# Release 0.24.2 + +## What's New + +* Bug fix: link verification could panic if link was established before control was finished establishing +* Bug fix: When checking edge terminator validity in the router, check terminator id as well the address +* Enhancement: Improve logging around links in routers. Ensure we close both channels when closing a split link +* Enhancement: Add support for inspect in `ziti fabric`. Works the same as `ziti-fabric inspect` + # Release 0.24.1 ## What's New diff --git a/Dockerfile.linux-build b/Dockerfile.linux-build new file mode 100644 index 000000000..b269bbf79 --- /dev/null +++ b/Dockerfile.linux-build @@ -0,0 +1,70 @@ +FROM ubuntu:18.04 +# +# this file mirrors the build params used in the GitHub Actions and enables +# reproducible builds for downstream forks and Ziti contributors +# + +ARG latest_golang=1.17.2 +ARG go_distribution_file=go${latest_golang}.linux-amd64.tar.gz +ARG GOPATH=/root/go +ARG GOROOT=/usr/local/go +RUN apt-get update +RUN apt-get -yq install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gcc-aarch64-linux-gnu +RUN apt-get -yq install wget build-essential +RUN wget -q https://golang.org/dl/${go_distribution_file} +RUN tar -xzf ${go_distribution_file} -C /usr/local/ +RUN mkdir ${GOPATH} +ENV GOPATH=${GOPATH} +ENV GOROOT=${GOROOT} +ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH +RUN go install github.com/mitchellh/gox@latest +WORKDIR /mnt +CMD ["./linux-build.sh"] + +## +# build this Dockerfile +## +# +# MINIMUM_GOLANG=$(grep -Po '^go\s+\K\d+\.\d+(\.\d+)?$' go.mod) +# LATEST_GOLANG=$(curl -sSf "https://golang.org/VERSION?m=text" | /bin/grep -Po '^go(\s+)?\K\d+\.\d+\.\d+$') +# docker build --tag=zitibuilder --file=Dockerfile.linux-build --build-arg latest_golang=${LATEST_GOLANG} . + +## +# build Ziti +## +# docker run --rm --name=zitibuilder --volume=$PWD:/mnt zitibuilder + +# $ tree ./release +# ./release +# ├── amd64 +# │   └── linux +# │   ├── ziti +# │   ├── ziti-controller +# │   ├── ziti-fabric +# │   ├── ziti-fabric-gw +# │   ├── ziti-fabric-test +# │   ├── ziti-probe +# │   ├── ziti-router +# │   └── ziti-tunnel +# ├── arm +# │   └── linux +# │   ├── ziti +# │   ├── ziti-controller +# │   ├── ziti-fabric +# │   ├── ziti-fabric-gw +# │   ├── ziti-fabric-test +# │   ├── ziti-probe +# │   ├── ziti-router +# │   └── ziti-tunnel +# └── arm64 +# └── linux +# ├── ziti +# ├── ziti-controller +# ├── ziti-fabric +# ├── ziti-fabric-gw +# ├── ziti-fabric-test +# ├── ziti-probe +# ├── ziti-router +# └── ziti-tunnel + +# 6 directories, 24 files diff --git a/go.mod b/go.mod index 46c2c2016..dcb921c77 100644 --- a/go.mod +++ b/go.mod @@ -14,11 +14,10 @@ go 1.17 //replace github.com/michaelquigley/pfxlog => ../pfxlog -replace go.etcd.io/bbolt => github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e +//replace go.etcd.io/bbolt => github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e require ( github.com/Jeffail/gabs v1.4.0 - github.com/Jeffail/gabs/v2 v2.6.1 github.com/MakeNowJust/heredoc v1.0.0 github.com/MichaelMure/go-term-markdown v0.1.4 github.com/alecthomas/chroma v0.9.2 @@ -34,10 +33,10 @@ 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/edge v0.21.3 - github.com/openziti/fabric v0.17.2 - github.com/openziti/foundation v0.16.7 - github.com/openziti/sdk-golang v0.15.117 + github.com/openziti/edge v0.21.16 + github.com/openziti/fabric v0.17.9 + github.com/openziti/foundation v0.16.9 + github.com/openziti/sdk-golang v0.15.122 github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 @@ -67,7 +66,7 @@ require ( github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211106181442-e4c1a74c66bd // indirect github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect github.com/biogo/store v0.0.0-20200525035639-8c94ae1e7c9c // indirect - github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/coreos/go-iptables v0.6.0 // indirect github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect @@ -123,7 +122,7 @@ require ( github.com/miekg/dns v1.1.43 // indirect github.com/miekg/pkcs11 v1.0.3 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/netfoundry/secretstream v0.1.2 // indirect github.com/nxadm/tail v1.4.8 // indirect diff --git a/go.sum b/go.sum index 9c6d235af..a6a5c6ba1 100644 --- a/go.sum +++ b/go.sum @@ -66,7 +66,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Jeffail/gabs/v2 v2.6.1 h1:wwbE6nTQTwIMsMxzi6XFQQYRZ6wDc1mSdxoAN+9U4Gk= github.com/Jeffail/gabs/v2 v2.6.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= @@ -138,8 +137,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= -github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -529,7 +528,7 @@ github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhK github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb-client-go/v2 v2.2.2/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0= -github.com/influxdata/influxdb-client-go/v2 v2.5.1/go.mod h1:Y/0W1+TZir7ypoQZYd2IrnVOKB3Tq6oegAQeSVN/+EU= +github.com/influxdata/influxdb-client-go/v2 v2.6.0/go.mod h1:Y/0W1+TZir7ypoQZYd2IrnVOKB3Tq6oegAQeSVN/+EU= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= @@ -714,8 +713,8 @@ github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -761,19 +760,16 @@ 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/bbolt v1.3.6-0.20210317142109-547da822475e h1:ST9+54UtCr96S5+Wa7LQtpGS6/xK7Z+KQXvOAtYgJlA= -github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= 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.3 h1:/cPPmvSHjpCV2S99tukD7YSe4E+MXeHtedFs+0bqOHU= -github.com/openziti/edge v0.21.3/go.mod h1:s3U82m//n12qE5rb9Ja3NQY/ZhOTwRxT9kdAahEsGnU= -github.com/openziti/fabric v0.17.1/go.mod h1:6AGi2vTZckhZ5W6DfUml8ITUh+UTq1jJabwVNVglcX0= -github.com/openziti/fabric v0.17.2 h1:xjZhTx8LGBVKOboaCFbFZwmpOIpi18ODELnNH/IutfQ= -github.com/openziti/fabric v0.17.2/go.mod h1:6AGi2vTZckhZ5W6DfUml8ITUh+UTq1jJabwVNVglcX0= -github.com/openziti/foundation v0.16.7 h1:Ryuo4wp5CeXJAZYujbXfxuo6/GPpHnvJimESNTopRFY= -github.com/openziti/foundation v0.16.7/go.mod h1:DrzmWd4wka7/RlA37KTN2q+dz9dVSH6YJ9VP6xxf28w= -github.com/openziti/sdk-golang v0.15.117 h1:XFniHPcc03YLy2ZxRz2E7GhRdiWOonNiMQDA4rjvvig= -github.com/openziti/sdk-golang v0.15.117/go.mod h1:ZI3nT0vQ5UgkvK+7P9sGYWajZSMfvq1J4DZUMZYHmPA= +github.com/openziti/edge v0.21.16 h1:IRlG6A7nuwu1KcT1LxeQHOPNEp6NPxHKV7Oo5cL5UyE= +github.com/openziti/edge v0.21.16/go.mod h1:scsApPeHqL58mza7r5T5AlvLwiZfVN3icygklKIX3fw= +github.com/openziti/fabric v0.17.9 h1:s8YmUehZXI6svwNJ01D3VyLr79AT/q470PPqT5q4qBg= +github.com/openziti/fabric v0.17.9/go.mod h1:U0oa6oD4alAiJepqPhzGRt5YZgs4aL79Lso/p2ItZqg= +github.com/openziti/foundation v0.16.9 h1:iAGPDESXRArGJQYBQSOif+fXfwYRxnvBh68tiXKB1g8= +github.com/openziti/foundation v0.16.9/go.mod h1:DrzmWd4wka7/RlA37KTN2q+dz9dVSH6YJ9VP6xxf28w= +github.com/openziti/sdk-golang v0.15.122 h1:RxFNpfsXb2wkLlvNpXUoBqABVkt/i8CnhDbk98VM6ig= +github.com/openziti/sdk-golang v0.15.122/go.mod h1:FROPdwoM1EkNxcttGtgvOZIJAHhaEe5RqSKF1Zr6aa0= 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= @@ -974,6 +970,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 h1:ASw9n1EHMftwnP3Az4XW6e308+gNsrHzmdhd0Olz9Hs= +go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= diff --git a/linux-build.sh b/linux-build.sh new file mode 100755 index 000000000..05383a33d --- /dev/null +++ b/linux-build.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# build the Linux artifacts for amd64, arm, arm64 +# +# see instructions to run reproducible build with Docker in ./Dockerfile.linux-build +# +set -o pipefail -e -u + +GOX_OUTPUT="release/{{.Arch}}/{{.OS}}/{{.Dir}}" +CGO_ENABLED=true gox -os=linux -arch=amd64 -output=${GOX_OUTPUT} ./... +CC=arm-linux-gnueabihf-gcc CGO_ENABLED=true gox -cgo -os=linux -arch=arm -output=${GOX_OUTPUT} ./... +CC=aarch64-linux-gnu-gcc CGO_ENABLED=true gox -cgo -os=linux -arch=arm64 -output=$GOX_OUTPUT ./... diff --git a/quickstart/docker/docker-compose.yml b/quickstart/docker/docker-compose.yml index 157b81b50..813dfef1c 100644 --- a/quickstart/docker/docker-compose.yml +++ b/quickstart/docker/docker-compose.yml @@ -94,6 +94,21 @@ services: networks: - zitiblue + ziti-console: + image: openziti/zac + environment: + - ZAC_SERVER_CERT_CHAIN=/openziti/pki/ziti-controller-intermediate/certs/ziti-controller-server.cert + - ZAC_SERVER_KEY=/openziti/pki/ziti-controller-intermediate/keys/ziti-controller-server.key -it + ports: + - "1408:1408" + - "8443:8443" + volumes: + - ziti-fs:/openziti + + networks: + - zitiblue + - zitired + networks: zitired: zitiblue: diff --git a/quickstart/docker/image/ziti-cli-functions.sh b/quickstart/docker/image/ziti-cli-functions.sh index c7caaaea2..0ce0d8b2b 100755 --- a/quickstart/docker/image/ziti-cli-functions.sh +++ b/quickstart/docker/image/ziti-cli-functions.sh @@ -45,13 +45,13 @@ function zitiLogin { "${ZITI_BIN_DIR-}/ziti" edge login "${ZITI_EDGE_CONTROLLER_API}" -u "${ZITI_USER-}" -p "${ZITI_PWD}" -c "${ZITI_PKI_OS_SPECIFIC}/${ZITI_EDGE_CONTROLLER_ROOTCA_NAME}/certs/${ZITI_EDGE_CONTROLLER_INTERMEDIATE_NAME}.cert" } function cleanZitiController { - ziti_home="${ZITI_HOME-}" - if [[ "${ziti_home}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_HOME is not set") " + checkEnvVariable ZITI_HOME + retVal=$? + if [[ "${retVal}" != 0 ]]; then return 1 fi - rm -rf "${ziti_home}/db" - mkdir "${ziti_home}/db" + rm -rf "${ZITI_HOME}/db" + mkdir "${ZITI_HOME}/db" initializeController } function initializeController { @@ -65,18 +65,26 @@ function startZitiController { echo -e "ziti-controller started as process id: $pid. log located at: $(BLUE "${ZITI_HOME-}/ziti-edge-controller.log")" return $pid } + function stopZitiController { killall ziti-controller + # shellcheck disable=SC2181 + if [[ $? == 0 ]]; then echo "Controller stopped."; fi } + function startExpressEdgeRouter { "${ZITI_BIN_DIR}/ziti-router" run "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.yaml" > "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.log" 2>&1 & pid=$! echo -e "Express Edge Router started as process id: $pid. log located at: $(BLUE "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.log")" return $pid } + function stopAllEdgeRouters { - killall ziti-router + killall ziti-controller + # shellcheck disable=SC2181 + if [[ $? == 0 ]]; then echo "Router(s) stopped."; fi } + function checkHostsFile { ctrlexists=$(grep -c "${ZITI_CONTROLLER_HOSTNAME}" /etc/hosts) edgectrlexists=$(grep -c "${ZITI_EDGE_CONTROLLER_HOSTNAME}" /etc/hosts) @@ -111,6 +119,8 @@ function checkHostsFile { echo " " echo "add these entries to your hosts file, and rerun the script when ready" return 1 + else + echo -e "$(GREEN "Hosts file looks good")" fi } @@ -140,8 +150,9 @@ function getLatestZitiVersion { function getLatestZiti { setupZitiHome - if [[ "${ZITI_HOME-}" == "" ]]; then - echo "ERROR: ZITI_HOME is not set!" + checkEnvVariable ZITI_HOME + retVal=$? + if [[ "${retVal}" != 0 ]]; then return 1 fi @@ -157,12 +168,7 @@ function getLatestZiti { return 1 fi - ziti_bin_ver="${ZITI_BINARIES_VERSION-}" - if [[ "${ziti_bin_ver}" == "" ]]; then - echo "ERROR: ZITI_BINARIES_VERSION is not set!" - return 1 - fi - export ZITI_BIN_DIR="${ziti_bin_root}/ziti-${ziti_bin_ver}" + export ZITI_BIN_DIR="${ziti_bin_root}/ziti-${ZITI_BINARIES_VERSION}" ZITI_BINARIES_FILE_ABSPATH="${ZITI_HOME-}/ziti-bin/${ZITI_BINARIES_FILE}" if ! test -f "${ZITI_BINARIES_FILE_ABSPATH}"; then @@ -220,10 +226,9 @@ function checkPrereqs { echo " " echo " " return 1 + else + echo -e "$(GREEN "Prerequisites confirmed")" fi - echo "Let's get stated creating your local development network!" - echo "" - echo "" } function checkControllerName { @@ -235,7 +240,12 @@ function checkControllerName { } function unsetZitiEnv { - for zEnvVar in $(set | grep -e "^ZITI_" | sort); do envvar="$(echo "${zEnvVar}" | cut -d '=' -f1)"; echo unsetting "[${envvar}]${zEnvVar}"; unset "${envvar}"; done + if [[ "${1-}" == "-s" ]]; then + # Silent... + for zEnvVar in $(set | grep -e "^ZITI_" | sort); do envvar="$(echo "${zEnvVar}" | cut -d '=' -f1)"; unset "${envvar}"; done + else + for zEnvVar in $(set | grep -e "^ZITI_" | sort); do envvar="$(echo "${zEnvVar}" | cut -d '=' -f1)"; echo unsetting "[${envvar}]${zEnvVar}"; unset "${envvar}"; done + fi unset ZITIx_EXPRESS_COMPLETE } @@ -267,7 +277,8 @@ function setupZitiNetwork { echo -n "what a hostname looks like. A good choice is to actually use your system's hostname: " echo -e "$(BLUE "$(hostname)")" echo " " - read -rp "$(echo -ne "Network Name [$(BLUE "$(hostname)")]: ")" ZITI_NETWORK + echo -en "$(echo -ne "Network Name [$(BLUE "$(hostname)")]: ")" + read -r ZITI_NETWORK echo " " if checkControllerName; then : #clear to continue @@ -276,8 +287,8 @@ function setupZitiNetwork { fi echo "name: ${ZITI_NETWORK-}" else - echo " " - echo "nah bro" + echo "" + echo "============ FAILED TO SETUP NETWORK ============" return 1 fi echo " " @@ -289,7 +300,7 @@ function setupZitiNetwork { function setupZitiHome { if [[ "${ZITI_HOME-}" == "" ]]; then export ZITI_HOME="${HOME}/.ziti/quickstart/${ZITI_NETWORK-}" - echo "using default ZITI_HOME: ${ZITI_HOME}" + echo -e "using default ZITI_HOME: $(BLUE "${ZITI_HOME}")" fi } @@ -317,14 +328,22 @@ function generateEnvFile { export ENV_FILE="${ZITI_HOME-}/${ZITI_NETWORK-}.env" - echo -e "environment file created and sourced from: $(BLUE "${ENV_FILE}")" + echo -e "environment file sourced from: $(BLUE "${ENV_FILE}")" } function ziti_expressConfiguration { if [[ "${ZITIx_EXPRESS_COMPLETE-}" != "" ]]; then echo -e "$(RED " --- It looks like you've run an express install in this shell already. ---")" - echo -e "$(RED " --- Please execute unsetZitiEnv to clear any variables already set. ---")" - return 1 + echo -en "Would you like to clear existing Ziti variables and continue (y/N)? " + read -r + echo " " + if [[ "${REPLY}" == [Yy]* ]]; then + echo -e "$(GREEN "Clearing existing Ziti variables and continuing with express install")" + unsetZitiEnv "-s" + else + echo -e "$(RED " --- Exiting express install ---")" + return 1 + fi fi export ZITIx_EXPRESS_COMPLETE="true" echo " " @@ -347,6 +366,9 @@ function ziti_expressConfiguration { if [[ "${ZITI_EDGE_ROUTER_HOSTNAME-}" != "" ]]; then echo "ZITI_EDGE_ROUTER_HOSTNAME OVERIDDEN: $ZITI_EDGE_ROUTER_HOSTNAME"; fi if [[ "${ZITI_EDGE_ROUTER_PORT-}" != "" ]]; then echo "ZITI_EDGE_ROUTER_PORT OVERIDDEN: $ZITI_EDGE_ROUTER_PORT"; fi + echo " " + echo " " + echo -e "******** Setting Up Environment ********" if [[ "${1-}" == "" ]]; then nw="$(hostname)" else @@ -355,7 +377,7 @@ function ziti_expressConfiguration { setupZitiNetwork "${nw}" setupZitiHome - echo "ZITI HOME SET TO: ${ZITI_HOME}" + echo "ZITI HOME SET TO: $(BLUE "${ZITI_HOME}")" if ! getLatestZiti "no"; then echo -e "$(RED "getLatestZiti failed")" @@ -367,9 +389,16 @@ function ziti_expressConfiguration { fi #checkHostsFile + echo " " + echo " " + echo -e "******** Setting Up Public Key Infrastructure ********" createPki - createControllerConfig - #createControllerSystemdFile + + echo " " + echo " " + echo -e "******** Setting Up Controller ********" + createControllerConfig "controller" + #createControllerSystemdFile controller initializeController startZitiController echo "waiting for the controller to come online to allow the edge router to enroll" @@ -377,6 +406,9 @@ function ziti_expressConfiguration { zitiLogin + echo " " + echo " " + echo -e "******** Setting Up Edge Routers ********" echo -e "---------- Creating an edge router policy allowing all identities to connect to routers with a $(GREEN "#public") attribute" "${ZITI_BIN_DIR-}/ziti" edge delete edge-router-policy allEdgeRouters > /dev/null "${ZITI_BIN_DIR-}/ziti" edge create edge-router-policy allEdgeRouters --edge-router-roles '#public' --identity-roles '#all' > /dev/null @@ -393,12 +425,12 @@ function ziti_expressConfiguration { "${ZITI_BIN_DIR-}/ziti" edge delete edge-router "${ZITI_EDGE_ROUTER_RAWNAME}" > /dev/null "${ZITI_BIN_DIR-}/ziti" edge create edge-router "${ZITI_EDGE_ROUTER_RAWNAME}" -o "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.jwt" -t -a "public"> /dev/null sleep 1 - echo "---------- Enrolling edge-router ${ZITI_EDGE_ROUTER_RAWNAME}...." + echo "---------- Enrolling edge-router ${ZITI_EDGE_ROUTER_RAWNAME}...." "${ZITI_BIN_DIR-}/ziti-router" enroll "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.yaml" --jwt "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.jwt" &> "${ZITI_HOME_OS_SPECIFIC}/${ZITI_EDGE_ROUTER_RAWNAME}.enrollment.log" echo "" - killall ziti-controller + stopZitiController echo "Edge Router enrolled. Controller stopped." echo "" @@ -414,9 +446,11 @@ function decideToUseDefaultZitiHome { do echo "ZITI_HOME has not been set. Do you want to use the default ZITI_HOME: ${DEFAULT_ZITI_HOME_LOCATION}" echo " " - read -rp "Select an action: " yn + echo -en "Select an action: " + read -r yn case $yn in [yY]* ) + ZITI_HOME="${DEFAULT_ZITI_HOME_LOCATION}" break;; [Nn]* ) echo "" @@ -441,7 +475,8 @@ function decideOperation { echo " 3.) Create Edge Router configuration - answer a few questions and an edge router config will be emitted" echo " 4.) Start a network with the provided name" echo " " - read -rp "Select an action: " yn + echo -en "Select an action: " + read -r yn fi case $yn in [1]* ) @@ -479,6 +514,10 @@ function expressInstall { #make sure the user has all the necessary commands to be successful checkPrereqs + echo "Let's get started creating your local development network!" + echo "" + echo "" + #prompt the user for input and do what they want/need decideOperation 1 "${1-}" } @@ -539,13 +578,11 @@ function pki_create_intermediate { fi echo " " } -function printUsage() -{ +function printUsage() { echo "Usage: ${1-} [cert to test] [ca pool to use]" } -function verifyCertAgainstPool() -{ +function verifyCertAgainstPool() { if [[ "" == "${1-}" ]] then printUsage "verifyCertAgainstPool" @@ -574,8 +611,7 @@ function verifyCertAgainstPool() fi } -function showIssuerAndSubjectForPEM() -{ +function showIssuerAndSubjectForPEM() { echo "Displaying Issuer and Subject for cert pool:" echo " ${1-}" openssl crl2pkcs7 -nocrl -certfile "${1-}" | openssl pkcs7 -print_certs -text -noout | grep -E "(Subject|Issuer)" @@ -586,18 +622,41 @@ function createRouterPki { } function createPrivateRouterConfig { + # Allow router name to be passed in as arg router_name="${1-}" if [[ "${router_name}" == "" ]]; then - echo -e " * ERROR: $(RED "createPrivateRouterConfig requires a parameter to be supplied") " + + # If router name is not passed as arg, prompt user for input + echo -e "$(YELLOW "createPrivateRouterConfig requires a router name to be supplied") " + default_router_name="${ZITI_EDGE_ROUTER_RAWNAME}" + echo -en "Enter router name (${default_router_name}):" + read -r router_name + + # Accept the default if no name provided + if [[ "${router_name}" == "" ]]; then + # Check for overwrite of default file + router_name="${default_router_name}" + if [[ -f "${ZITI_HOME-}/${router_name}.yaml" ]]; then + echo -en "This will overwrite the existing file, continue (y/N)? " + read -r + echo " ${REPLY}" + if [[ "${REPLY}" == [^Yy]* ]]; then + echo -e "$(RED " --- Cancelling overwrite ---")" + return 1 + fi + fi + fi + fi + + # Make sure necessary env variables are set + checkEnvVariable ZITI_HOME ZITI_BIN_DIR + retVal=$? + if [[ "${retVal}" != 0 ]]; then return 1 fi - ziti_home="${ZITI_HOME-}" - if [[ "${ziti_home}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_HOME is not set") " - return 1 - fi -cat > "${ZITI_HOME-}/${ZITI_EDGE_ROUTER_RAWNAME}.yaml" < "${output_file}" < "${ZITI_HOME}/${ZITI_EDGE_ROUTER_RAWNAME}.yaml" < "${output_file}" < "${ZITI_HOME-}/${router_name}.yaml" < "${output_file}" < "${ziti_home}/${router_name}.yaml" < "${output_file}" < "${ZITI_HOME}/identities.yml" < "${output_file}" < "${ziti_home}/controller.yaml" < "${ZITI_PKI_OS_SPECIFIC}/cas.pem" +cat "${ZITI_PKI_OS_SPECIFIC}/${ZITI_SIGNING_INTERMEDIATE_NAME}/certs/${ZITI_SIGNING_INTERMEDIATE_NAME}.cert" >> "${ZITI_PKI_OS_SPECIFIC}/cas.pem" +echo "wrote CA file to: $(BLUE "${ZITI_PKI_OS_SPECIFIC}/cas.pem")" + +output_file="${ZITI_HOME}/${controller_name}.yaml" +cat > "${output_file}" < "${systemd_file}" < "${output_file}" < "${systemd_file}" < "${output_file}" < "${launchd_file}" < "${output_file}" < Label - ziti-controller-${ZITI_BINARIES_VERSION} + ziti-controller-${controller_name} ProgramArguments - ./ziti-controller - + $ZITI_BIN_DIR/ziti-controller run - ./ctrl.with.edge.yml - - WorkingDirectory - ${ZITI_HOME} - KeepAlive - - SuccessfulExit - - - StandardOutPath - /Users/scarey/Library/Logs/ziti-controller-0.22.9.log - StandardErrorPath - /Users/scarey/Library/Logs/ziti-controller-0.22.9.log - - -HeredocForLaunchd - echo "Router launchd file written to: ${launchd_file}" -} -function createRouterLaunchdFile { - router_name="${1-}" - if [[ "${router_name}" == "" ]]; then - echo -e " * ERROR: $(RED "createRouterLaunchdFile requires parameter [router_name] to be supplied") " - return 1 - fi - - ziti_home="${ZITI_HOME-}" - if [[ "${ziti_home}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_HOME is not set") " - return 1 - fi - - ziti_bin_dir="${ZITI_BIN_DIR-}" - if [[ "${ziti_bin_dir}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_BIN_DIR is not set") " - return 1 - fi -launchd_file="${ziti_home}/ziti-router-${router_name}.launchd" -cat > "${launchd_file}" < - - - - Label - ziti-controller-0.22.9 - ProgramArguments - - ./ziti-controller - - run - ./ctrl.with.edge.yml + $ZITI_HOME/${controller_name}.yaml WorkingDirectory ${ZITI_HOME} @@ -1397,38 +1552,109 @@ cat > "${launchd_file}" < StandardOutPath - /Users/scarey/Library/Logs/ziti-controller-0.22.9.log + ${ZITI_HOME}/Logs/ziti-router-$ZITI_BINARIES_VERSION.log StandardErrorPath - /Users/scarey/Library/Logs/ziti-controller-0.22.9.log + ${ZITI_HOME}/Logs/ziti-router-$ZITI_BINARIES_VERSION.log HeredocForLaunchd - echo "Router launchd file written to: ${launchd_file}" + echo -e "Controller launchd file written to: $(BLUE "${output_file}")" + + showLaunchdMessage } +function createRouterLaunchdFile { + # Allow router name to be passed in as arg + router_name="${1-}" + if [[ "${router_name}" == "" ]]; then + + # If router name is not passed as arg, prompt user for input + echo -e "$(YELLOW "createRouterLaunchdFile requires a router name to be supplied") " + default_router_name="${ZITI_EDGE_ROUTER_RAWNAME}" + echo -en "Enter router name (${default_router_name}):" + read -r router_name + + # Accept the default if no name provided + if [[ "${router_name}" == "" ]]; then + # Check for overwrite of default file + router_name="${default_router_name}" + getFileOverwritePermission "${ZITI_HOME-}/ziti-router-${router_name}.plist" + retVal=$? + if [[ "${retVal}" != 0 ]]; then + return 1 + fi + fi + fi + + # Make sure necessary env variables are set + checkEnvVariable ZITI_HOME ZITI_BIN_DIR + retVal=$? + if [[ "${retVal}" != 0 ]]; then + return 1 + fi + +output_file="${ZITI_HOME-}/ziti-router-${router_name}.plist" +cat > "${output_file}" < + + + + Label + ziti-router-$router_name + ProgramArguments + + $ZITI_BIN_DIR/ziti-router + run + $ZITI_HOME/ctrl.with.edge.yml + + WorkingDirectory + ${ZITI_HOME} + KeepAlive + + + PathState + + ${ZITI_HOME}/launchd-enabled + + + + StandardOutPath + ${ZITI_HOME}/Logs/ziti-router-$ZITI_BINARIES_VERSION.log + StandardErrorPath + ${ZITI_HOME}/Logs/ziti-router-$ZITI_BINARIES_VERSION.log + + +HeredocForLaunchd + echo -e "Router launchd file written to: $(BLUE "${output_file}")" + + showLaunchdMessage +} + +function showLaunchdMessage { + echo -e " " + echo -e "$(YELLOW "The generated launchd file is designed to keep the service alive while the file")" + echo -e "$(BLUE "${ZITI_HOME}/launchd-enabled") $(YELLOW "remains present.")" + echo -e "$(YELLOW "If this file is not present, the service will end.")" +} function createZacSystemdFile { - ziti_home="${ZITI_HOME-}" - if [[ "${ziti_home}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_HOME is not set") " + + checkEnvVariable ZITI_HOME + retVal=$? + if [[ "${retVal}" != 0 ]]; then return 1 fi - ziti_bin_dir="${ZITI_BIN_DIR-}" - if [[ "${ziti_bin_dir}" == "" ]]; then - echo -e " * ERROR: $(RED "ZITI_BIN_DIR is not set") " - return 1 - fi -systemd_file="${ziti_home}/ziti-console.service" -cat > "${systemd_file}" < "${output_file}" < 0 { - input = input[idx:] - } - entry, err := gabs.ParseJSON([]byte(input)) - if err != nil { - return err - } - self.entry = entry - return nil -} - -func ScanJsonLines(ctx *JsonParseContext, callback func(ctx *JsonParseContext) error) error { - return ScanLines(&ctx.ParseContext, func(*ParseContext) error { - if ctx.eof { - return callback(ctx) - } - if err := ctx.ParseJsonEntry(); err != nil { - return err - } - if ctx.entry != nil { - return callback(ctx) - } - return nil - }) -} - -type LogMatcher interface { - Matches(ctx *JsonParseContext) (bool, error) -} - -type LogFilter interface { - LogMatcher - Id() string - Label() string - Desc() string -} - -type filter struct { - LogMatcher - id string - label string - desc string -} - -func (self *filter) Id() string { - return self.id -} - -func (self *filter) Label() string { - return self.label -} - -func (self *filter) Desc() string { - return self.desc -} - -type JsonLogsParser struct { - bucketSize time.Duration - currentBucket time.Time - filters []LogFilter - bucketMatches map[LogFilter]int - unmatched int - maxUnmatchedLoggedPerBucket int - ignore []string -} - -func (self *JsonLogsParser) validate() error { - ids := map[string]int{} - for idx, k := range self.filters { - if v, found := ids[k.Id()]; found { - return errors.Errorf("duplicate filter id %v at indices %v and %v", k.Id(), idx, v) - } - ids[k.Id()] = idx - } - return nil -} - -func (self *JsonLogsParser) ShowCategories(*cobra.Command, []string) { - for _, filter := range self.filters { - fmt.Printf("%v (%v): %v\n", filter.Id(), filter.Label(), filter.Desc()) - } -} - -func (self *JsonLogsParser) examineLogEntry(ctx *JsonParseContext) error { - if ctx.eof { - self.dumpBucket() - return nil - } - if err := self.bucket(ctx); err != nil { - return err - } - - for _, filter := range self.filters { - match, err := filter.Matches(ctx) - if err != nil { - return err - } - - if match { - current := self.bucketMatches[filter] - self.bucketMatches[filter] = current + 1 - return nil - } - } - - self.unmatched++ - if self.unmatched <= self.maxUnmatchedLoggedPerBucket { - fmt.Printf("WARN: unmatched line: %v\n\n", ctx.line) - } - - return nil -} - -func (self *JsonLogsParser) bucket(ctx *JsonParseContext) error { - s, err := ctx.RequiredString("time") - if err != nil { - return err - } - t, err := time.Parse(time.RFC3339, s) - if err != nil { - return errors.Errorf("time is in an unexpected format: %v", s) - } - interval := t.Truncate(self.bucketSize) - if interval != self.currentBucket { - if !self.currentBucket.IsZero() { - self.dumpBucket() - } - self.currentBucket = interval - self.bucketMatches = map[LogFilter]int{} - self.unmatched = 0 - } - return nil -} - -func (self *JsonLogsParser) dumpBucket() { - var filters []LogFilter - for k := range self.bucketMatches { - if !stringz.Contains(self.ignore, k.Id()) { - filters = append(filters, k) - } - } - sort.Slice(filters, func(i, j int) bool { - return filters[i].Label() < filters[j].Label() - }) - if len(filters) == 0 && self.unmatched == 0 { - return - } - fmt.Printf("%v\n---------------------------------------------------\n", self.currentBucket.Format(time.RFC3339)) - for _, filter := range filters { - fmt.Printf(" %v (%v): %0000v\n", filter.Id(), filter.Label(), self.bucketMatches[filter]) - } - if self.unmatched > 0 { - fmt.Printf(" unmatched: %0000v\n", self.unmatched) - } - fmt.Println() -} - -func FieldStartsWith(field, substring string) LogMatcher { - return &EntryFieldStartsWithMatcher{ - field: field, - prefix: substring, - } -} - -type EntryFieldStartsWithMatcher struct { - field string - prefix string -} - -func (self *EntryFieldStartsWithMatcher) Matches(ctx *JsonParseContext) (bool, error) { - fieldValue, err := ctx.RequiredString(self.field) - if err != nil { - return false, err - } - return strings.HasPrefix(fieldValue, self.prefix), nil -} - -func FieldContains(field, substring string) LogMatcher { - return &EntryFieldContainsMatcher{ - field: field, - substring: substring, - } -} - -type EntryFieldContainsMatcher struct { - field string - substring string -} - -func (self *EntryFieldContainsMatcher) Matches(ctx *JsonParseContext) (bool, error) { - fieldValue, err := ctx.RequiredString(self.field) - if err != nil { - return false, err - } - return strings.Contains(fieldValue, self.substring), nil -} - -func FieldEquals(field, substring string) LogMatcher { - return &EntryFieldContainsMatcher{ - field: field, - substring: substring, - } -} - -type EntryFieldEqualsMatcher struct { - field string - value string -} - -func (self *EntryFieldEqualsMatcher) Matches(ctx *JsonParseContext) (bool, error) { - fieldValue, err := ctx.RequiredString(self.field) - if err != nil { - return false, err - } - return fieldValue == self.value, nil -} - -func AndMatchers(matchers ...LogMatcher) LogMatcher { - return &AndMatcher{matchers: matchers} -} - -type AndMatcher struct { - matchers []LogMatcher -} - -func (self *AndMatcher) Matches(ctx *JsonParseContext) (bool, error) { - for _, matcher := range self.matchers { - result, err := matcher.Matches(ctx) - if !result || err != nil { - return result, err - } - } - return true, nil -} - -func FieldMatches(field, expr string) LogMatcher { - regex, err := regexp.Compile(expr) - if err != nil { - panic(err) - } - return &EntryFieldMatchesMatcher{ - field: field, - regex: regex, - } -} - -type EntryFieldMatchesMatcher struct { - field string - regex *regexp.Regexp -} - -func (self *EntryFieldMatchesMatcher) Matches(ctx *JsonParseContext) (bool, error) { - fieldValue, err := ctx.RequiredString(self.field) - if err != nil { - return false, err - } - return self.regex.MatchString(fieldValue), nil -} diff --git a/ziti-ops/logs/router_logs.go b/ziti-ops/logs/router_logs.go deleted file mode 100644 index fceb62aea..000000000 --- a/ziti-ops/logs/router_logs.go +++ /dev/null @@ -1,316 +0,0 @@ -package logs - -import ( - "github.com/spf13/cobra" - "time" -) - -func NewLogsCommand() *cobra.Command { - logsCmd := &cobra.Command{ - Use: "logs", - Short: "commands related to analyzing various ziti component logs", - } - - parseRouterLogs := &ParseRouterLogs{} - parseRouterLogs.Init() - - parseRouterLogsCmd := &cobra.Command{ - Use: "router", - Short: "Parse router logs", - Args: cobra.ExactArgs(1), - RunE: parseRouterLogs.run, - } - - parseRouterLogsCmd.Flags().DurationVarP(&parseRouterLogs.bucketSize, "interval", "n", time.Hour, "Interval for which to aggregate log messages") - parseRouterLogsCmd.Flags().IntVarP(&parseRouterLogs.maxUnmatchedLoggedPerBucket, "max-unmatched", "u", 1, "Maximum unmatched log messages to output per bucket") - parseRouterLogsCmd.Flags().StringSliceVar(&parseRouterLogs.ignore, "ignore", []string{"IDLE", "CONF"}, "Filters to ignore") - - showRouterLogCategoriesCmd := &cobra.Command{ - Use: "categories", - Short: "Show router log entry categories", - Run: parseRouterLogs.ShowCategories, - } - - parseRouterLogsCmd.AddCommand(showRouterLogCategoriesCmd) - - logsCmd.AddCommand(parseRouterLogsCmd) - - return logsCmd -} - -type ParseRouterLogs struct { - JsonLogsParser -} - -func (self *ParseRouterLogs) Init() { - self.filters = getRouterLogFilters() -} - -func getRouterLogFilters() []LogFilter { - return []LogFilter{ - &filter{ - id: "IDLE", - label: "idle circuit scanner", - desc: "a circuit has been idle for at least one minute and the controller will be checked to see if the circuit is still valid", - LogMatcher: AndMatchers( - FieldContains("file", "forwarder/scanner.go"), - FieldContains("msg", " idle after "), - )}, - &filter{ - id: "CONF", - label: "circuit confirmation send", - desc: "controller has been notified of idle circuits and can respond if they are no longer valid", - LogMatcher: AndMatchers( - FieldContains("msg", "sent confirmation for "), - FieldContains("file", "forwarder/scanner.go"), - )}, - &filter{ - id: "TSCX", - label: "tunnel dial success", - desc: "a router embedded tunneler has made a successful connection to a server hosting an application", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "successful connection "), - FieldContains("file", "xgress_edge_tunnel/dialer.go"), - )}, - &filter{ - id: "DSTX", - label: "routing destination exists", - desc: "attempting to establish a circuit, but a previous dial attempt already established the egress connection", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "destination exists for "), - FieldContains("file", "handler_ctrl/route.go"), - )}, - &filter{ - id: "XGRF", - label: "xgress read failure", - desc: "read failure on the client or server side of the circuit; will cause the circuit to be torn down", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "read failed"), - FieldContains("file", "xgress/xgress.go"), - )}, - &filter{ - id: "XGWF", - label: "xgress write failure", - desc: "write failure on the client or server side of the circuit; will cause the circuit to be torn down", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "write failed"), - FieldContains("file", "xgress/xgress.go"), - )}, - &filter{ - id: "XGBF", - label: "xgress can't buffer", - desc: "while a circuit was being closed, data was received from the client or server", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "failure to buffer payload"), - FieldEquals("error", "payload buffer closed"), - FieldContains("file", "xgress/xgress.go"), - )}, - &filter{ - id: "RCFM", - label: "can't forward", - desc: "router can't forward a message most likely because the circuit is in the middle of being torn down", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "unable to forward"), - FieldContains("file", "handler_xgress/receive.go"), - )}, - &filter{ - id: "CSTO", - label: "circuit not started in time", - desc: "the terminating side of the circuit didn't receive a start from the initiating side", - LogMatcher: AndMatchers( - FieldEquals("msg", "xgress circuit not started in time, closing"), - FieldContains("file", "xgress/xgress.go"), - )}, - &filter{ - id: "TLSC", - label: "no tls certification provided", - desc: "a connection attempt was made to a TLS listener but no certificate was provided", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "error receiving hello from "), - FieldContains("msg", "tls: client didn't provide a certificate"), - FieldContains("file", "channel2/classic_listener.go"), - )}, - &filter{ - id: "LCYT", - label: "latency timeout", - desc: "a latency ping was sent, but no response was received within the timeout", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "latency timeout after "), - FieldContains("file", "metrics/latency.go"), - )}, - &filter{ - id: "CHRX", - label: "channel rx error", - desc: "channel read failed", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "rx error"), - FieldContains("msg", "connection reset by peer"), - FieldContains("file", "channel2/impl.go"), - )}, - &filter{ - id: "LNKS", - label: "dialing split channel link", - desc: "a link is being dialed to another router with separate connections for data and acknowledgements", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "dialing link with split payload/ack channels"), - FieldContains("file", "xlink_transport/dialer.go"), - )}, - &filter{ - id: "LNKR", - label: "controller requesting dial", - desc: "received a request from the controller to dial another router", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "received link connect request"), - FieldContains("file", "handler_ctrl/dial.go"), - )}, - &filter{ - id: "LNKD", - label: "dialing link", - desc: "dialing another router to establish a link", - LogMatcher: AndMatchers( - FieldEquals("msg", "dialing link"), - FieldContains("file", "handler_ctrl/dial.go"), - )}, - &filter{ - id: "LNKE", - label: "link established", - desc: "a link to another router has been established", - LogMatcher: AndMatchers( - FieldEquals("msg", "link established"), - FieldContains("file", "handler_ctrl/dial.go"), - )}, - &filter{ - id: "LNKP", - label: "dialing link payload channel", - desc: "dialing the link payload channel of a link", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "dialing payload channel for"), - FieldContains("file", "xlink_transport/dialer.go"), - )}, - &filter{ - id: "LNKK", - label: "dialing link ack channel", - desc: "dialing the link ack channel of a link", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "dialing ack channel for"), - FieldContains("file", "xlink_transport/dialer.go"), - )}, - &filter{ - id: "LNKC", - label: "link closed", - desc: "a router to router link was closed", - LogMatcher: AndMatchers( - FieldEquals("msg", "link closed"), - FieldContains("file", "handler_link/close.go"), - )}, - &filter{ - id: "FLTS", - label: "link fault sent", - desc: "the router notified the controller that a link failed", - LogMatcher: AndMatchers( - FieldEquals("msg", "transmitted link fault"), - FieldContains("file", "handler_link/close.go"), - )}, - &filter{ - id: "LNKA", - label: "link accepted", - desc: "another router has dialed this router and a link has been established", - LogMatcher: AndMatchers( - FieldStartsWith("msg", "accepted new link"), - FieldContains("file", "router/accepter.go"), - )}, - &filter{ - id: "RCNB", - label: "starting reconnect", - desc: "the router to controller control channel connection died and the router trying to reconnect", - LogMatcher: AndMatchers( - FieldContains("msg", "starting reconnection process"), - FieldContains("file", "channel2/reconnecting_impl.go"), - )}, - &filter{ - id: "RCNF", - label: "reconnect failed", - desc: "the router attempted to reconnect the control channel and failed", - LogMatcher: AndMatchers( - FieldContains("file", "channel2/reconnecting_dialer.go"), - FieldMatches("msg", "reconnection attempt.*failed"), - )}, - &filter{ - id: "RCNS", - label: "reconnect succeeded", - desc: "the router attempted to reconnect the control channel and succeeded", - LogMatcher: AndMatchers( - FieldEquals("msg", "reconnected"), - FieldContains("file", "channel2/reconnecting_impl.go"), - )}, - &filter{ - id: "RCNP", - label: "reconnect ping", - desc: "the router is checking the control channel to see if it needs to be reconnected", - LogMatcher: AndMatchers( - FieldContains("file", "channel2/reconnecting_impl.go"), - FieldContains("func", "pingInstance"), - )}, - &filter{ - id: "RCPF", - label: "reconnect ping failed", - desc: "the router control channel ping failed", - LogMatcher: AndMatchers( - FieldContains("msg", "unable to ping"), - FieldContains("file", "channel2/reconnecting_dialer.go"), - )}, - &filter{ - id: "HELO", - label: "received ctrl hello", - desc: "the controller sent us a hello message after a control channel was established or reconnected", - LogMatcher: AndMatchers( - FieldContains("msg", "received server hello"), - FieldContains("file", "handler_edge_ctrl/hello.go"), - )}, - &filter{ - id: "SSST", - label: "api session sync started", - desc: "The controller has started a full api session sync", - LogMatcher: AndMatchers( - FieldContains("file", "handler_edge_ctrl/apiSessionAdded.go"), - FieldMatches("msg", "api session.*starting"), - )}, - &filter{ - id: "SSCH", - label: "api session data received", - desc: "The controller sent a chunk of api session data", - LogMatcher: AndMatchers( - FieldContains("file", "handler_edge_ctrl/apiSessionAdded.go"), - FieldStartsWith("msg", "received api session sync chunk"), - )}, - &filter{ - id: "SSDN", - label: "api session sync finished", - desc: "The controller has finished a full api session sync", - LogMatcher: AndMatchers( - FieldContains("file", "handler_edge_ctrl/apiSessionAdded.go"), - FieldStartsWith("msg", "finished sychronizing api sessions"), - )}, - &filter{ - id: "CHAC", - label: "accepted connection", - desc: "a tcp connection has been accepted", - LogMatcher: AndMatchers( - FieldEquals("msg", "accepted connection"), - FieldContains("file", "transport/tcp/listener.go"), - )}, - } -} - -func (self *ParseRouterLogs) run(cmd *cobra.Command, args []string) error { - if err := self.validate(); err != nil { - return err - } - - ctx := &JsonParseContext{ - ParseContext: ParseContext{ - path: args[0], - }, - } - return ScanJsonLines(ctx, self.examineLogEntry) -} diff --git a/ziti-ops/main.go b/ziti-ops/main.go deleted file mode 100644 index 761043245..000000000 --- a/ziti-ops/main.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build all - -/* - 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 main - -import ( - "fmt" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/fabric/build" - "github.com/openziti/ziti/common/version" - "github.com/openziti/ziti/ziti-ops/logs" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var verbose bool -var logFormatter string - -func init() { - options := pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").NoColor() - pfxlog.GlobalInit(logrus.InfoLevel, options) - build.InitBuildInfo(version.GetCmdBuildInfo()) - - root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging") - root.PersistentFlags().StringVar(&logFormatter, "log-formatter", "", "Specify log formatter [json|pfxlog|text]") - - root.AddCommand(&cobra.Command{ - Use: "version", - Short: "Show component version", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(version.GetBuildMetadata(verbose)) - }, - }) - - root.AddCommand(logs.NewLogsCommand()) -} - -var root = &cobra.Command{ - Use: "ziti-ops", - Short: "Ziti Ops Tools", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - if verbose { - logrus.SetLevel(logrus.DebugLevel) - } - - switch logFormatter { - case "pfxlog": - pfxlog.SetFormatter(pfxlog.NewFormatter(pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").StartingToday())) - case "json": - pfxlog.SetFormatter(&logrus.JSONFormatter{TimestampFormat: "2006-01-02T15:04:05.000Z"}) - case "text": - pfxlog.SetFormatter(&logrus.TextFormatter{}) - default: - // let logrus do its own thing - } - }, -} - -func main() { - if err := root.Execute(); err != nil { - fmt.Printf("error: %s\n", err) - } -} diff --git a/ziti/cmd/ziti/cmd/fabric/inspect.go b/ziti/cmd/ziti/cmd/fabric/inspect.go new file mode 100644 index 000000000..677ebd840 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/inspect.go @@ -0,0 +1,69 @@ +package fabric + +import ( + "context" + "fmt" + "github.com/openziti/fabric/rest_client/inspect" + "github.com/openziti/fabric/rest_model" + "github.com/openziti/foundation/util/stringz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" +) + +// newListCmd creates a command object for the "controller list" command +func newInspectCmd(p common.OptionsProvider) *cobra.Command { + listCmd := &ListCmd{Options: api.Options{CommonOptions: p()}} + return listCmd.newCobraCmd() +} + +type ListCmd struct { + api.Options +} + +func (self *ListCmd) newCobraCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "inspect", + Short: "Inspect runtime application values", + RunE: self.run, + Args: cobra.MinimumNArgs(2), + } + self.AddCommonFlags(cmd) + return cmd +} + +func (self *ListCmd) run(cmd *cobra.Command, args []string) error { + client, err := util.NewFabricManagementClient(self) + if err != nil { + return err + } + + inspectOk, err := client.Inspect.Inspect(&inspect.InspectParams{ + Request: &rest_model.InspectRequest{ + AppRegex: &args[0], + RequestedValues: args[1:], + }, + Context: context.Background(), + }) + + if err != nil { + return err + } + + result := inspectOk.Payload + if *result.Success { + fmt.Printf("\nResults: (%d)\n", len(result.Values)) + for _, value := range result.Values { + fmt.Printf("%v.%v\n", stringz.OrEmpty(value.AppID), stringz.OrEmpty(value.Name)) + fmt.Printf("%v\n\n", stringz.OrEmpty(value.Value)) + } + } else { + fmt.Printf("\nEncountered errors: (%d)\n", len(result.Errors)) + for _, err := range result.Errors { + fmt.Printf("\t%v\n", err) + } + } + + return nil +} diff --git a/ziti/cmd/ziti/cmd/fabric/root.go b/ziti/cmd/ziti/cmd/fabric/root.go index e48a30ddc..1061f9ebd 100644 --- a/ziti/cmd/ziti/cmd/fabric/root.go +++ b/ziti/cmd/ziti/cmd/fabric/root.go @@ -32,7 +32,7 @@ func NewFabricCmd(p common.OptionsProvider) *cobra.Command { fabricCmd.AddCommand(newAddIdentityCmd(p), newRemoveIdentityCmd(p)) fabricCmd.AddCommand(newCreateCommand(p), newListCmd(p), newUpdateCommand(p), newDeleteCmd(p)) - + fabricCmd.AddCommand(newInspectCmd(p)) return fabricCmd } diff --git a/ziti/cmd/ziti/util/identities.go b/ziti/cmd/ziti/util/identities.go index 44c1a5043..6eba87d3a 100644 --- a/ziti/cmd/ziti/util/identities.go +++ b/ziti/cmd/ziti/util/identities.go @@ -7,6 +7,7 @@ import ( "fmt" httptransport "github.com/go-openapi/runtime/client" "github.com/openziti/edge/rest_management_api_client" + fabric_rest_client "github.com/openziti/fabric/rest_client" "github.com/openziti/foundation/common/constants" "github.com/openziti/foundation/identity/identity" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" @@ -46,11 +47,13 @@ func (self *RestClientConfig) GetIdentity() string { } type RestClientIdentity interface { + NewTlsClientConfig() (*tls.Config, error) NewClient(timeout time.Duration, verbose bool) (*resty.Client, error) NewRequest(client *resty.Client) *resty.Request IsReadOnly() bool GetBaseUrlForApi(api API) (string, error) - NewEdgeManagementClient(clientOpts EdgeManagementClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) + NewEdgeManagementClient(clientOpts ClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) + NewFabricManagementClient(clientOpts ClientOpts) (*fabric_rest_client.ZitiFabric, error) } func NewRequest(restClientIdentity RestClientIdentity, timeoutInSeconds int, verbose bool) (*resty.Request, error) { @@ -74,6 +77,21 @@ func (self *RestClientEdgeIdentity) IsReadOnly() bool { return self.ReadOnly } +func (self *RestClientEdgeIdentity) NewTlsClientConfig() (*tls.Config, error) { + rootCaPool := x509.NewCertPool() + + rootPemData, err := ioutil.ReadFile(self.CaCert) + if err != nil { + return nil, errors.Errorf("could not read session certificates [%s]: %v", self.CaCert, err) + } + + rootCaPool.AppendCertsFromPEM(rootPemData) + + return &tls.Config{ + RootCAs: rootCaPool, + }, nil +} + func (self *RestClientEdgeIdentity) NewClient(timeout time.Duration, verbose bool) (*resty.Client, error) { client := newClient() client.SetRootCertificate(self.CaCert) @@ -102,85 +120,12 @@ func (self *RestClientEdgeIdentity) GetBaseUrlForApi(api API) (string, error) { return "", errors.Errorf("unsupport api %v", api) } -func (self *RestClientEdgeIdentity) NewEdgeManagementClient(clientOpts EdgeManagementClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { - respFunc := func(resp *http.Response, err error) { - if clientOpts.OutputResponseJson() { - if resp == nil || resp.Body == nil { - _, _ = fmt.Fprint(clientOpts.OutputWriter(), "\n") - return - } - - resp.Body = ioutil.NopCloser(resp.Body) - bodyContent, err := ioutil.ReadAll(resp.Body) - if err != nil { - _, _ = fmt.Fprintf(clientOpts.ErrOutputWriter(), "could not read response body: %v", err) - return - } - bodyStr := string(bodyContent) - _, _ = fmt.Fprint(clientOpts.OutputWriter(), bodyStr, "\n") - } - } - - reqFunc := func(request *http.Request) error { - if self.ReadOnly && !strings.EqualFold(request.Method, "get") { - return errors.New("this login is marked read-only, only GET operations are allowed") - } - if clientOpts.OutputRequestJson() { - if request == nil || request.Body == nil { - _, _ = fmt.Fprint(clientOpts.OutputWriter(), "\n") - return nil - } - - body, err := request.GetBody() - if err == nil { - _, _ = fmt.Fprintf(clientOpts.ErrOutputWriter(), "could not copy request body: %v", err) - return nil - } - bodyContent, err := ioutil.ReadAll(body) - if err != nil { - bodyStr := string(bodyContent) - _, _ = fmt.Fprint(clientOpts.OutputWriter(), bodyStr, "\n") - return nil - } - } - return nil - } - - httpClientTransport := &edgeTransport{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 10 * time.Second, - KeepAlive: 10 * time.Second, - }).DialContext, - - ForceAttemptHTTP2: true, - MaxIdleConns: 10, - IdleConnTimeout: 10 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - }, - ResponseFunc: respFunc, - RequestFunc: reqFunc, - } - - rootCaPool := x509.NewCertPool() - - rootPemData, err := ioutil.ReadFile(self.CaCert) +func (self *RestClientEdgeIdentity) NewEdgeManagementClient(clientOpts ClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { + httpClient, err := newRestClientTransport(clientOpts, self) if err != nil { - return nil, errors.Errorf("could not read session certificates [%s]: %v", self.CaCert, err) + return nil, err } - rootCaPool.AppendCertsFromPEM(rootPemData) - - httpClientTransport.TLSClientConfig = &tls.Config{ - RootCAs: rootCaPool, - } - - httpClient := &http.Client{ - Transport: httpClientTransport, - Timeout: 10 * time.Second, - } parsedHost, err := url.Parse(self.Url) if err != nil { return nil, err @@ -195,6 +140,26 @@ func (self *RestClientEdgeIdentity) NewEdgeManagementClient(clientOpts EdgeManag return rest_management_api_client.New(clientRuntime, nil), nil } +func (self *RestClientEdgeIdentity) NewFabricManagementClient(clientOpts ClientOpts) (*fabric_rest_client.ZitiFabric, error) { + httpClient, err := newRestClientTransport(clientOpts, self) + if err != nil { + return nil, err + } + + parsedHost, err := url.Parse(self.Url) + if err != nil { + return nil, err + } + + clientRuntime := httptransport.NewWithClient(parsedHost.Host, fabric_rest_client.DefaultBasePath, fabric_rest_client.DefaultSchemes, httpClient) + + clientRuntime.DefaultAuthentication = &EdgeManagementAuth{ + Token: self.Token, + } + + return fabric_rest_client.New(clientRuntime, nil), nil +} + type RestClientFabricIdentity struct { Url string `json:"url"` CaCert string `json:"caCert,omitempty"` @@ -203,6 +168,14 @@ type RestClientFabricIdentity struct { ReadOnly bool `json:"readOnly"` } +func (self *RestClientFabricIdentity) NewTlsClientConfig() (*tls.Config, error) { + id, err := identity.LoadClientIdentity(self.ClientCert, self.ClientKey, self.CaCert) + if err != nil { + return nil, errors.Wrap(err, "unable to load identity") + } + return id.ClientTLSConfig(), nil +} + func (self *RestClientFabricIdentity) NewClient(timeout time.Duration, verbose bool) (*resty.Client, error) { id, err := identity.LoadClientIdentity(self.ClientCert, self.ClientKey, self.CaCert) if err != nil { @@ -234,10 +207,26 @@ func (self *RestClientFabricIdentity) IsReadOnly() bool { return self.ReadOnly } -func (self *RestClientFabricIdentity) NewEdgeManagementClient(EdgeManagementClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { +func (self *RestClientFabricIdentity) NewEdgeManagementClient(ClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { return nil, errors.New("fabric identities cannot be used to connect to the edge management API") } +func (self *RestClientFabricIdentity) NewFabricManagementClient(clientOpts ClientOpts) (*fabric_rest_client.ZitiFabric, error) { + httpClient, err := newRestClientTransport(clientOpts, self) + if err != nil { + return nil, err + } + + parsedHost, err := url.Parse(self.Url) + if err != nil { + return nil, err + } + + clientRuntime := httptransport.NewWithClient(parsedHost.Host, fabric_rest_client.DefaultBasePath, fabric_rest_client.DefaultSchemes, httpClient) + + return fabric_rest_client.New(clientRuntime, nil), nil +} + func LoadRestClientConfig() (*RestClientConfig, string, error) { config := &RestClientConfig{} @@ -370,3 +359,83 @@ func LoadSelectedRWIdentityForApi(api API) (RestClientIdentity, error) { } return id, nil } + +func newRestClientResponseF(clientOpts ClientOpts) func(*http.Response, error) { + return func(resp *http.Response, err error) { + if clientOpts.OutputResponseJson() { + if resp == nil || resp.Body == nil { + _, _ = fmt.Fprint(clientOpts.OutputWriter(), "\n") + return + } + + resp.Body = ioutil.NopCloser(resp.Body) + bodyContent, err := ioutil.ReadAll(resp.Body) + if err != nil { + _, _ = fmt.Fprintf(clientOpts.ErrOutputWriter(), "could not read response body: %v", err) + return + } + bodyStr := string(bodyContent) + _, _ = fmt.Fprint(clientOpts.OutputWriter(), bodyStr, "\n") + } + } +} + +func newRestClientRequestF(clientOpts ClientOpts, readOnly bool) func(*http.Request) error { + return func(request *http.Request) error { + if readOnly && !strings.EqualFold(request.Method, "get") { + return errors.New("this login is marked read-only, only GET operations are allowed") + } + if clientOpts.OutputRequestJson() { + if request == nil || request.Body == nil { + _, _ = fmt.Fprint(clientOpts.OutputWriter(), "\n") + return nil + } + + body, err := request.GetBody() + if err == nil { + _, _ = fmt.Fprintf(clientOpts.ErrOutputWriter(), "could not copy request body: %v", err) + return nil + } + bodyContent, err := ioutil.ReadAll(body) + if err != nil { + bodyStr := string(bodyContent) + _, _ = fmt.Fprint(clientOpts.OutputWriter(), bodyStr, "\n") + return nil + } + } + return nil + } +} + +func newRestClientTransport(clientOpts ClientOpts, clientIdentity RestClientIdentity) (*http.Client, error) { + httpClientTransport := &edgeTransport{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 10 * time.Second, + KeepAlive: 10 * time.Second, + }).DialContext, + + ForceAttemptHTTP2: true, + MaxIdleConns: 10, + IdleConnTimeout: 10 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + }, + ResponseFunc: newRestClientResponseF(clientOpts), + RequestFunc: newRestClientRequestF(clientOpts, clientIdentity.IsReadOnly()), + } + + tlsClientConfig, err := clientIdentity.NewTlsClientConfig() + if err != nil { + return nil, err + } + + httpClientTransport.TLSClientConfig = tlsClientConfig + + httpClient := &http.Client{ + Transport: httpClientTransport, + Timeout: 10 * time.Second, + } + return httpClient, nil +} diff --git a/ziti/cmd/ziti/util/rest.go b/ziti/cmd/ziti/util/rest.go index eb6ef54a1..7dd498213 100644 --- a/ziti/cmd/ziti/util/rest.go +++ b/ziti/cmd/ziti/util/rest.go @@ -29,6 +29,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/openziti/edge/rest_management_api_client" "github.com/openziti/edge/rest_model" + fabric_rest_client "github.com/openziti/fabric/rest_client" "github.com/openziti/ziti/common/version" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" c "github.com/openziti/ziti/ziti/cmd/ziti/constants" @@ -766,14 +767,14 @@ func WrapIfApiError(err error) error { return err } -type EdgeManagementClientOpts interface { +type ClientOpts interface { OutputRequestJson() bool OutputResponseJson() bool OutputWriter() io.Writer ErrOutputWriter() io.Writer } -func NewEdgeManagementClient(clientOpts EdgeManagementClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { +func NewEdgeManagementClient(clientOpts ClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { restClientIdentity, err := LoadSelectedIdentity() if err != nil { return nil, err @@ -781,6 +782,14 @@ func NewEdgeManagementClient(clientOpts EdgeManagementClientOpts) (*rest_managem return restClientIdentity.NewEdgeManagementClient(clientOpts) } +func NewFabricManagementClient(clientOpts ClientOpts) (*fabric_rest_client.ZitiFabric, error) { + restClientIdentity, err := LoadSelectedIdentity() + if err != nil { + return nil, err + } + return restClientIdentity.NewFabricManagementClient(clientOpts) +} + type EdgeManagementAuth struct { Token string }