diff --git a/CHANGELOG.md b/CHANGELOG.md index a45222bff..cf748b743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,53 @@ +# Release 0.24.0 + +## Breaking Changes + +* ziti-fabric-gw has been removed since the fabric now has its own REST API +* ziti-fabric-test is no longer being built by default and won't be included in future release bundles. Use `go build --tags all ./...` to build it +* ziti-fabric has been deprecated. Most of its features are now available in the `ziti` CLI under `ziti fabric` + +## What's New + +* Feature: Fabric REST API +* Performance: Additional route selection work +* Bug Fix: Fix controller deadlock which can happen if a control channel is closed while controller is responding +* Bug fix: Fix panic for UDP-only tproxy intercepts + +## Fabric REST API + +The fabric now has a REST API in addition to the channel2 management API. To enable it, add the fabric binding to the apis section off the xweb config, as follows: + +``` + apis: + # binding - required + # Specifies an API to bind to this webListener. Built-in APIs are + # - health-checks + - binding: fabric +``` + +If running without the edge, the fabric API uses client certificates for authorization, much like the existing channel2 mgmt based API does. If running with the edge, the edge provides authentication/authorization for the fabric REST APIs. + +### Supported Operations + +These operations are supported in the REST API. The ziti CLI has been updated to use this in the new `ziti fabric` sub-command. + +* Services: create/read/update/delete +* Routers: create/read/update/delete +* Terminators: create/read/update/delete +* Links: read/update +* Circuits: read/delete + +### Unsupported Operations + +Some operations from ziti-fabric aren't get supported: + +* Stream metrics/traces/circuits + * This feature may be re-implemented in terms of websockets, or may be left as-is, or may be dropped +* Inspect (get stackdumps) + * This will be ported to `ziti fabric` +* Decode trace files + * This may be ported to `ziti-ops` + # Release 0.23.1 ## What's New diff --git a/etc/ctrl.with.edge.yml b/etc/ctrl.with.edge.yml index e0c12f242..06bb4a7b9 100644 --- a/etc/ctrl.with.edge.yml +++ b/etc/ctrl.with.edge.yml @@ -198,6 +198,7 @@ web: # - fabric-management - binding: health-checks options: { } + - binding: fabric - binding: edge-management # options - variable optional/required # This section is used to define values that are specified by the API they are associated with. diff --git a/etc/ctrl.yml b/etc/ctrl.yml index 78a2b0af1..503870f1e 100644 --- a/etc/ctrl.yml +++ b/etc/ctrl.yml @@ -196,4 +196,4 @@ web: # Specifies an API to bind to this webListener. Built-in APIs are # - health-checks - binding: health-checks - options: { } + - binding: fabric diff --git a/go.mod b/go.mod index 32f1c05ae..c60c8b477 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ replace go.etcd.io/bbolt => github.com/openziti/bbolt v1.3.6-0.20210317142109-54 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 @@ -30,18 +31,16 @@ require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.6 - github.com/gorilla/mux v1.8.0 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.20.133 - github.com/openziti/fabric v0.16.133 + github.com/openziti/edge v0.21.0 + github.com/openziti/fabric v0.17.0 github.com/openziti/foundation v0.16.7 github.com/openziti/sdk-golang v0.15.116 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/rs/cors v1.7.0 github.com/russross/blackfriday v1.5.2 github.com/shirou/gopsutil v2.20.9+incompatible github.com/sirupsen/logrus v1.8.1 @@ -49,7 +48,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.8.1 github.com/stretchr/testify v1.7.0 - github.com/urfave/negroni v1.0.0 github.com/valyala/fasttemplate v1.2.1 go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 golang.org/x/net v0.0.0-20211029224645-99673261e6eb @@ -98,6 +96,7 @@ require ( github.com/gomarkdown/markdown v0.0.0-20191123064959-2c17d62f5098 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect @@ -136,14 +135,13 @@ require ( github.com/parallaxsecond/parsec-client-go v0.0.0-20210416104105-e2d188152601 // indirect github.com/pelletier/go-toml v1.9.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/speps/go-hashids v2.0.0+incompatible // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect - github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // indirect + github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -166,3 +164,8 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) + +require ( + github.com/jedib0t/go-pretty/v6 v6.2.4 + github.com/rivo/uniseg v0.2.0 // indirect +) diff --git a/go.sum b/go.sum index bca412e62..9f95042be 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,7 @@ 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= @@ -228,6 +229,7 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -533,6 +535,8 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk= +github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= @@ -660,6 +664,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= @@ -760,10 +765,10 @@ github.com/openziti/bbolt v1.3.6-0.20210317142109-547da822475e h1:ST9+54UtCr96S5 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.20.133 h1:hOI4lgnBLDfXqN+TEiSQ+BWstpESXm5Bnb3a4tACdZ8= -github.com/openziti/edge v0.20.133/go.mod h1:qKZ1BGv2BFtqAVYLVRm8tUdMb0hJ4heMONDOVM6Kra8= -github.com/openziti/fabric v0.16.133 h1:BKzcPswTLSv5Mfu0DnDCP0alLyMsYTOr6ze89AOjgIY= -github.com/openziti/fabric v0.16.133/go.mod h1:GJF5f7Sz2WzQ4ov2TFALDsSyjw0paJYzzkY2mw1pZV8= +github.com/openziti/edge v0.21.0 h1:wQCCcWsPYGs3FCvjIKMXJnnc7C8Y4DLatnWDSSa84F0= +github.com/openziti/edge v0.21.0/go.mod h1:6EGDEyV5qUT4oQk2AzMzLKak5tsatxwVJOX6fvoRmyo= +github.com/openziti/fabric v0.17.0 h1:eE2vpnQcuR0k5WtU7n1qX4SxqKwbBmIsMGvk2nPbHH0= +github.com/openziti/fabric v0.17.0/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.116 h1:6/GqsQ4lLw62PZjl0KZyeOgo/1GVgCcX4pBfsZRX2CY= @@ -795,6 +800,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -836,8 +842,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -930,8 +934,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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= -github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= -github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 h1:3SNcvBmEPE1YlB1JpVZouslJpI3GBNoiqW7+wb0Rz7w= +github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -939,8 +943,6 @@ github.com/transip/gotransip/v6 v6.2.0/go.mod h1:pQZ36hWWRahCUXkFWlx9Hs711gLd8J4 github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -1174,6 +1176,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cO golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/version b/version index 39010d220..fd137eb17 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.23 +0.24 diff --git a/ziti-controller/main.go b/ziti-controller/main.go index bc05759b5..465b180fd 100644 --- a/ziti-controller/main.go +++ b/ziti-controller/main.go @@ -18,7 +18,7 @@ package main import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti/edge/build" + "github.com/openziti/fabric/build" "github.com/openziti/foundation/transport" "github.com/openziti/foundation/transport/quic" "github.com/openziti/foundation/transport/tcp" diff --git a/ziti-fabric-gw/main.go b/ziti-fabric-gw/main.go deleted file mode 100644 index e4217ed16..000000000 --- a/ziti-fabric-gw/main.go +++ /dev/null @@ -1,44 +0,0 @@ -/* - 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 ( - "github.com/michaelquigley/pfxlog" - "github.com/openziti/foundation/transport" - "github.com/openziti/foundation/transport/quic" - "github.com/openziti/foundation/transport/tcp" - "github.com/openziti/foundation/transport/tls" - "github.com/openziti/foundation/transport/transwarp" - "github.com/openziti/foundation/transport/transwarptls" - "github.com/openziti/foundation/transport/wss" - "github.com/openziti/ziti/ziti-fabric-gw/subcmd" - "github.com/sirupsen/logrus" -) - -func init() { - pfxlog.GlobalInit(logrus.InfoLevel, pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti/").NoColor()) - transport.AddAddressParser(quic.AddressParser{}) - transport.AddAddressParser(tls.AddressParser{}) - transport.AddAddressParser(tcp.AddressParser{}) - transport.AddAddressParser(transwarp.AddressParser{}) - transport.AddAddressParser(transwarptls.AddressParser{}) - transport.AddAddressParser(wss.AddressParser{}) -} - -func main() { - subcmd.Execute() -} diff --git a/ziti-fabric-gw/subcmd/config.go b/ziti-fabric-gw/subcmd/config.go deleted file mode 100644 index 440ea07f8..000000000 --- a/ziti-fabric-gw/subcmd/config.go +++ /dev/null @@ -1,78 +0,0 @@ -/* - 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 subcmd - -import ( - "errors" - "fmt" - "gopkg.in/yaml.v2" - "io/ioutil" - - "github.com/openziti/foundation/transport" - "bytes" -) - -type Config struct { - MgmtGwListenAddress string `yaml:"listenAddress"` - MgmtGwCertPath string `yaml:"certPath"` - MgmtGwKeyPath string `yaml:"keyPath"` - - MgmtAddr string `yaml:"mgmt"` - mgmtAddress transport.Address - MgmtCertPath string `yaml:"mgmtCertPath"` - MgmtKeyPath string `yaml:"mgmtKeyPath"` - MgmtCaCertPath string `yaml:"mgmtCaCertPath"` -} - -func loadConfig(path string) (*Config, error) { - buf, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - config := &Config{} - err = yaml.NewDecoder(bytes.NewBuffer(buf)).Decode(config) - if err != nil { - return nil, err - } - - if config.MgmtGwListenAddress == "" { - return nil, errors.New("configuration missing [listenAddress]") - } - - if config.MgmtAddr == "" { - return nil, errors.New("configuration missing [mgmt]") - } - config.mgmtAddress, err = transport.ParseAddress(config.MgmtAddr) - if err != nil { - return nil, errors.New(fmt.Sprintf("cannot parse [mgmt] (%s)", err)) - } - - if config.MgmtCertPath == "" { - return nil, errors.New("configuration missing [mgmtCertPath]") - } - - if config.MgmtKeyPath == "" { - return nil, errors.New("configuration missing [mgmtKeyPath]") - } - - if config.MgmtCaCertPath == "" { - return nil, errors.New("configuration missing [mgmtCaCertPath]") - } - - return config, nil -} diff --git a/ziti-fabric-gw/subcmd/create_service.go b/ziti-fabric-gw/subcmd/create_service.go deleted file mode 100644 index f97160585..000000000 --- a/ziti-fabric-gw/subcmd/create_service.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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 subcmd - -import ( - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/fabric/pb/mgmt_pb" - "github.com/openziti/foundation/channel2" - "net/http" -) - -func handleCreateService(w http.ResponseWriter, req *http.Request) { - defer func() { _ = req.Body.Close() }() - - decoder := json.NewDecoder(req.Body) - var svc service - err := decoder.Decode(&svc) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - return - } - - request := &mgmt_pb.CreateServiceRequest{ - Service: &mgmt_pb.Service{ - Id: svc.Id, - Terminators: []*mgmt_pb.Terminator{{ - RouterId: svc.Egress, - Binding: svc.Binding, - Address: svc.EndpointAddress, - }}, - }, - } - body, err := proto.Marshal(request) - if err != nil { - panic(err) - } - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_CreateServiceRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == channel2.ContentTypeResultType { - result := channel2.UnmarshalResult(responseMsg) - if result.Success { - if err := json.NewEncoder(w).Encode(&data{Data: make([]interface{}, 0)}); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - w.WriteHeader(http.StatusOK) - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(result.Message); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } - } - } else { - pfxlog.Logger().Errorf("unexpected error (%s)", err) - } -} diff --git a/ziti-fabric-gw/subcmd/get_service.go b/ziti-fabric-gw/subcmd/get_service.go deleted file mode 100644 index 936b4dff7..000000000 --- a/ziti-fabric-gw/subcmd/get_service.go +++ /dev/null @@ -1,109 +0,0 @@ -/* - 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 subcmd - -import ( - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/gorilla/mux" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/fabric/pb/mgmt_pb" - "github.com/openziti/foundation/channel2" - "net/http" - "time" -) - -func handleGetService(w http.ResponseWriter, req *http.Request) { - vars := mux.Vars(req) - id := vars["id"] - - request := &mgmt_pb.GetServiceRequest{ServiceId: id} - body, err := proto.Marshal(request) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_GetServiceRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == int32(mgmt_pb.ContentType_GetServiceResponseType) { - response := &mgmt_pb.GetServiceResponse{} - err := proto.Unmarshal(responseMsg.Body, response) - if err == nil { - if err := json.NewEncoder(w).Encode(convertService(response.Service)); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - - } else { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else if responseMsg.ContentType == channel2.ContentTypeResultType { - result := channel2.UnmarshalResult(responseMsg) - if result.Success { - // This should never happen (i.e. success should take the form of a GetServiceResponseType) - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } else { - w.WriteHeader(http.StatusNotFound) - if err := json.NewEncoder(w).Encode("invalid ID specified"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - pfxlog.Logger().Errorf("unexpected error (%s)", err) - } -} - -func convertService(svc *mgmt_pb.Service) interface{} { - d := &data{Data: make([]interface{}, 0)} - address := "" - router := "" - if len(svc.Terminators) > 0 { - address = svc.Terminators[0].Address - router = svc.Terminators[0].RouterId - } - d.Data = append(d.Data, &service{ - Id: svc.Id, - EndpointAddress: address, - Egress: router, - }) - return d -} diff --git a/ziti-fabric-gw/subcmd/list_links.go b/ziti-fabric-gw/subcmd/list_links.go deleted file mode 100644 index f20d89124..000000000 --- a/ziti-fabric-gw/subcmd/list_links.go +++ /dev/null @@ -1,95 +0,0 @@ -/* - 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 subcmd - -import ( - "github.com/openziti/foundation/channel2" - "github.com/openziti/fabric/pb/mgmt_pb" - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/michaelquigley/pfxlog" - "net/http" - "time" -) - -func handleListLinks(w http.ResponseWriter, _ *http.Request) { - request := &mgmt_pb.ListLinksRequest{} - body, err := proto.Marshal(request) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - pfxlog.Logger().Errorf("error encoding json (%s)", err) - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListLinksRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == int32(mgmt_pb.ContentType_ListLinksResponseType) { - response := &mgmt_pb.ListLinksResponse{} - err := proto.Unmarshal(responseMsg.Body, response) - if err == nil { - if err := json.NewEncoder(w).Encode(convertLinks(response.Links)); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } -} - -func convertLinks(in []*mgmt_pb.Link) interface{} { - d := &data{} - for _, l := range in { - srcLatency := float64(l.SrcLatency) / 1000000000.0 - dstLatency := float64(l.DstLatency) / 1000000000.0 - d.Data = append(d.Data, &link{ - Id: l.Id, - Src: l.Src, - Dst: l.Dst, - State: l.State, - Down: l.Down, - Cost: l.Cost, - SrcLatency: srcLatency, - DstLatency: dstLatency, - }) - } - return d -} diff --git a/ziti-fabric-gw/subcmd/list_routers.go b/ziti-fabric-gw/subcmd/list_routers.go deleted file mode 100644 index 86ac3d96e..000000000 --- a/ziti-fabric-gw/subcmd/list_routers.go +++ /dev/null @@ -1,86 +0,0 @@ -/* - 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 subcmd - -import ( - "github.com/openziti/foundation/channel2" - "github.com/openziti/fabric/pb/mgmt_pb" - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/michaelquigley/pfxlog" - "net/http" - "time" -) - -func handleListRouters(w http.ResponseWriter, req *http.Request) { - request := &mgmt_pb.ListRoutersRequest{} - body, err := proto.Marshal(request) - if err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListRoutersRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == int32(mgmt_pb.ContentType_ListRoutersResponseType) { - response := &mgmt_pb.ListRoutersResponse{} - err := proto.Unmarshal(responseMsg.Body, response) - if err == nil { - if err := json.NewEncoder(w).Encode(convertRouters(response.Routers)); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - pfxlog.Logger().Errorf("unexpected error (%s)", err) - } -} - -func convertRouters(in []*mgmt_pb.Router) interface{} { - d := &data{Data: make([]interface{}, 0)} - for _, r := range in { - d.Data = append(d.Data, &router{ - Id: r.Id, - Fingerprint: r.Fingerprint, - ListenerAddress: r.ListenerAddress, - Connected: r.Connected, - }) - } - return d -} diff --git a/ziti-fabric-gw/subcmd/list_services.go b/ziti-fabric-gw/subcmd/list_services.go deleted file mode 100644 index 313faed94..000000000 --- a/ziti-fabric-gw/subcmd/list_services.go +++ /dev/null @@ -1,91 +0,0 @@ -/* - 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 subcmd - -import ( - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/fabric/pb/mgmt_pb" - "github.com/openziti/foundation/channel2" - "net/http" - "time" -) - -func handleListServices(w http.ResponseWriter, req *http.Request) { - request := &mgmt_pb.ListServicesRequest{} - body, err := proto.Marshal(request) - if err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListServicesRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == int32(mgmt_pb.ContentType_ListServicesResponseType) { - response := &mgmt_pb.ListServicesResponse{} - err := proto.Unmarshal(responseMsg.Body, response) - if err == nil { - if err := json.NewEncoder(w).Encode(convertServices(response.Services)); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - pfxlog.Logger().Errorf("unexpected error (%s)", err) - } -} - -func convertServices(in []*mgmt_pb.Service) interface{} { - d := &data{Data: make([]interface{}, 0)} - for _, svc := range in { - address := "" - router := "" - if len(svc.Terminators) > 0 { - address = svc.Terminators[0].Address - router = svc.Terminators[0].RouterId - } - d.Data = append(d.Data, &service{ - Id: svc.Id, - EndpointAddress: address, - Egress: router, - }) - } - return d -} diff --git a/ziti-fabric-gw/subcmd/list_sessions.go b/ziti-fabric-gw/subcmd/list_sessions.go deleted file mode 100644 index ccc1c4bb9..000000000 --- a/ziti-fabric-gw/subcmd/list_sessions.go +++ /dev/null @@ -1,96 +0,0 @@ -/* - 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 subcmd - -import ( - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/fabric/pb/mgmt_pb" - "github.com/openziti/foundation/channel2" - "net/http" - "time" -) - -func handleListCircuits(w http.ResponseWriter, _ *http.Request) { - request := &mgmt_pb.ListCircuitsRequest{} - body, err := proto.Marshal(request) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - pfxlog.Logger().Errorf("error encoding json (%s)", err) - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListCircuitsRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == int32(mgmt_pb.ContentType_ListCircuitsResponseType) { - response := &mgmt_pb.ListCircuitsResponse{} - err := proto.Unmarshal(responseMsg.Body, response) - if err == nil { - if err := json.NewEncoder(w).Encode(convertCircuits(response.Circuits)); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } -} - -func convertCircuits(in []*mgmt_pb.Circuit) interface{} { - d := &data{} - for _, s := range in { - c := &path{} - for _, p := range s.Path.Nodes { - c.Path = append(c.Path, p) - } - for _, l := range s.Path.Links { - c.Links = append(c.Links, l) - } - d.Data = append(d.Data, &circuit{ - Id: s.Id, - ClientId: s.ClientId, - ServiceId: s.ServiceId, - Circuit: c, - }) - } - return d -} diff --git a/ziti-fabric-gw/subcmd/messages.go b/ziti-fabric-gw/subcmd/messages.go deleted file mode 100644 index ccb650a34..000000000 --- a/ziti-fabric-gw/subcmd/messages.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - 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 subcmd - -type path struct { - Path []string `json:"path"` - Links []string `json:"links"` -} - -type data struct { - Data []interface{} `json:"data"` -} - -type link struct { - Id string `json:"id"` - Src string `json:"src"` - Dst string `json:"dst"` - State string `json:"state"` - Down bool `json:"down"` - Cost int32 `json:"cost"` - SrcLatency float64 `json:"srcLatency"` - DstLatency float64 `json:"dstLatency"` -} - -type router struct { - Id string `json:"id"` - Fingerprint string `json:"fingerprint"` - ListenerAddress string `json:"listenerAddress"` - Connected bool `json:"connected"` -} - -type service struct { - Id string `json:"id"` - Binding string `json:"binding"` - EndpointAddress string `json:"endpointAddress"` - Egress string `json:"egress"` -} - -type circuit struct { - Id string `json:"id"` - ClientId string `json:"clientId"` - ServiceId string `json:"serviceId"` - Circuit *path `json:"circuit"` -} diff --git a/ziti-fabric-gw/subcmd/remove_service.go b/ziti-fabric-gw/subcmd/remove_service.go deleted file mode 100644 index 66633c301..000000000 --- a/ziti-fabric-gw/subcmd/remove_service.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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 subcmd - -import ( - "github.com/openziti/foundation/channel2" - "github.com/openziti/fabric/pb/mgmt_pb" - "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/gorilla/mux" - "github.com/michaelquigley/pfxlog" - "net/http" - "time" -) - -func handleRemoveService(w http.ResponseWriter, req *http.Request) { - defer func() { _ = req.Body.Close() }() - - vars := mux.Vars(req) - id := vars["id"] - - request := &mgmt_pb.RemoveServiceRequest{ServiceId: id} - body, err := proto.Marshal(request) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode(err.Error()); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - return - } - - requestMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_RemoveServiceRequestType), body) - waitCh, err := mgmtCh.SendAndWait(requestMsg) - if err == nil { - select { - case responseMsg := <-waitCh: - if responseMsg.ContentType == channel2.ContentTypeResultType { - result := channel2.UnmarshalResult(responseMsg) - if result.Success { - if err := json.NewEncoder(w).Encode(&data{Data: make([]interface{}, 0)}); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - w.WriteHeader(http.StatusOK) - - } else { - w.WriteHeader(http.StatusBadRequest) - } - } else { - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("unexpected response"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - return - } - - case <-time.After(5 * time.Second): - w.WriteHeader(http.StatusInternalServerError) - if err := json.NewEncoder(w).Encode("timeout"); err != nil { - pfxlog.Logger().Errorf("error encoding json (%s)", err) - } - } - } else { - pfxlog.Logger().Errorf("unexpected error (%s)", err) - } -} diff --git a/ziti-fabric-gw/subcmd/root.go b/ziti-fabric-gw/subcmd/root.go deleted file mode 100644 index b5a222c7d..000000000 --- a/ziti-fabric-gw/subcmd/root.go +++ /dev/null @@ -1,44 +0,0 @@ -/* - 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 subcmd - -import ( - "fmt" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -func init() { - root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging") -} - -var root = &cobra.Command{ - Use: "ziti-fabric-gw", - Short: "Ziti Fabric Management API Gateway", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - if verbose { - logrus.SetLevel(logrus.DebugLevel) - } - }, -} -var verbose bool - -func Execute() { - if err := root.Execute(); err != nil { - println(fmt.Errorf("error: %s", err)) - } -} diff --git a/ziti-fabric-gw/subcmd/run.go b/ziti-fabric-gw/subcmd/run.go deleted file mode 100644 index d72153a74..000000000 --- a/ziti-fabric-gw/subcmd/run.go +++ /dev/null @@ -1,124 +0,0 @@ -/* - 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 subcmd - -import ( - "github.com/gorilla/mux" - "github.com/michaelquigley/pfxlog" - "github.com/openziti/foundation/channel2" - "github.com/openziti/foundation/common/constants" - "github.com/openziti/foundation/identity/identity" - "github.com/openziti/foundation/transport" - "github.com/rs/cors" - "github.com/spf13/cobra" - "github.com/urfave/negroni" - "net/http" -) - -func init() { - root.AddCommand(runCmd) -} - -var ( - mgmtCh mgmtChannel - mgmtAddress transport.Address -) - -var runCmd = &cobra.Command{ - Use: "run ", - Short: "Run configuration", - Args: cobra.ExactArgs(1), - Run: run, -} - -func run(_ *cobra.Command, args []string) { - if config, err := loadConfig(args[0]); err == nil { - if id, err := identity.LoadClientIdentity(config.MgmtCertPath, config.MgmtKeyPath, config.MgmtCaCertPath); err == nil { - dialer := channel2.NewClassicDialer(id, config.mgmtAddress, nil) - if mc, err := channel2.NewChannel("ziti-fabric-gw", dialer, nil); err == nil { - log := pfxlog.Logger() - - SetMgmtCh(mc) - router := NewRouter() - - /** - * Configure the CORS handler - */ - c := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{ - "GET", "POST", "PATCH", "DELETE", "OPTIONS", - }, - AllowedHeaders: []string{ - "Content-Type", - "Accept", - constants.ZitiSession, - }, - Debug: false, // Enable Debugging for testing, disable this in production - }) - - n := negroni.New() - n.Use(negroni.NewLogger()) // Insert the REST tracing middleware - n.Use(c) // Insert the CORS middleware - n.UseHandler(router) - - log.Info("started") - if config.MgmtGwCertPath != "" && config.MgmtGwKeyPath != "" { - log.Fatal(http.ListenAndServeTLS(config.MgmtGwListenAddress, config.MgmtGwCertPath, config.MgmtGwKeyPath, n)) - } else { - log.Fatal(http.ListenAndServe(config.MgmtGwListenAddress, n)) - } - } else { - panic(err) - } - } else { - panic(err) - } - } else { - panic(err) - } -} - -type mgmtChannel interface { - SendAndWait(requestMsg *channel2.Message) (chan *channel2.Message, error) -} - -// SetMgmtCh sets the channel between this fabric-gw server and the controller. We export this method for testability -func SetMgmtCh(c mgmtChannel) { - mgmtCh = c -} - -// NewRouter builds the ziti-router for the server. We export this method for testability -func NewRouter() http.Handler { - router := mux.NewRouter() - router.Use(addJsonContentType) - router.HandleFunc("/ctrl/links", handleListLinks).Methods("GET") - router.HandleFunc("/ctrl/routers", handleListRouters).Methods("GET") - router.HandleFunc("/ctrl/services", handleListServices).Methods("GET") - router.HandleFunc("/ctrl/services", handleCreateService).Methods("POST") - router.HandleFunc("/ctrl/services/{id}", handleGetService).Methods("GET") - router.HandleFunc("/ctrl/services/{id}", handleRemoveService).Methods("DELETE") - router.HandleFunc("/ctrl/sessions", handleListCircuits).Methods("GET") - return router -} - -func addJsonContentType(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - next.ServeHTTP(w, r) - }) -} diff --git a/ziti-fabric-gw/subcmd/version.go b/ziti-fabric-gw/subcmd/version.go deleted file mode 100644 index 3120a5364..000000000 --- a/ziti-fabric-gw/subcmd/version.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - 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 subcmd - -import ( - "github.com/openziti/ziti/common/version" - "fmt" - "github.com/spf13/cobra" -) - -func init() { - root.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Show component version", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(version.GetBuildMetadata(verbose)) - }, -} diff --git a/ziti-fabric-test/main.go b/ziti-fabric-test/main.go index 7b68093f3..e095e4f12 100644 --- a/ziti-fabric-test/main.go +++ b/ziti-fabric-test/main.go @@ -1,3 +1,5 @@ +//go:build all + /* Copyright NetFoundry, Inc. diff --git a/ziti-fabric/main.go b/ziti-fabric/main.go index 2f0c1f027..f64783cac 100644 --- a/ziti-fabric/main.go +++ b/ziti-fabric/main.go @@ -17,6 +17,7 @@ package main import ( + "fmt" "github.com/michaelquigley/pfxlog" "github.com/openziti/foundation/transport" "github.com/openziti/foundation/transport/quic" @@ -41,5 +42,6 @@ func init() { } func main() { + fmt.Println("DEPRECATION WARNING: ziti-fabric is deprecated and will be removed in a future release. Use ziti fabric instead.") subcmd.Execute() } diff --git a/ziti-ops/logs/common.go b/ziti-ops/logs/common.go new file mode 100644 index 000000000..61c0530cc --- /dev/null +++ b/ziti-ops/logs/common.go @@ -0,0 +1,323 @@ +package logs + +import ( + "bufio" + "fmt" + "github.com/Jeffail/gabs/v2" + "github.com/openziti/foundation/util/stringz" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "os" + "regexp" + "sort" + "strings" + "time" +) + +type ParseContext struct { + path string + lineNumber int + eof bool + line string +} + +func ScanLines(ctx *ParseContext, callback func(ctx *ParseContext) error) error { + file, err := os.Open(ctx.path) + if err != nil { + return err + } + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + ctx.line = line + if err := callback(ctx); err != nil { + return errors.Wrapf(err, "error parsing %v on line %v", ctx.path, ctx.lineNumber) + } + ctx.lineNumber++ + } + ctx.eof = true + return callback(ctx) +} + +type JsonParseContext struct { + ParseContext + entry *gabs.Container +} + +func (self *JsonParseContext) RequiredString(path ...string) (string, error) { + v := self.entry.Search(path...) + if v == nil || v.Data() == nil { + return "", errors.Errorf("%v not found in log entry", strings.Join(path, ".")) + } + s, ok := v.Data().(string) + if !ok { + return "", errors.Errorf("%v is not a string", strings.Join(path, ".")) + } + return s, nil +} + +func (self *JsonParseContext) ParseJsonEntry() error { + input := self.line + idx := strings.IndexByte(self.line, '{') + if idx < 0 { + fmt.Printf("WARN: non-json line: %v", self.line) + return nil + } + if idx > 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 new file mode 100644 index 000000000..fceb62aea --- /dev/null +++ b/ziti-ops/logs/router_logs.go @@ -0,0 +1,316 @@ +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 new file mode 100644 index 000000000..761043245 --- /dev/null +++ b/ziti-ops/main.go @@ -0,0 +1,78 @@ +//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-router/main.go b/ziti-router/main.go index d2e3603b0..f96632ff5 100644 --- a/ziti-router/main.go +++ b/ziti-router/main.go @@ -18,7 +18,7 @@ package main import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti/edge/build" + "github.com/openziti/fabric/build" "github.com/openziti/foundation/transport" "github.com/openziti/foundation/transport/quic" "github.com/openziti/foundation/transport/tcp" diff --git a/ziti-router/subcmd/run.go b/ziti-router/subcmd/run.go index e38417e9e..bc8ce3594 100644 --- a/ziti-router/subcmd/run.go +++ b/ziti-router/subcmd/run.go @@ -135,6 +135,6 @@ func waitForShutdown(r *router.Router, config *router.Config) { pfxlog.Logger().Info("shutting down ziti-router") if err := r.Shutdown(); err != nil { - pfxlog.Logger().Info("error encountered during shutdown: %v", err) + pfxlog.Logger().WithError(err).Info("error encountered during shutdown") } } diff --git a/ziti/cmd/ziti/cmd/api/delete.go b/ziti/cmd/ziti/cmd/api/delete.go new file mode 100644 index 000000000..f09cc9cc2 --- /dev/null +++ b/ziti/cmd/ziti/cmd/api/delete.go @@ -0,0 +1,52 @@ +package api + +import ( + "github.com/fatih/color" + "github.com/openziti/foundation/storage/boltz" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "net/url" + "strings" +) + +func DeleteEntitiesOfType(api util.API, o *Options, entityType string, ids []string, body string) error { + for _, id := range ids { + err := util.ControllerDelete(api, entityType, id, body, o.Out, o.OutputJSONRequest, o.OutputJSONResponse, o.Timeout, o.Verbose) + if err != nil { + o.Printf("delete of %v with id %v: %v\n", boltz.GetSingularEntityType(entityType), id, color.New(color.FgRed, color.Bold).Sprint("FAIL")) + return err + } + o.Printf("delete of %v with id %v: %v\n", boltz.GetSingularEntityType(entityType), id, color.New(color.FgGreen, color.Bold).Sprint("OK")) + } + return nil +} + +// DeleteEntityOfTypeWhere implements the commands to delete various entity types +func DeleteEntityOfTypeWhere(api util.API, options *Options, entityType string, body string) error { + filter := strings.Join(options.Args, " ") + + params := url.Values{} + params.Add("filter", filter) + + children, pageInfo, err := ListEntitiesOfType(api, entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) + if err != nil { + return err + } + + options.Printf("filter returned ") + pageInfo.Output(options) + + var ids []string + for _, entity := range children { + id, _ := entity.Path("id").Data().(string) + ids = append(ids, id) + } + + return DeleteEntitiesOfType(api, options, entityType, ids, body) +} + +func GetPlural(entityType string) string { + if strings.HasSuffix(entityType, "y") { + return strings.TrimSuffix(entityType, "y") + "ies" + } + return entityType + "s" +} diff --git a/ziti/cmd/ziti/cmd/api/json.go b/ziti/cmd/ziti/cmd/api/json.go new file mode 100644 index 000000000..dcf99d538 --- /dev/null +++ b/ziti/cmd/ziti/cmd/api/json.go @@ -0,0 +1,24 @@ +package api + +import "github.com/Jeffail/gabs" + +func SetJSONValue(container *gabs.Container, value interface{}, path ...string) { + if _, err := container.Set(value, path...); err != nil { + panic(err) + } +} + +func GetJsonValue(container *gabs.Container, path string) interface{} { + return container.Path(path).Data() +} + +func GetJsonString(container *gabs.Container, path string) string { + v := GetJsonValue(container, path) + if v == nil { + return "" + } + if s, ok := v.(string); ok { + return s + } + return "" +} diff --git a/ziti/cmd/ziti/cmd/api/list.go b/ziti/cmd/ziti/cmd/api/list.go new file mode 100644 index 000000000..930fefc5f --- /dev/null +++ b/ziti/cmd/ziti/cmd/api/list.go @@ -0,0 +1,136 @@ +package api + +import ( + "fmt" + "github.com/Jeffail/gabs" + "github.com/openziti/foundation/util/errorz" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/pkg/errors" + "io" + "net/url" + "os" + "reflect" + "strings" +) + +// ListEntitiesOfType queries the Ziti Controller for entities of the given type +func ListEntitiesWithOptions(api util.API, entityType string, options *Options) ([]*gabs.Container, *Paging, error) { + params := url.Values{} + if len(options.Args) > 0 { + params.Add("filter", options.Args[0]) + } + + return ListEntitiesOfType(api, entityType, params, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) +} + +// ListEntitiesOfType queries the Ziti Controller for entities of the given type +func ListEntitiesOfType(api util.API, entityType string, params url.Values, logJSON bool, out io.Writer, timeout int, verbose bool) ([]*gabs.Container, *Paging, error) { + jsonParsed, err := util.ControllerList(api, entityType, params, logJSON, out, timeout, verbose) + + if err != nil { + return nil, nil, err + } + + children, err := jsonParsed.S("data").Children() + return children, getPaging(jsonParsed), err +} + +func getPaging(c *gabs.Container) *Paging { + pagingInfo := &Paging{} + pagination := c.S("meta", "pagination") + if pagination != nil { + pagingInfo.limit = toInt64(pagination, "limit", pagingInfo) + pagingInfo.offset = toInt64(pagination, "offset", pagingInfo) + pagingInfo.count = toInt64(pagination, "totalCount", pagingInfo) + } else { + pagingInfo.SetError(errors.New("meta.pagination section not found in result")) + } + return pagingInfo +} + +type Paging struct { + limit int64 + offset int64 + count int64 + errorz.ErrorHolderImpl +} + +func (p *Paging) Output(o *Options) { + if p.HasError() { + _, _ = fmt.Fprintf(o.Out, "unable to retrieve paging information: %v\n", p.Err) + } else if p.count == 0 { + _, _ = fmt.Fprintln(o.Out, "results: none") + } else { + first := p.offset + 1 + last := p.offset + p.limit + if last > p.count || last < 0 { // if p.limit is maxint, last will rollover and be negative + last = p.count + } + _, _ = fmt.Fprintf(o.Out, "results: %v-%v of %v\n", first, last, p.count) + } +} + +func toInt64(c *gabs.Container, path string, errorHolder errorz.ErrorHolder) int64 { + data := c.S(path).Data() + if data == nil { + errorHolder.SetError(errors.Errorf("%v not found", path)) + return 0 + } + val, ok := data.(float64) + if !ok { + errorHolder.SetError(errors.Errorf("%v not a number, it's a %v", path, reflect.TypeOf(data))) + return 0 + } + return int64(val) +} + +func FilterEntitiesOfType(api util.API, entityType string, filter string, logJSON bool, out io.Writer, timeout int, verbose bool) ([]*gabs.Container, *Paging, error) { + params := url.Values{} + params.Add("filter", filter) + return ListEntitiesOfType(api, entityType, params, logJSON, out, timeout, verbose) +} + +func MapNameToID(api util.API, entityType string, o *Options, idOrName string) (string, error) { + result, err := MapNamesToIDs(api, entityType, o, idOrName) + if err != nil { + return "", err + } + if len(result) != 1 { + return "", errors.Errorf("found %v results for input %v when mapping %v to id", len(result), idOrName, entityType) + } + return result[0], nil +} + +func MapNamesToIDs(api util.API, entityType string, o *Options, list ...string) ([]string, error) { + var result []string + for _, val := range list { + if strings.HasPrefix(val, "id") { + id := strings.TrimPrefix(val, "id:") + result = append(result, id) + } else { + query := fmt.Sprintf(`id = "%s" or name="%s"`, val, val) + if strings.HasPrefix(val, "name") { + name := strings.TrimPrefix(val, "name:") + query = fmt.Sprintf(`name="%s"`, name) + } + list, _, err := FilterEntitiesOfType(api, entityType, query, false, nil, o.Timeout, o.Verbose) + if err != nil { + return nil, err + } + + if len(list) > 1 { + fmt.Printf("Found multiple %v matching %v. Please specify which you want by prefixing with id: or name:\n", entityType, val) + return nil, errors.Errorf("ambigous if %v is id or name", val) + } + + for _, entity := range list { + entityId, _ := entity.Path("id").Data().(string) + result = append(result, entityId) + if val, found := os.LookupEnv("ZITI_CLI_DEBUG"); found && strings.EqualFold("true", val) { + fmt.Printf("Found %v with id %v for name %v\n", entityType, entityId, val) + } + } + } + } + return result, nil +} diff --git a/ziti/cmd/ziti/cmd/api/options.go b/ziti/cmd/ziti/cmd/api/options.go new file mode 100644 index 000000000..0f71878bb --- /dev/null +++ b/ziti/cmd/ziti/cmd/api/options.go @@ -0,0 +1,54 @@ +package api + +import ( + "fmt" + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/spf13/cobra" + "io" +) + +// Options are common options for edge controller commands +type Options struct { + common.CommonOptions + OutputJSONRequest bool + OutputJSONResponse bool + OutputCSV bool +} + +func (options *Options) OutputResponseJson() bool { + return options.OutputJSONResponse +} + +func (options *Options) OutputRequestJson() bool { + return options.OutputJSONRequest +} + +func (options *Options) OutputWriter() io.Writer { + return options.CommonOptions.Out +} + +func (options *Options) ErrOutputWriter() io.Writer { + return options.CommonOptions.Err +} + +func (options *Options) AddCommonFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&common.CliIdentity, "cli-identity", "i", "", "Specify the saved identity you want the CLI to use when connect to the controller with") + cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") + cmd.Flags().BoolVar(&options.OutputJSONRequest, "output-request-json", false, "Output the full JSON request to the Ziti Edge Controller") + cmd.Flags().IntVarP(&options.Timeout, "timeout", "", 5, "Timeout for REST operations (specified in seconds)") + cmd.Flags().BoolVarP(&options.Verbose, "verbose", "", false, "Enable verbose logging") +} + +func (options *Options) LogCreateResult(entityType string, result *gabs.Container, err error) error { + if err != nil { + return err + } + + if !options.OutputJSONResponse { + id := result.S("data", "id").Data() + _, err = fmt.Fprintf(options.Out, "New %v %v created with id: %v\n", entityType, options.Args[0], id) + return err + } + return nil +} diff --git a/ziti/cmd/ziti/cmd/cmd.go b/ziti/cmd/ziti/cmd/cmd.go index bc0ab39b4..c8fb557f6 100644 --- a/ziti/cmd/ziti/cmd/cmd.go +++ b/ziti/cmd/ziti/cmd/cmd.go @@ -19,6 +19,8 @@ package cmd import ( goflag "flag" "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/fabric" "io" "os" "path/filepath" @@ -123,12 +125,15 @@ func NewCmdRoot(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Comm // defaultClusterName := os.Getenv("ZITI_CLUSTER_NAME") // cmd.PersistentFlags().StringVarP(&rootCommand.clusterName, "name", "", defaultClusterName, "Name of cluster. Overrides ZITI_CLUSTER_NAME environment variable") + p := common.NewOptionsProvider(out, err) + initCommands := NewCmdInit(f, out, err) createCommands := NewCmdCreate(f, out, err) updateCommands := NewCmdUpdate(f, out, err) executeCommands := NewCmdExecute(f, out, err) psCommands := NewCmdPs(f, out, err) pkiCommands := NewCmdPKI(f, out, err) + fabricCommand := fabric.NewFabricCmd(p) edgeCommand := edge.NewCmdEdge(f, out, err) logFilter := NewCmdLogFormat(f, out, err) unwrapIdentityFileCommand := NewUnwrapIdentityFileCommand(f, out, err) @@ -162,8 +167,9 @@ func NewCmdRoot(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Comm }, }, { - Message: "Interacting with Ziti edge components", + Message: "Interacting with the Ziti controller", Commands: []*cobra.Command{ + fabricCommand, edgeCommand, }, }, diff --git a/ziti/cmd/ziti/cmd/common_init.go b/ziti/cmd/ziti/cmd/common_init.go index 522b3acbd..a7665ce07 100644 --- a/ziti/cmd/ziti/cmd/common_init.go +++ b/ziti/cmd/ziti/cmd/common_init.go @@ -29,10 +29,7 @@ import ( var ZITI_COMPONENTS = []string{ c.ZITI, c.ZITI_CONTROLLER, - c.ZITI_ENROLLER, c.ZITI_FABRIC, - c.ZITI_FABRIC_GW, - c.ZITI_FABRIC_TEST, c.ZITI_PROX_C, c.ZITI_ROUTER, c.ZITI_TUNNEL, @@ -169,55 +166,3 @@ func (o *CommonOptions) createInitialControllerConfig() error { return nil } - -func (o *CommonOptions) createInitialMgmtGwConfig() error { - - configDir, err := util.ConfigDir() - if err != nil { - return err - } - - gwConfigDir, err := util.ZitiAppConfigDir(c.ZITI_FABRIC_GW) - if err != nil { - return err - } - - fileName := filepath.Join(gwConfigDir, c.CONFIGFILENAME) + ".json" - - _, err = os.Stat(fileName) - if err == nil { - return fmt.Errorf("config file (%s) already exists", fileName) - } - - cfgfile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644) - if err != nil { - return err - } - if err := cfgfile.Close(); err != nil { - return err - } - - viper.SetConfigType("json") - viper.SetConfigName(c.CONFIGFILENAME) - viper.AddConfigPath(gwConfigDir) - - // Set some default values - viper.SetDefault("listenAddress", "localhost:10080") - viper.SetDefault("mgmt", "tls:0.0.0.0:10000") - viper.SetDefault("identity.default.description", "This identity is used if one is not specified at execution time") - viper.SetDefault("identity.default.mgmtGwCertPath", configDir+"/fabric/ca/intermediate/certs/mgmt-gw.cert.pem") - viper.SetDefault("identity.default.mgmtGwKeyPath", configDir+"/fabric/ca/intermediate/private/mgmt-gw.key.pem") - viper.SetDefault("identity.default.mgmtCertPath", configDir+"/fabric/ca/intermediate/certs/mgmt-gw.cert.pem") - viper.SetDefault("identity.default.mgmtKeyPath", configDir+"/fabric/ca/intermediate/private/mgmt-gw.key.pem") - viper.SetDefault("identity.default.mgmtCaCertPath", configDir+"/fabric/ca/intermediate/certs/ca-chain.cert.pem") - - viper.SetDefault("identity.a.description", "This identity is just demonstrating that multiple identities can exist (you need to fill out remaining fields)") - viper.SetDefault("identity.b.description", "This identity is just demonstrating that multiple identities can exist (you need to fill out remaining fields)") - - err = viper.WriteConfig() - if err != nil { - return err - } - - return nil -} diff --git a/ziti/cmd/ziti/cmd/edge/common.go b/ziti/cmd/ziti/cmd/edge/common.go index a8e68b681..48126fb4e 100644 --- a/ziti/cmd/ziti/cmd/edge/common.go +++ b/ziti/cmd/ziti/cmd/edge/common.go @@ -18,12 +18,13 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/pkg/errors" "os" "strings" ) -func mapNameToID(entityType string, val string, o edgeOptions) (string, error) { +func mapNameToID(entityType string, val string, o api.Options) (string, error) { list, _, err := filterEntitiesOfType(entityType, fmt.Sprintf("id=\"%s\"", val), false, nil, o.Timeout, o.Verbose) if err != nil { return "", err @@ -54,7 +55,7 @@ func mapNameToID(entityType string, val string, o edgeOptions) (string, error) { return entityId, nil } -func mapIdToName(entityType string, val string, o edgeOptions) (string, error) { +func mapIdToName(entityType string, val string, o api.Options) (string, error) { list, _, err := filterEntitiesOfType(entityType, fmt.Sprintf(`id="%s"`, val), false, nil, o.Timeout, o.Verbose) if err != nil { return "", err @@ -69,7 +70,7 @@ func mapIdToName(entityType string, val string, o edgeOptions) (string, error) { return name, nil } -func mapNamesToIDs(entityType string, o edgeOptions, list ...string) ([]string, error) { +func mapNamesToIDs(entityType string, o api.Options, list ...string) ([]string, error) { var result []string for _, val := range list { if strings.HasPrefix(val, "id") { @@ -103,10 +104,10 @@ func mapNamesToIDs(entityType string, o edgeOptions, list ...string) ([]string, return result, nil } -func mapIdentityNameToID(nameOrId string, o edgeOptions) (string, error) { +func mapIdentityNameToID(nameOrId string, o api.Options) (string, error) { return mapNameToID("identities", nameOrId, o) } -func mapCaNameToID(nameOrId string, o edgeOptions) (string, error) { +func mapCaNameToID(nameOrId string, o api.Options) (string, error) { return mapNameToID("cas", nameOrId, o) } diff --git a/ziti/cmd/ziti/cmd/edge/create.go b/ziti/cmd/ziti/cmd/edge/create.go index 4838ada0a..533f88788 100644 --- a/ziti/cmd/ziti/cmd/edge/create.go +++ b/ziti/cmd/ziti/cmd/edge/create.go @@ -17,12 +17,13 @@ package edge import ( + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/util" "io" - "github.com/Jeffail/gabs" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/spf13/cobra" ) @@ -53,7 +54,7 @@ func newCreateCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com return cmd } -// createEntityOfType create an entity of the given type on the Ziti Edge Controller -func createEntityOfType(entityType string, body string, options *edgeOptions) (*gabs.Container, error) { - return util.EdgeControllerCreate(entityType, body, options.Out, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) +// CreateEntityOfType create an entity of the given type on the Ziti Controller +func CreateEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { + return util.ControllerCreate("edge", entityType, body, options.Out, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) } diff --git a/ziti/cmd/ziti/cmd/edge/create_authenticator.go b/ziti/cmd/ziti/cmd/edge/create_authenticator.go index a3fb1b95b..b7187d9e9 100644 --- a/ziti/cmd/ziti/cmd/edge/create_authenticator.go +++ b/ziti/cmd/ziti/cmd/edge/create_authenticator.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" "github.com/spf13/cobra" @@ -25,7 +26,7 @@ import ( // newCreateAuthenticatorCmd creates the 'edge controller create authenticator' command func newCreateAuthenticatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := edgeOptions{ + options := api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, OutputJSONResponse: false, } diff --git a/ziti/cmd/ziti/cmd/edge/create_authenticator_updb.go b/ziti/cmd/ziti/cmd/edge/create_authenticator_updb.go index 77cc8cb1b..c5876c199 100644 --- a/ziti/cmd/ziti/cmd/edge/create_authenticator_updb.go +++ b/ziti/cmd/ziti/cmd/edge/create_authenticator_updb.go @@ -23,20 +23,21 @@ import ( "github.com/Jeffail/gabs" "github.com/openziti/edge/rest_management_api_client/authenticator" "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/spf13/cobra" ) type createAuthenticatorUpdb struct { - edgeOptions + api.Options idOrName string password string username string } -func newCreateAuthenticatorUpdb(idType string, options edgeOptions) *cobra.Command { - updbOptions := &createAuthenticatorUpdb{edgeOptions: options} +func newCreateAuthenticatorUpdb(idType string, options api.Options) *cobra.Command { + updbOptions := &createAuthenticatorUpdb{Options: options} cmd := &cobra.Command{ Use: idType + " []", @@ -81,7 +82,7 @@ func runCreateIdentityPassword(idType string, options *createAuthenticatorUpdb) return errors.New("an identity must be specified") } - identityId, err := mapIdentityNameToID(options.idOrName, options.edgeOptions) + identityId, err := mapIdentityNameToID(options.idOrName, options.Options) if err != nil { return err @@ -122,12 +123,12 @@ func runCreateIdentityPassword(idType string, options *createAuthenticatorUpdb) } authenticatorData := gabs.New() - setJSONValue(authenticatorData, identityId, "identityId") - setJSONValue(authenticatorData, options.password, "password") - setJSONValue(authenticatorData, options.username, "username") - setJSONValue(authenticatorData, "updb", "method") + api.SetJSONValue(authenticatorData, identityId, "identityId") + api.SetJSONValue(authenticatorData, options.password, "password") + api.SetJSONValue(authenticatorData, options.username, "username") + api.SetJSONValue(authenticatorData, "updb", "method") - if _, err = createEntityOfType("authenticators", authenticatorData.String(), &options.edgeOptions); err != nil { + if _, err = CreateEntityOfType("authenticators", authenticatorData.String(), &options.Options); err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/create_ca.go b/ziti/cmd/ziti/cmd/edge/create_ca.go index 6117b1e4e..4fa634458 100644 --- a/ziti/cmd/ziti/cmd/edge/create_ca.go +++ b/ziti/cmd/ziti/cmd/edge/create_ca.go @@ -19,6 +19,7 @@ package edge import ( "fmt" "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -28,7 +29,7 @@ import ( ) type createCaOptions struct { - edgeOptions + api.Options tags map[string]string name string caPath string @@ -43,7 +44,7 @@ type createCaOptions struct { // newCreateCaCmd creates the 'edge controller create ca local' command for the given entity type func newCreateCaCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createCaOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Factory: f, Out: out, @@ -99,17 +100,17 @@ func newCreateCaCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.C func runCreateCa(options *createCaOptions) (err error) { data := gabs.New() - setJSONValue(data, options.name, "name") - setJSONValue(data, options.autoCaEnrollment, "isAutoCaEnrollmentEnabled") - setJSONValue(data, options.ottCaEnrollment, "isOttCaEnrollmentEnabled") - setJSONValue(data, options.authEnabled, "isAuthEnabled") - setJSONValue(data, string(options.caPemBytes), "certPem") - setJSONValue(data, options.identityRoles, "identityRoles") + api.SetJSONValue(data, options.name, "name") + api.SetJSONValue(data, options.autoCaEnrollment, "isAutoCaEnrollmentEnabled") + api.SetJSONValue(data, options.ottCaEnrollment, "isOttCaEnrollmentEnabled") + api.SetJSONValue(data, options.authEnabled, "isAuthEnabled") + api.SetJSONValue(data, string(options.caPemBytes), "certPem") + api.SetJSONValue(data, options.identityRoles, "identityRoles") if options.Cmd.Flag("identity-name-format").Changed { - setJSONValue(data, options.identityNameFormat, "identityNameFormat") + api.SetJSONValue(data, options.identityNameFormat, "identityNameFormat") } - result, err := createEntityOfType("cas", data.String(), &options.edgeOptions) - return options.logCreateResult("ca", result, err) + result, err := CreateEntityOfType("cas", data.String(), &options.Options) + return options.LogCreateResult("ca", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_config.go b/ziti/cmd/ziti/cmd/edge/create_config.go index 7e88fd235..daa6f6ad0 100644 --- a/ziti/cmd/ziti/cmd/edge/create_config.go +++ b/ziti/cmd/ziti/cmd/edge/create_config.go @@ -19,6 +19,7 @@ package edge import ( "encoding/json" "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "io/ioutil" @@ -32,14 +33,14 @@ import ( ) type createConfigOptions struct { - edgeOptions + api.Options jsonFile string } // newCreateConfigCmd creates the 'edge controller create service-policy' command func newCreateConfigCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createConfigOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -95,15 +96,15 @@ func runCreateConfig(o *createConfigOptions) error { return errors.Errorf("unable to parse data as json: %v", err) } - configTypeId, err := mapNameToID("config-types", o.Args[1], o.edgeOptions) + configTypeId, err := mapNameToID("config-types", o.Args[1], o.Options) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, configTypeId, "configTypeId") - setJSONValue(entityData, dataMap, "data") - result, err := createEntityOfType("configs", entityData.String(), &o.edgeOptions) - return o.logCreateResult("config", result, err) + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, configTypeId, "configTypeId") + api.SetJSONValue(entityData, dataMap, "data") + result, err := CreateEntityOfType("configs", entityData.String(), &o.Options) + return o.LogCreateResult("config", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_config_type.go b/ziti/cmd/ziti/cmd/edge/create_config_type.go index 98819c532..4ab22ec38 100644 --- a/ziti/cmd/ziti/cmd/edge/create_config_type.go +++ b/ziti/cmd/ziti/cmd/edge/create_config_type.go @@ -19,6 +19,7 @@ package edge import ( "encoding/json" "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "io/ioutil" @@ -32,14 +33,14 @@ import ( ) type createConfigTypeOptions struct { - edgeOptions + api.Options schemaFile string } // newCreateConfigTypeCmd creates the 'edge controller create service-policy' command func newCreateConfigTypeCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createConfigTypeOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -96,11 +97,11 @@ func runCreateConfigType(o *createConfigTypeOptions) error { } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, o.Args[0], "name") if schemaMap != nil { - setJSONValue(entityData, schemaMap, "schema") + api.SetJSONValue(entityData, schemaMap, "schema") } - result, err := createEntityOfType("config-types", entityData.String(), &o.edgeOptions) - return o.logCreateResult("config type", result, err) + result, err := CreateEntityOfType("config-types", entityData.String(), &o.Options) + return o.LogCreateResult("config type", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_edge_router.go b/ziti/cmd/ziti/cmd/edge/create_edge_router.go index 976206717..d0bd4b33d 100644 --- a/ziti/cmd/ziti/cmd/edge/create_edge_router.go +++ b/ziti/cmd/ziti/cmd/edge/create_edge_router.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "io/ioutil" @@ -29,7 +30,7 @@ import ( ) type createEdgeRouterOptions struct { - edgeOptions + api.Options isTunnelerEnabled bool roleAttributes []string jwtOutputFile string @@ -39,7 +40,7 @@ type createEdgeRouterOptions struct { func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createEdgeRouterOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -75,14 +76,14 @@ func newCreateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // runCreateEdgeRouter implements the command to create a gateway on the edge controller func runCreateEdgeRouter(o *createEdgeRouterOptions) error { entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, o.isTunnelerEnabled, "isTunnelerEnabled") - setJSONValue(entityData, o.roleAttributes, "roleAttributes") - setJSONValue(entityData, o.tags, "tags") - setJSONValue(entityData, o.appData, "appData") + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, o.isTunnelerEnabled, "isTunnelerEnabled") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.tags, "tags") + api.SetJSONValue(entityData, o.appData, "appData") - result, err := createEntityOfType("edge-routers", entityData.String(), &o.edgeOptions) - if err := o.logCreateResult("edge router", result, err); err != nil { + result, err := CreateEntityOfType("edge-routers", entityData.String(), &o.Options) + if err := o.LogCreateResult("edge router", result, err); err != nil { return err } @@ -96,7 +97,7 @@ func runCreateEdgeRouter(o *createEdgeRouterOptions) error { } func getEdgeRouterJwt(o *createEdgeRouterOptions, id string) error { - newRouter, err := DetailEntityOfType("edge-routers", id, o.OutputJSONResponse, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + newRouter, err := DetailEntityOfType("edge-routers", id, o.OutputJSONResponse, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/create_edge_router_policy.go b/ziti/cmd/ziti/cmd/edge/create_edge_router_policy.go index 1dc0e0b54..445a2a8f7 100644 --- a/ziti/cmd/ziti/cmd/edge/create_edge_router_policy.go +++ b/ziti/cmd/ziti/cmd/edge/create_edge_router_policy.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/Jeffail/gabs" @@ -27,7 +28,7 @@ import ( ) type createEdgeRouterPolicyOptions struct { - edgeOptions + api.Options edgeRouterRoles []string identityRoles []string semantic string @@ -36,7 +37,7 @@ type createEdgeRouterPolicyOptions struct { // newCreateEdgeRouterPolicyCmd creates the 'edge controller create edge-router-policy' command func newCreateEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createEdgeRouterPolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -68,24 +69,24 @@ func newCreateEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Wr // runCreateEdgeRouterPolicy create a new edgeRouterPolicy on the Ziti Edge Controller func runCreateEdgeRouterPolicy(o *createEdgeRouterPolicyOptions) error { - edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.edgeOptions) + edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.Options) if err != nil { return err } - identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.edgeOptions) + identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.Options) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") - setJSONValue(entityData, identityRoles, "identityRoles") + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") + api.SetJSONValue(entityData, identityRoles, "identityRoles") if o.semantic != "" { - setJSONValue(entityData, o.semantic, "semantic") + api.SetJSONValue(entityData, o.semantic, "semantic") } - result, err := createEntityOfType("edge-router-policies", entityData.String(), &o.edgeOptions) - return o.logCreateResult("edge router policy", result, err) + result, err := CreateEntityOfType("edge-router-policies", entityData.String(), &o.Options) + return o.LogCreateResult("edge router policy", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_identity.go b/ziti/cmd/ziti/cmd/edge/create_identity.go index a2b874ff8..bc09c33a0 100644 --- a/ziti/cmd/ziti/cmd/edge/create_identity.go +++ b/ziti/cmd/ziti/cmd/edge/create_identity.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/pkg/errors" "io" "io/ioutil" @@ -33,7 +34,7 @@ import ( ) type createIdentityOptions struct { - edgeOptions + api.Options isAdmin bool roleAttributes []string jwtOutputFile string @@ -50,7 +51,7 @@ type createIdentityOptions struct { func newCreateIdentityCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { newOptions := func() *createIdentityOptions { return &createIdentityOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -104,19 +105,19 @@ func newCreateIdentityOfTypeCmd(idType string, options *createIdentityOptions) * func runCreateIdentity(idType string, o *createIdentityOptions) error { entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, strings.Title(idType), "type") + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, strings.Title(idType), "type") o.username = strings.TrimSpace(o.username) if o.username != "" { - setJSONValue(entityData, o.username, "enrollment", "updb") + api.SetJSONValue(entityData, o.username, "enrollment", "updb") } else { - setJSONValue(entityData, true, "enrollment", "ott") + api.SetJSONValue(entityData, true, "enrollment", "ott") } - setJSONValue(entityData, o.isAdmin, "isAdmin") - setJSONValue(entityData, o.roleAttributes, "roleAttributes") - setJSONValue(entityData, o.tags, "tags") - setJSONValue(entityData, o.appData, "appData") + api.SetJSONValue(entityData, o.isAdmin, "isAdmin") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.tags, "tags") + api.SetJSONValue(entityData, o.appData, "appData") if o.defaultHostingPrecedence != "" { prec, err := normalizeAndValidatePrecedence(o.defaultHostingPrecedence) @@ -124,26 +125,26 @@ func runCreateIdentity(idType string, o *createIdentityOptions) error { return err } - setJSONValue(entityData, prec, "defaultHostingPrecedence") + api.SetJSONValue(entityData, prec, "defaultHostingPrecedence") } - setJSONValue(entityData, o.defaultHostingCost, "defaultHostingCost") + api.SetJSONValue(entityData, o.defaultHostingCost, "defaultHostingCost") for k, v := range o.serviceCosts { if v < 0 || v > math.MaxUint16 { return errors.Errorf("hosting costs must be in the range %v-%v", 0, math.MaxUint16) } - id, err := mapNameToID("services", k, o.edgeOptions) + id, err := mapNameToID("services", k, o.Options) if err != nil { return err } delete(o.serviceCosts, k) o.serviceCosts[id] = v } - setJSONValue(entityData, o.serviceCosts, "serviceHostingCosts") + api.SetJSONValue(entityData, o.serviceCosts, "serviceHostingCosts") for k, v := range o.servicePrecedences { - id, err := mapNameToID("services", k, o.edgeOptions) + id, err := mapNameToID("services", k, o.Options) if err != nil { return err } @@ -156,16 +157,16 @@ func runCreateIdentity(idType string, o *createIdentityOptions) error { delete(o.servicePrecedences, k) o.servicePrecedences[id] = prec } - setJSONValue(entityData, o.servicePrecedences, "serviceHostingPrecedences") + api.SetJSONValue(entityData, o.servicePrecedences, "serviceHostingPrecedences") - result, err := createEntityOfType("identities", entityData.String(), &o.edgeOptions) - if err := o.logCreateResult("identity", result, err); err != nil { + result, err := CreateEntityOfType("identities", entityData.String(), &o.Options) + if err := o.LogCreateResult("identity", result, err); err != nil { return err } if o.jwtOutputFile != "" { id := result.S("data", "id").Data().(string) - if err := getIdentityJwt(o, id, o.edgeOptions.Timeout, o.edgeOptions.Verbose); err != nil { + if err := getIdentityJwt(o, id, o.Options.Timeout, o.Options.Verbose); err != nil { return err } } diff --git a/ziti/cmd/ziti/cmd/edge/create_posture_check.go b/ziti/cmd/ziti/cmd/edge/create_posture_check.go index e4c41a155..8a3261eae 100644 --- a/ziti/cmd/ziti/cmd/edge/create_posture_check.go +++ b/ziti/cmd/ziti/cmd/edge/create_posture_check.go @@ -21,6 +21,7 @@ import ( "github.com/Jeffail/gabs" "github.com/openziti/edge/rest_management_api_client/posture_checks" "github.com/openziti/edge/rest_model" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -47,7 +48,7 @@ func newCreatePostureCheckCmd(out io.Writer, errOut io.Writer) *cobra.Command { } type createPostureCheckOptions struct { - edgeOptions + api.Options name string tags map[string]string roleAttributes []string @@ -108,7 +109,7 @@ func (options *createPostureCheckOptions) addPostureFlags(cmd *cobra.Command) { func newCreatePostureCheckMacCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &createPostureCheckMacOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -147,7 +148,7 @@ func newCreatePostureCheckMacCmd(out io.Writer, errOut io.Writer) *cobra.Command func newCreatePostureCheckDomainCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &createPostureCheckDomainOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -186,7 +187,7 @@ func newCreatePostureCheckDomainCmd(out io.Writer, errOut io.Writer) *cobra.Comm func newCreatePostureCheckProcessCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &createPostureCheckProcessOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -239,7 +240,7 @@ func newCreatePostureCheckProcessCmd(out io.Writer, errOut io.Writer) *cobra.Com func newCreatePostureCheckProcessMultiCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &createPostureCheckProcessMultiOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -433,8 +434,8 @@ func runCreatePostureCheckProcess(o *createPostureCheckProcessOptions) error { entityData := gabs.New() setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeProcess) - setJSONValue(entityData, o.normalizedOs, "process", "osType") - setJSONValue(entityData, o.path, "process", "path") + api.SetJSONValue(entityData, o.normalizedOs, "process", "osType") + api.SetJSONValue(entityData, o.path, "process", "path") hashes, err := cleanSha512s(o.hashes) @@ -443,7 +444,7 @@ func runCreatePostureCheckProcess(o *createPostureCheckProcessOptions) error { } if len(hashes) > 0 { - setJSONValue(entityData, hashes, "process", "hashes") + api.SetJSONValue(entityData, hashes, "process", "hashes") } if o.signer != "" { @@ -453,11 +454,11 @@ func runCreatePostureCheckProcess(o *createPostureCheckProcessOptions) error { return err } - setJSONValue(entityData, cleanSigner, "process", "signerFingerprint") + api.SetJSONValue(entityData, cleanSigner, "process", "signerFingerprint") } - result, err := createEntityOfType("posture-checks", entityData.String(), &o.edgeOptions) - return o.logCreateResult("posture check", result, err) + result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options) + return o.LogCreateResult("posture check", result, err) } func runCreatePostureCheckProcessMulti(options *createPostureCheckProcessMultiOptions) error { @@ -514,10 +515,10 @@ func runCreatePostureCheckProcessMulti(options *createPostureCheckProcessMultiOp } func setPostureCheckEntityValues(entity *gabs.Container, options *createPostureCheckOptions, typeId string) { - setJSONValue(entity, options.Args[0], "name") - setJSONValue(entity, options.roleAttributes, "roleAttributes") - setJSONValue(entity, options.tags, "tags") - setJSONValue(entity, typeId, "typeId") + api.SetJSONValue(entity, options.Args[0], "name") + api.SetJSONValue(entity, options.roleAttributes, "roleAttributes") + api.SetJSONValue(entity, options.tags, "tags") + api.SetJSONValue(entity, typeId, "typeId") } func cleanMacAddresses(inAddresses []string) ([]string, error) { @@ -557,9 +558,9 @@ func runCreatePostureCheckMac(o *createPostureCheckMacOptions) (err error) { return fmt.Errorf("must specify at least one MAC Address, multiple values may be separated by commas") } - setJSONValue(entityData, addresses, "macAddresses") + api.SetJSONValue(entityData, addresses, "macAddresses") - result, err := createEntityOfType("posture-checks", entityData.String(), &o.edgeOptions) + result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options) if err != nil { panic(err) @@ -603,9 +604,9 @@ func runCreatePostureCheckDomain(o *createPostureCheckDomainOptions) (err error) return fmt.Errorf("must specify at least one domain, multiple values may be separated by commas or multiple flags") } - setJSONValue(entityData, domains, "domains") + api.SetJSONValue(entityData, domains, "domains") - result, err := createEntityOfType("posture-checks", entityData.String(), &o.edgeOptions) + result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options) if err != nil { panic(err) @@ -624,7 +625,7 @@ func newCreatePostureCheckOsCmd(out io.Writer, errOut io.Writer) *cobra.Command options := &createPostureCheckOsOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -677,9 +678,9 @@ func runCreatePostureCheckOs(o *createPostureCheckOsOptions) error { entityData := gabs.New() setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeOS) - setJSONValue(entityData, osSpecs, "operatingSystems") + api.SetJSONValue(entityData, osSpecs, "operatingSystems") - result, err := createEntityOfType("posture-checks", entityData.String(), &o.edgeOptions) + result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options) if err != nil { panic(err) @@ -728,7 +729,7 @@ func parseOsSpec(osSpecStr string) (*osSpec, error) { func newCreatePostureCheckMfaCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := createPostureCheckMfaOptions{ createPostureCheckOptions: createPostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -782,7 +783,7 @@ func runCreatePostureCheckMfa(o *createPostureCheckMfaOptions) error { setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeMFA) - result, err := createEntityOfType("posture-checks", entityData.String(), &o.edgeOptions) + result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options) if err != nil { panic(err) diff --git a/ziti/cmd/ziti/cmd/edge/create_service.go b/ziti/cmd/ziti/cmd/edge/create_service.go index 05a3c5a80..c7ffb0ddd 100644 --- a/ziti/cmd/ziti/cmd/edge/create_service.go +++ b/ziti/cmd/ziti/cmd/edge/create_service.go @@ -18,6 +18,7 @@ package edge import ( "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -26,7 +27,7 @@ import ( ) type createServiceOptions struct { - edgeOptions + api.Options terminatorStrategy string tags map[string]string roleAttributes []string @@ -38,7 +39,7 @@ type createServiceOptions struct { // newCreateServiceCmd creates the 'edge controller create service local' command for the given entity type func newCreateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createServiceOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Factory: f, Out: out, @@ -77,23 +78,23 @@ func newCreateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *co // runCreateService implements the command to create a service func runCreateService(o *createServiceOptions) (err error) { - configs, err := mapNamesToIDs("configs", o.edgeOptions, o.configs...) + configs, err := mapNamesToIDs("configs", o.Options, o.configs...) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, o.Args[0], "name") if o.terminatorStrategy != "" { - setJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") + api.SetJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") } - setJSONValue(entityData, o.encryption.Get(), "encryptionRequired") + api.SetJSONValue(entityData, o.encryption.Get(), "encryptionRequired") - setJSONValue(entityData, o.roleAttributes, "roleAttributes") - setJSONValue(entityData, configs, "configs") - setJSONValue(entityData, o.tags, "tags") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, configs, "configs") + api.SetJSONValue(entityData, o.tags, "tags") - result, err := createEntityOfType("services", entityData.String(), &o.edgeOptions) - return o.logCreateResult("service", result, err) + result, err := CreateEntityOfType("services", entityData.String(), &o.Options) + return o.LogCreateResult("service", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_service_edge_router_policy.go b/ziti/cmd/ziti/cmd/edge/create_service_edge_router_policy.go index 891e891f1..5e619357e 100644 --- a/ziti/cmd/ziti/cmd/edge/create_service_edge_router_policy.go +++ b/ziti/cmd/ziti/cmd/edge/create_service_edge_router_policy.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/Jeffail/gabs" @@ -27,7 +28,7 @@ import ( ) type createServiceEdgeRouterPolicyOptions struct { - edgeOptions + api.Options edgeRouterRoles []string serviceRoles []string semantic string @@ -36,7 +37,7 @@ type createServiceEdgeRouterPolicyOptions struct { // newCreateServiceEdgeRouterPolicyCmd creates the 'edge controller create service-edge-router-policy' command func newCreateServiceEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createServiceEdgeRouterPolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -68,23 +69,23 @@ func newCreateServiceEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOu // runCreateServiceEdgeRouterPolicy create a new edgeRouterPolicy on the Ziti Edge Controller func runCreateServiceEdgeRouterPolicy(o *createServiceEdgeRouterPolicyOptions) error { - edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.edgeOptions) + edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.Options) if err != nil { return err } - serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.edgeOptions) + serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.Options) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") - setJSONValue(entityData, serviceRoles, "serviceRoles") + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") + api.SetJSONValue(entityData, serviceRoles, "serviceRoles") if o.semantic != "" { - setJSONValue(entityData, o.semantic, "semantic") + api.SetJSONValue(entityData, o.semantic, "semantic") } - result, err := createEntityOfType("service-edge-router-policies", entityData.String(), &o.edgeOptions) - return o.logCreateResult("service edge router policy", result, err) + result, err := CreateEntityOfType("service-edge-router-policies", entityData.String(), &o.Options) + return o.LogCreateResult("service edge router policy", result, err) } diff --git a/ziti/cmd/ziti/cmd/edge/create_service_policy.go b/ziti/cmd/ziti/cmd/edge/create_service_policy.go index de0ac32ff..fc8ac856c 100644 --- a/ziti/cmd/ziti/cmd/edge/create_service_policy.go +++ b/ziti/cmd/ziti/cmd/edge/create_service_policy.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "strings" @@ -29,7 +30,7 @@ import ( ) type createServicePolicyOptions struct { - edgeOptions + api.Options serviceRoles []string identityRoles []string postureCheckRoles []string @@ -39,7 +40,7 @@ type createServicePolicyOptions struct { // newCreateServicePolicyCmd creates the 'edge controller create service-policy' command func newCreateServicePolicyCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &createServicePolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -77,36 +78,36 @@ func runCreateServicePolicy(o *createServicePolicyOptions) error { return errors.Errorf("Invalid policy type '%v'. Valid values: [Bind, Dial]", policyType) } - serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.edgeOptions) + serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.Options) if err != nil { return err } - identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.edgeOptions) + identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.Options) if err != nil { return err } - postureCheckRoles, err := convertNamesToIds(o.postureCheckRoles, "posture-checks", o.edgeOptions) + postureCheckRoles, err := convertNamesToIds(o.postureCheckRoles, "posture-checks", o.Options) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, o.Args[0], "name") - setJSONValue(entityData, o.Args[1], "type") - setJSONValue(entityData, serviceRoles, "serviceRoles") - setJSONValue(entityData, identityRoles, "identityRoles") - setJSONValue(entityData, postureCheckRoles, "postureCheckRoles") + api.SetJSONValue(entityData, o.Args[0], "name") + api.SetJSONValue(entityData, o.Args[1], "type") + api.SetJSONValue(entityData, serviceRoles, "serviceRoles") + api.SetJSONValue(entityData, identityRoles, "identityRoles") + api.SetJSONValue(entityData, postureCheckRoles, "postureCheckRoles") if o.semantic != "" { - setJSONValue(entityData, o.semantic, "semantic") + api.SetJSONValue(entityData, o.semantic, "semantic") } - result, err := createEntityOfType("service-policies", entityData.String(), &o.edgeOptions) - return o.logCreateResult("service policy", result, err) + result, err := CreateEntityOfType("service-policies", entityData.String(), &o.Options) + return o.LogCreateResult("service policy", result, err) } -func convertNamesToIds(roles []string, entityType string, o edgeOptions) ([]string, error) { +func convertNamesToIds(roles []string, entityType string, o api.Options) ([]string, error) { var result []string for _, val := range roles { if strings.HasPrefix(val, "@") { diff --git a/ziti/cmd/ziti/cmd/edge/create_terminator.go b/ziti/cmd/ziti/cmd/edge/create_terminator.go index 6b0220b9a..e920d6d80 100644 --- a/ziti/cmd/ziti/cmd/edge/create_terminator.go +++ b/ziti/cmd/ziti/cmd/edge/create_terminator.go @@ -21,6 +21,7 @@ import ( "github.com/Jeffail/gabs" "github.com/openziti/edge/router/xgress_edge_transport" "github.com/openziti/foundation/util/stringz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -30,7 +31,7 @@ import ( ) type createTerminatorOptions struct { - edgeOptions + api.Options binding string cost int32 precedence string @@ -40,7 +41,7 @@ type createTerminatorOptions struct { // newCreateTerminatorCmd creates the 'edge controller create Terminator local' command for the given entity type func newCreateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &createTerminatorOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Factory: f, Out: out, @@ -77,21 +78,21 @@ func newCreateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // runCreateTerminator implements the command to create a Terminator func runCreateTerminator(o *createTerminatorOptions) (err error) { entityData := gabs.New() - service, err := mapNameToID("services", o.Args[0], o.edgeOptions) + service, err := mapNameToID("services", o.Args[0], o.Options) if err != nil { return err } - router, err := mapNameToID("edge-routers", o.Args[1], o.edgeOptions) + router, err := mapNameToID("edge-routers", o.Args[1], o.Options) if err != nil { router = o.Args[1] // might be a pure fabric router, id might not be UUID } - setJSONValue(entityData, service, "service") - setJSONValue(entityData, router, "router") - setJSONValue(entityData, o.binding, "binding") - setJSONValue(entityData, o.Args[2], "address") - setJSONValue(entityData, o.identity, "identity") + api.SetJSONValue(entityData, service, "service") + api.SetJSONValue(entityData, router, "router") + api.SetJSONValue(entityData, o.binding, "binding") + api.SetJSONValue(entityData, o.Args[2], "address") + api.SetJSONValue(entityData, o.identity, "identity") if o.cost > 0 { if o.cost > math.MaxUint16 { if _, err = fmt.Fprintf(o.Out, "Invalid cost %v. Must be positive number less than or equal to %v\n", o.cost, math.MaxUint16); err != nil { @@ -99,7 +100,7 @@ func runCreateTerminator(o *createTerminatorOptions) (err error) { } return } - setJSONValue(entityData, o.cost, "cost") + api.SetJSONValue(entityData, o.cost, "cost") } if o.precedence != "" { validValues := []string{"default", "required", "failed"} @@ -109,10 +110,10 @@ func runCreateTerminator(o *createTerminatorOptions) (err error) { } return } - setJSONValue(entityData, o.precedence, "precedence") + api.SetJSONValue(entityData, o.precedence, "precedence") } - result, err := createEntityOfType("terminators", entityData.String(), &o.edgeOptions) + result, err := CreateEntityOfType("terminators", entityData.String(), &o.Options) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/db_check_integrity.go b/ziti/cmd/ziti/cmd/edge/db_check_integrity.go index ec359a802..910adf4ca 100644 --- a/ziti/cmd/ziti/cmd/edge/db_check_integrity.go +++ b/ziti/cmd/ziti/cmd/edge/db_check_integrity.go @@ -3,6 +3,7 @@ package edge import ( "fmt" "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -13,13 +14,13 @@ import ( ) type dbCheckIntegrityOptions struct { - edgeOptions + api.Options fix bool } func newDbCheckIntegrityCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &dbCheckIntegrityOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -53,7 +54,7 @@ func runCheckIntegrityDb(o *dbCheckIntegrityOptions) error { target = "database/check-data-integrity" } - if _, err := util.EdgeControllerUpdate(target, "", o.Out, http.MethodPost, o.OutputJSONRequest, o.OutputJSONResponse, o.edgeOptions.Timeout, o.edgeOptions.Verbose); err != nil { + if _, err := util.ControllerUpdate("edge", target, "", o.Out, http.MethodPost, o.OutputJSONRequest, o.OutputJSONResponse, o.Options.Timeout, o.Options.Verbose); err != nil { return err } @@ -63,7 +64,7 @@ func runCheckIntegrityDb(o *dbCheckIntegrityOptions) error { func newDbCheckIntegrityStatusCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &dbCheckIntegrityOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -89,7 +90,7 @@ func newDbCheckIntegrityStatusCmd(out io.Writer, errOut io.Writer) *cobra.Comman } func runCheckIntegrityStatus(o *dbCheckIntegrityOptions) error { - body, err := util.EdgeControllerList("database/data-integrity-results", nil, o.OutputJSONResponse, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + body, err := util.EdgeControllerList("database/data-integrity-results", nil, o.OutputJSONResponse, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/edge/db_snapshot.go b/ziti/cmd/ziti/cmd/edge/db_snapshot.go index 1d57dcea8..0ce9a214a 100644 --- a/ziti/cmd/ziti/cmd/edge/db_snapshot.go +++ b/ziti/cmd/ziti/cmd/edge/db_snapshot.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -26,12 +27,12 @@ import ( ) type dbSnapshotOptions struct { - edgeOptions + api.Options } func newDbSnapshotCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &dbSnapshotOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -57,6 +58,6 @@ func newDbSnapshotCmd(out io.Writer, errOut io.Writer) *cobra.Command { } func runSnapshotDb(o *dbSnapshotOptions) error { - _, err := util.EdgeControllerUpdate("database/snapshot", "", o.Out, http.MethodPost, false, false, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + _, err := util.ControllerUpdate("edge", "database/snapshot", "", o.Out, http.MethodPost, false, false, o.Options.Timeout, o.Options.Verbose) return err } diff --git a/ziti/cmd/ziti/cmd/edge/delete.go b/ziti/cmd/ziti/cmd/edge/delete.go index fc8d9886b..f1c91a429 100644 --- a/ziti/cmd/ziti/cmd/edge/delete.go +++ b/ziti/cmd/ziti/cmd/edge/delete.go @@ -19,11 +19,11 @@ package edge import ( "github.com/fatih/color" "github.com/openziti/foundation/storage/boltz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "net/url" "strings" - "github.com/Jeffail/gabs" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -42,8 +42,8 @@ func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command { }, } - newOptions := func() *edgeOptions { - return &edgeOptions{ + newOptions := func() *api.Options { + return &api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -70,7 +70,7 @@ func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command { } // newDeleteCmdForEntityType creates the delete command for the given entity type -func newDeleteCmdForEntityType(entityType string, options *edgeOptions, aliases ...string) *cobra.Command { +func newDeleteCmdForEntityType(entityType string, options *api.Options, aliases ...string) *cobra.Command { cmd := &cobra.Command{ Use: entityType + " ", Short: "deletes " + getPlural(entityType) + " managed by the Ziti Edge Controller", @@ -94,7 +94,7 @@ func newDeleteCmdForEntityType(entityType string, options *edgeOptions, aliases return cmd } -func newDeleteWhereCmdForEntityType(entityType string, options *edgeOptions) *cobra.Command { +func newDeleteWhereCmdForEntityType(entityType string, options *api.Options) *cobra.Command { cmd := &cobra.Command{ Use: "where ", Short: "deletes " + getPlural(entityType) + " matching the filter managed by the Ziti Edge Controller", @@ -116,7 +116,7 @@ func newDeleteWhereCmdForEntityType(entityType string, options *edgeOptions) *co } // runDeleteEntityOfType implements the commands to delete various entity types -func runDeleteEntityOfType(o *edgeOptions, entityType string) error { +func runDeleteEntityOfType(o *api.Options, entityType string) error { var err error ids := o.Args if entityType != "terminators" && entityType != "api-sessions" && entityType != "sessions" { @@ -128,9 +128,9 @@ func runDeleteEntityOfType(o *edgeOptions, entityType string) error { return deleteEntitiesOfType(o, entityType, ids) } -func deleteEntitiesOfType(o *edgeOptions, entityType string, ids []string) error { +func deleteEntitiesOfType(o *api.Options, entityType string, ids []string) error { for _, id := range ids { - _, err := util.EdgeControllerDelete(entityType, id, o.Out, o.OutputJSONResponse, o.Timeout, o.Verbose) + err := util.ControllerDelete("edge", entityType, id, "", o.Out, o.OutputJSONRequest, o.OutputJSONResponse, o.Timeout, o.Verbose) if err != nil { o.Printf("delete of %v with id %v: %v\n", boltz.GetSingularEntityType(entityType), id, color.New(color.FgRed, color.Bold).Sprint("FAIL")) return err @@ -141,7 +141,7 @@ func deleteEntitiesOfType(o *edgeOptions, entityType string, ids []string) error } // runDeleteEntityOfType implements the commands to delete various entity types -func runDeleteEntityOfTypeWhere(options *edgeOptions, entityType string) error { +func runDeleteEntityOfTypeWhere(options *api.Options, entityType string) error { filter := strings.Join(options.Args, " ") params := url.Values{} @@ -171,6 +171,6 @@ func getPlural(entityType string) string { return entityType + "s" } -func deleteEntityOfType(entityType string, id string, options *edgeOptions) (*gabs.Container, error) { - return util.EdgeControllerDelete(entityType, id, options.Out, options.OutputJSONResponse, options.Timeout, options.Verbose) +func deleteEntityOfType(entityType string, id string, options *api.Options) error { + return util.ControllerDelete("edge", entityType, id, "", options.Out, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) } diff --git a/ziti/cmd/ziti/cmd/edge/delete_authenticator.go b/ziti/cmd/ziti/cmd/edge/delete_authenticator.go index 93090a715..a315c1af4 100644 --- a/ziti/cmd/ziti/cmd/edge/delete_authenticator.go +++ b/ziti/cmd/ziti/cmd/edge/delete_authenticator.go @@ -17,10 +17,11 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/spf13/cobra" ) -func newDeleteAuthenticatorCmd(idType string, options *edgeOptions) *cobra.Command { +func newDeleteAuthenticatorCmd(idType string, options *api.Options) *cobra.Command { cmd := &cobra.Command{ Use: idType, diff --git a/ziti/cmd/ziti/cmd/edge/delete_authenticator_updb.go b/ziti/cmd/ziti/cmd/edge/delete_authenticator_updb.go index d8c52b31b..50f37bb98 100644 --- a/ziti/cmd/ziti/cmd/edge/delete_authenticator_updb.go +++ b/ziti/cmd/ziti/cmd/edge/delete_authenticator_updb.go @@ -20,18 +20,19 @@ import ( "context" "fmt" "github.com/openziti/edge/rest_management_api_client/authenticator" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/spf13/cobra" ) import cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" type deleteUpdbOptions struct { - edgeOptions + api.Options } -func newDeleteAuthenticatorUpdb(idType string, options *edgeOptions) *cobra.Command { +func newDeleteAuthenticatorUpdb(idType string, options *api.Options) *cobra.Command { updbOptions := deleteUpdbOptions{ - edgeOptions: *options, + Options: *options, } cmd := &cobra.Command{ @@ -55,7 +56,7 @@ func newDeleteAuthenticatorUpdb(idType string, options *edgeOptions) *cobra.Comm } func runDeleteUpdb(idOrName string, options *deleteUpdbOptions) error { - identityId, err := mapIdentityNameToID(idOrName, options.edgeOptions) + identityId, err := mapIdentityNameToID(idOrName, options.Options) if err != nil { return err @@ -91,7 +92,7 @@ func runDeleteUpdb(idOrName string, options *deleteUpdbOptions) error { authenticatorId := *result.Payload.Data[0].ID - _, err = deleteEntityOfType(fmt.Sprintf("authenticators/%s", authenticatorId), "", &options.edgeOptions) + err = deleteEntityOfType(fmt.Sprintf("authenticators/%s", authenticatorId), "", &options.Options) if err != nil { return err diff --git a/ziti/cmd/ziti/cmd/edge/detail.go b/ziti/cmd/ziti/cmd/edge/detail.go index f8a3d5dd9..4cd49460b 100644 --- a/ziti/cmd/ziti/cmd/edge/detail.go +++ b/ziti/cmd/ziti/cmd/edge/detail.go @@ -23,7 +23,7 @@ import ( ) func DetailEntityOfType(entityType, entityId string, logJSON bool, out io.Writer, timeout int, verbose bool) (*gabs.Container, error) { - jsonParsed, err := util.EdgeControllerDetailEntity(entityType, entityId, logJSON, out, timeout, verbose) + jsonParsed, err := util.ControllerDetailEntity("edge", entityType, entityId, logJSON, out, timeout, verbose) if err != nil { return nil, err diff --git a/ziti/cmd/ziti/cmd/edge/list.go b/ziti/cmd/ziti/cmd/edge/list.go index c01fca82e..0c5f338cf 100644 --- a/ziti/cmd/ziti/cmd/edge/list.go +++ b/ziti/cmd/ziti/cmd/edge/list.go @@ -23,6 +23,7 @@ import ( "github.com/openziti/edge/rest_management_api_client/certificate_authority" "github.com/openziti/edge/rest_model" "github.com/openziti/foundation/util/errorz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -46,8 +47,8 @@ func newListCmd(out io.Writer, errOut io.Writer) *cobra.Command { }, } - newOptions := func() *edgeOptions { - return &edgeOptions{ + newOptions := func() *api.Options { + return &api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, } } @@ -145,7 +146,7 @@ func newPagingInfo(meta *rest_model.Meta) paging { return paging{} } -func (p *paging) output(o *edgeOptions) { +func (p *paging) output(o *api.Options) { if p.HasError() { _, _ = fmt.Fprintf(o.Out, "unable to retrieve paging information: %v\n", p.Err) } else if p.count == 0 { @@ -160,9 +161,9 @@ func (p *paging) output(o *edgeOptions) { } } -type listCommandRunner func(*edgeOptions) error +type listCommandRunner func(*api.Options) error -type outputFunction func(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error +type outputFunction func(o *api.Options, children []*gabs.Container, pagingInfo *paging) error func newEntityListRootCmd(entityType string, aliases ...string) *cobra.Command { desc := fmt.Sprintf("list entities related to a %v instance managed by the Ziti Edge Controller", entityType) @@ -179,7 +180,7 @@ func newEntityListRootCmd(entityType string, aliases ...string) *cobra.Command { } // newListCmdForEntityType creates the list command for the given entity type -func newListCmdForEntityType(entityType string, command listCommandRunner, options *edgeOptions, aliases ...string) *cobra.Command { +func newListCmdForEntityType(entityType string, command listCommandRunner, options *api.Options, aliases ...string) *cobra.Command { cmd := &cobra.Command{ Use: entityType + " ?", Short: "lists " + entityType + " managed by the Ziti Edge Controller", @@ -203,7 +204,7 @@ func newListCmdForEntityType(entityType string, command listCommandRunner, optio } // newListServicesCmd creates the list command for the given entity type -func newListServicesCmd(options *edgeOptions) *cobra.Command { +func newListServicesCmd(options *api.Options) *cobra.Command { var asIdentity string var configTypes []string var roleFilters []string @@ -235,7 +236,7 @@ func newListServicesCmd(options *edgeOptions) *cobra.Command { } // newListEdgeRoutersCmd creates the list command for the given entity type -func newListEdgeRoutersCmd(options *edgeOptions) *cobra.Command { +func newListEdgeRoutersCmd(options *api.Options) *cobra.Command { var roleFilters []string var roleSemantic string @@ -264,7 +265,7 @@ func newListEdgeRoutersCmd(options *edgeOptions) *cobra.Command { } // newListEdgeRoutersCmd creates the list command for the given entity type -func newListIdentitiesCmd(options *edgeOptions) *cobra.Command { +func newListIdentitiesCmd(options *api.Options) *cobra.Command { var roleFilters []string var roleSemantic string @@ -292,7 +293,7 @@ func newListIdentitiesCmd(options *edgeOptions) *cobra.Command { } // newSubListCmdForEntityType creates the list command for the given entity type -func newSubListCmdForEntityType(entityType string, subType string, outputF outputFunction, options *edgeOptions) *cobra.Command { +func newSubListCmdForEntityType(entityType string, subType string, outputF outputFunction, options *api.Options) *cobra.Command { desc := fmt.Sprintf("lists %v related to a %v instanced managed by the Ziti Edge Controller", subType, entityType) cmd := &cobra.Command{ Use: fmt.Sprintf("%v ", subType), @@ -316,7 +317,7 @@ func newSubListCmdForEntityType(entityType string, subType string, outputF outpu } // listEntitiesOfType queries the Ziti Controller for entities of the given type -func listEntitiesWithOptions(entityType string, options *edgeOptions) ([]*gabs.Container, *paging, error) { +func listEntitiesWithOptions(entityType string, options *api.Options) ([]*gabs.Container, *paging, error) { params := url.Values{} if len(options.Args) > 0 { params.Add("filter", options.Args[0]) @@ -377,7 +378,7 @@ func getPaging(c *gabs.Container) *paging { } // listEntitiesOfType queries the Ziti Controller for entities of the given type -func filterSubEntitiesOfType(entityType, subType, entityId, filter string, o *edgeOptions) ([]*gabs.Container, *paging, error) { +func filterSubEntitiesOfType(entityType, subType, entityId, filter string, o *api.Options) ([]*gabs.Container, *paging, error) { jsonParsed, err := util.EdgeControllerListSubEntities(entityType, subType, entityId, filter, o.OutputJSONResponse, o.Out, o.Timeout, o.Verbose) if err != nil { @@ -391,7 +392,7 @@ func filterSubEntitiesOfType(entityType, subType, entityId, filter string, o *ed return children, getPaging(jsonParsed), err } -func runListEdgeRouters(roleFilters []string, roleSemantic string, options *edgeOptions) error { +func runListEdgeRouters(roleFilters []string, roleSemantic string, options *api.Options) error { params := url.Values{} if len(options.Args) > 0 { params.Add("filter", options.Args[0]) @@ -410,7 +411,7 @@ func runListEdgeRouters(roleFilters []string, roleSemantic string, options *edge return outputEdgeRouters(options, children, paging) } -func outputEdgeRouters(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputEdgeRouters(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -428,7 +429,7 @@ func outputEdgeRouters(o *edgeOptions, children []*gabs.Container, pagingInfo *p return nil } -func runListEdgeRouterPolicies(o *edgeOptions) error { +func runListEdgeRouterPolicies(o *api.Options) error { children, paging, err := listEntitiesWithOptions("edge-router-policies", o) if err != nil { return err @@ -436,7 +437,7 @@ func runListEdgeRouterPolicies(o *edgeOptions) error { return outputEdgeRouterPolicies(o, children, paging) } -func outputEdgeRouterPolicies(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputEdgeRouterPolicies(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -464,7 +465,7 @@ func outputEdgeRouterPolicies(o *edgeOptions, children []*gabs.Container, paging return nil } -func runListTerminators(o *edgeOptions) error { +func runListTerminators(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("terminators", o) if err != nil { return err @@ -472,7 +473,7 @@ func runListTerminators(o *edgeOptions) error { return outputTerminators(o, children, pagingInfo) } -func outputTerminators(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputTerminators(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -497,7 +498,7 @@ func outputTerminators(o *edgeOptions, children []*gabs.Container, pagingInfo *p return nil } -func runListServices(asIdentity string, configTypes []string, roleFilters []string, roleSemantic string, options *edgeOptions) error { +func runListServices(asIdentity string, configTypes []string, roleFilters []string, roleSemantic string, options *api.Options) error { params := url.Values{} if len(options.Args) > 0 { params.Add("filter", options.Args[0]) @@ -530,7 +531,7 @@ func runListServices(asIdentity string, configTypes []string, roleFilters []stri return outputServices(options, children, pagingInfo) } -func outputServices(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputServices(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -551,7 +552,7 @@ func outputServices(o *edgeOptions, children []*gabs.Container, pagingInfo *pagi return nil } -func outputServiceConfigs(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputServiceConfigs(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -570,7 +571,7 @@ func outputServiceConfigs(o *edgeOptions, children []*gabs.Container, pagingInfo return nil } -func runListServiceEdgeRouterPolices(o *edgeOptions) error { +func runListServiceEdgeRouterPolices(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("service-edge-router-policies", o) if err != nil { return err @@ -578,7 +579,7 @@ func runListServiceEdgeRouterPolices(o *edgeOptions) error { return outputServiceEdgeRouterPolicies(o, children, pagingInfo) } -func outputServiceEdgeRouterPolicies(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputServiceEdgeRouterPolicies(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -603,7 +604,7 @@ func outputServiceEdgeRouterPolicies(o *edgeOptions, children []*gabs.Container, return nil } -func runListServicePolices(o *edgeOptions) error { +func runListServicePolices(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("service-policies", o) if err != nil { return err @@ -611,7 +612,7 @@ func runListServicePolices(o *edgeOptions) error { return outputServicePolicies(o, children, pagingInfo) } -func outputServicePolicies(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputServicePolicies(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -681,7 +682,7 @@ func mapRoleIdsToNames(c *gabs.Container, path string) ([]string, error) { } // runListIdentities implements the command to list identities -func runListIdentities(roleFilters []string, roleSemantic string, options *edgeOptions) error { +func runListIdentities(roleFilters []string, roleSemantic string, options *api.Options) error { params := url.Values{} if len(options.Args) > 0 { params.Add("filter", options.Args[0]) @@ -700,7 +701,7 @@ func runListIdentities(roleFilters []string, roleSemantic string, options *edgeO } // outputIdentities implements the command to list identities -func outputIdentities(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputIdentities(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -719,7 +720,7 @@ func outputIdentities(o *edgeOptions, children []*gabs.Container, pagingInfo *pa return nil } -func outputPostureCheck(o *edgeOptions, entity *gabs.Container) error { +func outputPostureCheck(o *api.Options, entity *gabs.Container) error { id, _ := entity.Path("id").Data().(string) typeId, _ := entity.Path("typeId").Data().(string) name, _ := entity.Path("name").Data().(string) @@ -819,7 +820,7 @@ func getEllipsesStrings(values []string, lead, lag int) []string { return ret } -func outputPostureChecks(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputPostureChecks(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -834,7 +835,7 @@ func outputPostureChecks(o *edgeOptions, children []*gabs.Container, pagingInfo return nil } -func runListCAs(o *edgeOptions) error { +func runListCAs(o *api.Options) error { client, err := util.NewEdgeManagementClient(o) if err != nil { @@ -924,7 +925,7 @@ func runListCAs(o *edgeOptions) error { return nil } -func runListConfigTypes(o *edgeOptions) error { +func runListConfigTypes(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("config-types", o) if err != nil { return err @@ -945,7 +946,7 @@ func runListConfigTypes(o *edgeOptions) error { return nil } -func runListConfigs(o *edgeOptions) error { +func runListConfigs(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("configs", o) if err != nil { return err @@ -953,7 +954,7 @@ func runListConfigs(o *edgeOptions) error { return outputConfigs(o, children, pagingInfo) } -func outputConfigs(o *edgeOptions, children []*gabs.Container, pagingInfo *paging) error { +func outputConfigs(o *api.Options, children []*gabs.Container, pagingInfo *paging) error { if o.OutputJSONResponse { return nil } @@ -975,7 +976,7 @@ func outputConfigs(o *edgeOptions, children []*gabs.Container, pagingInfo *pagin return nil } -func runListApiSessions(o *edgeOptions) error { +func runListApiSessions(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("api-sessions", o) if err != nil { return err @@ -997,7 +998,7 @@ func runListApiSessions(o *edgeOptions) error { return err } -func runListSessions(o *edgeOptions) error { +func runListSessions(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("sessions", o) if err != nil { @@ -1021,7 +1022,7 @@ func runListSessions(o *edgeOptions) error { return err } -func runListTransitRouters(o *edgeOptions) error { +func runListTransitRouters(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("transit-routers", o) if err != nil { @@ -1043,19 +1044,19 @@ func runListTransitRouters(o *edgeOptions) error { return err } -func runListEdgeRouterRoleAttributes(o *edgeOptions) error { +func runListEdgeRouterRoleAttributes(o *api.Options) error { return runListRoleAttributes("edge-router", o) } -func runListIdentityRoleAttributes(o *edgeOptions) error { +func runListIdentityRoleAttributes(o *api.Options) error { return runListRoleAttributes("identity", o) } -func runListServiceRoleAttributes(o *edgeOptions) error { +func runListServiceRoleAttributes(o *api.Options) error { return runListRoleAttributes("service", o) } -func runListRoleAttributes(entityType string, o *edgeOptions) error { +func runListRoleAttributes(entityType string, o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions(entityType+"-role-attributes", o) if err != nil { @@ -1075,7 +1076,7 @@ func runListRoleAttributes(entityType string, o *edgeOptions) error { return err } -func runListChilden(parentType, childType string, o *edgeOptions, outputF outputFunction) error { +func runListChilden(parentType, childType string, o *api.Options, outputF outputFunction) error { idOrName := o.Args[0] parentId, err := mapNameToID(parentType, idOrName, *o) if err != nil { @@ -1099,7 +1100,7 @@ func runListChilden(parentType, childType string, o *edgeOptions, outputF output return outputF(o, children, pagingInfo) } -func runListPostureChecks(o *edgeOptions) error { +func runListPostureChecks(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("posture-checks", o) if err != nil { @@ -1113,7 +1114,7 @@ func runListPostureChecks(o *edgeOptions) error { return err } -func runListSummary(o *edgeOptions) error { +func runListSummary(o *api.Options) error { jsonParsed, err := util.EdgeControllerList("summary", url.Values{}, o.OutputJSONResponse, o.Out, o.Timeout, o.Verbose) if o.OutputJSONResponse { @@ -1150,7 +1151,7 @@ func containerArrayToString(containers []*gabs.Container, limit int) string { return strings.Join(values, ",") } -func runListPostureCheckTypes(o *edgeOptions) error { +func runListPostureCheckTypes(o *api.Options) error { children, pagingInfo, err := listEntitiesWithOptions("posture-check-types", o) if err != nil { diff --git a/ziti/cmd/ziti/cmd/edge/login.go b/ziti/cmd/ziti/cmd/edge/login.go index 0ac4d4f54..061c97f0d 100644 --- a/ziti/cmd/ziti/cmd/edge/login.go +++ b/ziti/cmd/ziti/cmd/edge/login.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/Jeffail/gabs" "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -34,11 +35,11 @@ import ( // loginOptions are the flags for login commands type loginOptions struct { - edgeOptions + api.Options Username string Password string Token string - Cert string + CaCert string ReadOnly bool Yes bool IgnoreConfig bool @@ -47,7 +48,7 @@ type loginOptions struct { // newLoginCmd creates the command func newLoginCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &loginOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -72,7 +73,7 @@ func newLoginCmd(out io.Writer, errOut io.Writer) *cobra.Command { cmd.Flags().StringVarP(&options.Username, "username", "u", "", "username to use for authenticating to the Ziti Edge Controller ") cmd.Flags().StringVarP(&options.Password, "password", "p", "", "password to use for authenticating to the Ziti Edge Controller, if -u is supplied and -p is not, a value will be prompted for") cmd.Flags().StringVarP(&options.Token, "token", "t", "", "if an api token has already been acquired, it can be set in the config with this option. This will set the session to read only by default") - cmd.Flags().StringVarP(&options.Cert, "cert", "c", "", "additional root certificates used by the Ziti Edge Controller") + cmd.Flags().StringVarP(&options.CaCert, "cert", "c", "", "additional root certificates used by the Ziti Edge Controller") cmd.Flags().BoolVar(&options.ReadOnly, "read-only", false, "marks this login as read-only. Note: this is not a guarantee that nothing can be changed on the server. Care should still be taken!") cmd.Flags().BoolVarP(&options.Yes, "yes", "y", false, "If set, responds to prompts with yes. This will result in untrusted certs being accepted or updated.") cmd.Flags().BoolVar(&options.IgnoreConfig, "ignore-config", false, "If set, does not use value from the config file for hostname or username. Values must be entered or will be prompted for.") @@ -92,7 +93,7 @@ func (o *loginOptions) Run() error { var host string if len(o.Args) == 0 { - if defaultId := config.Identities[id]; defaultId != nil && !o.IgnoreConfig { + if defaultId := config.EdgeIdentities[id]; defaultId != nil && !o.IgnoreConfig { host = defaultId.Url o.Printf("Using controller url: %v from identity '%v' in config file: %v\n", host, id, configFile) } else { @@ -122,12 +123,12 @@ func (o *loginOptions) Run() error { return err } - if certAbs, err := filepath.Abs(o.Cert); err == nil { - o.Cert = certAbs + if certAbs, err := filepath.Abs(o.CaCert); err == nil { + o.CaCert = certAbs } if ctrlUrl.Path == "" { - host = util.EdgeControllerGetManagementApiBasePath(host, o.Cert) + host = util.EdgeControllerGetManagementApiBasePath(host, o.CaCert) } else { host = host + ctrlUrl.Path } @@ -139,7 +140,7 @@ func (o *loginOptions) Run() error { if o.Token == "" { for o.Username == "" { - if defaultId := config.Identities[id]; defaultId != nil && defaultId.Username != "" && !o.IgnoreConfig { + if defaultId := config.EdgeIdentities[id]; defaultId != nil && defaultId.Username != "" && !o.IgnoreConfig { o.Username = defaultId.Username o.Printf("Using username: %v from identity '%v' in config file: %v\n", o.Username, id, configFile) } else if o.Username, err = term.Prompt("Enter username: "); err != nil { @@ -159,7 +160,7 @@ func (o *loginOptions) Run() error { body := container.String() - jsonParsed, err := util.EdgeControllerLogin(host, o.Cert, body, o.Out, o.OutputJSONResponse, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + jsonParsed, err := util.EdgeControllerLogin(host, o.CaCert, body, o.Out, o.OutputJSONResponse, o.Options.Timeout, o.Options.Verbose) if err != nil { return err @@ -181,22 +182,22 @@ func (o *loginOptions) Run() error { } } - absCertPath, err := filepath.Abs(o.Cert) + absCertPath, err := filepath.Abs(o.CaCert) if err == nil { - o.Cert = absCertPath + o.CaCert = absCertPath } - loginIdentity := &util.RestClientIdentity{ + loginIdentity := &util.RestClientEdgeIdentity{ Url: host, Username: o.Username, Token: o.Token, LoginTime: time.Now().Format(time.RFC3339), - Cert: o.Cert, + CaCert: o.CaCert, ReadOnly: o.ReadOnly, } o.Printf("Saving identity '%v' to %v\n", id, configFile) - config.Identities[id] = loginIdentity + config.EdgeIdentities[id] = loginIdentity err = util.PersistRestClientConfig(config) @@ -209,7 +210,7 @@ func (o *loginOptions) ConfigureCerts(host string, ctrlUrl *url.URL) error { return err } - if !isServerTrusted && o.Cert == "" { + if !isServerTrusted && o.CaCert == "" { wellKnownCerts, certs, err := util.GetWellKnownCerts(host) if err != nil { return errors.Wrapf(err, "unable to retrieve server certificate authority from %v", host) @@ -229,7 +230,7 @@ func (o *loginOptions) ConfigureCerts(host string, ctrlUrl *url.URL) error { } if savedCerts != nil { - o.Cert = certFile + o.CaCert = certFile if !util.AreCertsSame(o, wellKnownCerts, savedCerts) { o.Printf("WARNING: server supplied certificate authority doesn't match cached certs at %v\n", certFile) replace := o.Yes @@ -256,7 +257,7 @@ func (o *loginOptions) ConfigureCerts(host string, ctrlUrl *url.URL) error { } } if importCerts { - o.Cert, err = util.WriteCert(o, ctrlUrl.Hostname(), wellKnownCerts) + o.CaCert, err = util.WriteCert(o, ctrlUrl.Hostname(), wellKnownCerts) if err != nil { return err } @@ -264,13 +265,13 @@ func (o *loginOptions) ConfigureCerts(host string, ctrlUrl *url.URL) error { o.Println("WARNING: no certificate authority provided for server, continuing but login will likely fail") } } - } else if isServerTrusted && o.Cert != "" { + } else if isServerTrusted && o.CaCert != "" { override, err := o.askYesNo("Server certificate authority is already trusted. Are you sure you want to provide an additional CA [Y/N]: ") if err != nil { return err } if !override { - o.Cert = "" + o.CaCert = "" } } diff --git a/ziti/cmd/ziti/cmd/edge/logout.go b/ziti/cmd/ziti/cmd/edge/logout.go index 155476ca6..63c4710ed 100644 --- a/ziti/cmd/ziti/cmd/edge/logout.go +++ b/ziti/cmd/ziti/cmd/edge/logout.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -26,13 +27,13 @@ import ( // logoutOptions are the flags for logout commands type logoutOptions struct { - edgeOptions + api.Options } // newLogoutCmd creates the command func newLogoutCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &logoutOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -67,6 +68,6 @@ func (o *logoutOptions) Run() error { id := config.GetIdentity() o.Printf("Removing identity '%v' from %v\n", id, configFile) - delete(config.Identities, id) + delete(config.EdgeIdentities, id) return util.PersistRestClientConfig(config) } diff --git a/ziti/cmd/ziti/cmd/edge/policy_advisor.go b/ziti/cmd/ziti/cmd/edge/policy_advisor.go index ab8a4be71..932efa848 100644 --- a/ziti/cmd/ziti/cmd/edge/policy_advisor.go +++ b/ziti/cmd/ziti/cmd/edge/policy_advisor.go @@ -19,6 +19,7 @@ package edge import ( "fmt" "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -44,14 +45,14 @@ func newPolicyAdivsorCmd(out io.Writer, errOut io.Writer) *cobra.Command { } type policyAdvisorOptions struct { - edgeOptions + api.Options quiet bool } // newPolicyAdvisorIdentitiesCmd creates the 'edge controller policy-advisor identities' command func newPolicyAdvisorIdentitiesCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &policyAdvisorOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -80,7 +81,7 @@ func newPolicyAdvisorIdentitiesCmd(out io.Writer, errOut io.Writer) *cobra.Comma // newPolicyAdvisorServicesCmd creates the 'edge controller policy-advisor services' command func newPolicyAdvisorServicesCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &policyAdvisorOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -109,12 +110,12 @@ func newPolicyAdvisorServicesCmd(out io.Writer, errOut io.Writer) *cobra.Command // runIdentitiesPolicyAdvisor create a new policyAdvisor on the Ziti Edge Controller func runIdentitiesPolicyAdvisor(o *policyAdvisorOptions) error { if len(o.Args) > 0 { - identityId, err := mapNameToID("identities", o.Args[0], o.edgeOptions) + identityId, err := mapNameToID("identities", o.Args[0], o.Options) if err != nil { return err } if len(o.Args) > 1 { - serviceId, err := mapNameToID("services", o.Args[1], o.edgeOptions) + serviceId, err := mapNameToID("services", o.Args[1], o.Options) if err != nil { return err } @@ -139,13 +140,13 @@ func runIdentitiesPolicyAdvisor(o *policyAdvisorOptions) error { // runServicesPolicyAdvisor create a new policyAdvisor on the Ziti Edge Controller func runServicesPolicyAdvisor(o *policyAdvisorOptions) error { if len(o.Args) > 0 { - serviceId, err := mapNameToID("services", o.Args[0], o.edgeOptions) + serviceId, err := mapNameToID("services", o.Args[0], o.Options) if err != nil { return err } if len(o.Args) > 1 { - identityId, err := mapNameToID("identities", o.Args[1], o.edgeOptions) + identityId, err := mapNameToID("identities", o.Args[1], o.Options) if err != nil { return err } @@ -205,7 +206,7 @@ func runPolicyAdvisorForIdentities(o *policyAdvisorOptions) error { done := false for !done { filter := fmt.Sprintf(`true skip %v limit 2`, skip) - children, _, err := filterEntitiesOfType("identities", filter, false, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + children, _, err := filterEntitiesOfType("identities", filter, false, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil { panic(err) } @@ -235,7 +236,7 @@ func runPolicyAdvisorForServices(o *policyAdvisorOptions) error { done := false for !done { filter := fmt.Sprintf(`true skip %v limit 2`, skip) - children, _, err := filterEntitiesOfType("services", filter, false, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + children, _, err := filterEntitiesOfType("services", filter, false, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil { panic(err) } @@ -266,7 +267,7 @@ func runPolicyAdvisorForIdentity(identityId string, o *policyAdvisorOptions) err for !done { filter := "true limit 2" filter = fmt.Sprintf(`true skip %v limit 2`, skip) - children, _, err := filterSubEntitiesOfType("identities", "services", identityId, filter, &o.edgeOptions) + children, _, err := filterSubEntitiesOfType("identities", "services", identityId, filter, &o.Options) if err != nil { panic(err) } @@ -284,7 +285,7 @@ func runPolicyAdvisorForIdentity(identityId string, o *policyAdvisorOptions) err } if skip == 0 { - identityName, err := mapIdToName("identities", identityId, o.edgeOptions) + identityName, err := mapIdToName("identities", identityId, o.Options) if err != nil { return err } @@ -301,7 +302,7 @@ func runPolicyAdvisorForService(serviceId string, o *policyAdvisorOptions) error for !done { filter := "true limit 2" filter = fmt.Sprintf(`true skip %v limit 2`, skip) - children, _, err := filterSubEntitiesOfType("services", "identities", serviceId, filter, &o.edgeOptions) + children, _, err := filterSubEntitiesOfType("services", "identities", serviceId, filter, &o.Options) if err != nil { return err } @@ -319,7 +320,7 @@ func runPolicyAdvisorForService(serviceId string, o *policyAdvisorOptions) error } if skip == 0 { - serviceName, err := mapIdToName("services", serviceId, o.edgeOptions) + serviceName, err := mapIdToName("services", serviceId, o.Options) if err != nil { return err } @@ -331,7 +332,7 @@ func runPolicyAdvisorForService(serviceId string, o *policyAdvisorOptions) error } func runPolicyAdvisorForIdentityAndService(identityId, serviceId string, o *policyAdvisorOptions) error { - result, err := util.EdgeControllerList("identities/"+identityId+"/policy-advice/"+serviceId, nil, o.OutputJSONResponse, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + result, err := util.EdgeControllerList("identities/"+identityId+"/policy-advice/"+serviceId, nil, o.OutputJSONResponse, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil || o.OutputJSONResponse { return err } diff --git a/ziti/cmd/ziti/cmd/edge/root.go b/ziti/cmd/ziti/cmd/edge/root.go index 02e8cb14d..e34cc14ba 100644 --- a/ziti/cmd/ziti/cmd/edge/root.go +++ b/ziti/cmd/ziti/cmd/edge/root.go @@ -17,11 +17,9 @@ package edge import ( - "fmt" "github.com/openziti/ziti/common/enrollment" "io" - "github.com/Jeffail/gabs" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -35,49 +33,6 @@ func NewCmdEdge(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comma return cmd } -// edgeOptions are common options for edge controller commands -type edgeOptions struct { - common.CommonOptions - OutputJSONRequest bool - OutputJSONResponse bool -} - -func (options *edgeOptions) OutputRequestJson() bool { - return options.OutputJSONRequest -} - -func (options *edgeOptions) OutputResponseJson() bool { - return options.OutputJSONResponse -} - -func (options *edgeOptions) OutputWriter() io.Writer { - return options.CommonOptions.Out -} - -func (options *edgeOptions) ErrOutputWriter() io.Writer { - return options.CommonOptions.Err -} -func (options *edgeOptions) AddCommonFlags(cmd *cobra.Command) { - cmd.Flags().StringVarP(&common.CliIdentity, "cli-identity", "i", "", "Specify the saved identity you want the CLI to use when connect to the controller with") - cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller") - cmd.Flags().BoolVar(&options.OutputJSONRequest, "output-request-json", false, "Output the full JSON request to the Ziti Edge Controller") - cmd.Flags().IntVarP(&options.Timeout, "timeout", "", 5, "Timeout for REST operations (specified in seconds)") - cmd.Flags().BoolVarP(&options.Verbose, "verbose", "", false, "Enable verbose logging") -} - -func (options *edgeOptions) logCreateResult(entityType string, result *gabs.Container, err error) error { - if err != nil { - return err - } - - if !options.OutputJSONResponse { - id := result.S("data", "id").Data() - _, err = fmt.Fprintf(options.Out, "New %v %v created with id: %v\n", entityType, options.Args[0], id) - return err - } - return nil -} - func populateEdgeCommands(f cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Command) *cobra.Command { p := common.NewOptionsProvider(out, errOut) cmd.AddCommand(newCreateCmd(f, out, errOut)) @@ -97,9 +52,3 @@ func populateEdgeCommands(f cmdutil.Factory, out io.Writer, errOut io.Writer, cm cmd.AddCommand(newTraceRouteCmd(out, errOut)) return cmd } - -func setJSONValue(container *gabs.Container, value interface{}, path ...string) { - if _, err := container.Set(value, path...); err != nil { - panic(err) - } -} diff --git a/ziti/cmd/ziti/cmd/edge/trace_identity.go b/ziti/cmd/ziti/cmd/edge/trace_identity.go index 0d5063ea1..567df6a4a 100644 --- a/ziti/cmd/ziti/cmd/edge/trace_identity.go +++ b/ziti/cmd/ziti/cmd/edge/trace_identity.go @@ -19,6 +19,7 @@ package edge import ( "fmt" "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/spf13/cobra" @@ -26,7 +27,7 @@ import ( ) type traceIdentityOptions struct { - edgeOptions + api.Options disable bool duration string traceId string @@ -46,7 +47,7 @@ func newTraceCmd(out io.Writer, errOut io.Writer) *cobra.Command { func newTraceIdentityCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &traceIdentityOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -76,24 +77,24 @@ func newTraceIdentityCmd(out io.Writer, errOut io.Writer) *cobra.Command { } func runTraceIdentity(o *traceIdentityOptions) error { - id, err := mapNameToID("identities", o.Args[0], o.edgeOptions) + id, err := mapNameToID("identities", o.Args[0], o.Options) if err != nil { return err } entityData := gabs.New() - setJSONValue(entityData, !o.disable, "enabled") - setJSONValue(entityData, o.duration, "duration") + api.SetJSONValue(entityData, !o.disable, "enabled") + api.SetJSONValue(entityData, o.duration, "duration") if o.traceId != "" { - setJSONValue(entityData, o.traceId, "traceId") + api.SetJSONValue(entityData, o.traceId, "traceId") } if len(o.Args) > 1 { - setJSONValue(entityData, o.Args[1:], "channels") + api.SetJSONValue(entityData, o.Args[1:], "channels") } - result, err := putEntityOfType("identities/"+id+"/trace", entityData.String(), &o.edgeOptions) + result, err := putEntityOfType("identities/"+id+"/trace", entityData.String(), &o.Options) if err != nil { return err diff --git a/ziti/cmd/ziti/cmd/edge/traceroute.go b/ziti/cmd/ziti/cmd/edge/traceroute.go index 23e6450cb..3d370d3bf 100644 --- a/ziti/cmd/ziti/cmd/edge/traceroute.go +++ b/ziti/cmd/ziti/cmd/edge/traceroute.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/sirupsen/logrus" @@ -14,7 +15,7 @@ import ( ) type traceRouteOptions struct { - edgeOptions + api.Options skipIntermediate bool hops uint8 configFile string @@ -23,7 +24,7 @@ type traceRouteOptions struct { func newTraceRouteCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &traceRouteOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -98,7 +99,7 @@ func (o *traceRouteOptions) Run() error { hopLabel := result.HopId if result.HopType == "forwarder" { - hopLabel, err = mapIdToName("transit-routers", result.HopId, o.edgeOptions) + hopLabel, err = mapIdToName("transit-routers", result.HopId, o.Options) if err != nil { hopLabel = result.HopId routerNameLookupsFailed = true diff --git a/ziti/cmd/ziti/cmd/edge/tutorial.go b/ziti/cmd/ziti/cmd/edge/tutorial.go index 0dfbbde94..b0a1272cd 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial.go +++ b/ziti/cmd/ziti/cmd/edge/tutorial.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/fatih/color" "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/tutorial" @@ -61,13 +62,13 @@ type tutorialOptions struct { } type firstServiceTutorialOptions struct { - edgeOptions + api.Options tutorialOptions } func newFirstServiceTutorialCmd(p common.OptionsProvider) *cobra.Command { options := &firstServiceTutorialOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: p(), }, } diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go b/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go index e90f33047..bc8a06006 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go +++ b/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_client_cmd.go @@ -7,7 +7,7 @@ import ( "strings" ) -// edgeOptions are common options for edge controller commands +// Options are common options for edge controller commands type plainEchoClientOptions struct { common.CommonOptions port uint16 diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go b/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go index 0b4d1f4cc..c598c59c9 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go +++ b/ziti/cmd/ziti/cmd/edge/tutorial_plain_echo_server_cmd.go @@ -7,7 +7,7 @@ import ( "time" ) -// edgeOptions are common options for edge controller commands +// Options are common options for edge controller commands type plainEchoServerOptions struct { common.CommonOptions port uint16 diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go b/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go index cc029e025..0d9b51aef 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go +++ b/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_client_cmd.go @@ -8,7 +8,7 @@ import ( "strings" ) -// edgeOptions are common options for edge controller commands +// Options are common options for edge controller commands type zitiEchoClientOptions struct { common.CommonOptions identity string diff --git a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go b/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go index 667cbfa4b..d2b5908b8 100644 --- a/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go +++ b/ziti/cmd/ziti/cmd/edge/tutorial_ziti_echo_server_cmd.go @@ -7,7 +7,7 @@ import ( "time" ) -// edgeOptions are common options for edge controller commands +// Options are common options for edge controller commands type zitiEchoServerOptions struct { common.CommonOptions identity string diff --git a/ziti/cmd/ziti/cmd/edge/update.go b/ziti/cmd/ziti/cmd/edge/update.go index 1eb3ea0f4..743964ad0 100644 --- a/ziti/cmd/ziti/cmd/edge/update.go +++ b/ziti/cmd/ziti/cmd/edge/update.go @@ -18,6 +18,7 @@ package edge import ( "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -54,27 +55,27 @@ func newUpdateCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com return cmd } -func putEntityOfType(entityType string, body string, options *edgeOptions) (*gabs.Container, error) { +func putEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { return updateEntityOfType(entityType, body, options, resty.MethodPut) } -func patchEntityOfType(entityType string, body string, options *edgeOptions) (*gabs.Container, error) { +func patchEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { return updateEntityOfType(entityType, body, options, resty.MethodPatch) } -func postEntityOfType(entityType string, body string, options *edgeOptions) (*gabs.Container, error) { +func postEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { return updateEntityOfType(entityType, body, options, resty.MethodPost) } -func deleteEntityOfTypeWithBody(entityType string, body string, options *edgeOptions) (*gabs.Container, error) { +func deleteEntityOfTypeWithBody(entityType string, body string, options *api.Options) (*gabs.Container, error) { return updateEntityOfType(entityType, body, options, resty.MethodDelete) } // updateEntityOfType updates an entity of the given type on the Ziti Edge Controller -func updateEntityOfType(entityType string, body string, options *edgeOptions, method string) (*gabs.Container, error) { - return util.EdgeControllerUpdate(entityType, body, options.Out, method, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) +func updateEntityOfType(entityType string, body string, options *api.Options, method string) (*gabs.Container, error) { + return util.ControllerUpdate(util.EdgeAPI, entityType, body, options.Out, method, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) } -func doRequest(entityType string, options *edgeOptions, doRequest func(request *resty.Request, url string) (*resty.Response, error)) (*gabs.Container, error) { +func doRequest(entityType string, options *api.Options, doRequest func(request *resty.Request, url string) (*resty.Response, error)) (*gabs.Container, error) { return util.EdgeControllerRequest(entityType, options.Out, options.OutputJSONResponse, options.Timeout, options.Verbose, doRequest) } diff --git a/ziti/cmd/ziti/cmd/edge/update_authenticator.go b/ziti/cmd/ziti/cmd/edge/update_authenticator.go index ebc8f6250..59d0379ce 100644 --- a/ziti/cmd/ziti/cmd/edge/update_authenticator.go +++ b/ziti/cmd/ziti/cmd/edge/update_authenticator.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" "github.com/spf13/cobra" @@ -25,7 +26,7 @@ import ( // newUpdateAuthenticatorCmd creates the 'edge controller update authenticator' command func newUpdateAuthenticatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := edgeOptions{ + options := api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, OutputJSONResponse: false, } diff --git a/ziti/cmd/ziti/cmd/edge/update_authenticator_updb.go b/ziti/cmd/ziti/cmd/edge/update_authenticator_updb.go index 4d2693d7a..2ac9d2565 100644 --- a/ziti/cmd/ziti/cmd/edge/update_authenticator_updb.go +++ b/ziti/cmd/ziti/cmd/edge/update_authenticator_updb.go @@ -23,13 +23,14 @@ import ( "github.com/Jeffail/gabs" "github.com/openziti/edge/rest_management_api_client/authenticator" "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/util" "github.com/spf13/cobra" ) import cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" type updateUpdbOptions struct { - edgeOptions + api.Options identity string newPassword string currentPassword string @@ -37,9 +38,9 @@ type updateUpdbOptions struct { self bool } -func newUpdateAuthenticatorUpdb(idType string, options edgeOptions) *cobra.Command { +func newUpdateAuthenticatorUpdb(idType string, options api.Options) *cobra.Command { updbOptions := updateUpdbOptions{ - edgeOptions: options, + Options: options, } cmd := &cobra.Command{ Use: idType + " (--identity -p ) | (-c -n )", @@ -74,17 +75,17 @@ func runUpdateUpdbPassword(idType string, options *updateUpdbOptions) error { } if options.identity != "" { - return setIdentityPassword(options.identity, options.identityPassword, options.edgeOptions) + return setIdentityPassword(options.identity, options.identityPassword, options.Options) } if options.self { - return updateSelfPassword(options.currentPassword, options.newPassword, options.edgeOptions) + return updateSelfPassword(options.currentPassword, options.newPassword, options.Options) } return errors.New("invalid arguments, requires --self or --identity, see help for details") } -func updateSelfPassword(current string, new string, options edgeOptions) error { +func updateSelfPassword(current string, new string, options api.Options) error { var err error if current == "" { if current, err = term.PromptPassword("Enter your current password: ", false); err != nil { @@ -99,8 +100,8 @@ func updateSelfPassword(current string, new string, options edgeOptions) error { } passwordData := gabs.New() - setJSONValue(passwordData, current, "currentPassword") - setJSONValue(passwordData, new, "password") + api.SetJSONValue(passwordData, current, "currentPassword") + api.SetJSONValue(passwordData, new, "password") respEnvelope, err := util.EdgeControllerList("current-identity/authenticators", map[string][]string{"filter": {`method="updb"`}}, options.OutputJSONResponse, options.Out, options.Timeout, options.Verbose) @@ -129,7 +130,7 @@ func updateSelfPassword(current string, new string, options edgeOptions) error { return nil } -func setIdentityPassword(identity, password string, options edgeOptions) error { +func setIdentityPassword(identity, password string, options api.Options) error { id, err := mapIdentityNameToID(identity, options) if err != nil { @@ -182,7 +183,7 @@ func setIdentityPassword(identity, password string, options edgeOptions) error { } passwordData := gabs.New() - setJSONValue(passwordData, password, "password") + api.SetJSONValue(passwordData, password, "password") _, err = patchEntityOfType(fmt.Sprintf("authenticators/%s", *authenticatorId), passwordData.String(), &options) diff --git a/ziti/cmd/ziti/cmd/edge/update_ca.go b/ziti/cmd/ziti/cmd/edge/update_ca.go index c35664fcd..94bc27d2c 100644 --- a/ziti/cmd/ziti/cmd/edge/update_ca.go +++ b/ziti/cmd/ziti/cmd/edge/update_ca.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/openziti/edge/rest_management_api_client/certificate_authority" "github.com/openziti/edge/rest_model" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -32,7 +33,7 @@ import ( ) type updateCaOptions struct { - edgeOptions + api.Options verify bool verifyCertPath string verifyCertBytes []byte @@ -48,7 +49,7 @@ type updateCaOptions struct { // newUpdateAuthenticatorCmd creates the 'edge controller update authenticator' command func newUpdateCaCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := updateCaOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, OutputJSONResponse: false, }, @@ -115,7 +116,7 @@ func runUpdateCa(options updateCaOptions) error { return runVerifyCa(options) } - id, err := mapCaNameToID(options.nameOrId, options.edgeOptions) + id, err := mapCaNameToID(options.nameOrId, options.Options) if err != nil { return err @@ -181,13 +182,13 @@ func runUpdateCa(options updateCaOptions) error { } func runVerifyCa(options updateCaOptions) error { - id, err := mapCaNameToID(options.nameOrId, options.edgeOptions) + id, err := mapCaNameToID(options.nameOrId, options.Options) if err != nil { return err } - _, err = doRequest("cas/"+id+"/verify", &options.edgeOptions, func(request *resty.Request, url string) (response *resty.Response, e error) { + _, err = doRequest("cas/"+id+"/verify", &options.Options, func(request *resty.Request, url string) (response *resty.Response, e error) { return request.SetHeader("Content-Type", "text/plain"). SetBody(string(options.verifyCertBytes)). Post(url) diff --git a/ziti/cmd/ziti/cmd/edge/update_config.go b/ziti/cmd/ziti/cmd/edge/update_config.go index d27679c73..44697adae 100644 --- a/ziti/cmd/ziti/cmd/edge/update_config.go +++ b/ziti/cmd/ziti/cmd/edge/update_config.go @@ -19,6 +19,7 @@ package edge import ( "encoding/json" "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "io/ioutil" @@ -32,7 +33,7 @@ import ( ) type updateConfigOptions struct { - edgeOptions + api.Options name string data string jsonFile string @@ -41,7 +42,7 @@ type updateConfigOptions struct { // newUpdateConfigCmd updates the 'edge controller update service-policy' command func newUpdateConfigCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateConfigOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -72,7 +73,7 @@ func newUpdateConfigCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cob // runUpdateConfig update a new config on the Ziti Edge Controller func runUpdateConfig(o *updateConfigOptions) error { - id, err := mapNameToID("configs", o.Args[0], o.edgeOptions) + id, err := mapNameToID("configs", o.Args[0], o.Options) if err != nil { return err } @@ -80,7 +81,7 @@ func runUpdateConfig(o *updateConfigOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } @@ -107,7 +108,7 @@ func runUpdateConfig(o *updateConfigOptions) error { fmt.Printf("Failing parsing JSON: %+v\n", err) return errors.Errorf("unable to parse data as json: %v", err) } - setJSONValue(entityData, dataMap, "data") + api.SetJSONValue(entityData, dataMap, "data") change = true } @@ -115,7 +116,7 @@ func runUpdateConfig(o *updateConfigOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("configs/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("configs/%v", id), entityData.String(), &o.Options) if err != nil { panic(err) diff --git a/ziti/cmd/ziti/cmd/edge/update_edge_router.go b/ziti/cmd/ziti/cmd/edge/update_edge_router.go index 1b74fd965..0acf9c13b 100644 --- a/ziti/cmd/ziti/cmd/edge/update_edge_router.go +++ b/ziti/cmd/ziti/cmd/edge/update_edge_router.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/pkg/errors" @@ -30,7 +31,7 @@ import ( ) type updateEdgeRouterOptions struct { - edgeOptions + api.Options name string isTunnelerEnabled bool roleAttributes []string @@ -41,7 +42,7 @@ type updateEdgeRouterOptions struct { func newUpdateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateEdgeRouterOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -78,7 +79,7 @@ func newUpdateEdgeRouterCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) // runUpdateEdgeRouter update a new edgeRouter on the Ziti Edge Controller func runUpdateEdgeRouter(o *updateEdgeRouterOptions) error { - id, err := mapNameToID("edge-routers", o.Args[0], o.edgeOptions) + id, err := mapNameToID("edge-routers", o.Args[0], o.Options) if err != nil { return err } @@ -86,27 +87,27 @@ func runUpdateEdgeRouter(o *updateEdgeRouterOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("tunneler-enabled") { - setJSONValue(entityData, o.isTunnelerEnabled, "isTunnelerEnabled") + api.SetJSONValue(entityData, o.isTunnelerEnabled, "isTunnelerEnabled") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } if o.Cmd.Flags().Changed("tags") { - setJSONValue(entityData, o.tags, "tags") + api.SetJSONValue(entityData, o.tags, "tags") change = true } if o.Cmd.Flags().Changed("app-data") { - setJSONValue(entityData, o.appData, "appData") + api.SetJSONValue(entityData, o.appData, "appData") change = true } @@ -115,9 +116,9 @@ func runUpdateEdgeRouter(o *updateEdgeRouterOptions) error { } if o.usePut { - _, err = putEntityOfType(fmt.Sprintf("edge-routers/%v", id), entityData.String(), &o.edgeOptions) + _, err = putEntityOfType(fmt.Sprintf("edge-routers/%v", id), entityData.String(), &o.Options) } else { - _, err = patchEntityOfType(fmt.Sprintf("edge-routers/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("edge-routers/%v", id), entityData.String(), &o.Options) } return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_edge_router_policy.go b/ziti/cmd/ziti/cmd/edge/update_edge_router_policy.go index 59754d855..6812e92cd 100644 --- a/ziti/cmd/ziti/cmd/edge/update_edge_router_policy.go +++ b/ziti/cmd/ziti/cmd/edge/update_edge_router_policy.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/pkg/errors" @@ -30,7 +31,7 @@ import ( ) type updateEdgeRouterPolicyOptions struct { - edgeOptions + api.Options name string edgeRouterRoles []string identityRoles []string @@ -38,7 +39,7 @@ type updateEdgeRouterPolicyOptions struct { func newUpdateEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateEdgeRouterPolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -69,17 +70,17 @@ func newUpdateEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Wr } func runUpdateEdgeRouterPolicy(o *updateEdgeRouterPolicyOptions) error { - id, err := mapNameToID("edge-router-policies", o.Args[0], o.edgeOptions) + id, err := mapNameToID("edge-router-policies", o.Args[0], o.Options) if err != nil { return err } - edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.edgeOptions) + edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.Options) if err != nil { return err } - identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.edgeOptions) + identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.Options) if err != nil { return err } @@ -88,17 +89,17 @@ func runUpdateEdgeRouterPolicy(o *updateEdgeRouterPolicyOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("edge-router-roles") { - setJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") + api.SetJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") change = true } if o.Cmd.Flags().Changed("identity-roles") { - setJSONValue(entityData, identityRoles, "identityRoles") + api.SetJSONValue(entityData, identityRoles, "identityRoles") change = true } @@ -106,6 +107,6 @@ func runUpdateEdgeRouterPolicy(o *updateEdgeRouterPolicyOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("edge-router-policies/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("edge-router-policies/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_identity.go b/ziti/cmd/ziti/cmd/edge/update_identity.go index 273a1927b..f45e4c04d 100644 --- a/ziti/cmd/ziti/cmd/edge/update_identity.go +++ b/ziti/cmd/ziti/cmd/edge/update_identity.go @@ -19,6 +19,7 @@ package edge import ( "fmt" "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "math" "strings" @@ -33,7 +34,7 @@ import ( ) type updateIdentityOptions struct { - edgeOptions + api.Options name string roleAttributes []string defaultHostingPrecedence string @@ -46,7 +47,7 @@ type updateIdentityOptions struct { func newUpdateIdentityCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateIdentityOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -83,7 +84,7 @@ func newUpdateIdentityCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *c // runUpdateIdentity update a new identity on the Ziti Edge Controller func runUpdateIdentity(o *updateIdentityOptions) error { - id, err := mapNameToID("identities", o.Args[0], o.edgeOptions) + id, err := mapNameToID("identities", o.Args[0], o.Options) if err != nil { return err } @@ -91,17 +92,17 @@ func runUpdateIdentity(o *updateIdentityOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } if o.Cmd.Flags().Changed("default-hosting-cost") { - setJSONValue(entityData, o.defaultHostingCost, "defaultHostingCost") + api.SetJSONValue(entityData, o.defaultHostingCost, "defaultHostingCost") change = true } @@ -110,7 +111,7 @@ func runUpdateIdentity(o *updateIdentityOptions) error { if err != nil { return err } - setJSONValue(entityData, prec, "defaultHostingPrecedence") + api.SetJSONValue(entityData, prec, "defaultHostingPrecedence") change = true } @@ -119,20 +120,20 @@ func runUpdateIdentity(o *updateIdentityOptions) error { if v < 0 || v > math.MaxUint16 { return errors.Errorf("hosting costs must be in the range %v-%v", 0, math.MaxUint16) } - id, err := mapNameToID("services", k, o.edgeOptions) + id, err := mapNameToID("services", k, o.Options) if err != nil { return err } delete(o.serviceCosts, k) o.serviceCosts[id] = v } - setJSONValue(entityData, o.serviceCosts, "serviceHostingCosts") + api.SetJSONValue(entityData, o.serviceCosts, "serviceHostingCosts") change = true } if o.Cmd.Flags().Changed("service-precedences") { for k, v := range o.servicePrecedences { - id, err := mapNameToID("services", k, o.edgeOptions) + id, err := mapNameToID("services", k, o.Options) if err != nil { return err } @@ -145,17 +146,17 @@ func runUpdateIdentity(o *updateIdentityOptions) error { delete(o.servicePrecedences, k) o.servicePrecedences[id] = prec } - setJSONValue(entityData, o.servicePrecedences, "serviceHostingPrecedences") + api.SetJSONValue(entityData, o.servicePrecedences, "serviceHostingPrecedences") change = true } if o.Cmd.Flags().Changed("tags") { - setJSONValue(entityData, o.tags, "tags") + api.SetJSONValue(entityData, o.tags, "tags") change = true } if o.Cmd.Flags().Changed("app-data") { - setJSONValue(entityData, o.appData, "appData") + api.SetJSONValue(entityData, o.appData, "appData") change = true } @@ -163,7 +164,7 @@ func runUpdateIdentity(o *updateIdentityOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("identities/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("identities/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_identity_configs.go b/ziti/cmd/ziti/cmd/edge/update_identity_configs.go index ffe3fbd6c..345ddce9a 100644 --- a/ziti/cmd/ziti/cmd/edge/update_identity_configs.go +++ b/ziti/cmd/ziti/cmd/edge/update_identity_configs.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/Jeffail/gabs" @@ -28,13 +29,13 @@ import ( ) type updateIdentityConfigsOptions struct { - edgeOptions + api.Options remove bool } func newUpdateIdentityConfigsCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateIdentityConfigsOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -63,17 +64,17 @@ func newUpdateIdentityConfigsCmd(f cmdutil.Factory, out io.Writer, errOut io.Wri // runupdateIdentityConfigs update a new identity on the Ziti Edge Controller func runupdateIdentityConfigs(o *updateIdentityConfigsOptions) error { - id, err := mapNameToID("identities", o.Args[0], o.edgeOptions) + id, err := mapNameToID("identities", o.Args[0], o.Options) if err != nil { return err } - serviceId, err := mapNameToID("services", o.Args[1], o.edgeOptions) + serviceId, err := mapNameToID("services", o.Args[1], o.Options) if err != nil { return err } - configId, err := mapNameToID("configs", o.Args[2], o.edgeOptions) + configId, err := mapNameToID("configs", o.Args[2], o.Options) if err != nil { return err } @@ -89,9 +90,9 @@ func runupdateIdentityConfigs(o *updateIdentityConfigsOptions) error { body := entityData.String() if o.remove { - _, err = deleteEntityOfTypeWithBody(path, body, &o.edgeOptions) + _, err = deleteEntityOfTypeWithBody(path, body, &o.Options) } else { - _, err = postEntityOfType(path, body, &o.edgeOptions) + _, err = postEntityOfType(path, body, &o.Options) } return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_posture_check.go b/ziti/cmd/ziti/cmd/edge/update_posture_check.go index 7d9387357..6b4e2dc7b 100644 --- a/ziti/cmd/ziti/cmd/edge/update_posture_check.go +++ b/ziti/cmd/ziti/cmd/edge/update_posture_check.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "io" @@ -44,7 +45,7 @@ func newUpdatePostureCheckCmd(out io.Writer, errOut io.Writer) *cobra.Command { } type updatePostureCheckOptions struct { - edgeOptions + api.Options name string tags map[string]string roleAttributes []string @@ -84,7 +85,7 @@ type updatePostureCheckOsOptions struct { func newUpdatePostureCheckMacCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &updatePostureCheckMacOptions{ updatePostureCheckOptions: updatePostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, }, @@ -117,7 +118,7 @@ func newUpdatePostureCheckMacCmd(out io.Writer, errOut io.Writer) *cobra.Command // runUpdatePostureCheckMac update a new identity on the Ziti Edge Controller func runUpdatePostureCheckMac(o *updatePostureCheckMacOptions) error { - id, err := mapNameToID("posture-checks", o.Args[0], o.edgeOptions) + id, err := mapNameToID("posture-checks", o.Args[0], o.Options) if err != nil { return err } @@ -125,17 +126,17 @@ func runUpdatePostureCheckMac(o *updatePostureCheckMacOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } if o.Cmd.Flags().Changed("mac-addresses") { - setJSONValue(entityData, o.addresses, "macAddresses") + api.SetJSONValue(entityData, o.addresses, "macAddresses") change = true } @@ -143,16 +144,16 @@ func runUpdatePostureCheckMac(o *updatePostureCheckMacOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - setJSONValue(entityData, PostureCheckTypeMAC, "typeId") + api.SetJSONValue(entityData, PostureCheckTypeMAC, "typeId") - _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.Options) return err } func newUpdatePostureCheckDomainCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &updatePostureCheckDomainOptions{ updatePostureCheckOptions: updatePostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, }, @@ -186,7 +187,7 @@ func newUpdatePostureCheckDomainCmd(out io.Writer, errOut io.Writer) *cobra.Comm func newUpdatePostureCheckMfaCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &updatePostureCheckMfaOptions{ updatePostureCheckOptions: updatePostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, }, @@ -229,7 +230,7 @@ func newUpdatePostureCheckMfaCmd(out io.Writer, errOut io.Writer) *cobra.Command } func runUpdatePostureCheckMfa(o *updatePostureCheckMfaOptions) error { - id, err := mapNameToID("posture-checks", o.Args[0], o.edgeOptions) + id, err := mapNameToID("posture-checks", o.Args[0], o.Options) if err != nil { return err } @@ -237,47 +238,47 @@ func runUpdatePostureCheckMfa(o *updatePostureCheckMfaOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("seconds") { - setJSONValue(entityData, o.timeoutSeconds, "timeoutSeconds") + api.SetJSONValue(entityData, o.timeoutSeconds, "timeoutSeconds") change = true } if o.Cmd.Flags().Changed("wake") { - setJSONValue(entityData, o.promptOnWake, "promptOnWake") + api.SetJSONValue(entityData, o.promptOnWake, "promptOnWake") change = true } if o.Cmd.Flags().Changed("no-wake") { - setJSONValue(entityData, false, "promptOnWake") + api.SetJSONValue(entityData, false, "promptOnWake") change = true } if o.Cmd.Flags().Changed("unlock") { - setJSONValue(entityData, o.promptOnUnlock, "promptOnUnlock") + api.SetJSONValue(entityData, o.promptOnUnlock, "promptOnUnlock") change = true } if o.Cmd.Flags().Changed("no-unlock") { - setJSONValue(entityData, false, "promptOnUnlock") + api.SetJSONValue(entityData, false, "promptOnUnlock") change = true } if o.Cmd.Flags().Changed("ignore-legacy") { - setJSONValue(entityData, o.ignoreLegacyEndpoints, "ignoreLegacyEndpoints") + api.SetJSONValue(entityData, o.ignoreLegacyEndpoints, "ignoreLegacyEndpoints") change = true } if o.Cmd.Flags().Changed("no-ignore-legacy") { - setJSONValue(entityData, false, "ignoreLegacyEndpoints") + api.SetJSONValue(entityData, false, "ignoreLegacyEndpoints") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } @@ -285,15 +286,15 @@ func runUpdatePostureCheckMfa(o *updatePostureCheckMfaOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - setJSONValue(entityData, PostureCheckTypeMFA, "typeId") + api.SetJSONValue(entityData, PostureCheckTypeMFA, "typeId") - _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.Options) return err } // runUpdatePostureCheckDomain update a new identity on the Ziti Edge Controller func runUpdatePostureCheckDomain(o *updatePostureCheckDomainOptions) error { - id, err := mapNameToID("posture-checks", o.Args[0], o.edgeOptions) + id, err := mapNameToID("posture-checks", o.Args[0], o.Options) if err != nil { return err } @@ -301,12 +302,12 @@ func runUpdatePostureCheckDomain(o *updatePostureCheckDomainOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } @@ -315,7 +316,7 @@ func runUpdatePostureCheckDomain(o *updatePostureCheckDomainOptions) error { return fmt.Errorf("must specify at least one domain, multiple values may be separated by commas") } - setJSONValue(entityData, o.domains, "domains") + api.SetJSONValue(entityData, o.domains, "domains") change = true } @@ -323,9 +324,9 @@ func runUpdatePostureCheckDomain(o *updatePostureCheckDomainOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - setJSONValue(entityData, PostureCheckTypeDomain, "typeId") + api.SetJSONValue(entityData, PostureCheckTypeDomain, "typeId") - _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.Options) return err } @@ -334,7 +335,7 @@ func runUpdatePostureCheckDomain(o *updatePostureCheckDomainOptions) error { func newUpdatePostureCheckProcessCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &updatePostureCheckProcessOptions{ updatePostureCheckOptions: updatePostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, }, @@ -372,7 +373,7 @@ func newUpdatePostureCheckProcessCmd(out io.Writer, errOut io.Writer) *cobra.Com // runUpdatePostureCheckProcess update a new identity on the Ziti Edge Controller func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { - id, err := mapNameToID("posture-checks", o.Args[0], o.edgeOptions) + id, err := mapNameToID("posture-checks", o.Args[0], o.Options) if err != nil { return err } @@ -380,17 +381,17 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } if o.Cmd.Flags().Changed("path") { - setJSONValue(entityData, o.path, "process", "path") + api.SetJSONValue(entityData, o.path, "process", "path") change = true } @@ -401,7 +402,7 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { return err } - setJSONValue(entityData, o.hashes, "process", "hashes") + api.SetJSONValue(entityData, o.hashes, "process", "hashes") change = true } @@ -412,7 +413,7 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { return err } - setJSONValue(entityData, o.signer, "process", "signerFingerprint") + api.SetJSONValue(entityData, o.signer, "process", "signerFingerprint") change = true } @@ -423,7 +424,7 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { return fmt.Errorf("invalid os type [%s]: expected %s|%s|%s|%s", o.os, OsLinux, OsMacOs, OsWindows, OsWindowsServer) } - setJSONValue(entityData, o.os, "process", "osType") + api.SetJSONValue(entityData, o.os, "process", "osType") change = true } @@ -431,9 +432,9 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - setJSONValue(entityData, PostureCheckTypeProcess, "typeId") + api.SetJSONValue(entityData, PostureCheckTypeProcess, "typeId") - _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.Options) return err } @@ -441,7 +442,7 @@ func runUpdatePostureCheckProcess(o *updatePostureCheckProcessOptions) error { func newUpdatePostureCheckOsCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &updatePostureCheckOsOptions{ updatePostureCheckOptions: updatePostureCheckOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, }, @@ -474,7 +475,7 @@ func newUpdatePostureCheckOsCmd(out io.Writer, errOut io.Writer) *cobra.Command // runUpdatePostureCheckOs update a new identity on the Ziti Edge Controller func runUpdatePostureCheckOs(o *updatePostureCheckOsOptions) error { - id, err := mapNameToID("posture-checks", o.Args[0], o.edgeOptions) + id, err := mapNameToID("posture-checks", o.Args[0], o.Options) if err != nil { return err } @@ -482,12 +483,12 @@ func runUpdatePostureCheckOs(o *updatePostureCheckOsOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } @@ -500,7 +501,7 @@ func runUpdatePostureCheckOs(o *updatePostureCheckOsOptions) error { oses = append(oses, osSpec) } } - setJSONValue(entityData, oses, "operatingSystems") + api.SetJSONValue(entityData, oses, "operatingSystems") change = true } @@ -508,8 +509,8 @@ func runUpdatePostureCheckOs(o *updatePostureCheckOsOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - setJSONValue(entityData, PostureCheckTypeOS, "typeId") + api.SetJSONValue(entityData, PostureCheckTypeOS, "typeId") - _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("posture-checks/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_service.go b/ziti/cmd/ziti/cmd/edge/update_service.go index 6d611d9d4..12c4eb4d0 100644 --- a/ziti/cmd/ziti/cmd/edge/update_service.go +++ b/ziti/cmd/ziti/cmd/edge/update_service.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/pkg/errors" @@ -30,7 +31,7 @@ import ( ) type updateServiceOptions struct { - edgeOptions + api.Options name string terminatorStrategy string roleAttributes []string @@ -40,7 +41,7 @@ type updateServiceOptions struct { func newUpdateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateServiceOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -75,7 +76,7 @@ func newUpdateServiceCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *co // runUpdateService update a new service on the Ziti Edge Controller func runUpdateService(o *updateServiceOptions) error { - id, err := mapNameToID("services", o.Args[0], o.edgeOptions) + id, err := mapNameToID("services", o.Args[0], o.Options) if err != nil { return err } @@ -83,31 +84,31 @@ func runUpdateService(o *updateServiceOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("role-attributes") { - setJSONValue(entityData, o.roleAttributes, "roleAttributes") + api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") change = true } if o.Cmd.Flags().Changed("terminator-strategy") { - setJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") + api.SetJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") change = true } if o.Cmd.Flags().Changed("encryption") { - setJSONValue(entityData, o.encryption.Get(), "encryptionRequired") + api.SetJSONValue(entityData, o.encryption.Get(), "encryptionRequired") change = true } if o.Cmd.Flags().Changed("configs") { - configs, err := mapNamesToIDs("configs", o.edgeOptions, o.configs...) + configs, err := mapNamesToIDs("configs", o.Options, o.configs...) if err != nil { return err } - setJSONValue(entityData, configs, "configs") + api.SetJSONValue(entityData, configs, "configs") change = true } @@ -115,6 +116,6 @@ func runUpdateService(o *updateServiceOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("services/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("services/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_service_edge_router_policy.go b/ziti/cmd/ziti/cmd/edge/update_service_edge_router_policy.go index b5a4a248b..a2376dd94 100644 --- a/ziti/cmd/ziti/cmd/edge/update_service_edge_router_policy.go +++ b/ziti/cmd/ziti/cmd/edge/update_service_edge_router_policy.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/pkg/errors" @@ -30,7 +31,7 @@ import ( ) type updateServiceEdgeRouterPolicyOptions struct { - edgeOptions + api.Options name string edgeRouterRoles []string serviceRoles []string @@ -38,7 +39,7 @@ type updateServiceEdgeRouterPolicyOptions struct { func newUpdateServiceEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateServiceEdgeRouterPolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -69,17 +70,17 @@ func newUpdateServiceEdgeRouterPolicyCmd(f cmdutil.Factory, out io.Writer, errOu } func runUpdateServiceEdgeRouterPolicy(o *updateServiceEdgeRouterPolicyOptions) error { - id, err := mapNameToID("service-edge-router-policies", o.Args[0], o.edgeOptions) + id, err := mapNameToID("service-edge-router-policies", o.Args[0], o.Options) if err != nil { return err } - edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.edgeOptions) + edgeRouterRoles, err := convertNamesToIds(o.edgeRouterRoles, "edge-routers", o.Options) if err != nil { return err } - serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.edgeOptions) + serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.Options) if err != nil { return err } @@ -88,17 +89,17 @@ func runUpdateServiceEdgeRouterPolicy(o *updateServiceEdgeRouterPolicyOptions) e change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("edge-router-roles") { - setJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") + api.SetJSONValue(entityData, edgeRouterRoles, "edgeRouterRoles") change = true } if o.Cmd.Flags().Changed("service-roles") { - setJSONValue(entityData, serviceRoles, "serviceRoles") + api.SetJSONValue(entityData, serviceRoles, "serviceRoles") change = true } @@ -106,6 +107,6 @@ func runUpdateServiceEdgeRouterPolicy(o *updateServiceEdgeRouterPolicyOptions) e return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("service-edge-router-policies/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("service-edge-router-policies/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_service_policy.go b/ziti/cmd/ziti/cmd/edge/update_service_policy.go index 3837b4d27..2190dd72c 100644 --- a/ziti/cmd/ziti/cmd/edge/update_service_policy.go +++ b/ziti/cmd/ziti/cmd/edge/update_service_policy.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" "github.com/pkg/errors" @@ -30,7 +31,7 @@ import ( ) type updateServicePolicyOptions struct { - edgeOptions + api.Options name string serviceRoles []string identityRoles []string @@ -39,7 +40,7 @@ type updateServicePolicyOptions struct { func newUpdateServicePolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateServicePolicyOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut}, }, } @@ -71,22 +72,22 @@ func newUpdateServicePolicyCmd(f cmdutil.Factory, out io.Writer, errOut io.Write } func runUpdateServicePolicy(o *updateServicePolicyOptions) error { - id, err := mapNameToID("service-policies", o.Args[0], o.edgeOptions) + id, err := mapNameToID("service-policies", o.Args[0], o.Options) if err != nil { return err } - serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.edgeOptions) + serviceRoles, err := convertNamesToIds(o.serviceRoles, "services", o.Options) if err != nil { return err } - identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.edgeOptions) + identityRoles, err := convertNamesToIds(o.identityRoles, "identities", o.Options) if err != nil { return err } - postureCheckRoles, err := convertNamesToIds(o.postureCheckRoles, "posture-checks", o.edgeOptions) + postureCheckRoles, err := convertNamesToIds(o.postureCheckRoles, "posture-checks", o.Options) if err != nil { return err } @@ -95,22 +96,22 @@ func runUpdateServicePolicy(o *updateServicePolicyOptions) error { change := false if o.Cmd.Flags().Changed("name") { - setJSONValue(entityData, o.name, "name") + api.SetJSONValue(entityData, o.name, "name") change = true } if o.Cmd.Flags().Changed("service-roles") { - setJSONValue(entityData, serviceRoles, "serviceRoles") + api.SetJSONValue(entityData, serviceRoles, "serviceRoles") change = true } if o.Cmd.Flags().Changed("identity-roles") { - setJSONValue(entityData, identityRoles, "identityRoles") + api.SetJSONValue(entityData, identityRoles, "identityRoles") change = true } if o.Cmd.Flags().Changed("posture-check-roles") { - setJSONValue(entityData, postureCheckRoles, "postureCheckRoles") + api.SetJSONValue(entityData, postureCheckRoles, "postureCheckRoles") change = true } @@ -118,6 +119,6 @@ func runUpdateServicePolicy(o *updateServicePolicyOptions) error { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("service-policies/%v", id), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("service-policies/%v", id), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/update_terminator.go b/ziti/cmd/ziti/cmd/edge/update_terminator.go index c7cba6059..380b3b604 100644 --- a/ziti/cmd/ziti/cmd/edge/update_terminator.go +++ b/ziti/cmd/ziti/cmd/edge/update_terminator.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/Jeffail/gabs" "github.com/openziti/foundation/util/stringz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -31,7 +32,7 @@ import ( ) type updateTerminatorOptions struct { - edgeOptions + api.Options router string address string binding string @@ -41,7 +42,7 @@ type updateTerminatorOptions struct { func newUpdateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { options := &updateTerminatorOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Factory: f, Out: out, @@ -79,24 +80,24 @@ func newUpdateTerminatorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) func runUpdateTerminator(o *updateTerminatorOptions) (err error) { entityData := gabs.New() - router, err := mapNameToID("edge-routers", o.router, o.edgeOptions) + router, err := mapNameToID("edge-routers", o.router, o.Options) if err != nil { router = o.router // might be a pure fabric router, id might not be UUID } change := false if o.Cmd.Flags().Changed("router") { - setJSONValue(entityData, router, "router") + api.SetJSONValue(entityData, router, "router") change = true } if o.Cmd.Flags().Changed("binding") { - setJSONValue(entityData, o.binding, "binding") + api.SetJSONValue(entityData, o.binding, "binding") change = true } if o.Cmd.Flags().Changed("address") { - setJSONValue(entityData, o.address, "address") + api.SetJSONValue(entityData, o.address, "address") change = true } @@ -104,7 +105,7 @@ func runUpdateTerminator(o *updateTerminatorOptions) (err error) { if o.cost > math.MaxUint16 { return errors2.Errorf("Invalid cost %v. Must be positive number less than or equal to %v", o.cost, math.MaxUint16) } - setJSONValue(entityData, o.cost, "cost") + api.SetJSONValue(entityData, o.cost, "cost") change = true } @@ -113,7 +114,7 @@ func runUpdateTerminator(o *updateTerminatorOptions) (err error) { if !stringz.Contains(validValues, o.precedence) { return errors2.Errorf("Invalid precedence %v. Must be one of %+v", o.precedence, validValues) } - setJSONValue(entityData, o.precedence, "precedence") + api.SetJSONValue(entityData, o.precedence, "precedence") change = true } @@ -121,6 +122,6 @@ func runUpdateTerminator(o *updateTerminatorOptions) (err error) { return errors.New("no change specified. must specify at least one attribute to change") } - _, err = patchEntityOfType(fmt.Sprintf("terminators/%v", o.Args[0]), entityData.String(), &o.edgeOptions) + _, err = patchEntityOfType(fmt.Sprintf("terminators/%v", o.Args[0]), entityData.String(), &o.Options) return err } diff --git a/ziti/cmd/ziti/cmd/edge/use.go b/ziti/cmd/ziti/cmd/edge/use.go index c360a27bd..08f08110d 100644 --- a/ziti/cmd/ziti/cmd/edge/use.go +++ b/ziti/cmd/ziti/cmd/edge/use.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -26,13 +27,13 @@ import ( // useOptions are the flags for use commands type useOptions struct { - edgeOptions + api.Options } // newUseCmd creates the command func newUseCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &useOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -67,7 +68,7 @@ func (o *useOptions) Run() error { // If no identities specified, list known identities if len(o.Args) == 0 { id := config.GetIdentity() - for k, v := range config.Identities { + for k, v := range config.EdgeIdentities { o.Printf("id: %12v | current: %5v | read-only: %5v | urL: %v\n", k, k == id, v.ReadOnly, v.Url) } return nil @@ -75,6 +76,6 @@ func (o *useOptions) Run() error { id := o.Args[0] config.Default = id - o.Printf("Settting identity '%v' as default in %v\n", id, configFile) + o.Printf("Setting identity '%v' as default in %v\n", id, configFile) return util.PersistRestClientConfig(config) } diff --git a/ziti/cmd/ziti/cmd/edge/verify.go b/ziti/cmd/ziti/cmd/edge/verify.go index ad1518d06..c544b8291 100644 --- a/ziti/cmd/ziti/cmd/edge/verify.go +++ b/ziti/cmd/ziti/cmd/edge/verify.go @@ -17,6 +17,7 @@ package edge import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "io" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" @@ -42,6 +43,6 @@ func newVerifyCmd(out io.Writer, errOut io.Writer) *cobra.Command { } // createEntityOfType create an entity of the given type on the Ziti Edge Controller -func verifyEntityOfType(entityType, body, id string, options *edgeOptions) error { +func verifyEntityOfType(entityType, body, id string, options *api.Options) error { return util.EdgeControllerVerify(entityType, id, body, options.Out, options.OutputJSONResponse, options.Timeout, options.Verbose) } diff --git a/ziti/cmd/ziti/cmd/edge/verify_ca.go b/ziti/cmd/ziti/cmd/edge/verify_ca.go index 752ef7b39..689b6d8ea 100644 --- a/ziti/cmd/ziti/cmd/edge/verify_ca.go +++ b/ziti/cmd/ziti/cmd/edge/verify_ca.go @@ -28,6 +28,7 @@ import ( "fmt" nfpem "github.com/openziti/foundation/util/pem" "github.com/openziti/foundation/util/term" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -40,7 +41,7 @@ import ( ) type verifyCaOptions struct { - edgeOptions + api.Options certPath string certPemBytes []byte @@ -61,7 +62,7 @@ type verifyCaOptions struct { // newVerifyCaCmd creates the 'edge controller verify ca' command for the given entity type func newVerifyCaCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &verifyCaOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{ Out: out, Err: errOut, @@ -133,14 +134,14 @@ func newVerifyCaCmd(out io.Writer, errOut io.Writer) *cobra.Command { func runValidateCa(options *verifyCaOptions) error { var err error - options.caId, err = mapCaNameToID(options.caNameOrId, options.edgeOptions) + options.caId, err = mapCaNameToID(options.caNameOrId, options.Options) if err != nil { return err } if options.isGenerateCert { - jsonContainer, err := util.EdgeControllerRequest("cas/"+options.caId, options.Out, options.OutputJSONResponse, options.edgeOptions.Timeout, options.edgeOptions.Verbose, func(request *resty.Request, url string) (*resty.Response, error) { return request.Get(url) }) + jsonContainer, err := util.EdgeControllerRequest("cas/"+options.caId, options.Out, options.OutputJSONResponse, options.Options.Timeout, options.Options.Verbose, func(request *resty.Request, url string) (*resty.Response, error) { return request.Get(url) }) if err != nil { return fmt.Errorf("could not request ca [%s] (%v}", options.caId, err) @@ -159,7 +160,7 @@ func runValidateCa(options *verifyCaOptions) error { } } - return util.EdgeControllerVerify("cas", options.caId, string(options.certPemBytes), options.Out, options.OutputJSONResponse, options.edgeOptions.Timeout, options.edgeOptions.Verbose) + return util.EdgeControllerVerify("cas", options.caId, string(options.certPemBytes), options.Out, options.OutputJSONResponse, options.Options.Timeout, options.Options.Verbose) } func generateCert(options *verifyCaOptions, token string) ([]byte, crypto.Signer, error) { diff --git a/ziti/cmd/ziti/cmd/edge/version.go b/ziti/cmd/ziti/cmd/edge/version.go index 51587c564..41d1394f0 100644 --- a/ziti/cmd/ziti/cmd/edge/version.go +++ b/ziti/cmd/ziti/cmd/edge/version.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" "github.com/openziti/ziti/ziti/cmd/ziti/util" @@ -27,13 +28,13 @@ import ( // versionOptions are the flags for version commands type versionOptions struct { - edgeOptions + api.Options } // newVersionCmd creates the command func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command { options := &versionOptions{ - edgeOptions: edgeOptions{ + Options: api.Options{ CommonOptions: common.CommonOptions{Out: out, Err: errOut}, }, } @@ -58,7 +59,7 @@ func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command { // Run implements this command func (o *versionOptions) Run() error { - jsonParsed, err := util.EdgeControllerList("version", nil, o.OutputJSONResponse, o.Out, o.edgeOptions.Timeout, o.edgeOptions.Verbose) + jsonParsed, err := util.EdgeControllerList("version", nil, o.OutputJSONResponse, o.Out, o.Options.Timeout, o.Options.Verbose) if err != nil { return err } diff --git a/ziti/cmd/ziti/cmd/fabric/add_identity.go b/ziti/cmd/ziti/cmd/fabric/add_identity.go new file mode 100644 index 000000000..edc05f6ea --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/add_identity.go @@ -0,0 +1,82 @@ +/* + 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 fabric + +import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" +) + +type addIdentityOptions struct { + common.CommonOptions + caCert string + clientCert string + clientKey string + readOnly bool +} + +func newAddIdentityCmd(p common.OptionsProvider) *cobra.Command { + options := &addIdentityOptions{ + CommonOptions: p(), + } + + cmd := &cobra.Command{ + Use: "add-identity ", + Short: "adds a fabric identity for connecting to the Ziti Controller", + Args: cobra.ExactArgs(1), + RunE: options.run, + } + + cmd.Flags().StringVarP(&common.CliIdentity, "cli-identity", "i", "", "Specify the saved identity you want the CLI to use when connect to the controller with") + cmd.Flags().StringVar(&options.caCert, "ca-cert", "", "additional root certificates used by the Ziti Controller") + cmd.Flags().StringVar(&options.clientCert, "client-cert", "", "client certificate used to authenticate to the Ziti Controller") + cmd.Flags().StringVar(&options.clientKey, "client-key", "", "client certificate key used to authenticate to the Ziti Controller") + cmd.Flags().BoolVar(&options.readOnly, "read-only", false, "marks this login as read-only. Note: this is not a guarantee that nothing can be changed on the server. Care should still be taken!") + + for _, required := range []string{"ca-cert", "client-cert", "client-key"} { + if err := cmd.MarkFlagRequired(required); err != nil { + panic(err) + } + } + + return cmd +} + +func (o *addIdentityOptions) run(_ *cobra.Command, args []string) error { + config, configFile, err := util.LoadRestClientConfig() + if err != nil { + return err + } + + id := config.GetIdentity() + + loginIdentity := &util.RestClientFabricIdentity{ + Url: args[0], + CaCert: o.caCert, + ClientCert: o.clientCert, + ClientKey: o.clientKey, + ReadOnly: o.readOnly, + } + + o.Printf("Saving identity '%v' to %v\n", id, configFile) + config.FabricIdentities[id] = loginIdentity + + err = util.PersistRestClientConfig(config) + + return nil +} diff --git a/ziti/cmd/ziti/cmd/fabric/create_router.go b/ziti/cmd/ziti/cmd/fabric/create_router.go new file mode 100644 index 000000000..097e7ec13 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/create_router.go @@ -0,0 +1,91 @@ +/* + 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 fabric + +import ( + "crypto/sha1" + "fmt" + "github.com/Jeffail/gabs" + "github.com/openziti/foundation/identity/certtools" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/spf13/cobra" +) + +type createRouterOptions struct { + api.Options + name string + tags map[string]string +} + +// newCreateRouterCmd creates the 'fabric create router' command for the given entity type +func newCreateRouterCmd(p common.OptionsProvider) *cobra.Command { + options := &createRouterOptions{ + Options: api.Options{ + CommonOptions: p(), + }, + tags: make(map[string]string), + } + + cmd := &cobra.Command{ + Use: "router ", + Short: "creates a router managed by the Ziti Controller", + Args: cobra.MinimumNArgs(1), + RunE: options.createRouter, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringToStringVarP(&options.tags, "tags", "t", nil, "Add tags to router definition") + cmd.Flags().StringVar(&options.name, "name", "", "Specifies the router name. If not specified, the id in the controller cert will be used") + options.AddCommonFlags(cmd) + + return cmd +} + +// createRouter implements the command to create a router +func (o *createRouterOptions) createRouter(_ *cobra.Command, args []string) error { + cert, err := certtools.LoadCertFromFile(args[0]) + if err != nil { + return err + } + + entityData := gabs.New() + id := cert[0].Subject.CommonName + name := id + if o.name != "" { + name = o.name + } + fingerprint := fmt.Sprintf("%x", sha1.Sum(cert[0].Raw)) + api.SetJSONValue(entityData, id, "id") + api.SetJSONValue(entityData, name, "name") + api.SetJSONValue(entityData, fingerprint, "fingerprint") + api.SetJSONValue(entityData, o.tags, "tags") + + result, err := createEntityOfType("routers", entityData.String(), &o.Options) + if err != nil { + return err + } + + if !o.OutputJSONResponse { + id := result.S("data", "id").Data() + _, err = fmt.Fprintf(o.Out, "New %v %v created with id: %v\n", "router", name, id) + return err + } + return nil +} diff --git a/ziti/cmd/ziti/cmd/fabric/create_service.go b/ziti/cmd/ziti/cmd/fabric/create_service.go new file mode 100644 index 000000000..92e94a730 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/create_service.go @@ -0,0 +1,71 @@ +/* + 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 fabric + +import ( + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + "github.com/spf13/cobra" +) + +type createServiceOptions struct { + api.Options + terminatorStrategy string + tags map[string]string +} + +// newCreateServiceCmd creates the 'fabric create service' command for the given entity type +func newCreateServiceCmd(p common.OptionsProvider) *cobra.Command { + options := &createServiceOptions{ + Options: api.Options{ + CommonOptions: p(), + }, + tags: make(map[string]string), + } + + cmd := &cobra.Command{ + Use: "service ", + Short: "creates a service managed by the Ziti Controller", + Args: cobra.MinimumNArgs(1), + RunE: options.createService, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringToStringVarP(&options.tags, "tags", "t", nil, "Add tags to service definition") + cmd.Flags().StringVar(&options.terminatorStrategy, "terminator-strategy", "", "Specifies the terminator strategy for the service") + options.AddCommonFlags(cmd) + + return cmd +} + +// createService implements the command to create a service +func (o *createServiceOptions) createService(_ *cobra.Command, args []string) (err error) { + o.Args = args + entityData := gabs.New() + api.SetJSONValue(entityData, args[0], "name") + if o.terminatorStrategy != "" { + api.SetJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") + } + + api.SetJSONValue(entityData, o.tags, "tags") + + result, err := createEntityOfType("services", entityData.String(), &o.Options) + return o.LogCreateResult("service", result, err) +} diff --git a/ziti/cmd/ziti/cmd/fabric/create_terminator.go b/ziti/cmd/ziti/cmd/fabric/create_terminator.go new file mode 100644 index 000000000..cbb396d29 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/create_terminator.go @@ -0,0 +1,110 @@ +/* + 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 fabric + +import ( + "fmt" + "github.com/Jeffail/gabs" + "github.com/openziti/edge/router/xgress_edge_transport" + "github.com/openziti/foundation/util/stringz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" + "math" +) + +type createTerminatorOptions struct { + api.Options + binding string + cost int32 + precedence string + identity string +} + +// newCreateTerminatorCmd creates the 'fabric create terminator' command +func newCreateTerminatorCmd(p common.OptionsProvider) *cobra.Command { + options := &createTerminatorOptions{ + Options: api.Options{CommonOptions: p()}, + } + + cmd := &cobra.Command{ + Use: "terminator service router address", + Short: "creates a service terminator managed by the Ziti Controller", + Args: cobra.ExactArgs(3), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runCreateTerminator(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVar(&options.binding, "binding", xgress_edge_transport.BindingName, "Set the terminator binding") + cmd.Flags().Int32VarP(&options.cost, "cost", "c", 0, "Set the terminator cost") + cmd.Flags().StringVarP(&options.precedence, "precedence", "p", "", "Set the terminator precedence ('default', 'required' or 'failed')") + cmd.Flags().StringVar(&options.identity, "identity", "", "Set the terminator identity") + options.AddCommonFlags(cmd) + + return cmd +} + +// runCreateTerminator implements the command to create a Terminator +func runCreateTerminator(o *createTerminatorOptions) (err error) { + entityData := gabs.New() + service, err := api.MapNameToID(util.FabricAPI, "services", &o.Options, o.Args[0]) + if err != nil { + return err + } + + router, err := api.MapNameToID(util.FabricAPI, "routers", &o.Options, o.Args[1]) + if err != nil { + return err + } + + api.SetJSONValue(entityData, service, "service") + api.SetJSONValue(entityData, router, "router") + api.SetJSONValue(entityData, o.binding, "binding") + api.SetJSONValue(entityData, o.Args[2], "address") + api.SetJSONValue(entityData, o.identity, "identity") + if o.cost > 0 { + if o.cost > math.MaxUint16 { + if _, err = fmt.Fprintf(o.Out, "Invalid cost %v. Must be positive number less than or equal to %v\n", o.cost, math.MaxUint16); err != nil { + panic(err) + } + return + } + api.SetJSONValue(entityData, o.cost, "cost") + } + if o.precedence != "" { + validValues := []string{"default", "required", "failed"} + if !stringz.Contains(validValues, o.precedence) { + if _, err = fmt.Fprintf(o.Out, "Invalid precedence %v. Must be one of %+v\n", o.precedence, validValues); err != nil { + panic(err) + } + return + } + api.SetJSONValue(entityData, o.precedence, "precedence") + } + + result, err := createEntityOfType("terminators", entityData.String(), &o.Options) + return o.LogCreateResult("terminator", result, err) +} diff --git a/ziti/cmd/ziti/cmd/fabric/delete.go b/ziti/cmd/ziti/cmd/fabric/delete.go new file mode 100644 index 000000000..9c3179f8b --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/delete.go @@ -0,0 +1,136 @@ +/* + 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 fabric + +import ( + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" +) + +type deleteOptions struct { + api.Options + isCircuit bool + immediate bool +} + +func (self *deleteOptions) AddCommonFlags(cmd *cobra.Command) { + self.Options.AddCommonFlags(cmd) + if self.isCircuit { + if self.isCircuit { + cmd.Flags().BoolVar(&self.immediate, "immediate", false, "delete the circuit immediately, without allowing a graceful shutdown") + } + } +} + +func (self *deleteOptions) GetBody() string { + if self.isCircuit { + c := gabs.New() + api.SetJSONValue(c, self.immediate, "immediate") + return c.String() + } + return "" +} + +// newDeleteCmd creates a command object for the "edge controller delete" command +func newDeleteCmd(p common.OptionsProvider) *cobra.Command { + cmd := &cobra.Command{ + Use: "delete", + Short: "deletes various entities managed by the Ziti Controller", + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + cmdhelper.CheckErr(err) + }, + } + + newOptions := func(isCircuit bool) *deleteOptions { + return &deleteOptions{ + Options: api.Options{CommonOptions: p()}, + isCircuit: true, + } + } + + cmd.AddCommand(newDeleteCmdForEntityType("circuit", newOptions(true))) + cmd.AddCommand(newDeleteCmdForEntityType("router", newOptions(false))) + cmd.AddCommand(newDeleteCmdForEntityType("service", newOptions(false))) + cmd.AddCommand(newDeleteCmdForEntityType("terminator", newOptions(false))) + + return cmd +} + +// newDeleteCmdForEntityType creates the delete command for the given entity type +func newDeleteCmdForEntityType(entityType string, options *deleteOptions, aliases ...string) *cobra.Command { + cmd := &cobra.Command{ + Use: entityType + " ", + Short: "deletes " + api.GetPlural(entityType) + " managed by the Ziti Controller", + Args: cobra.MinimumNArgs(1), + Aliases: append(aliases, api.GetPlural(entityType)), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runDeleteEntityOfType(options, api.GetPlural(entityType)) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + options.AddCommonFlags(cmd) + + cmd.AddCommand(newDeleteWhereCmdForEntityType(entityType, options)) + + return cmd +} + +func newDeleteWhereCmdForEntityType(entityType string, options *deleteOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "where ", + Short: "deletes " + api.GetPlural(entityType) + " matching the filter managed by the Ziti Controller", + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := api.DeleteEntityOfTypeWhere("fabric", &options.Options, api.GetPlural(entityType), options.GetBody()) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + options.AddCommonFlags(cmd) + + return cmd +} + +// runDeleteEntityOfType implements the commands to delete various entity types +func runDeleteEntityOfType(o *deleteOptions, entityType string) error { + var err error + ids := o.Args + if entityType != "terminators" && entityType != "links" && entityType != "circuits" { + ids, err = api.MapNamesToIDs("fabric", entityType, &o.Options, ids...) + } + if err != nil { + return err + } + + return api.DeleteEntitiesOfType(util.FabricAPI, &o.Options, entityType, ids, o.GetBody()) +} diff --git a/ziti/cmd/ziti/cmd/fabric/list.go b/ziti/cmd/ziti/cmd/fabric/list.go new file mode 100644 index 000000000..588da9e83 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/list.go @@ -0,0 +1,326 @@ +/* + 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 fabric + +import ( + "fmt" + "github.com/Jeffail/gabs" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" + "strings" +) + +// newListCmd creates a command object for the "controller list" command +func newListCmd(p common.OptionsProvider) *cobra.Command { + listCmd := &cobra.Command{ + Use: "list", + Short: "Lists various entities managed by the Ziti Controller", + Run: func(cmd *cobra.Command, args []string) { + err := cmd.Help() + cmdhelper.CheckErr(err) + }, + } + + newOptions := func() *api.Options { + return &api.Options{CommonOptions: p()} + } + + listCmd.AddCommand(newListCmdForEntityType("circuits", runListCircuits, newOptions())) + listCmd.AddCommand(newListCmdForEntityType("links", runListLinks, newOptions())) + listCmd.AddCommand(newListCmdForEntityType("routers", runListRouters, newOptions())) + listCmd.AddCommand(newListCmdForEntityType("services", runListServices, newOptions())) + listCmd.AddCommand(newListCmdForEntityType("terminators", runListTerminators, newOptions())) + + return listCmd +} + +func listEntitiesWithOptions(entityType string, options *api.Options) ([]*gabs.Container, *api.Paging, error) { + return api.ListEntitiesWithOptions(util.FabricAPI, entityType, options) +} + +type listCommandRunner func(*api.Options) error + +// newListCmdForEntityType creates the list command for the given entity type +func newListCmdForEntityType(entityType string, command listCommandRunner, options *api.Options, aliases ...string) *cobra.Command { + cmd := &cobra.Command{ + Use: entityType + " ?", + Short: "lists " + entityType + " managed by the Ziti Controller", + Args: cobra.MaximumNArgs(1), + Aliases: aliases, + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := command(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().BoolVar(&options.OutputCSV, "csv", false, "Output CSV instead of a formatted table") + options.AddCommonFlags(cmd) + + return cmd +} + +func runListCircuits(o *api.Options) error { + children, pagingInfo, err := listEntitiesWithOptions("circuits", o) + if err != nil { + return err + } + return outputCircuits(o, children, pagingInfo) +} + +func outputCircuits(o *api.Options, children []*gabs.Container, pagingInfo *api.Paging) error { + if o.OutputJSONResponse { + return nil + } + + t := table.NewWriter() + t.SetStyle(table.StyleRounded) + t.AppendHeader(table.Row{"ID", "Client", "Service", "Path"}) + + for _, entity := range children { + id := api.GetJsonString(entity, "id") + client := api.GetJsonString(entity, "clientId") + service := api.GetJsonString(entity, "service.name") + + path := strings.Builder{} + + nodes, err := getEntityRef(entity.Path("path.nodes")) + if err != nil { + return err + } + + links, err := getEntityRef(entity.Path("path.links")) + if err != nil { + return err + } + + if len(nodes) > 0 { + path.WriteString("r/") + path.WriteString(nodes[0].name) + for idx, node := range nodes[1:] { + link := links[idx] + path.WriteString(" -> l/") + path.WriteString(link.id) + path.WriteString(" -> r/") + path.WriteString(node.name) + } + } + + t.AppendRow(table.Row{id, client, service, path.String()}) + } + + renderTable(o, t, pagingInfo) + + return nil +} + +type entityRef struct { + id string + name string +} + +func getEntityRef(c *gabs.Container) ([]*entityRef, error) { + if c == nil || c.Data() == nil { + return nil, nil + } + children, err := c.Children() + if err != nil { + return nil, err + } + + var result []*entityRef + + for _, child := range children { + id := api.GetJsonString(child, "id") + name := api.GetJsonString(child, "name") + result = append(result, &entityRef{ + id: id, + name: name, + }) + } + return result, nil +} + +func runListLinks(o *api.Options) error { + children, pagingInfo, err := listEntitiesWithOptions("links", o) + if err != nil { + return err + } + return outputLinks(o, children, pagingInfo) +} + +func outputLinks(o *api.Options, children []*gabs.Container, pagingInfo *api.Paging) error { + if o.OutputJSONResponse { + return nil + } + + t := table.NewWriter() + t.SetStyle(table.StyleRounded) + columnConfigs := make([]table.ColumnConfig, 9) + columnConfigs[4] = table.ColumnConfig{Align: text.AlignRight} + columnConfigs[5] = table.ColumnConfig{Align: text.AlignRight} + t.SetColumnConfigs(columnConfigs) + t.AppendHeader(table.Row{"ID", "Dialer", "Acceptor", "Static Cost", "Src Latency", "Dst Latency", "State", "Status", "Full Cost"}) + + for _, entity := range children { + id := entity.Path("id").Data().(string) + srcRouter := entity.Path("sourceRouter.name").Data().(string) + dstRouter := entity.Path("destRouter.name").Data().(string) + staticCost := entity.Path("staticCost").Data().(float64) + srcLatency := entity.Path("sourceLatency").Data().(float64) / 1_000_000 + dstLatency := entity.Path("destLatency").Data().(float64) / 1_000_000 + state := entity.Path("state").Data().(string) + down := entity.Path("down").Data().(bool) + cost := entity.Path("cost").Data().(float64) + + status := "up" + if down { + status = "down" + } + + t.AppendRow(table.Row{id, srcRouter, dstRouter, staticCost, + fmt.Sprintf("%.2vms", srcLatency), + fmt.Sprintf("%.2vms", dstLatency), + state, status, cost}) + } + + renderTable(o, t, pagingInfo) + + return nil +} + +func runListTerminators(o *api.Options) error { + children, pagingInfo, err := listEntitiesWithOptions("terminators", o) + if err != nil { + return err + } + return outputTerminators(o, children, pagingInfo) +} + +func outputTerminators(o *api.Options, children []*gabs.Container, pagingInfo *api.Paging) error { + if o.OutputJSONResponse { + return nil + } + + t := table.NewWriter() + t.SetStyle(table.StyleRounded) + t.AppendHeader(table.Row{"ID", "Service", "Router", "Binding", "Address", "Identity", "Cost", "Precedence", "Dynamic Cost"}) + + for _, entity := range children { + id, _ := entity.Path("id").Data().(string) + service := entity.Path("service.name").Data().(string) + router := entity.Path("router.name").Data().(string) + binding := entity.Path("binding").Data().(string) + address := entity.Path("address").Data().(string) + identity := entity.Path("identity").Data().(string) + staticCost := entity.Path("cost").Data().(float64) + precedence := entity.Path("precedence").Data().(string) + dynamicCost := entity.Path("dynamicCost").Data().(float64) + + t.AppendRow(table.Row{id, service, router, binding, address, identity, staticCost, precedence, dynamicCost}) + } + renderTable(o, t, pagingInfo) + return nil +} + +func runListServices(o *api.Options) error { + children, pagingInfo, err := listEntitiesWithOptions("services", o) + if err != nil { + return err + } + return outputServices(o, children, pagingInfo) +} + +func outputServices(o *api.Options, children []*gabs.Container, pagingInfo *api.Paging) error { + if o.OutputJSONResponse { + return nil + } + + t := table.NewWriter() + t.SetStyle(table.StyleRounded) + t.AppendHeader(table.Row{"ID", "Name", "Terminator Strategy"}) + + for _, entity := range children { + id := entity.Path("id").Data().(string) + name := entity.Path("name").Data().(string) + terminatorStrategy, _ := entity.Path("terminatorStrategy").Data().(string) + t.AppendRow(table.Row{id, name, terminatorStrategy}) + } + + renderTable(o, t, pagingInfo) + + return nil +} + +func runListRouters(o *api.Options) error { + children, pagingInfo, err := listEntitiesWithOptions("routers", o) + if err != nil { + return err + } + return outputRouters(o, children, pagingInfo) +} + +func outputRouters(o *api.Options, children []*gabs.Container, pagingInfo *api.Paging) error { + if o.OutputJSONResponse { + return nil + } + + t := table.NewWriter() + t.SetStyle(table.StyleRounded) + t.AppendHeader(table.Row{"ID", "Name", "Online", "Version"}) + + for _, entity := range children { + id := entity.Path("id").Data().(string) + name := entity.Path("name").Data().(string) + connected := entity.Path("connected").Data().(bool) + versionInfo := entity.Path("versionInfo") + var version string + if versionInfo != nil { + v := versionInfo.Path("version").Data().(string) + os := versionInfo.Path("os").Data().(string) + arch := versionInfo.Path("arch").Data().(string) + version = fmt.Sprintf("%v on %v/%v", v, os, arch) + } + t.AppendRow(table.Row{id, name, connected, version}) + } + + renderTable(o, t, pagingInfo) + + return nil +} + +func renderTable(o *api.Options, t table.Writer, pagingInfo *api.Paging) { + if o.OutputCSV { + if _, err := fmt.Fprintln(o.Cmd.OutOrStdout(), t.RenderCSV()); err != nil { + panic(err) + } + } else { + if _, err := fmt.Fprintln(o.Cmd.OutOrStdout(), t.Render()); err != nil { + panic(err) + } + pagingInfo.Output(o) + } +} diff --git a/ziti/cmd/ziti/cmd/fabric/remove_identity.go b/ziti/cmd/ziti/cmd/fabric/remove_identity.go new file mode 100644 index 000000000..ae14ab3eb --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/remove_identity.go @@ -0,0 +1,68 @@ +/* + 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 fabric + +import ( + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" +) + +// removeIdentityOptions are the flags for removeIdentity commands +type removeIdentityOptions struct { + common.CommonOptions +} + +// newRemoveIdentityCmd creates the command +func newRemoveIdentityCmd(p common.OptionsProvider) *cobra.Command { + options := &removeIdentityOptions{ + CommonOptions: p(), + } + + cmd := &cobra.Command{ + Use: "remove-identity", + Short: "remove an identity for a Ziti Controller instance", + Args: cobra.ExactArgs(0), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := options.Run() + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVarP(&common.CliIdentity, "cli-identity", "i", "", "Specify the saved identity you want the CLI to use when connect to the controller with") + + return cmd +} + +// Run implements this command +func (o *removeIdentityOptions) Run() error { + config, configFile, err := util.LoadRestClientConfig() + if err != nil { + return err + } + + id := config.GetIdentity() + o.Printf("Removing fabric identity '%v' from %v\n", id, configFile) + delete(config.FabricIdentities, id) + return util.PersistRestClientConfig(config) +} diff --git a/ziti/cmd/ziti/cmd/fabric/root.go b/ziti/cmd/ziti/cmd/fabric/root.go new file mode 100644 index 000000000..e48a30ddc --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/root.go @@ -0,0 +1,84 @@ +/* + 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 fabric + +import ( + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/spf13/cobra" + "gopkg.in/resty.v1" +) + +// NewFabricCmd creates a command object for the fabric command +func NewFabricCmd(p common.OptionsProvider) *cobra.Command { + fabricCmd := util.NewEmptyParentCmd("fabric", "Interact with Ziti Fabric Components") + + fabricCmd.AddCommand(newAddIdentityCmd(p), newRemoveIdentityCmd(p)) + fabricCmd.AddCommand(newCreateCommand(p), newListCmd(p), newUpdateCommand(p), newDeleteCmd(p)) + + return fabricCmd +} + +func newCreateCommand(p common.OptionsProvider) *cobra.Command { + createCmd := &cobra.Command{ + Use: "create", + Short: "creates various entities managed by the Ziti Controller", + Run: func(cmd *cobra.Command, args []string) { + cmdhelper.CheckErr(cmd.Help()) + }, + } + + createCmd.AddCommand(newCreateRouterCmd(p)) + createCmd.AddCommand(newCreateServiceCmd(p)) + createCmd.AddCommand(newCreateTerminatorCmd(p)) + + return createCmd +} + +func newUpdateCommand(p common.OptionsProvider) *cobra.Command { + updateCmd := &cobra.Command{ + Use: "update", + Short: "update various entities managed by the Ziti Controller", + Run: func(cmd *cobra.Command, args []string) { + cmdhelper.CheckErr(cmd.Help()) + }, + } + + updateCmd.AddCommand(newUpdateLinkCmd(p)) + updateCmd.AddCommand(newUpdateRouterCmd(p)) + updateCmd.AddCommand(newUpdateServiceCmd(p)) + updateCmd.AddCommand(newUpdateTerminatorCmd(p)) + + return updateCmd +} + +// createEntityOfType create an entity of the given type on the Ziti Controller +func createEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { + return util.ControllerCreate("fabric", entityType, body, options.Out, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) +} + +func patchEntityOfType(entityType string, body string, options *api.Options) (*gabs.Container, error) { + return updateEntityOfType(entityType, body, options, resty.MethodPatch) +} + +// updateEntityOfType updates an entity of the given type on the Ziti Edge Controller +func updateEntityOfType(entityType string, body string, options *api.Options, method string) (*gabs.Container, error) { + return util.ControllerUpdate(util.FabricAPI, entityType, body, options.Out, method, options.OutputJSONRequest, options.OutputJSONResponse, options.Timeout, options.Verbose) +} diff --git a/ziti/cmd/ziti/cmd/fabric/update_link.go b/ziti/cmd/ziti/cmd/fabric/update_link.go new file mode 100644 index 000000000..404214cce --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/update_link.go @@ -0,0 +1,84 @@ +/* + 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 fabric + +import ( + "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/pkg/errors" + + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" +) + +type updateLinkOptions struct { + api.Options + down bool + staticCost uint32 +} + +func newUpdateLinkCmd(p common.OptionsProvider) *cobra.Command { + options := &updateLinkOptions{ + Options: api.Options{CommonOptions: p()}, + } + + cmd := &cobra.Command{ + Use: "link ", + Short: "updates a link managed by the Ziti Controller", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runUpdateLink(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().BoolVar(&options.down, "down", true, "Set link up or down") + cmd.Flags().Uint32Var(&options.staticCost, "static-cost", 0, "Specifies the static cost of the link") + options.AddCommonFlags(cmd) + + return cmd +} + +// runUpdateLink update a new link on the Ziti Edge Controller +func runUpdateLink(o *updateLinkOptions) error { + entityData := gabs.New() + change := false + + if o.Cmd.Flags().Changed("down") { + api.SetJSONValue(entityData, o.down, "down") + change = true + } + + if o.Cmd.Flags().Changed("static-cost") { + api.SetJSONValue(entityData, o.staticCost, "staticCost") + change = true + } + + if !change { + return errors.New("no change specified. must specify at least one attribute to change") + } + + _, err := patchEntityOfType(fmt.Sprintf("links/%v", o.Args[0]), entityData.String(), &o.Options) + return err +} diff --git a/ziti/cmd/ziti/cmd/fabric/update_router.go b/ziti/cmd/ziti/cmd/fabric/update_router.go new file mode 100644 index 000000000..0a2e42b4d --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/update_router.go @@ -0,0 +1,89 @@ +/* + 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 fabric + +import ( + "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/pkg/errors" + + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" +) + +type updateRouterOptions struct { + api.Options + name string + fingerprint string +} + +func newUpdateRouterCmd(p common.OptionsProvider) *cobra.Command { + options := &updateRouterOptions{ + Options: api.Options{CommonOptions: p()}, + } + + cmd := &cobra.Command{ + Use: "router ", + Short: "updates a router managed by the Ziti Controller", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runUpdateRouter(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVarP(&options.name, "name", "n", "", "Set the router name") + cmd.Flags().StringVar(&options.fingerprint, "fingerprint", "", "Sets the router fingerprint") + options.AddCommonFlags(cmd) + + return cmd +} + +// runUpdateRouter update a new router on the Ziti Edge Controller +func runUpdateRouter(o *updateRouterOptions) error { + id, err := api.MapNameToID(util.FabricAPI, "routers", &o.Options, o.Args[0]) + if err != nil { + return err + } + entityData := gabs.New() + change := false + + if o.Cmd.Flags().Changed("name") { + api.SetJSONValue(entityData, o.name, "name") + change = true + } + + if o.Cmd.Flags().Changed("fingerprint") { + api.SetJSONValue(entityData, o.fingerprint, "fingerprint") + change = true + } + + if !change { + return errors.New("no change specified. must specify at least one attribute to change") + } + + _, err = patchEntityOfType(fmt.Sprintf("routers/%v", id), entityData.String(), &o.Options) + return err +} diff --git a/ziti/cmd/ziti/cmd/fabric/update_service.go b/ziti/cmd/ziti/cmd/fabric/update_service.go new file mode 100644 index 000000000..a5381bea2 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/update_service.go @@ -0,0 +1,89 @@ +/* + 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 fabric + +import ( + "fmt" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + "github.com/pkg/errors" + + "github.com/Jeffail/gabs" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/spf13/cobra" +) + +type updateServiceOptions struct { + api.Options + name string + terminatorStrategy string +} + +func newUpdateServiceCmd(p common.OptionsProvider) *cobra.Command { + options := &updateServiceOptions{ + Options: api.Options{CommonOptions: p()}, + } + + cmd := &cobra.Command{ + Use: "service ", + Short: "updates a service managed by the Ziti Controller", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runUpdateService(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVarP(&options.name, "name", "n", "", "Set the name of the service") + cmd.Flags().StringVar(&options.terminatorStrategy, "terminator-strategy", "", "Specifies the terminator strategy for the service") + options.AddCommonFlags(cmd) + + return cmd +} + +// runUpdateService update a new service on the Ziti Edge Controller +func runUpdateService(o *updateServiceOptions) error { + id, err := api.MapNameToID(util.FabricAPI, "services", &o.Options, o.Args[0]) + if err != nil { + return err + } + entityData := gabs.New() + change := false + + if o.Cmd.Flags().Changed("name") { + api.SetJSONValue(entityData, o.name, "name") + change = true + } + + if o.Cmd.Flags().Changed("terminator-strategy") { + api.SetJSONValue(entityData, o.terminatorStrategy, "terminatorStrategy") + change = true + } + + if !change { + return errors.New("no change specified. must specify at least one attribute to change") + } + + _, err = patchEntityOfType(fmt.Sprintf("services/%v", id), entityData.String(), &o.Options) + return err +} diff --git a/ziti/cmd/ziti/cmd/fabric/update_terminator.go b/ziti/cmd/ziti/cmd/fabric/update_terminator.go new file mode 100644 index 000000000..45f242369 --- /dev/null +++ b/ziti/cmd/ziti/cmd/fabric/update_terminator.go @@ -0,0 +1,120 @@ +/* + 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 fabric + +import ( + "errors" + "fmt" + "github.com/Jeffail/gabs" + "github.com/openziti/foundation/util/stringz" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/api" + "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" + cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" + "github.com/openziti/ziti/ziti/cmd/ziti/util" + errors2 "github.com/pkg/errors" + "github.com/spf13/cobra" + "math" +) + +type updateTerminatorOptions struct { + api.Options + router string + address string + binding string + cost int32 + precedence string +} + +func newUpdateTerminatorCmd(p common.OptionsProvider) *cobra.Command { + options := &updateTerminatorOptions{ + Options: api.Options{CommonOptions: p()}, + } + + cmd := &cobra.Command{ + Use: "terminator ", + Short: "updates a service terminator", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + options.Cmd = cmd + options.Args = args + err := runUpdateTerminator(options) + cmdhelper.CheckErr(err) + }, + SuggestFor: []string{}, + } + + // allow interspersing positional args and flags + cmd.Flags().SetInterspersed(true) + cmd.Flags().StringVar(&options.router, "router", "", "Set the terminator router") + cmd.Flags().StringVar(&options.address, "address", "", "Set the terminator address") + cmd.Flags().StringVar(&options.binding, "binding", "", "Set the terminator binding") + cmd.Flags().Int32VarP(&options.cost, "cost", "c", 0, "Set the terminator cost") + cmd.Flags().StringVarP(&options.precedence, "precedence", "p", "", "Set the terminator precedence ('default', 'required' or 'failed')") + options.AddCommonFlags(cmd) + + return cmd +} + +// runUpdateTerminator implements the command to update a Terminator +func runUpdateTerminator(o *updateTerminatorOptions) (err error) { + entityData := gabs.New() + + router, err := api.MapNameToID(util.FabricAPI, "routers", &o.Options, o.router) + if err != nil { + return err + } + + change := false + if o.Cmd.Flags().Changed("router") { + api.SetJSONValue(entityData, router, "router") + change = true + } + + if o.Cmd.Flags().Changed("binding") { + api.SetJSONValue(entityData, o.binding, "binding") + change = true + } + + if o.Cmd.Flags().Changed("address") { + api.SetJSONValue(entityData, o.address, "address") + change = true + } + + if o.Cmd.Flags().Changed("cost") { + if o.cost > math.MaxUint16 { + return errors2.Errorf("Invalid cost %v. Must be positive number less than or equal to %v", o.cost, math.MaxUint16) + } + api.SetJSONValue(entityData, o.cost, "cost") + change = true + } + + if o.Cmd.Flags().Changed("precedence") { + validValues := []string{"default", "required", "failed"} + if !stringz.Contains(validValues, o.precedence) { + return errors2.Errorf("Invalid precedence %v. Must be one of %+v", o.precedence, validValues) + } + api.SetJSONValue(entityData, o.precedence, "precedence") + change = true + } + + if !change { + return errors.New("no change specified. must specify at least one attribute to change") + } + + _, err = patchEntityOfType(fmt.Sprintf("terminators/%v", o.Args[0]), entityData.String(), &o.Options) + return err +} diff --git a/ziti/cmd/ziti/cmd/init.go b/ziti/cmd/ziti/cmd/init.go index fc5760873..4a3143433 100644 --- a/ziti/cmd/ziti/cmd/init.go +++ b/ziti/cmd/ziti/cmd/init.go @@ -100,8 +100,6 @@ func (o *InitOptions) Run() error { return nil case c.ZITI_FABRIC: return nil - case c.ZITI_FABRIC_GW: - err = o.createInitialMgmtGwConfig() case c.ZITI: err = o.createInitialZitiConfig() default: diff --git a/ziti/cmd/ziti/cmd/install.go b/ziti/cmd/ziti/cmd/install.go index 3c4788e0a..33769e9e9 100644 --- a/ziti/cmd/ziti/cmd/install.go +++ b/ziti/cmd/ziti/cmd/install.go @@ -70,12 +70,9 @@ func NewCmdInstall(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Co cmd.AddCommand(NewCmdInstallZitiController(f, out, errOut)) cmd.AddCommand(NewCmdInstallZitiFabric(f, out, errOut)) - cmd.AddCommand(NewCmdInstallZitiFabricTest(f, out, errOut)) - cmd.AddCommand(NewCmdInstallZitiMgmtGw(f, out, errOut)) cmd.AddCommand(NewCmdInstallZitiRouter(f, out, errOut)) cmd.AddCommand(NewCmdInstallZitiTunnel(f, out, errOut)) cmd.AddCommand(NewCmdInstallZitiEdgeTunnel(f, out, errOut)) - cmd.AddCommand(NewCmdInstallZitiEnroller(f, out, errOut)) cmd.AddCommand(NewCmdInstallZitiProxC(f, out, errOut)) // cmd.AddCommand(NewCmdInstallAnsible(f, out, errOut)) // Disable/hide this for now diff --git a/ziti/cmd/ziti/cmd/install_ziti_ALL.go b/ziti/cmd/ziti/cmd/install_ziti_ALL.go index edd99da64..ac8f12e52 100644 --- a/ziti/cmd/ziti/cmd/install_ziti_ALL.go +++ b/ziti/cmd/ziti/cmd/install_ziti_ALL.go @@ -100,26 +100,11 @@ func (o *InstallZitiALLOptions) Run() error { log.Errorf("Error: install failed %s \n", err.Error()) } - err = o.install(c.ZITI_ENROLLER) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } - err = o.install(c.ZITI_FABRIC) if err != nil { log.Errorf("Error: install failed %s \n", err.Error()) } - err = o.install(c.ZITI_FABRIC_GW) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } - - err = o.install(c.ZITI_FABRIC_TEST) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } - err = o.install(c.ZITI_PROX_C) if err != nil { log.Errorf("Error: install failed %s \n", err.Error()) diff --git a/ziti/cmd/ziti/cmd/install_ziti_enroller.go b/ziti/cmd/ziti/cmd/install_ziti_enroller.go deleted file mode 100644 index c68a13011..000000000 --- a/ziti/cmd/ziti/cmd/install_ziti_enroller.go +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/openziti/ziti/ziti/cmd/ziti/internal/log" - "github.com/openziti/ziti/common/version" - "github.com/blang/semver" - "github.com/spf13/cobra" -) - -var ( - installZitiEnrollerLong = templates.LongDesc(` - Installs the Ziti Enroller app if it has not been installed already -`) - - installZitiEnrollerExample = templates.Examples(` - # Install the Ziti Enroller app - ziti install ziti-enroller - `) -) - -// InstallZitiEnrollerOptions the options for the upgrade ziti-enroller command -type InstallZitiEnrollerOptions struct { - InstallOptions - - Version string -} - -// NewCmdInstallZitiEnroller defines the command -func NewCmdInstallZitiEnroller(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &InstallZitiEnrollerOptions{ - InstallOptions: InstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-enroller", - Short: "Installs the Ziti Enroller app - if it has not been installed already", - Aliases: []string{"enroller"}, - Long: installZitiEnrollerLong, - Example: installZitiEnrollerExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - cmd.Flags().StringVarP(&options.Version, "version", "v", "", "The specific version to install") - options.addCommonFlags(cmd) - return cmd -} - -// Run implements the command -func (o *InstallZitiEnrollerOptions) Run() error { - newVersion, err := o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_ENROLLER) - if err != nil { - return err - } - - if o.Version != "" { - newVersion, err = semver.Make(o.Version) - } - - log.Infoln("Attempting to install '" + c.ZITI_ENROLLER + "' version: " + newVersion.String()) - - return o.installZitiApp(version.GetBranch(), c.ZITI_ENROLLER, false, newVersion.String()) -} diff --git a/ziti/cmd/ziti/cmd/install_ziti_fabrictest.go b/ziti/cmd/ziti/cmd/install_ziti_fabrictest.go deleted file mode 100644 index 199d74624..000000000 --- a/ziti/cmd/ziti/cmd/install_ziti_fabrictest.go +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/openziti/ziti/ziti/cmd/ziti/internal/log" - "github.com/openziti/ziti/common/version" - "github.com/blang/semver" - "github.com/spf13/cobra" -) - -var ( - installZitiFabricTestLong = templates.LongDesc(` - Installs the Ziti Fabric Test app if it has not been installed already -`) - - installZitiFabricTestExample = templates.Examples(` - # Install the Ziti Fabric Test app - ziti install ziti-fabric-test - `) -) - -// InstallZitiFabricTestOptions the options for the upgrade ziti-channel command -type InstallZitiFabricTestOptions struct { - InstallOptions - - Version string -} - -// NewCmdInstallZitiFabricTest defines the command -func NewCmdInstallZitiFabricTest(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &InstallZitiFabricTestOptions{ - InstallOptions: InstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-test", - Short: "Installs the Ziti Fabric Test app - if it has not been installed already", - Aliases: []string{"ft"}, - Long: installZitiFabricTestLong, - Example: installZitiFabricTestExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - cmd.Flags().StringVarP(&options.Version, "version", "v", "", "The specific version to install") - options.addCommonFlags(cmd) - return cmd -} - -// Run implements the command -func (o *InstallZitiFabricTestOptions) Run() error { - newVersion, err := o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_TEST) - if err != nil { - return err - } - - if o.Version != "" { - newVersion, err = semver.Make(o.Version) - } - - log.Infoln("Attempting to install '" + c.ZITI_FABRIC_TEST + "' version: " + newVersion.String()) - - return o.installZitiApp(version.GetBranch(), c.ZITI_FABRIC_TEST, false, newVersion.String()) -} diff --git a/ziti/cmd/ziti/cmd/install_ziti_mgmt_gw.go b/ziti/cmd/ziti/cmd/install_ziti_mgmt_gw.go deleted file mode 100644 index 50b5b647e..000000000 --- a/ziti/cmd/ziti/cmd/install_ziti_mgmt_gw.go +++ /dev/null @@ -1,94 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/openziti/ziti/ziti/cmd/ziti/internal/log" - "github.com/openziti/ziti/common/version" - "github.com/blang/semver" - "github.com/spf13/cobra" -) - -var ( - installZitiMgmtGwLong = templates.LongDesc(` - Installs the Ziti MgmtGw app if it has not been installed already -`) - - installZitiMgmtGwExample = templates.Examples(` - # Install the Ziti MgmtGw app - ziti install ziti-fabric-gw - `) -) - -// InstallZitiMgmtGwOptions the options for the upgrade ziti-fabric-gw command -type InstallZitiMgmtGwOptions struct { - InstallOptions - - Version string -} - -// NewCmdInstallZitiMgmtGw defines the command -func NewCmdInstallZitiMgmtGw(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &InstallZitiMgmtGwOptions{ - InstallOptions: InstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-gw", - Short: "Installs the Ziti MgmtGw app - if it has not been installed already", - Aliases: []string{"fabric-gw"}, - Long: installZitiMgmtGwLong, - Example: installZitiMgmtGwExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - cmd.Flags().StringVarP(&options.Version, "version", "v", "", "The specific version to install") - options.addCommonFlags(cmd) - return cmd -} - -// Run implements the command -func (o *InstallZitiMgmtGwOptions) Run() error { - newVersion, err := o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_GW) - if err != nil { - return err - } - - if o.Version != "" { - newVersion, err = semver.Make(o.Version) - } - - log.Infoln("Attempting to install '" + c.ZITI_FABRIC_GW + "' version: " + newVersion.String()) - - return o.installZitiApp(version.GetBranch(), c.ZITI_FABRIC_GW, false, newVersion.String()) -} diff --git a/ziti/cmd/ziti/cmd/lets_encrypt/revoke.go b/ziti/cmd/ziti/cmd/lets_encrypt/revoke.go index c257d41ff..8be0d9fe4 100644 --- a/ziti/cmd/ziti/cmd/lets_encrypt/revoke.go +++ b/ziti/cmd/ziti/cmd/lets_encrypt/revoke.go @@ -93,7 +93,7 @@ func runRevoke(options *leOptions) (err error) { return err } - log.Infof("Certificate was archived for domain:", options.domain) + log.Infof("Certificate was archived for domain: %v", options.domain) return nil diff --git a/ziti/cmd/ziti/cmd/uninstall.go b/ziti/cmd/ziti/cmd/uninstall.go index f61d64be9..a56f10f2e 100644 --- a/ziti/cmd/ziti/cmd/uninstall.go +++ b/ziti/cmd/ziti/cmd/uninstall.go @@ -68,12 +68,9 @@ func NewCmdUnInstall(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra. cmd.AddCommand(NewCmdUnInstallZitiController(f, out, errOut)) cmd.AddCommand(NewCmdUnInstallZitiFabric(f, out, errOut)) - cmd.AddCommand(NewCmdUnInstallZitiFabricTest(f, out, errOut)) - cmd.AddCommand(NewCmdUnInstallZitiMgmtGw(f, out, errOut)) cmd.AddCommand(NewCmdUnInstallZitiRouter(f, out, errOut)) cmd.AddCommand(NewCmdUnInstallZitiTunnel(f, out, errOut)) cmd.AddCommand(NewCmdUnInstallZitiEdgeTunnel(f, out, errOut)) - cmd.AddCommand(NewCmdUnInstallZitiEnroller(f, out, errOut)) cmd.AddCommand(NewCmdUnInstallZitiProxC(f, out, errOut)) return cmd diff --git a/ziti/cmd/ziti/cmd/uninstall_ziti_enroller.go b/ziti/cmd/ziti/cmd/uninstall_ziti_enroller.go deleted file mode 100644 index 35fa9f17e..000000000 --- a/ziti/cmd/ziti/cmd/uninstall_ziti_enroller.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/spf13/cobra" -) - -var ( - uninstallZitiEnrollerLong = templates.LongDesc(` - UnInstalls the Ziti Enroller app if it has previously been installed -`) - - uninstallZitiEnrollerExample = templates.Examples(` - # UnInstall the Ziti Enroller app - ziti uninstall ziti-enroller - `) -) - -// UnInstallZitiEnrollerOptions the options for the upgrade ziti-enroller command -type UnInstallZitiEnrollerOptions struct { - UnInstallOptions - - Version string -} - -// NewCmdUnInstallZitiEnroller defines the command -func NewCmdUnInstallZitiEnroller(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &UnInstallZitiEnrollerOptions{ - UnInstallOptions: UnInstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-enroller", - Short: "UnInstalls the Ziti Enroller app - if it has previously been installed", - Aliases: []string{"enroller"}, - Long: uninstallZitiEnrollerLong, - Example: uninstallZitiEnrollerExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - return cmd -} - -// Run implements the command -func (o *UnInstallZitiEnrollerOptions) Run() error { - o.deleteInstalledBinary(c.ZITI_ENROLLER) - return nil -} diff --git a/ziti/cmd/ziti/cmd/uninstall_ziti_fabrictest.go b/ziti/cmd/ziti/cmd/uninstall_ziti_fabrictest.go deleted file mode 100644 index c61df4683..000000000 --- a/ziti/cmd/ziti/cmd/uninstall_ziti_fabrictest.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/spf13/cobra" -) - -var ( - uninstallZitiFabricTestLong = templates.LongDesc(` - UnInstalls the Ziti Fabric Test app if it has previously been installed -`) - - uninstallZitiFabricTestExample = templates.Examples(` - # UnInstall the Ziti Fabric Test app - ziti uninstall ziti-fabric-test - `) -) - -// UnInstallZitiFabricTestOptions the options for the upgrade ziti-channel command -type UnInstallZitiFabricTestOptions struct { - UnInstallOptions - - Version string -} - -// NewCmdUnInstallZitiFabricTest defines the command -func NewCmdUnInstallZitiFabricTest(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &UnInstallZitiFabricTestOptions{ - UnInstallOptions: UnInstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-test", - Short: "UnInstalls the Ziti Fabric Test app - if it has previously been installed", - Aliases: []string{"ft"}, - Long: uninstallZitiFabricTestLong, - Example: uninstallZitiFabricTestExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - return cmd -} - -// Run implements the command -func (o *UnInstallZitiFabricTestOptions) Run() error { - o.deleteInstalledBinary(c.ZITI_FABRIC_TEST) - return nil -} diff --git a/ziti/cmd/ziti/cmd/uninstall_ziti_mgmt_gw.go b/ziti/cmd/ziti/cmd/uninstall_ziti_mgmt_gw.go deleted file mode 100644 index 706242778..000000000 --- a/ziti/cmd/ziti/cmd/uninstall_ziti_mgmt_gw.go +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/spf13/cobra" -) - -var ( - uninstallZitiMgmtGwLong = templates.LongDesc(` - UnInstalls the Ziti MgmtGw app if it has previously been installed -`) - - uninstallZitiMgmtGwExample = templates.Examples(` - # UnInstall the Ziti MgmtGw app - ziti uninstall ziti-fabric-gw - `) -) - -// UnInstallZitiMgmtGwOptions the options for the upgrade ziti-fabric-gw command -type UnInstallZitiMgmtGwOptions struct { - UnInstallOptions - - Version string -} - -// NewCmdUnInstallZitiMgmtGw defines the command -func NewCmdUnInstallZitiMgmtGw(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &UnInstallZitiMgmtGwOptions{ - UnInstallOptions: UnInstallOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-gw", - Short: "UnInstalls the Ziti MgmtGw app - if it has previously been installed", - Aliases: []string{"fabric-gw"}, - Long: uninstallZitiMgmtGwLong, - Example: uninstallZitiMgmtGwExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - return cmd -} - -// Run implements the command -func (o *UnInstallZitiMgmtGwOptions) Run() error { - o.deleteInstalledBinary(c.ZITI_FABRIC_GW) - return nil -} diff --git a/ziti/cmd/ziti/cmd/upgrade.go b/ziti/cmd/ziti/cmd/upgrade.go index 38613d79e..0a3ef2a49 100644 --- a/ziti/cmd/ziti/cmd/upgrade.go +++ b/ziti/cmd/ziti/cmd/upgrade.go @@ -69,8 +69,6 @@ func NewCmdUpgrade(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Co cmd.AddCommand(NewCmdUpgradeZiti(f, out, errOut)) cmd.AddCommand(NewCmdUpgradeZitiController(f, out, errOut)) cmd.AddCommand(NewCmdUpgradeZitiFabric(f, out, errOut)) - cmd.AddCommand(NewCmdUpgradeZitiFabricTest(f, out, errOut)) - cmd.AddCommand(NewCmdUpgradeZitiMgmtGw(f, out, errOut)) cmd.AddCommand(NewCmdUpgradeZitiRouter(f, out, errOut)) cmd.AddCommand(NewCmdUpgradeZitiTunnel(f, out, errOut)) cmd.AddCommand(NewCmdUpgradeZitiProxC(f, out, errOut)) diff --git a/ziti/cmd/ziti/cmd/upgrade_ziti_fabrictest.go b/ziti/cmd/ziti/cmd/upgrade_ziti_fabrictest.go deleted file mode 100644 index d4560d0b8..000000000 --- a/ziti/cmd/ziti/cmd/upgrade_ziti_fabrictest.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - "github.com/openziti/ziti/common/version" - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/spf13/cobra" -) - -var ( - upgradeZitiFabricTestLong = templates.LongDesc(` - Upgrades the Ziti Fabric Test app if there is a newer release -`) - - upgradeZitiFabricTestExample = templates.Examples(` - # Upgrades the Ziti Fabric Test app - ziti upgrade ziti-fabric-test - `) -) - -// UpgradeZitiFabricTestOptions the options for the upgrade ziti-fabric-test command -type UpgradeZitiFabricTestOptions struct { - CommonOptions - - Version string -} - -// NewCmdUpgradeZitiFabricTest defines the command -func NewCmdUpgradeZitiFabricTest(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &UpgradeZitiFabricTestOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-test", - Short: "Upgrades the Ziti Fabric Test app - if there is a new version available", - Aliases: []string{"ft"}, - Long: upgradeZitiFabricTestLong, - Example: upgradeZitiFabricTestExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - cmd.Flags().StringVarP(&options.Version, "version", "v", "", "The specific version to upgrade to") - options.addCommonFlags(cmd) - return cmd -} - -// Run implements the command -func (o *UpgradeZitiFabricTestOptions) Run() error { - newVersion, err := o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_TEST) - if err != nil { - return err - } - - newVersionStr := newVersion.String() - - if o.Version != "" { - newVersionStr = o.Version - } - - o.deleteInstalledBinary(c.ZITI_FABRIC_TEST) - - return o.installZitiApp(version.GetBranch(), c.ZITI_FABRIC_TEST, true, newVersionStr) -} diff --git a/ziti/cmd/ziti/cmd/upgrade_ziti_mgmt_gw.go b/ziti/cmd/ziti/cmd/upgrade_ziti_mgmt_gw.go deleted file mode 100644 index 1ba639e0b..000000000 --- a/ziti/cmd/ziti/cmd/upgrade_ziti_mgmt_gw.go +++ /dev/null @@ -1,92 +0,0 @@ -/* - 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 cmd - -import ( - "io" - - "github.com/openziti/ziti/common/version" - cmdutil "github.com/openziti/ziti/ziti/cmd/ziti/cmd/factory" - cmdhelper "github.com/openziti/ziti/ziti/cmd/ziti/cmd/helpers" - "github.com/openziti/ziti/ziti/cmd/ziti/cmd/templates" - c "github.com/openziti/ziti/ziti/cmd/ziti/constants" - "github.com/spf13/cobra" -) - -var ( - upgradeZitiMgmtGwLong = templates.LongDesc(` - Upgrades the Ziti MgmtGw app if there is a newer release -`) - - upgradeZitiMgmtGwExample = templates.Examples(` - # Upgrades the Ziti MgmtGw app - ziti upgrade ziti-fabric-gw - `) -) - -// UpgradeZitiMgmtGwOptions the options for the upgrade ziti-fabric-gw command -type UpgradeZitiMgmtGwOptions struct { - CommonOptions - - Version string -} - -// NewCmdUpgradeZitiMgmtGw defines the command -func NewCmdUpgradeZitiMgmtGw(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { - options := &UpgradeZitiMgmtGwOptions{ - CommonOptions: CommonOptions{ - Factory: f, - Out: out, - Err: errOut, - }, - } - - cmd := &cobra.Command{ - Use: "ziti-fabric-gw", - Short: "Upgrades the Ziti MgmtGw app - if there is a new version available", - Aliases: []string{"fabric-gw", "gw"}, - Long: upgradeZitiMgmtGwLong, - Example: upgradeZitiMgmtGwExample, - Run: func(cmd *cobra.Command, args []string) { - options.Cmd = cmd - options.Args = args - err := options.Run() - cmdhelper.CheckErr(err) - }, - } - cmd.Flags().StringVarP(&options.Version, "version", "v", "", "The specific version to upgrade to") - options.addCommonFlags(cmd) - return cmd -} - -// Run implements the command -func (o *UpgradeZitiMgmtGwOptions) Run() error { - newVersion, err := o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_GW) - if err != nil { - return err - } - - newVersionStr := newVersion.String() - - if o.Version != "" { - newVersionStr = o.Version - } - - o.deleteInstalledBinary(c.ZITI_FABRIC_GW) - - return o.installZitiApp(version.GetBranch(), c.ZITI_FABRIC_GW, true, newVersionStr) -} diff --git a/ziti/cmd/ziti/cmd/use.go b/ziti/cmd/ziti/cmd/use.go index 018a013ce..fd3719825 100644 --- a/ziti/cmd/ziti/cmd/use.go +++ b/ziti/cmd/ziti/cmd/use.go @@ -136,14 +136,6 @@ func (o *UseOptions) Run() error { if err != nil { log.Errorf("Error: install failed %s \n", err.Error()) } - err = o.install(branch, c.ZITI_FABRIC_GW) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } - err = o.install(branch, c.ZITI_FABRIC_TEST) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } err = o.install(branch, c.ZITI_ROUTER) if err != nil { log.Errorf("Error: install failed %s \n", err.Error()) @@ -152,10 +144,6 @@ func (o *UseOptions) Run() error { if err != nil { log.Errorf("Error: install failed %s \n", err.Error()) } - err = o.install(branch, c.ZITI_ENROLLER) - if err != nil { - log.Errorf("Error: install failed %s \n", err.Error()) - } err = o.installZitiProxC("") if err != nil { diff --git a/ziti/cmd/ziti/cmd/version.go b/ziti/cmd/ziti/cmd/version.go index a4a315c69..5792c176b 100644 --- a/ziti/cmd/ziti/cmd/version.go +++ b/ziti/cmd/ziti/cmd/version.go @@ -83,10 +83,7 @@ func (o *VersionOptions) Run() error { table.AddRow(c.ZITI, info(version.GetBuildMetadata(o.Verbose))) o.versionPrintZitiApp(c.ZITI_CONTROLLER, &table) - o.versionPrintZitiApp(c.ZITI_ENROLLER, &table) o.versionPrintZitiApp(c.ZITI_FABRIC, &table) - o.versionPrintZitiApp(c.ZITI_FABRIC_GW, &table) - o.versionPrintZitiApp(c.ZITI_FABRIC_TEST, &table) o.versionPrintZitiApp(c.ZITI_PROX_C, &table) o.versionPrintZitiApp(c.ZITI_ROUTER, &table) o.versionPrintZitiApp(c.ZITI_TUNNEL, &table) @@ -133,8 +130,6 @@ func (o *VersionOptions) versionCheck() error { o.versionCheckZitiApp(c.ZITI) o.versionCheckZitiApp(c.ZITI_CONTROLLER) o.versionCheckZitiApp(c.ZITI_FABRIC) - o.versionCheckZitiApp(c.ZITI_FABRIC_TEST) - o.versionCheckZitiApp(c.ZITI_FABRIC_GW) o.versionCheckZitiApp(c.ZITI_PROX_C) o.versionCheckZitiApp(c.ZITI_ROUTER) o.versionCheckZitiApp(c.ZITI_TUNNEL) @@ -158,10 +153,6 @@ func (o *VersionOptions) versionCheckZitiApp(zitiApp string) error { newVersion, err = o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_CONTROLLER) case c.ZITI_FABRIC: newVersion, err = o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC) - case c.ZITI_FABRIC_TEST: - newVersion, err = o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_TEST) - case c.ZITI_FABRIC_GW: - newVersion, err = o.getLatestZitiAppVersion(version.GetBranch(), c.ZITI_FABRIC_GW) case c.ZITI_PROX_C: newVersion, err = o.getLatestGitHubReleaseVersion(version.GetBranch(), c.ZITI_SDK_C_GITHUB) case c.ZITI_ROUTER: @@ -202,10 +193,6 @@ func (o *VersionOptions) versionCheckZitiApp(zitiApp string) error { err = o.upgradeZitiController() case c.ZITI_FABRIC: err = o.upgradeZitiFabric() - case c.ZITI_FABRIC_TEST: - err = o.upgradeZitiFabricTest() - case c.ZITI_FABRIC_GW: - err = o.upgradeZitiMgmtGw() case c.ZITI_PROX_C: err = o.upgradeZitiProxC() case c.ZITI_ROUTER: @@ -248,20 +235,6 @@ func (o *VersionOptions) upgradeZitiFabric() error { return options.Run() } -func (o *VersionOptions) upgradeZitiFabricTest() error { - options := &UpgradeZitiFabricTestOptions{ - CommonOptions: o.CommonOptions, - } - return options.Run() -} - -func (o *VersionOptions) upgradeZitiMgmtGw() error { - options := &UpgradeZitiMgmtGwOptions{ - CommonOptions: o.CommonOptions, - } - return options.Run() -} - func (o *VersionOptions) upgradeZitiProxC() error { options := &UpgradeZitiProxCOptions{ CommonOptions: o.CommonOptions, diff --git a/ziti/cmd/ziti/constants/constants.go b/ziti/cmd/ziti/constants/constants.go index d4840b5dc..75aa1ec00 100644 --- a/ziti/cmd/ziti/constants/constants.go +++ b/ziti/cmd/ziti/constants/constants.go @@ -20,13 +20,10 @@ const ( ZITI = "ziti" ZITI_CONTROLLER = "ziti-controller" ZITI_FABRIC = "ziti-fabric" - ZITI_FABRIC_TEST = "ziti-fabric-test" - ZITI_FABRIC_GW = "ziti-fabric-gw" ZITI_ROUTER = "ziti-router" ZITI_TUNNEL = "ziti-tunnel" ZITI_EDGE_TUNNEL = "ziti-edge-tunnel" ZITI_EDGE_TUNNEL_GITHUB = "ziti-tunnel-sdk-c" - ZITI_ENROLLER = "ziti-enroller" ZITI_PROX_C = "ziti-prox-c" ZITI_SDK_C_GITHUB = "ziti-sdk-c" diff --git a/ziti/cmd/ziti/util/identities.go b/ziti/cmd/ziti/util/identities.go index 29f4d3d93..cb77368a2 100644 --- a/ziti/cmd/ziti/util/identities.go +++ b/ziti/cmd/ziti/util/identities.go @@ -1,17 +1,38 @@ package util import ( + "crypto/tls" + "crypto/x509" "encoding/json" + "fmt" + httptransport "github.com/go-openapi/runtime/client" + "github.com/openziti/edge/rest_management_api_client" + "github.com/openziti/foundation/common/constants" + "github.com/openziti/foundation/identity/identity" "github.com/openziti/ziti/ziti/cmd/ziti/cmd/common" "github.com/pkg/errors" + "gopkg.in/resty.v1" "io/ioutil" + "net" + "net/http" + "net/url" "os" "path/filepath" + "strings" + "time" +) + +type API string + +const ( + FabricAPI API = "fabric" + EdgeAPI API = "edge" ) type RestClientConfig struct { - Identities map[string]*RestClientIdentity `json:"identities"` - Default string `json:"default"` + EdgeIdentities map[string]*RestClientEdgeIdentity `json:"edgeIdentities"` + FabricIdentities map[string]*RestClientFabricIdentity `json:"fabricIdentities"` + Default string `json:"default"` } func (self *RestClientConfig) GetIdentity() string { @@ -24,31 +45,201 @@ func (self *RestClientConfig) GetIdentity() string { return "default" } -type RestClientIdentity struct { +type RestClientIdentity interface { + 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) +} + +func NewRequest(restClientIdentity RestClientIdentity, timeoutInSeconds int, verbose bool) (*resty.Request, error) { + client, err := restClientIdentity.NewClient(time.Duration(timeoutInSeconds)*time.Second, verbose) + if err != nil { + return nil, err + } + return restClientIdentity.NewRequest(client).SetHeader("Content-Type", "application/json"), nil +} + +type RestClientEdgeIdentity struct { Url string `json:"url"` Username string `json:"username"` Token string `json:"token"` LoginTime string `json:"loginTime"` - Cert string `json:"cert,omitempty"` + CaCert string `json:"caCert,omitempty"` ReadOnly bool `json:"readOnly"` } -func (self *RestClientIdentity) GetCert() string { - return self.Cert +func (self *RestClientEdgeIdentity) IsReadOnly() bool { + return self.ReadOnly } -func (self *RestClientIdentity) GetToken() string { - return self.Token +func (self *RestClientEdgeIdentity) NewClient(timeout time.Duration, verbose bool) (*resty.Client, error) { + client := newClient() + client.SetRootCertificate(self.CaCert) + client.SetTimeout(timeout) + client.SetDebug(verbose) + return client, nil } -func (self *RestClientIdentity) GetBaseUrl() string { - return self.Url +func (self *RestClientEdgeIdentity) NewRequest(client *resty.Client) *resty.Request { + r := client.R() + r.SetHeader(constants.ZitiSession, self.Token) + return r +} + +func (self *RestClientEdgeIdentity) GetBaseUrlForApi(api API) (string, error) { + if api == EdgeAPI { + return self.Url, nil + } + if api == FabricAPI { + u, err := url.Parse(self.Url) + if err != nil { + return "", err + } + return u.Scheme + "://" + u.Host + "/fabric/v1", nil + } + 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) + if err != nil { + return nil, errors.Errorf("could not read session certificates [%s]: %v", self.CaCert, 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 + } + + clientRuntime := httptransport.NewWithClient(parsedHost.Host, rest_management_api_client.DefaultBasePath, rest_management_api_client.DefaultSchemes, httpClient) + + clientRuntime.DefaultAuthentication = &EdgeManagementAuth{ + Token: self.Token, + } + + return rest_management_api_client.New(clientRuntime, nil), nil +} + +type RestClientFabricIdentity struct { + Url string `json:"url"` + CaCert string `json:"caCert,omitempty"` + ClientCert string `json:"clientCert,omitempty"` + ClientKey string `json:"clientKey,omitempty"` + ReadOnly bool `json:"readOnly"` +} + +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 { + return nil, errors.Wrap(err, "unable to load identity") + } + client := newClient() + client.SetTLSClientConfig(id.ClientTLSConfig()) + client.SetTimeout(timeout) + client.SetDebug(verbose) + return client, nil +} + +func (self *RestClientFabricIdentity) NewRequest(client *resty.Client) *resty.Request { + return client.R() +} + +func (self *RestClientFabricIdentity) GetBaseUrlForApi(api API) (string, error) { + if api == FabricAPI { + u, err := url.Parse(self.Url) + if err != nil { + return "", err + } + return u.Scheme + "://" + u.Host + "/fabric/v1", nil + } + return "", errors.Errorf("unsupport api %v", api) +} + +func (self *RestClientFabricIdentity) IsReadOnly() bool { + return self.ReadOnly +} + +func (self *RestClientFabricIdentity) NewEdgeManagementClient(EdgeManagementClientOpts) (*rest_management_api_client.ZitiEdgeManagement, error) { + return nil, errors.New("fabric identities cannot be used to connect to the edge management API") } func LoadRestClientConfig() (*RestClientConfig, string, error) { - config := &RestClientConfig{ - Identities: map[string]*RestClientIdentity{}, - } + config := &RestClientConfig{} cfgDir, err := ConfigDir() if err != nil { @@ -71,6 +262,14 @@ func LoadRestClientConfig() (*RestClientConfig, string, error) { return nil, "", errors.Wrapf(err, "error while parsing JSON config file %v", configFile) } + if config.EdgeIdentities == nil { + config.EdgeIdentities = map[string]*RestClientEdgeIdentity{} + } + + if config.FabricIdentities == nil { + config.FabricIdentities = map[string]*RestClientFabricIdentity{} + } + return config, configFile, nil } @@ -102,16 +301,16 @@ func PersistRestClientConfig(config *RestClientConfig) error { return nil } -var selectedIdentity *RestClientIdentity +var selectedIdentity RestClientIdentity -func LoadSelectedIdentity() (*RestClientIdentity, error) { +func LoadSelectedIdentity() (RestClientIdentity, error) { if selectedIdentity == nil { config, configFile, err := LoadRestClientConfig() if err != nil { return nil, err } id := config.GetIdentity() - clientIdentity, found := config.Identities[id] + clientIdentity, found := config.EdgeIdentities[id] if !found { return nil, errors.Errorf("no identity '%v' found in cli config %v", id, configFile) } @@ -120,12 +319,51 @@ func LoadSelectedIdentity() (*RestClientIdentity, error) { return selectedIdentity, nil } -func LoadSelectedRWIdentity() (*RestClientIdentity, error) { +func LoadSelectedRWIdentity() (RestClientIdentity, error) { id, err := LoadSelectedIdentity() if err != nil { return nil, err } - if id.ReadOnly { + if id.IsReadOnly() { + return nil, errors.New("this login is marked read-only, only GET operations are allowed") + } + return id, nil +} + +func LoadSelectedIdentityForApi(api API) (RestClientIdentity, error) { + if api == EdgeAPI { + return LoadSelectedIdentity() + } + + if api == FabricAPI { + if selectedIdentity == nil { + config, configFile, err := LoadRestClientConfig() + if err != nil { + return nil, err + } + id := config.GetIdentity() + var clientIdentity RestClientIdentity + var found bool + clientIdentity, found = config.EdgeIdentities[id] + if !found { + clientIdentity, found = config.FabricIdentities[id] + if !found { + return nil, errors.Errorf("no identity '%v' found in cli config %v", id, configFile) + } + } + selectedIdentity = clientIdentity + } + return selectedIdentity, nil + } + return nil, errors.Errorf("unsupported API: '%v'", api) +} + +func LoadSelectedRWIdentityForApi(api API) (RestClientIdentity, error) { + id, err := LoadSelectedIdentityForApi(api) + if err != nil { + return nil, err + } + if id.IsReadOnly() { return nil, errors.New("this login is marked read-only, only GET operations are allowed") } return id, nil diff --git a/ziti/cmd/ziti/util/rest.go b/ziti/cmd/ziti/util/rest.go index 31806e6b6..eb6ef54a1 100644 --- a/ziti/cmd/ziti/util/rest.go +++ b/ziti/cmd/ziti/util/rest.go @@ -21,26 +21,19 @@ import ( "archive/zip" "bytes" "compress/gzip" - "crypto/tls" - "crypto/x509" "encoding/json" "fmt" "github.com/Jeffail/gabs" "github.com/blang/semver" openApiRuntime "github.com/go-openapi/runtime" - httptransport "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" "github.com/openziti/edge/rest_management_api_client" "github.com/openziti/edge/rest_model" - "github.com/openziti/foundation/common/constants" "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" - "github.com/pkg/errors" "gopkg.in/resty.v1" "io" - "io/ioutil" - "net" "net/http" "net/url" "os" @@ -602,30 +595,28 @@ func outputJson(out io.Writer, data []byte) { } } -func EdgeControllerDetailEntity(entityType, entityId string, logJSON bool, out io.Writer, timeout int, verbose bool) (*gabs.Container, error) { - restClientIdentity, err := LoadSelectedIdentity() +func ControllerDetailEntity(api API, entityType, entityId string, logJSON bool, out io.Writer, timeout int, verbose bool) (*gabs.Container, error) { + restClientIdentity, err := LoadSelectedRWIdentityForApi(api) if err != nil { return nil, err } - client := newClient() - - if restClientIdentity.GetCert() != "" { - client.SetRootCertificate(restClientIdentity.GetCert()) + baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) + if err != nil { + return nil, err } - queryUrl := restClientIdentity.GetBaseUrl() + "/" + path.Join(entityType, entityId) + req, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return nil, err + } - resp, err := client. - SetTimeout(time.Duration(time.Duration(timeout)*time.Second)). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.GetToken()). - Get(queryUrl) + queryUrl := baseUrl + "/" + path.Join(entityType, entityId) + + resp, err := req.Get(queryUrl) if err != nil { - return nil, fmt.Errorf("unable to list entities at %v in Ziti Edge Controller at %v. Error: %v", queryUrl, restClientIdentity.GetBaseUrl(), err) + return nil, fmt.Errorf("unable to list entities at %v in Ziti Edge Controller at %v. Error: %v", queryUrl, baseUrl, err) } if resp.StatusCode() != http.StatusOK { @@ -657,33 +648,36 @@ func EdgeControllerListSubEntities(entityType, subType, entityId string, filter // EdgeControllerList will list entities of the given type in the given Edge Controller func EdgeControllerList(path string, params url.Values, logJSON bool, out io.Writer, timeout int, verbose bool) (*gabs.Container, error) { - restClientIdentity, err := LoadSelectedIdentity() + return ControllerList("edge", path, params, logJSON, out, timeout, verbose) +} + +// ControllerList will list entities of the given type in the given Edge Controller +func ControllerList(api API, path string, params url.Values, logJSON bool, out io.Writer, timeout int, verbose bool) (*gabs.Container, error) { + restClientIdentity, err := LoadSelectedIdentityForApi(api) if err != nil { return nil, err } - client := newClient() - - if restClientIdentity.GetCert() != "" { - client.SetRootCertificate(restClientIdentity.GetCert()) + baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) + if err != nil { + return nil, err } - queryUrl := restClientIdentity.GetBaseUrl() + "/" + path + req, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return nil, err + } + + queryUrl := baseUrl + "/" + path if len(params) > 0 { queryUrl += "?" + params.Encode() } - resp, err := client. - SetTimeout(time.Duration(timeout)*time.Second). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.GetToken()). - Get(queryUrl) + resp, err := req.Get(queryUrl) if err != nil { - return nil, fmt.Errorf("unable to list entities at %v in Ziti Edge Controller at %v. Error: %v", queryUrl, restClientIdentity.GetBaseUrl(), err) + return nil, fmt.Errorf("unable to list entities at %v in Ziti Controller at %v. Error: %v", queryUrl, baseUrl, err) } if resp.StatusCode() != http.StatusOK { @@ -784,97 +778,7 @@ func NewEdgeManagementClient(clientOpts EdgeManagementClientOpts) (*rest_managem if err != nil { return nil, err } - - 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 restClientIdentity.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(restClientIdentity.Cert) - if err != nil { - return nil, errors.Errorf("could not read session certificates [%s]: %v", restClientIdentity.Cert, err) - } - - rootCaPool.AppendCertsFromPEM(rootPemData) - - httpClientTransport.TLSClientConfig = &tls.Config{ - RootCAs: rootCaPool, - } - - httpClient := &http.Client{ - Transport: httpClientTransport, - Timeout: 10 * time.Second, - } - parsedHost, err := url.Parse(restClientIdentity.Url) - if err != nil { - return nil, err - } - - clientRuntime := httptransport.NewWithClient(parsedHost.Host, rest_management_api_client.DefaultBasePath, rest_management_api_client.DefaultSchemes, httpClient) - - clientRuntime.DefaultAuthentication = &EdgeManagementAuth{ - Token: restClientIdentity.Token, - } - - return rest_management_api_client.New(clientRuntime, nil), nil + return restClientIdentity.NewEdgeManagementClient(clientOpts) } type EdgeManagementAuth struct { @@ -885,42 +789,39 @@ func (e EdgeManagementAuth) AuthenticateRequest(request openApiRuntime.ClientReq return request.SetHeaderParam("zt-session", e.Token) } -// EdgeControllerCreate will create entities of the given type in the given Edge Controller -func EdgeControllerCreate(entityType string, body string, out io.Writer, logRequestJson, logResponseJson bool, timeout int, verbose bool) (*gabs.Container, error) { - restClientIdentity, err := LoadSelectedRWIdentity() +// ControllerCreate will create entities of the given type in the given Edge Controller +func ControllerCreate(api API, entityType string, body string, out io.Writer, logRequestJson, logResponseJson bool, timeout int, verbose bool) (*gabs.Container, error) { + restClientIdentity, err := LoadSelectedRWIdentityForApi(api) if err != nil { return nil, err } - client := newClient() - - if restClientIdentity.Cert != "" { - client.SetRootCertificate(restClientIdentity.Cert) + baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) + if err != nil { + return nil, err } - url := restClientIdentity.GetBaseUrl() + "/" + entityType + req, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return nil, err + } + + url := baseUrl + "/" + entityType if logRequestJson { fmt.Printf("%v to %v\n", "POST", url) outputJson(out, []byte(body)) fmt.Println() } - resp, err := client. - SetTimeout(time.Duration(timeout)*time.Second). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.Token). - SetBody(body). - Post(url) + resp, err := req.SetBody(body).Post(url) if err != nil { - return nil, fmt.Errorf("unable to create %v instance in Ziti Edge Controller at %v. Error: %v", entityType, restClientIdentity.Url, err) + return nil, fmt.Errorf("unable to create %v instance in Ziti Edge Controller at %v. Error: %v", entityType, baseUrl, err) } if resp.StatusCode() != http.StatusCreated { return nil, fmt.Errorf("error creating %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - entityType, restClientIdentity.GetBaseUrl(), resp.Status(), prettyPrintResponse(resp)) + entityType, baseUrl, resp.Status(), prettyPrintResponse(resp)) } if logResponseJson { @@ -930,71 +831,78 @@ func EdgeControllerCreate(entityType string, body string, out io.Writer, logRequ jsonParsed, err := gabs.ParseJSON(resp.Body()) if err != nil { - return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", restClientIdentity.GetBaseUrl(), resp.String()) + return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", baseUrl, resp.String()) } return jsonParsed, nil } -// EdgeControllerDelete will delete entities of the given type in the given Edge Controller -func EdgeControllerDelete(entityType string, id string, out io.Writer, logResponseJson bool, timeout int, verbose bool) (*gabs.Container, error) { - restClientIdentity, err := LoadSelectedRWIdentity() +// ControllerDelete will delete entities of the given type in the given Controller +func ControllerDelete(api API, entityType string, id string, body string, out io.Writer, logRequestJson bool, logResponseJson bool, timeout int, verbose bool) error { + restClientIdentity, err := LoadSelectedRWIdentityForApi(api) if err != nil { - return nil, err + return err } - client := newClient() - - if restClientIdentity.Cert != "" { - client.SetRootCertificate(restClientIdentity.Cert) + baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) + if err != nil { + return err } + + req, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return err + } + entityPath := entityType + "/" + id - fullUrl := restClientIdentity.GetBaseUrl() + "/" + entityPath + fullUrl := baseUrl + "/" + entityPath - resp, err := client. - SetTimeout(time.Duration(timeout)*time.Second). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.Token). - Delete(fullUrl) + if logRequestJson { + fmt.Printf("%v to %v\n", "POST", fullUrl) + outputJson(out, []byte(body)) + fmt.Println() + } + + if body != "" { + req = req.SetBody(body) + } + + resp, err := req.Delete(fullUrl) if err != nil { - return nil, fmt.Errorf("unable to delete %v instance in Ziti Edge Controller at %v. Error: %v", entityPath, restClientIdentity.Url, err) + return fmt.Errorf("unable to delete %v instance in Ziti Edge Controller at %v. Error: %v", entityPath, baseUrl, err) } if resp.StatusCode() != http.StatusOK { - return nil, fmt.Errorf("error deleting %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - entityPath, restClientIdentity.GetBaseUrl(), resp.Status(), prettyPrintResponse(resp)) + return fmt.Errorf("error deleting %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", + entityPath, baseUrl, resp.Status(), prettyPrintResponse(resp)) } if logResponseJson { outputJson(out, resp.Body()) } - jsonParsed, err := gabs.ParseJSON(resp.Body()) - - if err != nil { - return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", restClientIdentity.GetBaseUrl(), resp.String()) - } - - return jsonParsed, nil + return nil } -// EdgeControllerUpdate will update entities of the given type in the given Edge Controller -func EdgeControllerUpdate(entityType string, body string, out io.Writer, method string, logRequestJson, logResponseJSON bool, timeout int, verbose bool) (*gabs.Container, error) { - restClientIdentity, err := LoadSelectedRWIdentity() +// ControllerUpdate will update entities of the given type in the given Edge Controller +func ControllerUpdate(api API, entityType string, body string, out io.Writer, method string, logRequestJson, logResponseJSON bool, timeout int, verbose bool) (*gabs.Container, error) { + restClientIdentity, err := LoadSelectedRWIdentityForApi(api) if err != nil { return nil, err } - client := newClient() - - if restClientIdentity.Cert != "" { - client.SetRootCertificate(restClientIdentity.Cert) + baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) + if err != nil { + return nil, err } - url := restClientIdentity.GetBaseUrl() + "/" + entityType + req, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return nil, err + } + + url := baseUrl + "/" + entityType if logRequestJson { fmt.Printf("%v to %v\n", method, url) @@ -1002,22 +910,15 @@ func EdgeControllerUpdate(entityType string, body string, out io.Writer, method fmt.Println() } - resp, err := client. - SetTimeout(time.Duration(timeout)*time.Second). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.Token). - SetBody(body). - Execute(method, url) + resp, err := req.SetBody(body).Execute(method, url) if err != nil { - return nil, fmt.Errorf("unable to update %v instance in Ziti Edge Controller at %v. Error: %v", entityType, restClientIdentity.GetBaseUrl(), err) + return nil, fmt.Errorf("unable to update %v instance in Ziti Edge Controller at %v. Error: %v", entityType, baseUrl, err) } if resp.StatusCode() != http.StatusOK && resp.StatusCode() != http.StatusAccepted { return nil, fmt.Errorf("error updating %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - entityType, restClientIdentity.GetBaseUrl(), resp.Status(), prettyPrintResponse(resp)) + entityType, baseUrl, resp.Status(), prettyPrintResponse(resp)) } if logResponseJSON { @@ -1031,40 +932,43 @@ func EdgeControllerUpdate(entityType string, body string, out io.Writer, method jsonParsed, err := gabs.ParseJSON(resp.Body()) if err != nil { - return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", restClientIdentity.GetBaseUrl(), resp.String()) + return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", baseUrl, resp.String()) } return jsonParsed, nil } -// EdgeControllerVerify will create entities of the given type in the given Edge Controller +// EdgeControllerVerify will verify entities of the given type in the given Edge Controller func EdgeControllerVerify(entityType, id, body string, out io.Writer, logJSON bool, timeout int, verbose bool) error { restClientIdentity, err := LoadSelectedRWIdentity() if err != nil { return err } - client := newClient() - - if restClientIdentity.Cert != "" { - client.SetRootCertificate(restClientIdentity.Cert) + baseUrl, err := restClientIdentity.GetBaseUrlForApi("edge") + if err != nil { + return err } - resp, err := client. - SetTimeout(time.Duration(timeout)*time.Second). - SetDebug(verbose). - R(). + + client, err := restClientIdentity.NewClient(time.Duration(timeout)*time.Second, verbose) + if err != nil { + return err + } + + req := restClientIdentity.NewRequest(client) + + resp, err := req. SetHeader("Content-Type", "text/plain"). - SetHeader(constants.ZitiSession, restClientIdentity.Token). SetBody(body). - Post(restClientIdentity.GetBaseUrl() + "/" + entityType + "/" + id + "/verify") + Post(baseUrl + "/" + entityType + "/" + id + "/verify") if err != nil { - return fmt.Errorf("unable to verify %v instance [%s] in Ziti Edge Controller at %v. Error: %v", entityType, id, restClientIdentity.GetBaseUrl(), err) + return fmt.Errorf("unable to verify %v instance [%s] in Ziti Edge Controller at %v. Error: %v", entityType, id, baseUrl, err) } if resp.StatusCode() != http.StatusOK { return fmt.Errorf("error verifying %v instance (%v) in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - entityType, id, restClientIdentity.GetBaseUrl(), resp.Status(), prettyPrintResponse(resp)) + entityType, id, baseUrl, resp.Status(), prettyPrintResponse(resp)) } if logJSON { @@ -1080,28 +984,25 @@ func EdgeControllerRequest(entityType string, out io.Writer, logJSON bool, timeo return nil, err } - client := newClient() - - if restClientIdentity.Cert != "" { - client.SetRootCertificate(restClientIdentity.Cert) + baseUrl, err := restClientIdentity.GetBaseUrlForApi("edge") + if err != nil { + return nil, err } - request := client. - SetTimeout(time.Duration(time.Duration(timeout)*time.Second)). - SetDebug(verbose). - R(). - SetHeader("Content-Type", "application/json"). - SetHeader(constants.ZitiSession, restClientIdentity.Token) + request, err := NewRequest(restClientIdentity, timeout, verbose) + if err != nil { + return nil, err + } - resp, err := doRequest(request, restClientIdentity.GetBaseUrl()+"/"+entityType) + resp, err := doRequest(request, baseUrl+"/"+entityType) if err != nil { - return nil, fmt.Errorf("unable to [%s] %v instance in Ziti Edge Controller at %v. Error: %v", request.Method, entityType, restClientIdentity.GetBaseUrl(), err) + return nil, fmt.Errorf("unable to [%s] %v instance in Ziti Edge Controller at %v. Error: %v", request.Method, entityType, baseUrl, err) } if resp.StatusCode() != http.StatusOK { return nil, fmt.Errorf("error performing request [%s] %v instance in Ziti Edge Controller at %v. Status code: %v, Server returned: %v", - request.Method, entityType, restClientIdentity.GetBaseUrl(), resp.Status(), prettyPrintResponse(resp)) + request.Method, entityType, baseUrl, resp.Status(), prettyPrintResponse(resp)) } if logJSON { @@ -1115,7 +1016,7 @@ func EdgeControllerRequest(entityType string, out io.Writer, logJSON bool, timeo jsonParsed, err := gabs.ParseJSON(resp.Body()) if err != nil { - return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", restClientIdentity.GetBaseUrl(), resp.String()) + return nil, fmt.Errorf("unable to parse response from %v. Server returned: %v", baseUrl, resp.String()) } return jsonParsed, nil