diff --git a/.github/workflows/fablab-db-creation.yml b/.github/workflows/fablab-db-creation.yml new file mode 100644 index 000000000..3f1cce1e0 --- /dev/null +++ b/.github/workflows/fablab-db-creation.yml @@ -0,0 +1,61 @@ +name: fablab db-creation workflow + +on: + workflow_dispatch: + push: + branches: + - main +env: + GOFLAGS: "-trimpath" + GOX_OUTPUT: "release/{{.Arch}}/{{.OS}}/{{.Dir}}" + GOX_TEST_OUTPUT: "test/{{.Arch}}/{{.OS}}/bin/{{.Dir}}" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: "us-east-1" + gh_ci_key: ${{ secrets.GH_CI_KEY }} + S3_KEY: ${{ secrets.AWS_ACCESS_KEY_ID }} + S3_SECRET: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + +jobs: + build: + name: Build and Run + runs-on: ubuntu-latest + steps: + - name: Checkout ziti + uses: actions/checkout@v3 + with: + path: ziti + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: '1.20.x' + + - name: Install Ziti CI + uses: openziti/ziti-ci@v1 + + - name: Configure Git + run: | + cd ziti + $(go env GOPATH)/bin/ziti-ci configure-git + + - name: Pull ZITI_VERSION and set as $GITHUB_ENV for use with fablab + run: | + cd ziti + version="$($(go env GOPATH)/bin/ziti-ci -q get-current-version)" + echo "Ziti Version: $version" + echo "ZITI_VERSION=$version" >> $GITHUB_ENV + + - name: Build and Run + run: | + cd ziti/zititest/models/db-creation + go build -o db-creation main.go + echo "ZITI_ROOT=$(go env GOPATH)/bin" >> "$GITHUB_ENV" + ./db-creation create db-creation + ./db-creation up + + - name: Teardown + if: always() + run: | + cd ziti/zititest/models/db-creation + ./db-creation dispose \ No newline at end of file diff --git a/ADOPTERS.md b/ADOPTERS.md index 0daefead4..14b8cb154 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -27,3 +27,4 @@ Here's the list of projects using and adopting OpenZiti | KubeZT - Zero Trust Kubernetes | https://KubeZT.com/ | | KubeZT is an on-demand Kubernetes environment that enables developers to build and deploy highly secure applications for high-compliance organizations. | | Analytics HQ | https://AnalyticsHQ.com/ | | Analytics HQ is a next-generation unified platform built for modern data management and advanced analytics. | | PITS Global Data Recovery Services | https://www.pitsdatarecovery.net/ | | PITS Global Data Recovery Services is a data recovery company in the United States that offers services for recovering data from hard drives, SSDs, flash drives, RAID arrays and more. | +| KEOIC | http://www.keoic.com/ | | KEO International Consultants is a multifaceted AEC firm with a presence across the Middle East and Europe. KEO uses the CloudZiti platform to facilitate zero-trust connections for users, devices, and applications throughout their worldwide network of branch offices and sites. | diff --git a/CHANGELOG.md b/CHANGELOG.md index 81c14be56..5c91da482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,61 @@ +# Release 0.31.0 + +## What's New + +* Rate limited for model changes + +## Rate Limiter for Model Changes + +To prevent the controller from being overwhelmed by a flood of changes, a rate limiter +can be enabled in the configuration file. A maximum number of queued changes can also +be configured. The rate limited is disabled by default for now. If not specified the +default number of queued changes is 100. + +When the rate limit is hit, an error will be returned. If the request came in from +the REST API, the response will use HTTP status code 429 (too many requests). + +The OpenAPI specs have been updated, so if you're using a generated client to make +REST calls, it's recommened that you regenerate your client. + + +``` +commandRateLimiter: + enabled: true + maxQueued: 100 +``` + +If the rate limiter is enabled, the following metrics will be produced: + +* `command.limiter.queued_count` - guage of the current number of queued operations +* `command.limiter.work_timer` - timer for operations. Includes the following: + * A histogram of how long operations take to complete + * A meter showing that rate at which operations are executed + * A count of how many operations have been executed + +## Component Updates and Bug Fixes + +* github.com/openziti/agent: [v1.0.15 -> v1.0.16](https://github.com/openziti/agent/compare/v1.0.15...v1.0.16) +* github.com/openziti/channel/v2: [v2.0.101 -> v2.0.105](https://github.com/openziti/channel/compare/v2.0.101...v2.0.105) +* github.com/openziti/edge-api: [v0.25.38 -> v0.26.0](https://github.com/openziti/edge-api/compare/v0.25.38...v0.26.0) + * [Issue #49](https://github.com/openziti/edge-api/issues/49) - Add 429 responses to allow indicating that the server is too busy + +* github.com/openziti/identity: [v1.0.64 -> v1.0.66](https://github.com/openziti/identity/compare/v1.0.64...v1.0.66) +* github.com/openziti/metrics: [v1.2.36 -> v1.2.37](https://github.com/openziti/metrics/compare/v1.2.36...v1.2.37) +* github.com/openziti/sdk-golang: [v0.20.122 -> v0.20.129](https://github.com/openziti/sdk-golang/compare/v0.20.122...v0.20.129) + * [Issue #443](https://github.com/openziti/sdk-golang/issues/443) - Don't send close in reponse to a close on a listener + +* github.com/openziti/secretstream: [v0.1.12 -> v0.1.13](https://github.com/openziti/secretstream/compare/v0.1.12...v0.1.13) +* github.com/openziti/storage: [v0.2.20 -> v0.2.23](https://github.com/openziti/storage/compare/v0.2.20...v0.2.23) +* github.com/openziti/transport/v2: [v2.0.109 -> v2.0.113](https://github.com/openziti/transport/compare/v2.0.109...v2.0.113) +* github.com/openziti/ziti: [v0.30.5 -> v0.31.0](https://github.com/openziti/ziti/compare/v0.30.5...v0.31.0) + * [Issue #1471](https://github.com/openziti/ziti/issues/1471) - Router links not resilient to controller crash + * [Issue #1468](https://github.com/openziti/ziti/issues/1468) - Quickstart quietly fails if password is < 5 characters long + * [Issue #1445](https://github.com/openziti/ziti/issues/1445) - Add controller update guardrail + * [Issue #1442](https://github.com/openziti/ziti/issues/1442) - Network watchdog not shutting down when controller shuts down + * [Issue #1465](https://github.com/openziti/ziti/issues/1465) - Upgrade functions `getZiti` and `performMigration` were only functional on Mac OS, now they are functional for Linux and Mac OSs. + * [Issue #1217](https://github.com/openziti/ziti/issues/1217) - Quickstart was improperly handling special characters in `ZITI_PWD`. Special characters are now supported for `ZITI_PWD` in quickstart functions. + + # Release 0.30.5 ## What's New @@ -11,6 +69,7 @@ Currently only HTTP Connect proxies which don't require authentication are suppo **Example using `host.v1`** +``` { "address": "192.168.2.50", "port": 1234, @@ -20,6 +79,7 @@ Currently only HTTP Connect proxies which don't require authentication are suppo "type": "http" } } +``` ## Component Updates and Bug Fixes diff --git a/common/getziti/github.go b/common/getziti/github.go index 229c3c445..ae7c6a787 100644 --- a/common/getziti/github.go +++ b/common/getziti/github.go @@ -6,6 +6,7 @@ import ( "github.com/blang/semver" "github.com/go-resty/resty/v2" "github.com/michaelquigley/pfxlog" + "github.com/openziti/foundation/v2/versions" c "github.com/openziti/ziti/ziti/constants" "github.com/pkg/errors" "net/http" @@ -177,15 +178,21 @@ func DownloadGitHubReleaseAsset(fullUrl string, filepath string) (err error) { } func FindVersionAndInstallGitHubRelease(zitiApp string, zitiAppGitHub string, targetOS, targetArch string, binDir string, version string, verbose bool) error { - if version != "" { + releaseVersion := version + if version != "" && version != "latest" { if _, err := semver.Make(strings.TrimPrefix(version, "v")); err != nil { return err } } else { version = "latest" + v, err := GetLatestGitHubReleaseVersion(zitiApp, verbose) + if err != nil { + return err + } + releaseVersion = v.String() } - release, err := GetLatestGitHubReleaseAsset(zitiApp, zitiAppGitHub, version, verbose) + release, err := GetLatestGitHubReleaseAsset(zitiApp, zitiAppGitHub, releaseVersion, verbose) if err != nil { return err } @@ -247,8 +254,20 @@ func InstallGitHubRelease(zitiApp string, release *GitHubReleasesData, binDir st if zitiApp == c.ZITI { count := 0 zitiFileName := "ziti-" + version + expectedPath := "ziti" + if version != "latest" { + semVer, err := versions.ParseSemVer(version) + if err != nil { + return err + } + + pathChangedVersion := versions.MustParseSemVer("0.29.0") + if semVer.CompareTo(pathChangedVersion) < 0 { + expectedPath = "ziti/ziti" + } + } err = UnTarGz(fullPath, binDir, func(path string) (string, bool) { - if path == "ziti/ziti" { + if path == expectedPath { count++ return zitiFileName, true } diff --git a/common/getziti/install_ziti.go b/common/getziti/install_ziti.go index ecb285c2b..9ab194979 100644 --- a/common/getziti/install_ziti.go +++ b/common/getziti/install_ziti.go @@ -2,25 +2,11 @@ package getziti import ( "fmt" - "github.com/blang/semver" c "github.com/openziti/ziti/ziti/constants" - "strings" ) func InstallZiti(targetVersion, targetOS, targetArch, binDir string, verbose bool) error { - var newVersion semver.Version - - if targetVersion != "" { - newVersion = semver.MustParse(strings.TrimPrefix(targetVersion, "v")) - } else { - v, err := GetLatestGitHubReleaseVersion(c.ZITI, verbose) - if err != nil { - return err - } - newVersion = v - } - - fmt.Println("Attempting to install '" + c.ZITI + "' version: v" + newVersion.String()) + fmt.Println("Attempting to install '" + c.ZITI + "' version: " + targetVersion) return FindVersionAndInstallGitHubRelease( - c.ZITI, c.ZITI, targetOS, targetArch, binDir, "v"+newVersion.String(), verbose) + c.ZITI, c.ZITI, targetOS, targetArch, binDir, targetVersion, verbose) } diff --git a/controller/api_impl/helpers.go b/controller/api_impl/helpers.go index aef4bea38..3ac4f4ef1 100644 --- a/controller/api_impl/helpers.go +++ b/controller/api_impl/helpers.go @@ -4,10 +4,10 @@ import ( "fmt" openApiErrors "github.com/go-openapi/errors" "github.com/michaelquigley/pfxlog" + "github.com/openziti/foundation/v2/errorz" "github.com/openziti/ziti/controller/api" apierror2 "github.com/openziti/ziti/controller/apierror" "github.com/openziti/ziti/controller/rest_model" - "github.com/openziti/foundation/v2/errorz" "net/http" ) @@ -124,7 +124,7 @@ func ToRestModel(e *errorz.ApiError, requestId string) *rest_model.APIError { ret.Code = errorz.CouldNotValidateCode ret.Message = errorz.CouldNotValidateMessage - } else if genericErr, ok := e.Cause.(apierror2.GenericCauseError); ok { + } else if genericErr, ok := e.Cause.(*apierror2.GenericCauseError); ok { ret.Cause = &rest_model.APIErrorCause{ APIError: rest_model.APIError{ Data: genericErr.DataMap, diff --git a/controller/apierror/api.go b/controller/apierror/api.go index ba63676f9..ba04aa35e 100644 --- a/controller/apierror/api.go +++ b/controller/apierror/api.go @@ -25,7 +25,7 @@ type GenericCauseError struct { DataMap map[string]interface{} } -func (e GenericCauseError) Error() string { +func (e *GenericCauseError) Error() string { return e.Message } diff --git a/controller/apierror/helpers.go b/controller/apierror/helpers.go index 0c5274d8c..8a325b528 100644 --- a/controller/apierror/helpers.go +++ b/controller/apierror/helpers.go @@ -375,3 +375,11 @@ func NewEnrollmentExists(enrollmentMethod string) *errorz.ApiError { AppendCause: true, } } + +func NewTooManyUpdatesError() *errorz.ApiError { + return &errorz.ApiError{ + Code: ServerTooManyRequestsCode, + Message: ServerTooManyRequestsMessage, + Status: ServerTooManyRequestsStatus, + } +} diff --git a/controller/apierror/messages.go b/controller/apierror/messages.go index b75622569..fdf0b21db 100644 --- a/controller/apierror/messages.go +++ b/controller/apierror/messages.go @@ -194,4 +194,8 @@ const ( EnrollmentExistsCode string = "ENROLLMENT_EXISTS" EnrollmentExistsMessage string = "ENROLLMENT_EXISTS" EnrollmentExistsStatus int = http.StatusConflict + + ServerTooManyRequestsCode string = "SERVER_TOO_MANY_REQUESTS" + ServerTooManyRequestsMessage string = "Too many requests to alter state have been issued. Please slow your request rate or try again later." + ServerTooManyRequestsStatus int = http.StatusTooManyRequests ) diff --git a/controller/command/command.go b/controller/command/command.go index 832359bbb..c6eb26cb0 100644 --- a/controller/command/command.go +++ b/controller/command/command.go @@ -19,9 +19,9 @@ package command import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" - "github.com/openziti/ziti/controller/change" "github.com/openziti/foundation/v2/debugz" "github.com/openziti/storage/boltz" + "github.com/openziti/ziti/controller/change" "github.com/sirupsen/logrus" "reflect" ) @@ -56,6 +56,7 @@ type Dispatcher interface { // LocalDispatcher should be used when running a non-clustered system type LocalDispatcher struct { EncodeDecodeCommands bool + Limiter RateLimiter } func (self *LocalDispatcher) IsLeaderOrLeaderless() bool { @@ -82,7 +83,7 @@ func (self *LocalDispatcher) Dispatch(command Command) error { if changeCtx == nil { changeCtx = change.New().SetSourceType("unattributed").SetChangeAuthorType(change.AuthorTypeUnattributed) } - ctx := changeCtx.NewMutateContext() + if self.EncodeDecodeCommands { bytes, err := command.Encode() if err != nil { @@ -92,10 +93,13 @@ func (self *LocalDispatcher) Dispatch(command Command) error { if err != nil { return err } - return cmd.Apply(ctx) + command = cmd } - return command.Apply(ctx) + return self.Limiter.RunRateLimited(func() error { + ctx := changeCtx.NewMutateContext() + return command.Apply(ctx) + }) } // Decoder instances know how to decode encoded commands diff --git a/controller/command/rate_limiter.go b/controller/command/rate_limiter.go new file mode 100644 index 000000000..197611c67 --- /dev/null +++ b/controller/command/rate_limiter.go @@ -0,0 +1,129 @@ +/* + 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 command + +import ( + "github.com/openziti/metrics" + "github.com/openziti/ziti/controller/apierror" + "github.com/pkg/errors" + "sync/atomic" + "time" +) + +const ( + MetricLimiterCurrentQueuedCount = "command.limiter.queued_count" + MetricLimiterWorkTimer = "command.limiter.work_timer" + + DefaultLimiterSize = 100 + MinLimiterSize = 10 +) + +type RateLimiterConfig struct { + Enabled bool + QueueSize uint32 +} + +func NewRateLimiter(config RateLimiterConfig, registry metrics.Registry, closeNotify <-chan struct{}) RateLimiter { + if !config.Enabled { + return NoOpRateLimiter{} + } + + if config.QueueSize < MinLimiterSize { + config.QueueSize = MinLimiterSize + } + + result := &DefaultRateLimiter{ + queue: make(chan *rateLimitedWork, config.QueueSize), + closeNotify: closeNotify, + workRate: registry.Timer(MetricLimiterWorkTimer), + } + + if existing := registry.GetGauge(MetricLimiterCurrentQueuedCount); existing != nil { + existing.Dispose() + } + + registry.FuncGauge(MetricLimiterCurrentQueuedCount, func() int64 { + return int64(result.currentSize.Load()) + }) + + go result.run() + + return result +} + +type RateLimiter interface { + RunRateLimited(func() error) error +} + +type NoOpRateLimiter struct{} + +func (self NoOpRateLimiter) RunRateLimited(f func() error) error { + return f() +} + +type rateLimitedWork struct { + wrapped func() error + result chan error +} + +type DefaultRateLimiter struct { + currentSize atomic.Int32 + queue chan *rateLimitedWork + closeNotify <-chan struct{} + workRate metrics.Timer +} + +func (self *DefaultRateLimiter) RunRateLimited(f func() error) error { + work := &rateLimitedWork{ + wrapped: f, + result: make(chan error, 1), + } + select { + case self.queue <- work: + self.currentSize.Add(1) + select { + case result := <-work.result: + return result + case <-self.closeNotify: + return errors.New("rate limiter shutting down") + } + case <-self.closeNotify: + return errors.New("rate limiter shutting down") + default: + return apierror.NewTooManyUpdatesError() + } +} + +func (self *DefaultRateLimiter) run() { + defer self.workRate.Dispose() + + for { + select { + case work := <-self.queue: + self.currentSize.Add(-1) + startTime := time.Now() + result := work.wrapped() + self.workRate.UpdateSince(startTime) + if result != nil { + work.result <- result + } + close(work.result) + case <-self.closeNotify: + return + } + } +} diff --git a/controller/config.go b/controller/config.go index b3e011b69..43d6b46dc 100644 --- a/controller/config.go +++ b/controller/config.go @@ -24,18 +24,20 @@ import ( "github.com/hashicorp/go-hclog" "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" + "github.com/openziti/identity" + "github.com/openziti/storage/boltz" + "github.com/openziti/transport/v2" "github.com/openziti/ziti/common/config" "github.com/openziti/ziti/common/pb/ctrl_pb" "github.com/openziti/ziti/common/pb/mgmt_pb" + "github.com/openziti/ziti/controller/command" "github.com/openziti/ziti/controller/db" "github.com/openziti/ziti/controller/network" "github.com/openziti/ziti/controller/raft" "github.com/openziti/ziti/router/xgress" - "github.com/openziti/identity" - "github.com/openziti/storage/boltz" - "github.com/openziti/transport/v2" "github.com/pkg/errors" "gopkg.in/yaml.v2" + "math" "os" "strings" "time" @@ -78,7 +80,8 @@ type Config struct { InitialDelay time.Duration } } - src map[interface{}]interface{} + CommandRateLimiter command.RateLimiterConfig + src map[interface{}]interface{} } // CtrlOptions extends channel.Options to include support for additional, non-channel specific options @@ -459,6 +462,31 @@ func LoadConfig(path string) (*Config, error) { } } + controllerConfig.CommandRateLimiter.QueueSize = command.DefaultLimiterSize + + if value, found := cfgmap["commandRateLimiter"]; found { + if submap, ok := value.(map[interface{}]interface{}); ok { + if value, found := submap["enabled"]; found { + controllerConfig.CommandRateLimiter.Enabled = strings.EqualFold("true", fmt.Sprintf("%v", value)) + } + + if value, found := submap["maxQueued"]; found { + if intVal, ok := value.(int); ok { + v := int64(intVal) + if v < command.MinLimiterSize { + return nil, errors.Errorf("invalid value %v for commandRateLimiter, must be at least %v", value, command.MinLimiterSize) + } + if v > math.MaxUint32 { + return nil, errors.Errorf("invalid value %v for commandRateLimiter, must be at most %v", value, int64(math.MaxUint32)) + } + controllerConfig.CommandRateLimiter.QueueSize = uint32(v) + } else { + return nil, errors.Errorf("invalid value %v for commandRateLimiter, must be integer value", value) + } + } + } + } + return controllerConfig, nil } diff --git a/controller/config/config.go b/controller/config/config.go index 59bb77840..e2662c5b7 100644 --- a/controller/config/config.go +++ b/controller/config/config.go @@ -19,6 +19,7 @@ package config import ( "bytes" "crypto/sha1" + "crypto/x509" "encoding/pem" "fmt" "github.com/michaelquigley/pfxlog" @@ -434,11 +435,39 @@ func CalculateCaPems(caPems *bytes.Buffer) *bytes.Buffer { newCaPems := bytes.Buffer{} blocksToProcess := caPems.Bytes() + for len(blocksToProcess) != 0 { var block *pem.Block block, blocksToProcess = pem.Decode(blocksToProcess) if block != nil { + + if block.Type != "CERTIFICATE" { + pfxlog.Logger(). + WithField("type", block.Type). + WithField("block", pem.EncodeToMemory(block)). + Warn("encountered an invalid PEM block type loading configured CAs, block will be ignored") + continue + } + + cert, err := x509.ParseCertificate(block.Bytes) + + if err != nil { + pfxlog.Logger(). + WithField("type", block.Type). + WithField("block", pem.EncodeToMemory(block)). + WithError(err). + Warn("block could not be parsed as a certificate, block will be ignored") + continue + } + + if !cert.IsCA { + pfxlog.Logger(). + WithField("type", block.Type). + WithField("block", pem.EncodeToMemory(block)). + Warn("block is not a CA, block will be ignored") + continue + } // #nosec hash := sha1.Sum(block.Bytes) fingerprint := toHex(hash[:]) diff --git a/controller/config/config_test.go b/controller/config/config_test.go index 3b6b82225..710fc548a 100644 --- a/controller/config/config_test.go +++ b/controller/config/config_test.go @@ -195,13 +195,16 @@ func Test_validateHostPortString(t *testing.T) { } func Test_CalculateCaPems(t *testing.T) { - ca1, _ := newSelfSignedCert(uuid.NewString()) - ca2, _ := newSelfSignedCert(uuid.NewString()) - ca3, _ := newSelfSignedCert(uuid.NewString()) + ca1, _ := newSelfSignedCert(uuid.NewString(), true) + ca2, _ := newSelfSignedCert(uuid.NewString(), true) + ca3, _ := newSelfSignedCert(uuid.NewString(), true) + + notCaSelfSigned, _ := newSelfSignedCert(uuid.NewString(), false) ca1Pem := nfpem.EncodeToBytes(ca1) ca2Pem := nfpem.EncodeToBytes(ca2) ca3Pem := nfpem.EncodeToBytes(ca3) + notCaSelfSignedPem := nfpem.EncodeToBytes(notCaSelfSigned) inCas := []*x509.Certificate{ ca1, @@ -209,6 +212,49 @@ func Test_CalculateCaPems(t *testing.T) { ca3, } + t.Run("1 non-ca in, 0 out", func(t *testing.T) { + req := require.New(t) + + buf := bytes.NewBuffer([]byte{}) + + buf.Write(notCaSelfSignedPem) + + outBuf := CalculateCaPems(buf) + + outCerts := nfpem.PemBytesToCertificates(outBuf.Bytes()) + + req.Len(outCerts, 0) + }) + + t.Run("1 non-ca + 3 ca in, 3 out", func(t *testing.T) { + req := require.New(t) + + buf := bytes.NewBuffer([]byte{}) + + buf.Write(notCaSelfSignedPem) + buf.Write(ca1Pem) + buf.Write(ca2Pem) + buf.Write(ca3Pem) + + outBuf := CalculateCaPems(buf) + + outCerts := nfpem.PemBytesToCertificates(outBuf.Bytes()) + + req.Len(outCerts, 3) + + for _, inCert := range inCas { + found := false + for _, outCert := range outCerts { + if bytes.Equal(inCert.Raw, outCert.Raw) { + req.Falsef(found, "certificate %s was found multiple times, expected once instance in output", inCert.Subject.String()) + + found = true + } + } + req.Truef(found, "certificate %s was provided as input but not found as output", inCert.Subject.String()) + } + }) + t.Run("three unique CAs in, three out", func(t *testing.T) { req := require.New(t) @@ -315,7 +361,7 @@ func Test_CalculateCaPems(t *testing.T) { } -func newSelfSignedCert(commonName string) (*x509.Certificate, crypto.PrivateKey) { +func newSelfSignedCert(commonName string, isCas bool) (*x509.Certificate, crypto.PrivateKey) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { panic(err) @@ -326,14 +372,17 @@ func newSelfSignedCert(commonName string) (*x509.Certificate, crypto.PrivateKey) CommonName: commonName, Organization: []string{"API Test Co"}, }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 180), - + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 180), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } + if isCas { + template.IsCA = true + } + der, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { panic(err) diff --git a/controller/controller.go b/controller/controller.go index 2c8d5324f..00931edc9 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -22,12 +22,12 @@ import ( "crypto/x509" "encoding/json" "fmt" + "github.com/openziti/transport/v2" "github.com/openziti/ziti/common/capabilities" "github.com/openziti/ziti/common/config" "github.com/openziti/ziti/controller/event" "github.com/openziti/ziti/controller/events" "github.com/openziti/ziti/controller/handler_peer_ctrl" - "github.com/openziti/transport/v2" "math/big" "os" "sync/atomic" @@ -39,6 +39,11 @@ import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" "github.com/openziti/channel/v2/protobufs" + "github.com/openziti/foundation/v2/versions" + "github.com/openziti/identity" + "github.com/openziti/metrics" + "github.com/openziti/storage/boltz" + "github.com/openziti/xweb/v2" "github.com/openziti/ziti/common/health" fabricMetrics "github.com/openziti/ziti/common/metrics" "github.com/openziti/ziti/common/pb/ctrl_pb" @@ -55,11 +60,6 @@ import ( "github.com/openziti/ziti/controller/xt_random" "github.com/openziti/ziti/controller/xt_smartrouting" "github.com/openziti/ziti/controller/xt_weighted" - "github.com/openziti/foundation/v2/versions" - "github.com/openziti/identity" - "github.com/openziti/metrics" - "github.com/openziti/storage/boltz" - "github.com/openziti/xweb/v2" "github.com/sirupsen/logrus" ) @@ -67,6 +67,7 @@ type Controller struct { config *Config network *network.Network raftController *raft.Controller + localDispatcher *command.LocalDispatcher ctrlConnectHandler *handler_ctrl.ConnectHandler xctrls []xctrl.Xctrl xmgmts []xmgmt.Xmgmt @@ -113,7 +114,16 @@ func (c *Controller) GetOptions() *network.Options { func (c *Controller) GetCommandDispatcher() command.Dispatcher { if c.raftController == nil { - return nil + if c.localDispatcher != nil { + return c.localDispatcher + } + devVersion := versions.MustParseSemVer("0.0.0") + version := versions.MustParseSemVer(c.GetVersionProvider().Version()) + c.localDispatcher = &command.LocalDispatcher{ + EncodeDecodeCommands: devVersion.Equals(version), + Limiter: command.NewRateLimiter(c.config.CommandRateLimiter, c.metricsRegistry, c.shutdownC), + } + return c.localDispatcher } return c.raftController } @@ -138,6 +148,10 @@ func (c *Controller) GetRaftConfig() *raft.Config { return c.config.Raft } +func (c *Controller) GetCommandRateLimiterConfig() command.RateLimiterConfig { + return c.config.CommandRateLimiter +} + func (c *Controller) RenderJsonConfig() (string, error) { jsonMap, err := config.ToJsonCompatibleMap(c.config.src) if err != nil { diff --git a/controller/events/metrics_test.go b/controller/events/metrics_test.go index 33de60112..09b9f70e7 100644 --- a/controller/events/metrics_test.go +++ b/controller/events/metrics_test.go @@ -130,6 +130,7 @@ func Test_MetricsFormat(t *testing.T) { go func() { registry := metrics2.NewRegistry("test", nil) meter := registry.Meter("foo.bar") + time.Sleep(10 * time.Millisecond) meter.Mark(1) dispatcher.AcceptMetricsMsg(registry.Poll()) }() diff --git a/controller/handler_ctrl/accept.go b/controller/handler_ctrl/accept.go index 23bdda1ed..50b9f14c0 100644 --- a/controller/handler_ctrl/accept.go +++ b/controller/handler_ctrl/accept.go @@ -59,64 +59,75 @@ func (self *CtrlAccepter) Bind(binding channel.Binding) error { ch := binding.GetChannel() log := pfxlog.Logger().WithField("routerId", ch.Id()) - // Use a new copy of the router instance each time we connect. That way we can tell on disconnect // if we're working with the right connection, in case connects and disconnects happen quickly. // It also means that the channel and connected time fields don't change and we don't have to protect them - if r, err := self.network.GetReloadedRouter(ch.Id()); err == nil { - if ch.Underlay().Headers() != nil { - if versionValue, found := ch.Underlay().Headers()[channel.HelloVersionHeader]; found { - if versionInfo, err := self.network.VersionProvider.EncoderDecoder().Decode(versionValue); err == nil { - r.VersionInfo = versionInfo - } else { - return errors.Wrap(err, "could not parse version info from router hello, closing router connection") - } + r, err := self.network.GetReloadedRouter(ch.Id()) + if err != nil { + return err + } + if r == nil { + return errors.Errorf("no router with id [%v] found, closing connection", ch.Id()) + } + + if ch.Underlay().Headers() != nil { + if versionValue, found := ch.Underlay().Headers()[channel.HelloVersionHeader]; found { + if versionInfo, err := self.network.VersionProvider.EncoderDecoder().Decode(versionValue); err == nil { + r.VersionInfo = versionInfo + log = log.WithField("version", r.VersionInfo.Version). + WithField("revision", r.VersionInfo.Revision). + WithField("buildDate", r.VersionInfo.BuildDate). + WithField("os", r.VersionInfo.OS). + WithField("arch", r.VersionInfo.Arch) } else { - return errors.New("no version info header, closing router connection") + return errors.Wrap(err, "could not parse version info from router hello, not accepting router connection") } - r.Listeners = nil - if val, found := ch.Underlay().Headers()[int32(ctrl_pb.ContentType_ListenersHeader)]; found { - log.Debug("router reported listeners using listeners header") - listeners := &ctrl_pb.Listeners{} - if err := proto.Unmarshal(val, listeners); err != nil { - log.WithError(err).Error("unable to unmarshall listeners value") - } else { - r.SetLinkListeners(listeners.Listeners) - for _, listener := range listeners.Listeners { - log.WithField("address", listener.GetAddress()). - WithField("protocol", listener.GetProtocol()). - WithField("costTags", listener.GetCostTags()). - Debug("router listener") - } - } + } else { + return errors.New("no version info header, not accepting router connection") + } + + r.Listeners = nil + if val, found := ch.Underlay().Headers()[int32(ctrl_pb.ContentType_ListenersHeader)]; found { + listeners := &ctrl_pb.Listeners{} + if err = proto.Unmarshal(val, listeners); err != nil { + log.WithError(err).Error("unable to unmarshall listeners value") } else { - log.Warn("no advertised listeners") - } - if val, found := ch.Underlay().Headers()[int32(ctrl_pb.ContentType_RouterMetadataHeader)]; found { - log.Debug("router reported listeners using listeners header") - routerMetadata := &ctrl_pb.RouterMetadata{} - if err = proto.Unmarshal(val, routerMetadata); err != nil { - log.WithError(err).Error("unable to unmarshall router metadata value") + r.SetLinkListeners(listeners.Listeners) + for _, listener := range listeners.Listeners { + log.WithField("address", listener.GetAddress()). + WithField("protocol", listener.GetProtocol()). + WithField("costTags", listener.GetCostTags()). + Debug("router listener") } - r.SetMetadata(routerMetadata) } } else { - return errors.New("no version info header, closing router connection") - } - - r.Control = ch - r.ConnectTime = time.Now() - if err := binding.Bind(newBindHandler(self.heartbeatOptions, r, self.network, self.xctrls)); err != nil { - return errors.Wrap(err, "error binding router") + log.Debug("no advertised listeners") } - if self.traceHandler != nil { - binding.AddPeekHandler(self.traceHandler) + if val, found := ch.Underlay().Headers()[int32(ctrl_pb.ContentType_RouterMetadataHeader)]; found { + routerMetadata := &ctrl_pb.RouterMetadata{} + if err = proto.Unmarshal(val, routerMetadata); err != nil { + log.WithError(err).Error("unable to unmarshall router metadata value") + } + r.SetMetadata(routerMetadata) } + } else { + return errors.New("channel provided no headers, not accepting router connection as version info not provided") + } - log.Infof("accepted new router connection [r/%s]", r.Id) + r.Control = ch + r.ConnectTime = time.Now() + if err := binding.Bind(newBindHandler(self.heartbeatOptions, r, self.network, self.xctrls)); err != nil { + return errors.Wrap(err, "error binding router") + } - self.network.ConnectRouter(r) + if self.traceHandler != nil { + binding.AddPeekHandler(self.traceHandler) } + + log.Info("accepted new router connection") + + self.network.ConnectRouter(r) + return nil } diff --git a/controller/handler_edge_ctrl/hello.go b/controller/handler_edge_ctrl/hello.go index 060e958af..e79ffed4e 100644 --- a/controller/handler_edge_ctrl/hello.go +++ b/controller/handler_edge_ctrl/hello.go @@ -21,16 +21,15 @@ import ( "github.com/openziti/channel/v2" "github.com/openziti/ziti/common/pb/edge_ctrl_pb" "github.com/openziti/ziti/controller/env" - "github.com/openziti/ziti/controller/network" "google.golang.org/protobuf/proto" ) type helloHandler struct { appEnv *env.AppEnv - callback func(r *network.Router, respHello *edge_ctrl_pb.ClientHello) + callback func(routerId string, respHello *edge_ctrl_pb.ClientHello) } -func NewHelloHandler(appEnv *env.AppEnv, callback func(r *network.Router, respHello *edge_ctrl_pb.ClientHello)) *helloHandler { +func NewHelloHandler(appEnv *env.AppEnv, callback func(routerId string, respHello *edge_ctrl_pb.ClientHello)) *helloHandler { return &helloHandler{ appEnv: appEnv, callback: callback, @@ -48,12 +47,5 @@ func (h *helloHandler) HandleReceive(msg *channel.Message, ch channel.Channel) { return } - r := h.appEnv.GetHostController().GetNetwork().GetConnectedRouter(ch.Id()) - if r == nil { - pfxlog.Logger().Errorf("could not find router %v, closing channel", ch.Id()) - _ = ch.Close() - return - } - - h.callback(r, respHello) + h.callback(ch.Id(), respHello) } diff --git a/controller/handler_edge_ctrl/resync.go b/controller/handler_edge_ctrl/resync.go index 5ac65f4aa..45401b113 100644 --- a/controller/handler_edge_ctrl/resync.go +++ b/controller/handler_edge_ctrl/resync.go @@ -21,16 +21,15 @@ import ( "github.com/openziti/channel/v2" "github.com/openziti/ziti/common/pb/edge_ctrl_pb" "github.com/openziti/ziti/controller/env" - "github.com/openziti/ziti/controller/network" "google.golang.org/protobuf/proto" ) type resyncHandler struct { appEnv *env.AppEnv - callback func(r *network.Router, respHello *edge_ctrl_pb.RequestClientReSync) + callback func(routerId string, respHello *edge_ctrl_pb.RequestClientReSync) } -func NewResyncHandler(appEnv *env.AppEnv, callback func(r *network.Router, respHello *edge_ctrl_pb.RequestClientReSync)) *resyncHandler { +func NewResyncHandler(appEnv *env.AppEnv, callback func(routerId string, respHello *edge_ctrl_pb.RequestClientReSync)) *resyncHandler { return &resyncHandler{ appEnv: appEnv, callback: callback, @@ -48,12 +47,5 @@ func (h *resyncHandler) HandleReceive(msg *channel.Message, ch channel.Channel) return } - r, err := h.appEnv.GetHostController().GetNetwork().GetRouter(ch.Id()) - if err != nil { - pfxlog.Logger().WithError(err).Errorf("could not find router %v, closing channel", ch.Id()) - _ = ch.Close() - return - } - - h.callback(r, resyncReq) + h.callback(ch.Id(), resyncReq) } diff --git a/controller/internal/routes/version_router.go b/controller/internal/routes/version_router.go index 7f13c920c..be613c91f 100644 --- a/controller/internal/routes/version_router.go +++ b/controller/internal/routes/version_router.go @@ -58,6 +58,10 @@ func (ir *VersionRouter) Register(ae *env.AppEnv) { return ae.IsAllowed(ir.List, params.HTTPRequest, "", "", permissions.Always()) }) + ae.ClientApi.InformationalListEnumeratedCapabilitiesHandler = clientInformational.ListEnumeratedCapabilitiesHandlerFunc(func(params clientInformational.ListEnumeratedCapabilitiesParams) middleware.Responder { + return ae.IsAllowed(ir.ListCapabilities, params.HTTPRequest, "", "", permissions.Always()) + }) + ae.ManagementApi.InformationalListVersionHandler = managementInformational.ListVersionHandlerFunc(func(params managementInformational.ListVersionParams) middleware.Responder { return ae.IsAllowed(ir.List, params.HTTPRequest, "", "", permissions.Always()) }) @@ -65,9 +69,13 @@ func (ir *VersionRouter) Register(ae *env.AppEnv) { ae.ManagementApi.InformationalListRootHandler = managementInformational.ListRootHandlerFunc(func(params managementInformational.ListRootParams) middleware.Responder { return ae.IsAllowed(ir.List, params.HTTPRequest, "", "", permissions.Always()) }) + + ae.ManagementApi.InformationalListEnumeratedCapabilitiesHandler = managementInformational.ListEnumeratedCapabilitiesHandlerFunc(func(params managementInformational.ListEnumeratedCapabilitiesParams) middleware.Responder { + return ae.IsAllowed(ir.ListCapabilities, params.HTTPRequest, "", "", permissions.Always()) + }) } -func (ir *VersionRouter) List(_ *env.AppEnv, rc *response.RequestContext) { +func (ir *VersionRouter) List(ae *env.AppEnv, rc *response.RequestContext) { ir.cachedVersionsOnce.Do(func() { buildInfo := build.GetBuildInfo() @@ -80,6 +88,7 @@ func (ir *VersionRouter) List(_ *env.AppEnv, rc *response.RequestContext) { controller.ClientApiBinding: {controller.VersionV1: mapApiVersionToRestModel(controller.ClientRestApiBaseUrlV1)}, controller.ManagementApiBinding: {controller.VersionV1: mapApiVersionToRestModel(controller.ManagementRestApiBaseUrlV1)}, }, + Capabilities: []string{}, } for apiBinding, apiVersionToPathMap := range controller.AllApiBindingVersions { @@ -107,6 +116,21 @@ func (ir *VersionRouter) List(_ *env.AppEnv, rc *response.RequestContext) { } } + oidcEnabled := false + + for _, serverConfig := range ae.HostController.GetXWebInstance().GetConfig().ServerConfigs { + for _, api := range serverConfig.APIs { + if api.Binding() == controller.OidcApiBinding { + oidcEnabled = true + break + } + } + + if oidcEnabled { + break + } + } + for apiBinding, apiVersionMap := range ir.cachedVersions.APIVersions { for apiBaseUrl := range apiToBaseUrls[apiBinding] { apiVersion := apiVersionMap["v1"] @@ -116,11 +140,29 @@ func (ir *VersionRouter) List(_ *env.AppEnv, rc *response.RequestContext) { } ir.cachedVersions.APIVersions[controller.LegacyClientApiBinding] = ir.cachedVersions.APIVersions[controller.ClientApiBinding] + + if oidcEnabled { + ir.cachedVersions.Capabilities = append(ir.cachedVersions.Capabilities, string(rest_model.CapabilitiesOIDCAUTH)) + } + + if ae.HostController.IsRaftEnabled() { + ir.cachedVersions.Capabilities = append(ir.cachedVersions.Capabilities, string(rest_model.CapabilitiesHACONTROLLER)) + } + }) rc.RespondWithOk(ir.cachedVersions, &rest_model.Meta{}) } +func (ir *VersionRouter) ListCapabilities(_ *env.AppEnv, rc *response.RequestContext) { + capabilities := []rest_model.Capabilities{ + rest_model.CapabilitiesOIDCAUTH, + rest_model.CapabilitiesHACONTROLLER, + } + + rc.RespondWithOk(capabilities, &rest_model.Meta{}) +} + func apiBindingToPath(binding string) string { switch binding { case "edge": diff --git a/controller/model/edge_service_manager.go b/controller/model/edge_service_manager.go index da9171607..09c3170bd 100644 --- a/controller/model/edge_service_manager.go +++ b/controller/model/edge_service_manager.go @@ -18,16 +18,16 @@ package model import ( "github.com/michaelquigley/pfxlog" + "github.com/openziti/storage/ast" + "github.com/openziti/storage/boltz" "github.com/openziti/ziti/common/pb/edge_cmd_pb" - "github.com/openziti/ziti/controller/persistence" "github.com/openziti/ziti/controller/change" "github.com/openziti/ziti/controller/command" "github.com/openziti/ziti/controller/db" "github.com/openziti/ziti/controller/fields" "github.com/openziti/ziti/controller/models" "github.com/openziti/ziti/controller/network" - "github.com/openziti/storage/ast" - "github.com/openziti/storage/boltz" + "github.com/openziti/ziti/controller/persistence" "go.etcd.io/bbolt" "google.golang.org/protobuf/proto" ) diff --git a/controller/network/network.go b/controller/network/network.go index 17196e690..4029f07b3 100644 --- a/controller/network/network.go +++ b/controller/network/network.go @@ -21,9 +21,9 @@ import ( "compress/gzip" "encoding/json" "fmt" + "github.com/openziti/foundation/v2/goroutines" fabricMetrics "github.com/openziti/ziti/common/metrics" "github.com/openziti/ziti/controller/event" - "github.com/openziti/foundation/v2/goroutines" "os" "path/filepath" "runtime/debug" @@ -32,17 +32,11 @@ import ( "sync" "time" - "github.com/openziti/ziti/controller/command" "github.com/openziti/foundation/v2/versions" + "github.com/openziti/ziti/controller/command" "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2/protobufs" - "github.com/openziti/ziti/common/ctrl_msg" - "github.com/openziti/ziti/common/logcontext" - "github.com/openziti/ziti/common/pb/ctrl_pb" - "github.com/openziti/ziti/common/trace" - "github.com/openziti/ziti/controller/db" - "github.com/openziti/ziti/controller/xt" "github.com/openziti/foundation/v2/debugz" "github.com/openziti/foundation/v2/errorz" "github.com/openziti/foundation/v2/sequence" @@ -50,6 +44,12 @@ import ( "github.com/openziti/metrics" "github.com/openziti/metrics/metrics_pb" "github.com/openziti/storage/boltz" + "github.com/openziti/ziti/common/ctrl_msg" + "github.com/openziti/ziti/common/logcontext" + "github.com/openziti/ziti/common/pb/ctrl_pb" + "github.com/openziti/ziti/common/trace" + "github.com/openziti/ziti/controller/db" + "github.com/openziti/ziti/controller/xt" "github.com/pkg/errors" "github.com/sirupsen/logrus" "go.etcd.io/bbolt" @@ -909,6 +909,8 @@ func (network *Network) watchdog() { case <-network.watchdogCh: consecutiveFails = 0 continue + case <-network.closeNotify: + return default: consecutiveFails++ // network.Run didn't complete, something is stalling it diff --git a/controller/network/network_test.go b/controller/network/network_test.go index c63e7900e..3396f060e 100644 --- a/controller/network/network_test.go +++ b/controller/network/network_test.go @@ -7,16 +7,16 @@ import ( "testing" "time" - "github.com/openziti/ziti/controller/command" - "github.com/openziti/ziti/controller/db" - "github.com/openziti/ziti/controller/models" - "github.com/openziti/ziti/controller/xt" - "github.com/openziti/ziti/common/logcontext" "github.com/openziti/foundation/v2/versions" "github.com/openziti/identity" "github.com/openziti/metrics" "github.com/openziti/storage/boltz" "github.com/openziti/transport/v2/tcp" + "github.com/openziti/ziti/common/logcontext" + "github.com/openziti/ziti/controller/command" + "github.com/openziti/ziti/controller/db" + "github.com/openziti/ziti/controller/models" + "github.com/openziti/ziti/controller/xt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -64,7 +64,9 @@ func (self *testConfig) GetOptions() *Options { } func (self *testConfig) GetCommandDispatcher() command.Dispatcher { - return &command.LocalDispatcher{} + return &command.LocalDispatcher{ + Limiter: command.NoOpRateLimiter{}, + } } func (self *testConfig) GetDb() boltz.Db { diff --git a/controller/persistence/testing.go b/controller/persistence/testing.go index e30f608d9..3bd772bb1 100644 --- a/controller/persistence/testing.go +++ b/controller/persistence/testing.go @@ -72,7 +72,9 @@ func (self *testConfig) GetOptions() *network.Options { } func (self *testConfig) GetCommandDispatcher() command.Dispatcher { - return nil + return &command.LocalDispatcher{ + Limiter: command.NoOpRateLimiter{}, + } } func (self *testConfig) GetDb() boltz.Db { diff --git a/controller/raft/index_tracker_test.go b/controller/raft/index_tracker_test.go index 695f1b74e..e159e8d8d 100644 --- a/controller/raft/index_tracker_test.go +++ b/controller/raft/index_tracker_test.go @@ -23,62 +23,105 @@ import ( ) func TestIndexTracker(t *testing.T) { - indexTracker := NewIndexTracker() - - req := require.New(t) - indexTracker.NotifyOfIndex(1) - req.NoError(indexTracker.WaitForIndex(1, time.Now())) // if it's already complete, should work - - // If it never completes, should fail - req.Error(indexTracker.WaitForIndex(2, time.Now().Add(20*time.Millisecond))) - - notifyAsync := func(index uint64, after time.Duration) { - go func() { - time.Sleep(after) - indexTracker.NotifyOfIndex(index) - }() - } - - notifyAsync(2, 20*time.Millisecond) - req.NoError(indexTracker.WaitForIndex(2, time.Now().Add(30*time.Millisecond))) - req.NoError(indexTracker.WaitForIndex(2, time.Now())) - - waitAsync := func(index uint64, timeout time.Duration) <-chan error { - result := make(chan error, 1) - go func() { - err := indexTracker.WaitForIndex(index, time.Now().Add(timeout)) - if err == nil { - close(result) + + t.Run("index 1 can be set and notifies", func(t *testing.T) { + req := require.New(t) + indexTracker := &testTracker{ + NewIndexTracker(), + } + + indexTracker.NotifyOfIndex(1) + req.NoError(indexTracker.WaitForIndex(1, time.Now())) // if it's already complete, should work + + // If it never completes, should fail + req.Error(indexTracker.WaitForIndex(2, time.Now().Add(100*time.Millisecond))) + }) + + t.Run("index 2 is received. no error", func(t *testing.T) { + req := require.New(t) + + indexTracker := &testTracker{ + NewIndexTracker(), + } + + indexTracker.notifyAsync(1, 20*time.Millisecond) + indexTracker.notifyAsync(2, 20*time.Millisecond) + + req.NoError(indexTracker.WaitForIndex(2, time.Now().Add(100*time.Millisecond))) + req.NoError(indexTracker.WaitForIndex(2, time.Now())) + + }) + + t.Run("index 3 has time out errors until it is added", func(t *testing.T) { + req := require.New(t) + + indexTracker := &testTracker{ + NewIndexTracker(), + } + + //move the index forward 2 + indexTracker.notifyAsync(1, 5*time.Millisecond) + indexTracker.notifyAsync(2, 20*time.Millisecond) + + //wait for index 2 to appear + req.NoError(indexTracker.WaitForIndex(2, time.Now().Add(100*time.Millisecond))) + + //notify of index 3 after a delay + //during the delay check to see if the index has arrived after varying levels of timeouts + indexTracker.notifyAsync(3, 200*time.Millisecond) + + var results []<-chan error + + //add waits for index 3 starting a 30ms and increased by 30ms till 330ms + for i := 0; i < 10; i++ { + results = append(results, indexTracker.waitAsync(3, time.Duration((i+1)*30)*time.Millisecond)) + } + + //once index3Notified is true, no timeout errors should be received + index3Notified := false + + for _, result := range results { + err := <-result + + if index3Notified { + if err != nil { + req.Fail("received error after first notification of index received, expected no more errors") + } } else { - result <- err - close(result) + //no notification yet, if no error, that is the notification + if err == nil { + index3Notified = true + } } - }() - return result - } - - notifyAsync(3, 20*time.Millisecond) - var results []<-chan error - for i := 0; i < 10; i++ { - results = append(results, waitAsync(3, 30*time.Millisecond)) - } - req.Error(indexTracker.WaitForIndex(3, time.Now().Add(10*time.Millisecond))) - time.Sleep(15 * time.Millisecond) - - for _, result := range results { - var err error - select { - case err = <-result: - default: } - req.NoError(err) - closed := false - select { - case <-result: - closed = true - default: + //make sure we didn't receive all errors and index 3 was eventually notified + req.True(index3Notified, "index 3 was never received") + }) +} + +// testTracker adds helper function used to power async index notification used in the above tests. +type testTracker struct { + IndexTracker +} + +func (t *testTracker) notifyAsync(index uint64, after time.Duration) { + go func() { + time.Sleep(after) + t.NotifyOfIndex(index) + }() +} + +func (t *testTracker) waitAsync(index uint64, timeout time.Duration) <-chan error { + result := make(chan error, 1) + go func() { + err := t.WaitForIndex(index, time.Now().Add(timeout)) + if err == nil { + close(result) + } else { + result <- err + close(result) } - req.True(closed) - } + }() + return result } diff --git a/controller/raft/raft.go b/controller/raft/raft.go index 00dae08ea..f1b30c92c 100644 --- a/controller/raft/raft.go +++ b/controller/raft/raft.go @@ -21,12 +21,12 @@ import ( "encoding/json" "fmt" "github.com/hashicorp/go-hclog" - "github.com/openziti/ziti/common/pb/cmd_pb" - "github.com/openziti/ziti/controller/event" - "github.com/openziti/ziti/controller/peermsg" "github.com/openziti/foundation/v2/concurrenz" "github.com/openziti/foundation/v2/versions" "github.com/openziti/transport/v2" + "github.com/openziti/ziti/common/pb/cmd_pb" + "github.com/openziti/ziti/controller/event" + "github.com/openziti/ziti/controller/peermsg" "os" "path" "reflect" @@ -39,12 +39,12 @@ import ( raftboltdb "github.com/hashicorp/raft-boltdb" "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" - "github.com/openziti/ziti/controller/command" - "github.com/openziti/ziti/controller/raft/mesh" "github.com/openziti/foundation/v2/errorz" "github.com/openziti/identity" "github.com/openziti/metrics" "github.com/openziti/storage/boltz" + "github.com/openziti/ziti/controller/command" + "github.com/openziti/ziti/controller/raft/mesh" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -192,18 +192,21 @@ func newClusterState(isLeader, isReadWrite bool) ClusterState { type Env interface { GetId() *identity.TokenId GetVersionProvider() versions.VersionProvider + GetCommandRateLimiterConfig() command.RateLimiterConfig GetRaftConfig() *Config GetMetricsRegistry() metrics.Registry GetEventDispatcher() event.Dispatcher + GetCloseNotify() <-chan struct{} } func NewController(env Env, migrationMgr MigrationManager) *Controller { result := &Controller{ - env: env, - Config: env.GetRaftConfig(), - indexTracker: NewIndexTracker(), - migrationMgr: migrationMgr, - clusterEvents: make(chan raft.Observation, 16), + env: env, + Config: env.GetRaftConfig(), + indexTracker: NewIndexTracker(), + migrationMgr: migrationMgr, + clusterEvents: make(chan raft.Observation, 16), + commandRateLimiter: command.NewRateLimiter(env.GetCommandRateLimiterConfig(), env.GetMetricsRegistry(), env.GetCloseNotify()), } return result } @@ -224,6 +227,7 @@ type Controller struct { clusterStateChangeHandlers concurrenz.CopyOnWriteSlice[func(event ClusterEvent, state ClusterState)] isLeader atomic.Bool clusterEvents chan raft.Observation + commandRateLimiter command.RateLimiter } func (self *Controller) RegisterClusterEventHandler(f func(event ClusterEvent, state ClusterState)) { @@ -448,6 +452,7 @@ func (self *Controller) applyCommand(cmd command.Command) (uint64, error) { if err != nil { return 0, err } + return self.ApplyEncodedCommand(encoded) } @@ -473,11 +478,24 @@ func (self *Controller) ApplyEncodedCommand(encoded []byte) (uint64, error) { // ApplyWithTimeout applies the given command to the RAFT distributed log with the given timeout func (self *Controller) ApplyWithTimeout(log []byte, timeout time.Duration) (interface{}, uint64, error) { - f := self.Raft.Apply(log, timeout) - if err := f.Error(); err != nil { + returnValue := atomic.Value{} + index := atomic.Uint64{} + err := self.commandRateLimiter.RunRateLimited(func() error { + f := self.Raft.Apply(log, timeout) + if err := f.Error(); err != nil { + return err + } + + returnValue.Store(f.Response()) + index.Store(f.Index()) + return nil + }) + + if err != nil { return nil, 0, err } - return f.Response(), f.Index(), nil + + return returnValue.Load(), index.Load(), nil } // Init sets up the Mesh and Raft instances diff --git a/controller/response/responder.go b/controller/response/responder.go index d598b5572..80cc3d48a 100644 --- a/controller/response/responder.go +++ b/controller/response/responder.go @@ -20,9 +20,9 @@ import ( "fmt" "github.com/go-openapi/errors" "github.com/openziti/edge-api/rest_model" + "github.com/openziti/foundation/v2/errorz" "github.com/openziti/ziti/controller/api" "github.com/openziti/ziti/controller/apierror" - "github.com/openziti/foundation/v2/errorz" "net/http" ) @@ -110,7 +110,7 @@ func (self EdgeResponseMapper) toRestModel(e *errorz.ApiError, requestId string) ret.Code = errorz.CouldNotValidateCode ret.Message = errorz.CouldNotValidateMessage - } else if genericErr, ok := e.Cause.(apierror.GenericCauseError); ok { + } else if genericErr, ok := e.Cause.(*apierror.GenericCauseError); ok { ret.Cause = &rest_model.APIErrorCause{ APIError: rest_model.APIError{ Data: genericErr.DataMap, diff --git a/controller/rest_client/circuit/delete_circuit_responses.go b/controller/rest_client/circuit/delete_circuit_responses.go index f4659a81a..3f31fafdc 100644 --- a/controller/rest_client/circuit/delete_circuit_responses.go +++ b/controller/rest_client/circuit/delete_circuit_responses.go @@ -71,6 +71,12 @@ func (o *DeleteCircuitReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewDeleteCircuitTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *DeleteCircuitConflict) readResponse(response runtime.ClientResponse, co return nil } + +// NewDeleteCircuitTooManyRequests creates a DeleteCircuitTooManyRequests with default headers values +func NewDeleteCircuitTooManyRequests() *DeleteCircuitTooManyRequests { + return &DeleteCircuitTooManyRequests{} +} + +/* DeleteCircuitTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DeleteCircuitTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DeleteCircuitTooManyRequests) Error() string { + return fmt.Sprintf("[DELETE /circuits/{id}][%d] deleteCircuitTooManyRequests %+v", 429, o.Payload) +} +func (o *DeleteCircuitTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DeleteCircuitTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/circuit/detail_circuit_responses.go b/controller/rest_client/circuit/detail_circuit_responses.go index e07901016..6479c48aa 100644 --- a/controller/rest_client/circuit/detail_circuit_responses.go +++ b/controller/rest_client/circuit/detail_circuit_responses.go @@ -65,6 +65,12 @@ func (o *DetailCircuitReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewDetailCircuitTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DetailCircuitNotFound) readResponse(response runtime.ClientResponse, co return nil } + +// NewDetailCircuitTooManyRequests creates a DetailCircuitTooManyRequests with default headers values +func NewDetailCircuitTooManyRequests() *DetailCircuitTooManyRequests { + return &DetailCircuitTooManyRequests{} +} + +/* DetailCircuitTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DetailCircuitTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DetailCircuitTooManyRequests) Error() string { + return fmt.Sprintf("[GET /circuits/{id}][%d] detailCircuitTooManyRequests %+v", 429, o.Payload) +} +func (o *DetailCircuitTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DetailCircuitTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/circuit/list_circuits_responses.go b/controller/rest_client/circuit/list_circuits_responses.go index 76f212d02..cbc6c4d79 100644 --- a/controller/rest_client/circuit/list_circuits_responses.go +++ b/controller/rest_client/circuit/list_circuits_responses.go @@ -59,6 +59,12 @@ func (o *ListCircuitsReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewListCircuitsTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *ListCircuitsUnauthorized) readResponse(response runtime.ClientResponse, return nil } + +// NewListCircuitsTooManyRequests creates a ListCircuitsTooManyRequests with default headers values +func NewListCircuitsTooManyRequests() *ListCircuitsTooManyRequests { + return &ListCircuitsTooManyRequests{} +} + +/* ListCircuitsTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListCircuitsTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListCircuitsTooManyRequests) Error() string { + return fmt.Sprintf("[GET /circuits][%d] listCircuitsTooManyRequests %+v", 429, o.Payload) +} +func (o *ListCircuitsTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListCircuitsTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/database/data_integrity_results_responses.go b/controller/rest_client/database/data_integrity_results_responses.go index 04d24beee..97ae75163 100644 --- a/controller/rest_client/database/data_integrity_results_responses.go +++ b/controller/rest_client/database/data_integrity_results_responses.go @@ -59,6 +59,12 @@ func (o *DataIntegrityResultsReader) ReadResponse(response runtime.ClientRespons return nil, err } return nil, result + case 429: + result := NewDataIntegrityResultsTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *DataIntegrityResultsUnauthorized) readResponse(response runtime.ClientR return nil } + +// NewDataIntegrityResultsTooManyRequests creates a DataIntegrityResultsTooManyRequests with default headers values +func NewDataIntegrityResultsTooManyRequests() *DataIntegrityResultsTooManyRequests { + return &DataIntegrityResultsTooManyRequests{} +} + +/* DataIntegrityResultsTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DataIntegrityResultsTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DataIntegrityResultsTooManyRequests) Error() string { + return fmt.Sprintf("[GET /database/data-integrity-results][%d] dataIntegrityResultsTooManyRequests %+v", 429, o.Payload) +} +func (o *DataIntegrityResultsTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DataIntegrityResultsTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/inspect/inspect_responses.go b/controller/rest_client/inspect/inspect_responses.go index c6b131fbc..7fb3fa117 100644 --- a/controller/rest_client/inspect/inspect_responses.go +++ b/controller/rest_client/inspect/inspect_responses.go @@ -59,6 +59,12 @@ func (o *InspectReader) ReadResponse(response runtime.ClientResponse, consumer r return nil, err } return nil, result + case 429: + result := NewInspectTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *InspectUnauthorized) readResponse(response runtime.ClientResponse, cons return nil } + +// NewInspectTooManyRequests creates a InspectTooManyRequests with default headers values +func NewInspectTooManyRequests() *InspectTooManyRequests { + return &InspectTooManyRequests{} +} + +/* InspectTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type InspectTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *InspectTooManyRequests) Error() string { + return fmt.Sprintf("[POST /inspections][%d] inspectTooManyRequests %+v", 429, o.Payload) +} +func (o *InspectTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *InspectTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/link/delete_link_responses.go b/controller/rest_client/link/delete_link_responses.go index 6a8c22e05..c11beecfa 100644 --- a/controller/rest_client/link/delete_link_responses.go +++ b/controller/rest_client/link/delete_link_responses.go @@ -65,6 +65,12 @@ func (o *DeleteLinkReader) ReadResponse(response runtime.ClientResponse, consume return nil, err } return nil, result + case 429: + result := NewDeleteLinkTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DeleteLinkUnauthorized) readResponse(response runtime.ClientResponse, c return nil } + +// NewDeleteLinkTooManyRequests creates a DeleteLinkTooManyRequests with default headers values +func NewDeleteLinkTooManyRequests() *DeleteLinkTooManyRequests { + return &DeleteLinkTooManyRequests{} +} + +/* DeleteLinkTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DeleteLinkTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DeleteLinkTooManyRequests) Error() string { + return fmt.Sprintf("[DELETE /links/{id}][%d] deleteLinkTooManyRequests %+v", 429, o.Payload) +} +func (o *DeleteLinkTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DeleteLinkTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/link/detail_link_responses.go b/controller/rest_client/link/detail_link_responses.go index 03d427fb7..5959fc74e 100644 --- a/controller/rest_client/link/detail_link_responses.go +++ b/controller/rest_client/link/detail_link_responses.go @@ -65,6 +65,12 @@ func (o *DetailLinkReader) ReadResponse(response runtime.ClientResponse, consume return nil, err } return nil, result + case 429: + result := NewDetailLinkTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DetailLinkNotFound) readResponse(response runtime.ClientResponse, consu return nil } + +// NewDetailLinkTooManyRequests creates a DetailLinkTooManyRequests with default headers values +func NewDetailLinkTooManyRequests() *DetailLinkTooManyRequests { + return &DetailLinkTooManyRequests{} +} + +/* DetailLinkTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DetailLinkTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DetailLinkTooManyRequests) Error() string { + return fmt.Sprintf("[GET /links/{id}][%d] detailLinkTooManyRequests %+v", 429, o.Payload) +} +func (o *DetailLinkTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DetailLinkTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/link/list_links_responses.go b/controller/rest_client/link/list_links_responses.go index 93820d150..886059738 100644 --- a/controller/rest_client/link/list_links_responses.go +++ b/controller/rest_client/link/list_links_responses.go @@ -59,6 +59,12 @@ func (o *ListLinksReader) ReadResponse(response runtime.ClientResponse, consumer return nil, err } return nil, result + case 429: + result := NewListLinksTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *ListLinksUnauthorized) readResponse(response runtime.ClientResponse, co return nil } + +// NewListLinksTooManyRequests creates a ListLinksTooManyRequests with default headers values +func NewListLinksTooManyRequests() *ListLinksTooManyRequests { + return &ListLinksTooManyRequests{} +} + +/* ListLinksTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListLinksTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListLinksTooManyRequests) Error() string { + return fmt.Sprintf("[GET /links][%d] listLinksTooManyRequests %+v", 429, o.Payload) +} +func (o *ListLinksTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListLinksTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/link/patch_link_responses.go b/controller/rest_client/link/patch_link_responses.go index 7a14d0875..41dab6794 100644 --- a/controller/rest_client/link/patch_link_responses.go +++ b/controller/rest_client/link/patch_link_responses.go @@ -71,6 +71,12 @@ func (o *PatchLinkReader) ReadResponse(response runtime.ClientResponse, consumer return nil, err } return nil, result + case 429: + result := NewPatchLinkTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *PatchLinkNotFound) readResponse(response runtime.ClientResponse, consum return nil } + +// NewPatchLinkTooManyRequests creates a PatchLinkTooManyRequests with default headers values +func NewPatchLinkTooManyRequests() *PatchLinkTooManyRequests { + return &PatchLinkTooManyRequests{} +} + +/* PatchLinkTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type PatchLinkTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *PatchLinkTooManyRequests) Error() string { + return fmt.Sprintf("[PATCH /links/{id}][%d] patchLinkTooManyRequests %+v", 429, o.Payload) +} +func (o *PatchLinkTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *PatchLinkTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/raft/raft_list_members_responses.go b/controller/rest_client/raft/raft_list_members_responses.go index 09d41bc3f..6c8d87092 100644 --- a/controller/rest_client/raft/raft_list_members_responses.go +++ b/controller/rest_client/raft/raft_list_members_responses.go @@ -59,6 +59,12 @@ func (o *RaftListMembersReader) ReadResponse(response runtime.ClientResponse, co return nil, err } return nil, result + case 429: + result := NewRaftListMembersTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *RaftListMembersUnauthorized) readResponse(response runtime.ClientRespon return nil } + +// NewRaftListMembersTooManyRequests creates a RaftListMembersTooManyRequests with default headers values +func NewRaftListMembersTooManyRequests() *RaftListMembersTooManyRequests { + return &RaftListMembersTooManyRequests{} +} + +/* RaftListMembersTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type RaftListMembersTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *RaftListMembersTooManyRequests) Error() string { + return fmt.Sprintf("[GET /raft/list-members][%d] raftListMembersTooManyRequests %+v", 429, o.Payload) +} +func (o *RaftListMembersTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *RaftListMembersTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/create_router_responses.go b/controller/rest_client/router/create_router_responses.go index 2c2d7a8f1..67122ed22 100644 --- a/controller/rest_client/router/create_router_responses.go +++ b/controller/rest_client/router/create_router_responses.go @@ -65,6 +65,12 @@ func (o *CreateRouterReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewCreateRouterTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *CreateRouterUnauthorized) readResponse(response runtime.ClientResponse, return nil } + +// NewCreateRouterTooManyRequests creates a CreateRouterTooManyRequests with default headers values +func NewCreateRouterTooManyRequests() *CreateRouterTooManyRequests { + return &CreateRouterTooManyRequests{} +} + +/* CreateRouterTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type CreateRouterTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *CreateRouterTooManyRequests) Error() string { + return fmt.Sprintf("[POST /routers][%d] createRouterTooManyRequests %+v", 429, o.Payload) +} +func (o *CreateRouterTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *CreateRouterTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/delete_router_responses.go b/controller/rest_client/router/delete_router_responses.go index e55e3ba7d..46cfbcccc 100644 --- a/controller/rest_client/router/delete_router_responses.go +++ b/controller/rest_client/router/delete_router_responses.go @@ -71,6 +71,12 @@ func (o *DeleteRouterReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewDeleteRouterTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *DeleteRouterConflict) readResponse(response runtime.ClientResponse, con return nil } + +// NewDeleteRouterTooManyRequests creates a DeleteRouterTooManyRequests with default headers values +func NewDeleteRouterTooManyRequests() *DeleteRouterTooManyRequests { + return &DeleteRouterTooManyRequests{} +} + +/* DeleteRouterTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DeleteRouterTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DeleteRouterTooManyRequests) Error() string { + return fmt.Sprintf("[DELETE /routers/{id}][%d] deleteRouterTooManyRequests %+v", 429, o.Payload) +} +func (o *DeleteRouterTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DeleteRouterTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/detail_router_responses.go b/controller/rest_client/router/detail_router_responses.go index 3d30fe573..84815d9ad 100644 --- a/controller/rest_client/router/detail_router_responses.go +++ b/controller/rest_client/router/detail_router_responses.go @@ -65,6 +65,12 @@ func (o *DetailRouterReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewDetailRouterTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DetailRouterNotFound) readResponse(response runtime.ClientResponse, con return nil } + +// NewDetailRouterTooManyRequests creates a DetailRouterTooManyRequests with default headers values +func NewDetailRouterTooManyRequests() *DetailRouterTooManyRequests { + return &DetailRouterTooManyRequests{} +} + +/* DetailRouterTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DetailRouterTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DetailRouterTooManyRequests) Error() string { + return fmt.Sprintf("[GET /routers/{id}][%d] detailRouterTooManyRequests %+v", 429, o.Payload) +} +func (o *DetailRouterTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DetailRouterTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/list_router_terminators_responses.go b/controller/rest_client/router/list_router_terminators_responses.go index 939368597..7e059859f 100644 --- a/controller/rest_client/router/list_router_terminators_responses.go +++ b/controller/rest_client/router/list_router_terminators_responses.go @@ -65,6 +65,12 @@ func (o *ListRouterTerminatorsReader) ReadResponse(response runtime.ClientRespon return nil, err } return nil, result + case 429: + result := NewListRouterTerminatorsTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *ListRouterTerminatorsUnauthorized) readResponse(response runtime.Client return nil } + +// NewListRouterTerminatorsTooManyRequests creates a ListRouterTerminatorsTooManyRequests with default headers values +func NewListRouterTerminatorsTooManyRequests() *ListRouterTerminatorsTooManyRequests { + return &ListRouterTerminatorsTooManyRequests{} +} + +/* ListRouterTerminatorsTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListRouterTerminatorsTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListRouterTerminatorsTooManyRequests) Error() string { + return fmt.Sprintf("[GET /routers/{id}/terminators][%d] listRouterTerminatorsTooManyRequests %+v", 429, o.Payload) +} +func (o *ListRouterTerminatorsTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListRouterTerminatorsTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/list_routers_responses.go b/controller/rest_client/router/list_routers_responses.go index 2d9cfa2bf..f23ed5aa9 100644 --- a/controller/rest_client/router/list_routers_responses.go +++ b/controller/rest_client/router/list_routers_responses.go @@ -59,6 +59,12 @@ func (o *ListRoutersReader) ReadResponse(response runtime.ClientResponse, consum return nil, err } return nil, result + case 429: + result := NewListRoutersTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *ListRoutersUnauthorized) readResponse(response runtime.ClientResponse, return nil } + +// NewListRoutersTooManyRequests creates a ListRoutersTooManyRequests with default headers values +func NewListRoutersTooManyRequests() *ListRoutersTooManyRequests { + return &ListRoutersTooManyRequests{} +} + +/* ListRoutersTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListRoutersTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListRoutersTooManyRequests) Error() string { + return fmt.Sprintf("[GET /routers][%d] listRoutersTooManyRequests %+v", 429, o.Payload) +} +func (o *ListRoutersTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListRoutersTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/patch_router_responses.go b/controller/rest_client/router/patch_router_responses.go index 249cb52cb..5a062da9b 100644 --- a/controller/rest_client/router/patch_router_responses.go +++ b/controller/rest_client/router/patch_router_responses.go @@ -71,6 +71,12 @@ func (o *PatchRouterReader) ReadResponse(response runtime.ClientResponse, consum return nil, err } return nil, result + case 429: + result := NewPatchRouterTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *PatchRouterNotFound) readResponse(response runtime.ClientResponse, cons return nil } + +// NewPatchRouterTooManyRequests creates a PatchRouterTooManyRequests with default headers values +func NewPatchRouterTooManyRequests() *PatchRouterTooManyRequests { + return &PatchRouterTooManyRequests{} +} + +/* PatchRouterTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type PatchRouterTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *PatchRouterTooManyRequests) Error() string { + return fmt.Sprintf("[PATCH /routers/{id}][%d] patchRouterTooManyRequests %+v", 429, o.Payload) +} +func (o *PatchRouterTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *PatchRouterTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/router/update_router_responses.go b/controller/rest_client/router/update_router_responses.go index e9ba48ddf..05fec1a76 100644 --- a/controller/rest_client/router/update_router_responses.go +++ b/controller/rest_client/router/update_router_responses.go @@ -71,6 +71,12 @@ func (o *UpdateRouterReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewUpdateRouterTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *UpdateRouterNotFound) readResponse(response runtime.ClientResponse, con return nil } + +// NewUpdateRouterTooManyRequests creates a UpdateRouterTooManyRequests with default headers values +func NewUpdateRouterTooManyRequests() *UpdateRouterTooManyRequests { + return &UpdateRouterTooManyRequests{} +} + +/* UpdateRouterTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type UpdateRouterTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *UpdateRouterTooManyRequests) Error() string { + return fmt.Sprintf("[PUT /routers/{id}][%d] updateRouterTooManyRequests %+v", 429, o.Payload) +} +func (o *UpdateRouterTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *UpdateRouterTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/create_service_responses.go b/controller/rest_client/service/create_service_responses.go index 02114b05d..4aba359ef 100644 --- a/controller/rest_client/service/create_service_responses.go +++ b/controller/rest_client/service/create_service_responses.go @@ -65,6 +65,12 @@ func (o *CreateServiceReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewCreateServiceTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *CreateServiceUnauthorized) readResponse(response runtime.ClientResponse return nil } + +// NewCreateServiceTooManyRequests creates a CreateServiceTooManyRequests with default headers values +func NewCreateServiceTooManyRequests() *CreateServiceTooManyRequests { + return &CreateServiceTooManyRequests{} +} + +/* CreateServiceTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type CreateServiceTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *CreateServiceTooManyRequests) Error() string { + return fmt.Sprintf("[POST /services][%d] createServiceTooManyRequests %+v", 429, o.Payload) +} +func (o *CreateServiceTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *CreateServiceTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/delete_service_responses.go b/controller/rest_client/service/delete_service_responses.go index fa94e8e1b..ab2ecabf8 100644 --- a/controller/rest_client/service/delete_service_responses.go +++ b/controller/rest_client/service/delete_service_responses.go @@ -71,6 +71,12 @@ func (o *DeleteServiceReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewDeleteServiceTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *DeleteServiceConflict) readResponse(response runtime.ClientResponse, co return nil } + +// NewDeleteServiceTooManyRequests creates a DeleteServiceTooManyRequests with default headers values +func NewDeleteServiceTooManyRequests() *DeleteServiceTooManyRequests { + return &DeleteServiceTooManyRequests{} +} + +/* DeleteServiceTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DeleteServiceTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DeleteServiceTooManyRequests) Error() string { + return fmt.Sprintf("[DELETE /services/{id}][%d] deleteServiceTooManyRequests %+v", 429, o.Payload) +} +func (o *DeleteServiceTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DeleteServiceTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/detail_service_responses.go b/controller/rest_client/service/detail_service_responses.go index 1191e69c9..e7abdf31a 100644 --- a/controller/rest_client/service/detail_service_responses.go +++ b/controller/rest_client/service/detail_service_responses.go @@ -65,6 +65,12 @@ func (o *DetailServiceReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewDetailServiceTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DetailServiceNotFound) readResponse(response runtime.ClientResponse, co return nil } + +// NewDetailServiceTooManyRequests creates a DetailServiceTooManyRequests with default headers values +func NewDetailServiceTooManyRequests() *DetailServiceTooManyRequests { + return &DetailServiceTooManyRequests{} +} + +/* DetailServiceTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DetailServiceTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DetailServiceTooManyRequests) Error() string { + return fmt.Sprintf("[GET /services/{id}][%d] detailServiceTooManyRequests %+v", 429, o.Payload) +} +func (o *DetailServiceTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DetailServiceTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/list_service_terminators_responses.go b/controller/rest_client/service/list_service_terminators_responses.go index f7480dd1e..ce483b4e6 100644 --- a/controller/rest_client/service/list_service_terminators_responses.go +++ b/controller/rest_client/service/list_service_terminators_responses.go @@ -65,6 +65,12 @@ func (o *ListServiceTerminatorsReader) ReadResponse(response runtime.ClientRespo return nil, err } return nil, result + case 429: + result := NewListServiceTerminatorsTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *ListServiceTerminatorsUnauthorized) readResponse(response runtime.Clien return nil } + +// NewListServiceTerminatorsTooManyRequests creates a ListServiceTerminatorsTooManyRequests with default headers values +func NewListServiceTerminatorsTooManyRequests() *ListServiceTerminatorsTooManyRequests { + return &ListServiceTerminatorsTooManyRequests{} +} + +/* ListServiceTerminatorsTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListServiceTerminatorsTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListServiceTerminatorsTooManyRequests) Error() string { + return fmt.Sprintf("[GET /services/{id}/terminators][%d] listServiceTerminatorsTooManyRequests %+v", 429, o.Payload) +} +func (o *ListServiceTerminatorsTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListServiceTerminatorsTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/list_services_responses.go b/controller/rest_client/service/list_services_responses.go index f9b4bb332..0cf244810 100644 --- a/controller/rest_client/service/list_services_responses.go +++ b/controller/rest_client/service/list_services_responses.go @@ -59,6 +59,12 @@ func (o *ListServicesReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewListServicesTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -127,3 +133,35 @@ func (o *ListServicesUnauthorized) readResponse(response runtime.ClientResponse, return nil } + +// NewListServicesTooManyRequests creates a ListServicesTooManyRequests with default headers values +func NewListServicesTooManyRequests() *ListServicesTooManyRequests { + return &ListServicesTooManyRequests{} +} + +/* ListServicesTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListServicesTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListServicesTooManyRequests) Error() string { + return fmt.Sprintf("[GET /services][%d] listServicesTooManyRequests %+v", 429, o.Payload) +} +func (o *ListServicesTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListServicesTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/patch_service_responses.go b/controller/rest_client/service/patch_service_responses.go index 60010983e..c7e2812d4 100644 --- a/controller/rest_client/service/patch_service_responses.go +++ b/controller/rest_client/service/patch_service_responses.go @@ -71,6 +71,12 @@ func (o *PatchServiceReader) ReadResponse(response runtime.ClientResponse, consu return nil, err } return nil, result + case 429: + result := NewPatchServiceTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *PatchServiceNotFound) readResponse(response runtime.ClientResponse, con return nil } + +// NewPatchServiceTooManyRequests creates a PatchServiceTooManyRequests with default headers values +func NewPatchServiceTooManyRequests() *PatchServiceTooManyRequests { + return &PatchServiceTooManyRequests{} +} + +/* PatchServiceTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type PatchServiceTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *PatchServiceTooManyRequests) Error() string { + return fmt.Sprintf("[PATCH /services/{id}][%d] patchServiceTooManyRequests %+v", 429, o.Payload) +} +func (o *PatchServiceTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *PatchServiceTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/service/update_service_responses.go b/controller/rest_client/service/update_service_responses.go index d06505dad..6a5ace99d 100644 --- a/controller/rest_client/service/update_service_responses.go +++ b/controller/rest_client/service/update_service_responses.go @@ -71,6 +71,12 @@ func (o *UpdateServiceReader) ReadResponse(response runtime.ClientResponse, cons return nil, err } return nil, result + case 429: + result := NewUpdateServiceTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *UpdateServiceNotFound) readResponse(response runtime.ClientResponse, co return nil } + +// NewUpdateServiceTooManyRequests creates a UpdateServiceTooManyRequests with default headers values +func NewUpdateServiceTooManyRequests() *UpdateServiceTooManyRequests { + return &UpdateServiceTooManyRequests{} +} + +/* UpdateServiceTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type UpdateServiceTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *UpdateServiceTooManyRequests) Error() string { + return fmt.Sprintf("[PUT /services/{id}][%d] updateServiceTooManyRequests %+v", 429, o.Payload) +} +func (o *UpdateServiceTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *UpdateServiceTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/create_terminator_responses.go b/controller/rest_client/terminator/create_terminator_responses.go index 3cf6eb07d..262de8616 100644 --- a/controller/rest_client/terminator/create_terminator_responses.go +++ b/controller/rest_client/terminator/create_terminator_responses.go @@ -65,6 +65,12 @@ func (o *CreateTerminatorReader) ReadResponse(response runtime.ClientResponse, c return nil, err } return nil, result + case 429: + result := NewCreateTerminatorTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *CreateTerminatorUnauthorized) readResponse(response runtime.ClientRespo return nil } + +// NewCreateTerminatorTooManyRequests creates a CreateTerminatorTooManyRequests with default headers values +func NewCreateTerminatorTooManyRequests() *CreateTerminatorTooManyRequests { + return &CreateTerminatorTooManyRequests{} +} + +/* CreateTerminatorTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type CreateTerminatorTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *CreateTerminatorTooManyRequests) Error() string { + return fmt.Sprintf("[POST /terminators][%d] createTerminatorTooManyRequests %+v", 429, o.Payload) +} +func (o *CreateTerminatorTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *CreateTerminatorTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/delete_terminator_responses.go b/controller/rest_client/terminator/delete_terminator_responses.go index 9c312af19..c230f533f 100644 --- a/controller/rest_client/terminator/delete_terminator_responses.go +++ b/controller/rest_client/terminator/delete_terminator_responses.go @@ -71,6 +71,12 @@ func (o *DeleteTerminatorReader) ReadResponse(response runtime.ClientResponse, c return nil, err } return nil, result + case 429: + result := NewDeleteTerminatorTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *DeleteTerminatorConflict) readResponse(response runtime.ClientResponse, return nil } + +// NewDeleteTerminatorTooManyRequests creates a DeleteTerminatorTooManyRequests with default headers values +func NewDeleteTerminatorTooManyRequests() *DeleteTerminatorTooManyRequests { + return &DeleteTerminatorTooManyRequests{} +} + +/* DeleteTerminatorTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DeleteTerminatorTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DeleteTerminatorTooManyRequests) Error() string { + return fmt.Sprintf("[DELETE /terminators/{id}][%d] deleteTerminatorTooManyRequests %+v", 429, o.Payload) +} +func (o *DeleteTerminatorTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DeleteTerminatorTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/detail_terminator_responses.go b/controller/rest_client/terminator/detail_terminator_responses.go index 2eb4cffcd..888a60d70 100644 --- a/controller/rest_client/terminator/detail_terminator_responses.go +++ b/controller/rest_client/terminator/detail_terminator_responses.go @@ -65,6 +65,12 @@ func (o *DetailTerminatorReader) ReadResponse(response runtime.ClientResponse, c return nil, err } return nil, result + case 429: + result := NewDetailTerminatorTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *DetailTerminatorNotFound) readResponse(response runtime.ClientResponse, return nil } + +// NewDetailTerminatorTooManyRequests creates a DetailTerminatorTooManyRequests with default headers values +func NewDetailTerminatorTooManyRequests() *DetailTerminatorTooManyRequests { + return &DetailTerminatorTooManyRequests{} +} + +/* DetailTerminatorTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type DetailTerminatorTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *DetailTerminatorTooManyRequests) Error() string { + return fmt.Sprintf("[GET /terminators/{id}][%d] detailTerminatorTooManyRequests %+v", 429, o.Payload) +} +func (o *DetailTerminatorTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *DetailTerminatorTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/list_terminators_responses.go b/controller/rest_client/terminator/list_terminators_responses.go index 688d3ee90..25b3488a9 100644 --- a/controller/rest_client/terminator/list_terminators_responses.go +++ b/controller/rest_client/terminator/list_terminators_responses.go @@ -65,6 +65,12 @@ func (o *ListTerminatorsReader) ReadResponse(response runtime.ClientResponse, co return nil, err } return nil, result + case 429: + result := NewListTerminatorsTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -165,3 +171,35 @@ func (o *ListTerminatorsUnauthorized) readResponse(response runtime.ClientRespon return nil } + +// NewListTerminatorsTooManyRequests creates a ListTerminatorsTooManyRequests with default headers values +func NewListTerminatorsTooManyRequests() *ListTerminatorsTooManyRequests { + return &ListTerminatorsTooManyRequests{} +} + +/* ListTerminatorsTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type ListTerminatorsTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *ListTerminatorsTooManyRequests) Error() string { + return fmt.Sprintf("[GET /terminators][%d] listTerminatorsTooManyRequests %+v", 429, o.Payload) +} +func (o *ListTerminatorsTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *ListTerminatorsTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/patch_terminator_responses.go b/controller/rest_client/terminator/patch_terminator_responses.go index 6d0e76e3f..8c6e5e399 100644 --- a/controller/rest_client/terminator/patch_terminator_responses.go +++ b/controller/rest_client/terminator/patch_terminator_responses.go @@ -71,6 +71,12 @@ func (o *PatchTerminatorReader) ReadResponse(response runtime.ClientResponse, co return nil, err } return nil, result + case 429: + result := NewPatchTerminatorTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *PatchTerminatorNotFound) readResponse(response runtime.ClientResponse, return nil } + +// NewPatchTerminatorTooManyRequests creates a PatchTerminatorTooManyRequests with default headers values +func NewPatchTerminatorTooManyRequests() *PatchTerminatorTooManyRequests { + return &PatchTerminatorTooManyRequests{} +} + +/* PatchTerminatorTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type PatchTerminatorTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *PatchTerminatorTooManyRequests) Error() string { + return fmt.Sprintf("[PATCH /terminators/{id}][%d] patchTerminatorTooManyRequests %+v", 429, o.Payload) +} +func (o *PatchTerminatorTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *PatchTerminatorTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_client/terminator/update_terminator_responses.go b/controller/rest_client/terminator/update_terminator_responses.go index 09ca6b58d..b2f7e9ee4 100644 --- a/controller/rest_client/terminator/update_terminator_responses.go +++ b/controller/rest_client/terminator/update_terminator_responses.go @@ -71,6 +71,12 @@ func (o *UpdateTerminatorReader) ReadResponse(response runtime.ClientResponse, c return nil, err } return nil, result + case 429: + result := NewUpdateTerminatorTooManyRequests() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result default: return nil, runtime.NewAPIError("response status code does not match any response statuses defined for this endpoint in the swagger spec", response, response.Code()) } @@ -203,3 +209,35 @@ func (o *UpdateTerminatorNotFound) readResponse(response runtime.ClientResponse, return nil } + +// NewUpdateTerminatorTooManyRequests creates a UpdateTerminatorTooManyRequests with default headers values +func NewUpdateTerminatorTooManyRequests() *UpdateTerminatorTooManyRequests { + return &UpdateTerminatorTooManyRequests{} +} + +/* UpdateTerminatorTooManyRequests describes a response with status code 429, with default header values. + +The resource requested is rate limited and the rate limit has been exceeded +*/ +type UpdateTerminatorTooManyRequests struct { + Payload *rest_model.APIErrorEnvelope +} + +func (o *UpdateTerminatorTooManyRequests) Error() string { + return fmt.Sprintf("[PUT /terminators/{id}][%d] updateTerminatorTooManyRequests %+v", 429, o.Payload) +} +func (o *UpdateTerminatorTooManyRequests) GetPayload() *rest_model.APIErrorEnvelope { + return o.Payload +} + +func (o *UpdateTerminatorTooManyRequests) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(rest_model.APIErrorEnvelope) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/controller/rest_server/embedded_spec.go b/controller/rest_server/embedded_spec.go index 586ff3210..9872057f5 100644 --- a/controller/rest_server/embedded_spec.go +++ b/controller/rest_server/embedded_spec.go @@ -83,6 +83,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -104,6 +107,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -136,6 +142,9 @@ func init() { }, "409": { "$ref": "#/responses/cannotDeleteReferencedResourceResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -216,6 +225,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -303,6 +315,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -321,6 +336,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -342,6 +360,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -361,6 +382,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -394,6 +418,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -417,6 +444,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -446,6 +476,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -476,6 +509,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -497,6 +533,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -530,6 +569,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -552,6 +594,9 @@ func init() { }, "409": { "$ref": "#/responses/cannotDeleteReferencedResourceResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -585,6 +630,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -622,6 +670,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -656,6 +707,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -686,6 +740,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -707,6 +764,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -740,6 +800,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -762,6 +825,9 @@ func init() { }, "409": { "$ref": "#/responses/cannotDeleteReferencedResourceResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -795,6 +861,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -832,6 +901,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -869,6 +941,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -899,6 +974,9 @@ func init() { }, "401": { "$ref": "#/responses/unauthorizedResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } } @@ -920,6 +998,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -953,6 +1034,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -975,6 +1059,9 @@ func init() { }, "409": { "$ref": "#/responses/cannotDeleteReferencedResourceResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -1008,6 +1095,9 @@ func init() { }, "404": { "$ref": "#/responses/notFoundResponse" + }, + "429": { + "$ref": "#/responses/rateLimitedResponse" } } }, @@ -2581,6 +2671,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -2649,6 +2762,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -2761,6 +2897,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -2957,6 +3116,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -3156,6 +3338,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -3198,6 +3403,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -3266,6 +3494,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -3343,11 +3594,34 @@ func init() { } } } - } - } - }, - "patch": { - "description": "Update the supplied fields on a link. Requires admin access.", + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } + } + } + }, + "patch": { + "description": "Update the supplied fields on a link. Requires admin access.", "tags": [ "Link" ], @@ -3457,6 +3731,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -3508,6 +3805,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -3567,6 +3887,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -3655,6 +3998,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -3723,6 +4089,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -3837,6 +4226,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -3939,6 +4351,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4053,6 +4488,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4158,6 +4616,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4226,6 +4707,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4314,6 +4818,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -4382,6 +4909,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4496,6 +5046,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4598,6 +5171,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4712,6 +5308,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4817,6 +5436,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -4922,6 +5564,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -5010,6 +5675,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } } @@ -5078,6 +5766,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -5192,6 +5903,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -5294,6 +6028,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, @@ -5408,6 +6165,29 @@ func init() { } } } + }, + "429": { + "description": "The resource requested is rate limited and the rate limit has been exceeded", + "schema": { + "$ref": "#/definitions/apiErrorEnvelope" + }, + "examples": { + "application/json": { + "error": { + "args": { + "urlVars": {} + }, + "causeMessage": "you have hit a rate limit in the requested operation", + "code": "RATE_LIMITED", + "message": "The resource is rate limited and the rate limit has been exceeded. Please try again later", + "requestId": "270908d6-f2ef-4577-b973-67bec18ae376" + }, + "meta": { + "apiEnrollmentVersion": "0.0.1", + "apiVersion": "0.0.1" + } + } + } } } }, diff --git a/controller/rest_server/operations/circuit/delete_circuit_responses.go b/controller/rest_server/operations/circuit/delete_circuit_responses.go index 272f31a94..bf3cdd849 100644 --- a/controller/rest_server/operations/circuit/delete_circuit_responses.go +++ b/controller/rest_server/operations/circuit/delete_circuit_responses.go @@ -212,3 +212,47 @@ func (o *DeleteCircuitConflict) WriteResponse(rw http.ResponseWriter, producer r } } } + +// DeleteCircuitTooManyRequestsCode is the HTTP code returned for type DeleteCircuitTooManyRequests +const DeleteCircuitTooManyRequestsCode int = 429 + +/*DeleteCircuitTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response deleteCircuitTooManyRequests +*/ +type DeleteCircuitTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDeleteCircuitTooManyRequests creates DeleteCircuitTooManyRequests with default headers values +func NewDeleteCircuitTooManyRequests() *DeleteCircuitTooManyRequests { + + return &DeleteCircuitTooManyRequests{} +} + +// WithPayload adds the payload to the delete circuit too many requests response +func (o *DeleteCircuitTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DeleteCircuitTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete circuit too many requests response +func (o *DeleteCircuitTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteCircuitTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/circuit/detail_circuit_responses.go b/controller/rest_server/operations/circuit/detail_circuit_responses.go index c67acc916..b7f7771a6 100644 --- a/controller/rest_server/operations/circuit/detail_circuit_responses.go +++ b/controller/rest_server/operations/circuit/detail_circuit_responses.go @@ -168,3 +168,47 @@ func (o *DetailCircuitNotFound) WriteResponse(rw http.ResponseWriter, producer r } } } + +// DetailCircuitTooManyRequestsCode is the HTTP code returned for type DetailCircuitTooManyRequests +const DetailCircuitTooManyRequestsCode int = 429 + +/*DetailCircuitTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response detailCircuitTooManyRequests +*/ +type DetailCircuitTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDetailCircuitTooManyRequests creates DetailCircuitTooManyRequests with default headers values +func NewDetailCircuitTooManyRequests() *DetailCircuitTooManyRequests { + + return &DetailCircuitTooManyRequests{} +} + +// WithPayload adds the payload to the detail circuit too many requests response +func (o *DetailCircuitTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DetailCircuitTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the detail circuit too many requests response +func (o *DetailCircuitTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DetailCircuitTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/circuit/list_circuits_responses.go b/controller/rest_server/operations/circuit/list_circuits_responses.go index 9ca6417ed..5cb52c325 100644 --- a/controller/rest_server/operations/circuit/list_circuits_responses.go +++ b/controller/rest_server/operations/circuit/list_circuits_responses.go @@ -124,3 +124,47 @@ func (o *ListCircuitsUnauthorized) WriteResponse(rw http.ResponseWriter, produce } } } + +// ListCircuitsTooManyRequestsCode is the HTTP code returned for type ListCircuitsTooManyRequests +const ListCircuitsTooManyRequestsCode int = 429 + +/*ListCircuitsTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listCircuitsTooManyRequests +*/ +type ListCircuitsTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListCircuitsTooManyRequests creates ListCircuitsTooManyRequests with default headers values +func NewListCircuitsTooManyRequests() *ListCircuitsTooManyRequests { + + return &ListCircuitsTooManyRequests{} +} + +// WithPayload adds the payload to the list circuits too many requests response +func (o *ListCircuitsTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListCircuitsTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list circuits too many requests response +func (o *ListCircuitsTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListCircuitsTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/database/data_integrity_results_responses.go b/controller/rest_server/operations/database/data_integrity_results_responses.go index 11c095f4b..cd65e12e7 100644 --- a/controller/rest_server/operations/database/data_integrity_results_responses.go +++ b/controller/rest_server/operations/database/data_integrity_results_responses.go @@ -124,3 +124,47 @@ func (o *DataIntegrityResultsUnauthorized) WriteResponse(rw http.ResponseWriter, } } } + +// DataIntegrityResultsTooManyRequestsCode is the HTTP code returned for type DataIntegrityResultsTooManyRequests +const DataIntegrityResultsTooManyRequestsCode int = 429 + +/*DataIntegrityResultsTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response dataIntegrityResultsTooManyRequests +*/ +type DataIntegrityResultsTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDataIntegrityResultsTooManyRequests creates DataIntegrityResultsTooManyRequests with default headers values +func NewDataIntegrityResultsTooManyRequests() *DataIntegrityResultsTooManyRequests { + + return &DataIntegrityResultsTooManyRequests{} +} + +// WithPayload adds the payload to the data integrity results too many requests response +func (o *DataIntegrityResultsTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DataIntegrityResultsTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the data integrity results too many requests response +func (o *DataIntegrityResultsTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DataIntegrityResultsTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/inspect/inspect_responses.go b/controller/rest_server/operations/inspect/inspect_responses.go index 74a2a792e..4f9dc4bb9 100644 --- a/controller/rest_server/operations/inspect/inspect_responses.go +++ b/controller/rest_server/operations/inspect/inspect_responses.go @@ -124,3 +124,47 @@ func (o *InspectUnauthorized) WriteResponse(rw http.ResponseWriter, producer run } } } + +// InspectTooManyRequestsCode is the HTTP code returned for type InspectTooManyRequests +const InspectTooManyRequestsCode int = 429 + +/*InspectTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response inspectTooManyRequests +*/ +type InspectTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewInspectTooManyRequests creates InspectTooManyRequests with default headers values +func NewInspectTooManyRequests() *InspectTooManyRequests { + + return &InspectTooManyRequests{} +} + +// WithPayload adds the payload to the inspect too many requests response +func (o *InspectTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *InspectTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the inspect too many requests response +func (o *InspectTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *InspectTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/link/delete_link_responses.go b/controller/rest_server/operations/link/delete_link_responses.go index e426ada03..e456d57e5 100644 --- a/controller/rest_server/operations/link/delete_link_responses.go +++ b/controller/rest_server/operations/link/delete_link_responses.go @@ -168,3 +168,47 @@ func (o *DeleteLinkUnauthorized) WriteResponse(rw http.ResponseWriter, producer } } } + +// DeleteLinkTooManyRequestsCode is the HTTP code returned for type DeleteLinkTooManyRequests +const DeleteLinkTooManyRequestsCode int = 429 + +/*DeleteLinkTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response deleteLinkTooManyRequests +*/ +type DeleteLinkTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDeleteLinkTooManyRequests creates DeleteLinkTooManyRequests with default headers values +func NewDeleteLinkTooManyRequests() *DeleteLinkTooManyRequests { + + return &DeleteLinkTooManyRequests{} +} + +// WithPayload adds the payload to the delete link too many requests response +func (o *DeleteLinkTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DeleteLinkTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete link too many requests response +func (o *DeleteLinkTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteLinkTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/link/detail_link_responses.go b/controller/rest_server/operations/link/detail_link_responses.go index 3dd6de72c..db7ebe183 100644 --- a/controller/rest_server/operations/link/detail_link_responses.go +++ b/controller/rest_server/operations/link/detail_link_responses.go @@ -168,3 +168,47 @@ func (o *DetailLinkNotFound) WriteResponse(rw http.ResponseWriter, producer runt } } } + +// DetailLinkTooManyRequestsCode is the HTTP code returned for type DetailLinkTooManyRequests +const DetailLinkTooManyRequestsCode int = 429 + +/*DetailLinkTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response detailLinkTooManyRequests +*/ +type DetailLinkTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDetailLinkTooManyRequests creates DetailLinkTooManyRequests with default headers values +func NewDetailLinkTooManyRequests() *DetailLinkTooManyRequests { + + return &DetailLinkTooManyRequests{} +} + +// WithPayload adds the payload to the detail link too many requests response +func (o *DetailLinkTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DetailLinkTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the detail link too many requests response +func (o *DetailLinkTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DetailLinkTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/link/list_links_responses.go b/controller/rest_server/operations/link/list_links_responses.go index b1b0967a8..895b27946 100644 --- a/controller/rest_server/operations/link/list_links_responses.go +++ b/controller/rest_server/operations/link/list_links_responses.go @@ -124,3 +124,47 @@ func (o *ListLinksUnauthorized) WriteResponse(rw http.ResponseWriter, producer r } } } + +// ListLinksTooManyRequestsCode is the HTTP code returned for type ListLinksTooManyRequests +const ListLinksTooManyRequestsCode int = 429 + +/*ListLinksTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listLinksTooManyRequests +*/ +type ListLinksTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListLinksTooManyRequests creates ListLinksTooManyRequests with default headers values +func NewListLinksTooManyRequests() *ListLinksTooManyRequests { + + return &ListLinksTooManyRequests{} +} + +// WithPayload adds the payload to the list links too many requests response +func (o *ListLinksTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListLinksTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list links too many requests response +func (o *ListLinksTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListLinksTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/link/patch_link_responses.go b/controller/rest_server/operations/link/patch_link_responses.go index bcd7d81e0..704153f5c 100644 --- a/controller/rest_server/operations/link/patch_link_responses.go +++ b/controller/rest_server/operations/link/patch_link_responses.go @@ -212,3 +212,47 @@ func (o *PatchLinkNotFound) WriteResponse(rw http.ResponseWriter, producer runti } } } + +// PatchLinkTooManyRequestsCode is the HTTP code returned for type PatchLinkTooManyRequests +const PatchLinkTooManyRequestsCode int = 429 + +/*PatchLinkTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response patchLinkTooManyRequests +*/ +type PatchLinkTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewPatchLinkTooManyRequests creates PatchLinkTooManyRequests with default headers values +func NewPatchLinkTooManyRequests() *PatchLinkTooManyRequests { + + return &PatchLinkTooManyRequests{} +} + +// WithPayload adds the payload to the patch link too many requests response +func (o *PatchLinkTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *PatchLinkTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the patch link too many requests response +func (o *PatchLinkTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *PatchLinkTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/raft/raft_list_members_responses.go b/controller/rest_server/operations/raft/raft_list_members_responses.go index 7b3df864a..53822fd85 100644 --- a/controller/rest_server/operations/raft/raft_list_members_responses.go +++ b/controller/rest_server/operations/raft/raft_list_members_responses.go @@ -124,3 +124,47 @@ func (o *RaftListMembersUnauthorized) WriteResponse(rw http.ResponseWriter, prod } } } + +// RaftListMembersTooManyRequestsCode is the HTTP code returned for type RaftListMembersTooManyRequests +const RaftListMembersTooManyRequestsCode int = 429 + +/*RaftListMembersTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response raftListMembersTooManyRequests +*/ +type RaftListMembersTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewRaftListMembersTooManyRequests creates RaftListMembersTooManyRequests with default headers values +func NewRaftListMembersTooManyRequests() *RaftListMembersTooManyRequests { + + return &RaftListMembersTooManyRequests{} +} + +// WithPayload adds the payload to the raft list members too many requests response +func (o *RaftListMembersTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *RaftListMembersTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the raft list members too many requests response +func (o *RaftListMembersTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *RaftListMembersTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/create_router_responses.go b/controller/rest_server/operations/router/create_router_responses.go index 4ef55ffc0..00ffa8339 100644 --- a/controller/rest_server/operations/router/create_router_responses.go +++ b/controller/rest_server/operations/router/create_router_responses.go @@ -168,3 +168,47 @@ func (o *CreateRouterUnauthorized) WriteResponse(rw http.ResponseWriter, produce } } } + +// CreateRouterTooManyRequestsCode is the HTTP code returned for type CreateRouterTooManyRequests +const CreateRouterTooManyRequestsCode int = 429 + +/*CreateRouterTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response createRouterTooManyRequests +*/ +type CreateRouterTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewCreateRouterTooManyRequests creates CreateRouterTooManyRequests with default headers values +func NewCreateRouterTooManyRequests() *CreateRouterTooManyRequests { + + return &CreateRouterTooManyRequests{} +} + +// WithPayload adds the payload to the create router too many requests response +func (o *CreateRouterTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *CreateRouterTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create router too many requests response +func (o *CreateRouterTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateRouterTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/delete_router_responses.go b/controller/rest_server/operations/router/delete_router_responses.go index c7b1ea3ed..0e245eb90 100644 --- a/controller/rest_server/operations/router/delete_router_responses.go +++ b/controller/rest_server/operations/router/delete_router_responses.go @@ -212,3 +212,47 @@ func (o *DeleteRouterConflict) WriteResponse(rw http.ResponseWriter, producer ru } } } + +// DeleteRouterTooManyRequestsCode is the HTTP code returned for type DeleteRouterTooManyRequests +const DeleteRouterTooManyRequestsCode int = 429 + +/*DeleteRouterTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response deleteRouterTooManyRequests +*/ +type DeleteRouterTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDeleteRouterTooManyRequests creates DeleteRouterTooManyRequests with default headers values +func NewDeleteRouterTooManyRequests() *DeleteRouterTooManyRequests { + + return &DeleteRouterTooManyRequests{} +} + +// WithPayload adds the payload to the delete router too many requests response +func (o *DeleteRouterTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DeleteRouterTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete router too many requests response +func (o *DeleteRouterTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteRouterTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/detail_router_responses.go b/controller/rest_server/operations/router/detail_router_responses.go index a4f176c7b..697fdbd1f 100644 --- a/controller/rest_server/operations/router/detail_router_responses.go +++ b/controller/rest_server/operations/router/detail_router_responses.go @@ -168,3 +168,47 @@ func (o *DetailRouterNotFound) WriteResponse(rw http.ResponseWriter, producer ru } } } + +// DetailRouterTooManyRequestsCode is the HTTP code returned for type DetailRouterTooManyRequests +const DetailRouterTooManyRequestsCode int = 429 + +/*DetailRouterTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response detailRouterTooManyRequests +*/ +type DetailRouterTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDetailRouterTooManyRequests creates DetailRouterTooManyRequests with default headers values +func NewDetailRouterTooManyRequests() *DetailRouterTooManyRequests { + + return &DetailRouterTooManyRequests{} +} + +// WithPayload adds the payload to the detail router too many requests response +func (o *DetailRouterTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DetailRouterTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the detail router too many requests response +func (o *DetailRouterTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DetailRouterTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/list_router_terminators_responses.go b/controller/rest_server/operations/router/list_router_terminators_responses.go index 7ba0c1343..c17cfab3b 100644 --- a/controller/rest_server/operations/router/list_router_terminators_responses.go +++ b/controller/rest_server/operations/router/list_router_terminators_responses.go @@ -168,3 +168,47 @@ func (o *ListRouterTerminatorsUnauthorized) WriteResponse(rw http.ResponseWriter } } } + +// ListRouterTerminatorsTooManyRequestsCode is the HTTP code returned for type ListRouterTerminatorsTooManyRequests +const ListRouterTerminatorsTooManyRequestsCode int = 429 + +/*ListRouterTerminatorsTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listRouterTerminatorsTooManyRequests +*/ +type ListRouterTerminatorsTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListRouterTerminatorsTooManyRequests creates ListRouterTerminatorsTooManyRequests with default headers values +func NewListRouterTerminatorsTooManyRequests() *ListRouterTerminatorsTooManyRequests { + + return &ListRouterTerminatorsTooManyRequests{} +} + +// WithPayload adds the payload to the list router terminators too many requests response +func (o *ListRouterTerminatorsTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListRouterTerminatorsTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list router terminators too many requests response +func (o *ListRouterTerminatorsTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListRouterTerminatorsTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/list_routers_responses.go b/controller/rest_server/operations/router/list_routers_responses.go index 3c990d4e3..1eb30d62d 100644 --- a/controller/rest_server/operations/router/list_routers_responses.go +++ b/controller/rest_server/operations/router/list_routers_responses.go @@ -124,3 +124,47 @@ func (o *ListRoutersUnauthorized) WriteResponse(rw http.ResponseWriter, producer } } } + +// ListRoutersTooManyRequestsCode is the HTTP code returned for type ListRoutersTooManyRequests +const ListRoutersTooManyRequestsCode int = 429 + +/*ListRoutersTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listRoutersTooManyRequests +*/ +type ListRoutersTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListRoutersTooManyRequests creates ListRoutersTooManyRequests with default headers values +func NewListRoutersTooManyRequests() *ListRoutersTooManyRequests { + + return &ListRoutersTooManyRequests{} +} + +// WithPayload adds the payload to the list routers too many requests response +func (o *ListRoutersTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListRoutersTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list routers too many requests response +func (o *ListRoutersTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListRoutersTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/patch_router_responses.go b/controller/rest_server/operations/router/patch_router_responses.go index 64d96feef..8076c43d2 100644 --- a/controller/rest_server/operations/router/patch_router_responses.go +++ b/controller/rest_server/operations/router/patch_router_responses.go @@ -212,3 +212,47 @@ func (o *PatchRouterNotFound) WriteResponse(rw http.ResponseWriter, producer run } } } + +// PatchRouterTooManyRequestsCode is the HTTP code returned for type PatchRouterTooManyRequests +const PatchRouterTooManyRequestsCode int = 429 + +/*PatchRouterTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response patchRouterTooManyRequests +*/ +type PatchRouterTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewPatchRouterTooManyRequests creates PatchRouterTooManyRequests with default headers values +func NewPatchRouterTooManyRequests() *PatchRouterTooManyRequests { + + return &PatchRouterTooManyRequests{} +} + +// WithPayload adds the payload to the patch router too many requests response +func (o *PatchRouterTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *PatchRouterTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the patch router too many requests response +func (o *PatchRouterTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *PatchRouterTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/router/update_router_responses.go b/controller/rest_server/operations/router/update_router_responses.go index 0d1e53f93..62e375c7b 100644 --- a/controller/rest_server/operations/router/update_router_responses.go +++ b/controller/rest_server/operations/router/update_router_responses.go @@ -212,3 +212,47 @@ func (o *UpdateRouterNotFound) WriteResponse(rw http.ResponseWriter, producer ru } } } + +// UpdateRouterTooManyRequestsCode is the HTTP code returned for type UpdateRouterTooManyRequests +const UpdateRouterTooManyRequestsCode int = 429 + +/*UpdateRouterTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response updateRouterTooManyRequests +*/ +type UpdateRouterTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewUpdateRouterTooManyRequests creates UpdateRouterTooManyRequests with default headers values +func NewUpdateRouterTooManyRequests() *UpdateRouterTooManyRequests { + + return &UpdateRouterTooManyRequests{} +} + +// WithPayload adds the payload to the update router too many requests response +func (o *UpdateRouterTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *UpdateRouterTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the update router too many requests response +func (o *UpdateRouterTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *UpdateRouterTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/create_service_responses.go b/controller/rest_server/operations/service/create_service_responses.go index 726af8090..c27c349f3 100644 --- a/controller/rest_server/operations/service/create_service_responses.go +++ b/controller/rest_server/operations/service/create_service_responses.go @@ -168,3 +168,47 @@ func (o *CreateServiceUnauthorized) WriteResponse(rw http.ResponseWriter, produc } } } + +// CreateServiceTooManyRequestsCode is the HTTP code returned for type CreateServiceTooManyRequests +const CreateServiceTooManyRequestsCode int = 429 + +/*CreateServiceTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response createServiceTooManyRequests +*/ +type CreateServiceTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewCreateServiceTooManyRequests creates CreateServiceTooManyRequests with default headers values +func NewCreateServiceTooManyRequests() *CreateServiceTooManyRequests { + + return &CreateServiceTooManyRequests{} +} + +// WithPayload adds the payload to the create service too many requests response +func (o *CreateServiceTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *CreateServiceTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create service too many requests response +func (o *CreateServiceTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateServiceTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/delete_service_responses.go b/controller/rest_server/operations/service/delete_service_responses.go index de2c0e86f..c7ce4a61a 100644 --- a/controller/rest_server/operations/service/delete_service_responses.go +++ b/controller/rest_server/operations/service/delete_service_responses.go @@ -212,3 +212,47 @@ func (o *DeleteServiceConflict) WriteResponse(rw http.ResponseWriter, producer r } } } + +// DeleteServiceTooManyRequestsCode is the HTTP code returned for type DeleteServiceTooManyRequests +const DeleteServiceTooManyRequestsCode int = 429 + +/*DeleteServiceTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response deleteServiceTooManyRequests +*/ +type DeleteServiceTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDeleteServiceTooManyRequests creates DeleteServiceTooManyRequests with default headers values +func NewDeleteServiceTooManyRequests() *DeleteServiceTooManyRequests { + + return &DeleteServiceTooManyRequests{} +} + +// WithPayload adds the payload to the delete service too many requests response +func (o *DeleteServiceTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DeleteServiceTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete service too many requests response +func (o *DeleteServiceTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteServiceTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/detail_service_responses.go b/controller/rest_server/operations/service/detail_service_responses.go index f382a56bc..1ed31212a 100644 --- a/controller/rest_server/operations/service/detail_service_responses.go +++ b/controller/rest_server/operations/service/detail_service_responses.go @@ -168,3 +168,47 @@ func (o *DetailServiceNotFound) WriteResponse(rw http.ResponseWriter, producer r } } } + +// DetailServiceTooManyRequestsCode is the HTTP code returned for type DetailServiceTooManyRequests +const DetailServiceTooManyRequestsCode int = 429 + +/*DetailServiceTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response detailServiceTooManyRequests +*/ +type DetailServiceTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDetailServiceTooManyRequests creates DetailServiceTooManyRequests with default headers values +func NewDetailServiceTooManyRequests() *DetailServiceTooManyRequests { + + return &DetailServiceTooManyRequests{} +} + +// WithPayload adds the payload to the detail service too many requests response +func (o *DetailServiceTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DetailServiceTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the detail service too many requests response +func (o *DetailServiceTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DetailServiceTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/list_service_terminators_responses.go b/controller/rest_server/operations/service/list_service_terminators_responses.go index 5ed6a064a..1a487dea2 100644 --- a/controller/rest_server/operations/service/list_service_terminators_responses.go +++ b/controller/rest_server/operations/service/list_service_terminators_responses.go @@ -168,3 +168,47 @@ func (o *ListServiceTerminatorsUnauthorized) WriteResponse(rw http.ResponseWrite } } } + +// ListServiceTerminatorsTooManyRequestsCode is the HTTP code returned for type ListServiceTerminatorsTooManyRequests +const ListServiceTerminatorsTooManyRequestsCode int = 429 + +/*ListServiceTerminatorsTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listServiceTerminatorsTooManyRequests +*/ +type ListServiceTerminatorsTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListServiceTerminatorsTooManyRequests creates ListServiceTerminatorsTooManyRequests with default headers values +func NewListServiceTerminatorsTooManyRequests() *ListServiceTerminatorsTooManyRequests { + + return &ListServiceTerminatorsTooManyRequests{} +} + +// WithPayload adds the payload to the list service terminators too many requests response +func (o *ListServiceTerminatorsTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListServiceTerminatorsTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list service terminators too many requests response +func (o *ListServiceTerminatorsTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListServiceTerminatorsTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/list_services_responses.go b/controller/rest_server/operations/service/list_services_responses.go index 286a6d6d6..6161fa79a 100644 --- a/controller/rest_server/operations/service/list_services_responses.go +++ b/controller/rest_server/operations/service/list_services_responses.go @@ -124,3 +124,47 @@ func (o *ListServicesUnauthorized) WriteResponse(rw http.ResponseWriter, produce } } } + +// ListServicesTooManyRequestsCode is the HTTP code returned for type ListServicesTooManyRequests +const ListServicesTooManyRequestsCode int = 429 + +/*ListServicesTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listServicesTooManyRequests +*/ +type ListServicesTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListServicesTooManyRequests creates ListServicesTooManyRequests with default headers values +func NewListServicesTooManyRequests() *ListServicesTooManyRequests { + + return &ListServicesTooManyRequests{} +} + +// WithPayload adds the payload to the list services too many requests response +func (o *ListServicesTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListServicesTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list services too many requests response +func (o *ListServicesTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListServicesTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/patch_service_responses.go b/controller/rest_server/operations/service/patch_service_responses.go index c73c7d237..efa04e967 100644 --- a/controller/rest_server/operations/service/patch_service_responses.go +++ b/controller/rest_server/operations/service/patch_service_responses.go @@ -212,3 +212,47 @@ func (o *PatchServiceNotFound) WriteResponse(rw http.ResponseWriter, producer ru } } } + +// PatchServiceTooManyRequestsCode is the HTTP code returned for type PatchServiceTooManyRequests +const PatchServiceTooManyRequestsCode int = 429 + +/*PatchServiceTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response patchServiceTooManyRequests +*/ +type PatchServiceTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewPatchServiceTooManyRequests creates PatchServiceTooManyRequests with default headers values +func NewPatchServiceTooManyRequests() *PatchServiceTooManyRequests { + + return &PatchServiceTooManyRequests{} +} + +// WithPayload adds the payload to the patch service too many requests response +func (o *PatchServiceTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *PatchServiceTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the patch service too many requests response +func (o *PatchServiceTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *PatchServiceTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/service/update_service_responses.go b/controller/rest_server/operations/service/update_service_responses.go index 2f99ef7ae..d493df4a4 100644 --- a/controller/rest_server/operations/service/update_service_responses.go +++ b/controller/rest_server/operations/service/update_service_responses.go @@ -212,3 +212,47 @@ func (o *UpdateServiceNotFound) WriteResponse(rw http.ResponseWriter, producer r } } } + +// UpdateServiceTooManyRequestsCode is the HTTP code returned for type UpdateServiceTooManyRequests +const UpdateServiceTooManyRequestsCode int = 429 + +/*UpdateServiceTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response updateServiceTooManyRequests +*/ +type UpdateServiceTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewUpdateServiceTooManyRequests creates UpdateServiceTooManyRequests with default headers values +func NewUpdateServiceTooManyRequests() *UpdateServiceTooManyRequests { + + return &UpdateServiceTooManyRequests{} +} + +// WithPayload adds the payload to the update service too many requests response +func (o *UpdateServiceTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *UpdateServiceTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the update service too many requests response +func (o *UpdateServiceTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *UpdateServiceTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/create_terminator_responses.go b/controller/rest_server/operations/terminator/create_terminator_responses.go index ffc7305a9..8f1240e1e 100644 --- a/controller/rest_server/operations/terminator/create_terminator_responses.go +++ b/controller/rest_server/operations/terminator/create_terminator_responses.go @@ -168,3 +168,47 @@ func (o *CreateTerminatorUnauthorized) WriteResponse(rw http.ResponseWriter, pro } } } + +// CreateTerminatorTooManyRequestsCode is the HTTP code returned for type CreateTerminatorTooManyRequests +const CreateTerminatorTooManyRequestsCode int = 429 + +/*CreateTerminatorTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response createTerminatorTooManyRequests +*/ +type CreateTerminatorTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewCreateTerminatorTooManyRequests creates CreateTerminatorTooManyRequests with default headers values +func NewCreateTerminatorTooManyRequests() *CreateTerminatorTooManyRequests { + + return &CreateTerminatorTooManyRequests{} +} + +// WithPayload adds the payload to the create terminator too many requests response +func (o *CreateTerminatorTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *CreateTerminatorTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the create terminator too many requests response +func (o *CreateTerminatorTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *CreateTerminatorTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/delete_terminator_responses.go b/controller/rest_server/operations/terminator/delete_terminator_responses.go index cdf8cca82..0a478627b 100644 --- a/controller/rest_server/operations/terminator/delete_terminator_responses.go +++ b/controller/rest_server/operations/terminator/delete_terminator_responses.go @@ -212,3 +212,47 @@ func (o *DeleteTerminatorConflict) WriteResponse(rw http.ResponseWriter, produce } } } + +// DeleteTerminatorTooManyRequestsCode is the HTTP code returned for type DeleteTerminatorTooManyRequests +const DeleteTerminatorTooManyRequestsCode int = 429 + +/*DeleteTerminatorTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response deleteTerminatorTooManyRequests +*/ +type DeleteTerminatorTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDeleteTerminatorTooManyRequests creates DeleteTerminatorTooManyRequests with default headers values +func NewDeleteTerminatorTooManyRequests() *DeleteTerminatorTooManyRequests { + + return &DeleteTerminatorTooManyRequests{} +} + +// WithPayload adds the payload to the delete terminator too many requests response +func (o *DeleteTerminatorTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DeleteTerminatorTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete terminator too many requests response +func (o *DeleteTerminatorTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DeleteTerminatorTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/detail_terminator_responses.go b/controller/rest_server/operations/terminator/detail_terminator_responses.go index b3be05c7b..fe576f89a 100644 --- a/controller/rest_server/operations/terminator/detail_terminator_responses.go +++ b/controller/rest_server/operations/terminator/detail_terminator_responses.go @@ -168,3 +168,47 @@ func (o *DetailTerminatorNotFound) WriteResponse(rw http.ResponseWriter, produce } } } + +// DetailTerminatorTooManyRequestsCode is the HTTP code returned for type DetailTerminatorTooManyRequests +const DetailTerminatorTooManyRequestsCode int = 429 + +/*DetailTerminatorTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response detailTerminatorTooManyRequests +*/ +type DetailTerminatorTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewDetailTerminatorTooManyRequests creates DetailTerminatorTooManyRequests with default headers values +func NewDetailTerminatorTooManyRequests() *DetailTerminatorTooManyRequests { + + return &DetailTerminatorTooManyRequests{} +} + +// WithPayload adds the payload to the detail terminator too many requests response +func (o *DetailTerminatorTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *DetailTerminatorTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the detail terminator too many requests response +func (o *DetailTerminatorTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *DetailTerminatorTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/list_terminators_responses.go b/controller/rest_server/operations/terminator/list_terminators_responses.go index 81c1a07d4..6af0c53b9 100644 --- a/controller/rest_server/operations/terminator/list_terminators_responses.go +++ b/controller/rest_server/operations/terminator/list_terminators_responses.go @@ -168,3 +168,47 @@ func (o *ListTerminatorsUnauthorized) WriteResponse(rw http.ResponseWriter, prod } } } + +// ListTerminatorsTooManyRequestsCode is the HTTP code returned for type ListTerminatorsTooManyRequests +const ListTerminatorsTooManyRequestsCode int = 429 + +/*ListTerminatorsTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response listTerminatorsTooManyRequests +*/ +type ListTerminatorsTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewListTerminatorsTooManyRequests creates ListTerminatorsTooManyRequests with default headers values +func NewListTerminatorsTooManyRequests() *ListTerminatorsTooManyRequests { + + return &ListTerminatorsTooManyRequests{} +} + +// WithPayload adds the payload to the list terminators too many requests response +func (o *ListTerminatorsTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *ListTerminatorsTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the list terminators too many requests response +func (o *ListTerminatorsTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *ListTerminatorsTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/patch_terminator_responses.go b/controller/rest_server/operations/terminator/patch_terminator_responses.go index 0cd041598..4b76243fc 100644 --- a/controller/rest_server/operations/terminator/patch_terminator_responses.go +++ b/controller/rest_server/operations/terminator/patch_terminator_responses.go @@ -212,3 +212,47 @@ func (o *PatchTerminatorNotFound) WriteResponse(rw http.ResponseWriter, producer } } } + +// PatchTerminatorTooManyRequestsCode is the HTTP code returned for type PatchTerminatorTooManyRequests +const PatchTerminatorTooManyRequestsCode int = 429 + +/*PatchTerminatorTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response patchTerminatorTooManyRequests +*/ +type PatchTerminatorTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewPatchTerminatorTooManyRequests creates PatchTerminatorTooManyRequests with default headers values +func NewPatchTerminatorTooManyRequests() *PatchTerminatorTooManyRequests { + + return &PatchTerminatorTooManyRequests{} +} + +// WithPayload adds the payload to the patch terminator too many requests response +func (o *PatchTerminatorTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *PatchTerminatorTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the patch terminator too many requests response +func (o *PatchTerminatorTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *PatchTerminatorTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/rest_server/operations/terminator/update_terminator_responses.go b/controller/rest_server/operations/terminator/update_terminator_responses.go index 6bbe5b703..f4e1af130 100644 --- a/controller/rest_server/operations/terminator/update_terminator_responses.go +++ b/controller/rest_server/operations/terminator/update_terminator_responses.go @@ -212,3 +212,47 @@ func (o *UpdateTerminatorNotFound) WriteResponse(rw http.ResponseWriter, produce } } } + +// UpdateTerminatorTooManyRequestsCode is the HTTP code returned for type UpdateTerminatorTooManyRequests +const UpdateTerminatorTooManyRequestsCode int = 429 + +/*UpdateTerminatorTooManyRequests The resource requested is rate limited and the rate limit has been exceeded + +swagger:response updateTerminatorTooManyRequests +*/ +type UpdateTerminatorTooManyRequests struct { + + /* + In: Body + */ + Payload *rest_model.APIErrorEnvelope `json:"body,omitempty"` +} + +// NewUpdateTerminatorTooManyRequests creates UpdateTerminatorTooManyRequests with default headers values +func NewUpdateTerminatorTooManyRequests() *UpdateTerminatorTooManyRequests { + + return &UpdateTerminatorTooManyRequests{} +} + +// WithPayload adds the payload to the update terminator too many requests response +func (o *UpdateTerminatorTooManyRequests) WithPayload(payload *rest_model.APIErrorEnvelope) *UpdateTerminatorTooManyRequests { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the update terminator too many requests response +func (o *UpdateTerminatorTooManyRequests) SetPayload(payload *rest_model.APIErrorEnvelope) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *UpdateTerminatorTooManyRequests) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(429) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/controller/specs/swagger.yml b/controller/specs/swagger.yml index a36a3dd8a..1cdd6a64e 100644 --- a/controller/specs/swagger.yml +++ b/controller/specs/swagger.yml @@ -46,6 +46,9 @@ paths: $ref: '#/responses/listServices' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + post: summary: Create a service resource description: Create a service resource. Requires admin access. @@ -66,6 +69,9 @@ paths: $ref: '#/responses/badRequestResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + '/services/{id}': parameters: - $ref: '#/parameters/id' @@ -82,6 +88,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + put: summary: Update all fields on a service description: Update all fields on a service by id. Requires admin access. @@ -104,6 +113,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + patch: summary: Update the supplied fields on a service description: Update the supplied fields on a service. Requires admin access. @@ -126,6 +138,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + delete: summary: Delete a service description: Delete a service by id. Requires admin access. @@ -141,6 +156,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '409': $ref: '#/responses/cannotDeleteReferencedResourceResponse' + '429': + $ref: '#/responses/rateLimitedResponse' '/services/{id}/terminators': parameters: @@ -163,6 +180,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '400': $ref: '#/responses/badRequestResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Routers @@ -184,6 +203,9 @@ paths: $ref: '#/responses/listRouters' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + post: summary: Create a router resource description: Create a router resource. Requires admin access. @@ -204,6 +226,9 @@ paths: $ref: '#/responses/badRequestResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + '/routers/{id}': parameters: - $ref: '#/parameters/id' @@ -220,6 +245,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + put: summary: Update all fields on a router description: Update all fields on a router by id. Requires admin access. @@ -242,6 +270,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + patch: summary: Update the supplied fields on a router description: Update the supplied fields on a router. Requires admin access. @@ -264,6 +295,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + delete: summary: Delete a router description: Delete a router by id. Requires admin access. @@ -279,6 +313,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '409': $ref: '#/responses/cannotDeleteReferencedResourceResponse' + '429': + $ref: '#/responses/rateLimitedResponse' '/routers/{id}/terminators': parameters: @@ -301,6 +337,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '400': $ref: '#/responses/badRequestResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Terminators @@ -324,6 +362,9 @@ paths: $ref: '#/responses/unauthorizedResponse' '400': $ref: '#/responses/badRequestResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + post: summary: Create a terminator resource description: Create a terminator resource. Requires admin access. @@ -344,6 +385,9 @@ paths: $ref: '#/responses/badRequestResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + '/terminators/{id}': parameters: - $ref: '#/parameters/id' @@ -360,6 +404,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + put: summary: Update all fields on a terminator description: Update all fields on a terminator by id. Requires admin access. @@ -382,6 +429,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + patch: summary: Update the supplied fields on a terminator description: Update the supplied fields on a terminator. Requires admin access. @@ -404,6 +454,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + delete: summary: Delete a terminator description: Delete a terminator by id. Requires admin access. @@ -419,6 +472,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '409': $ref: '#/responses/cannotDeleteReferencedResourceResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Links @@ -436,6 +491,9 @@ paths: $ref: '#/responses/listLinks' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + '/links/{id}': parameters: - $ref: '#/parameters/id' @@ -452,6 +510,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + patch: summary: Update the supplied fields on a link description: Update the supplied fields on a link. Requires admin access. @@ -474,6 +535,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + delete: summary: Delete a link description: Delete a link by id. Requires admin access. @@ -487,6 +551,8 @@ paths: $ref: '#/responses/badRequestResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Circuits @@ -504,6 +570,9 @@ paths: $ref: '#/responses/listCircuits' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + '/circuits/{id}': parameters: - $ref: '#/parameters/id' @@ -520,6 +589,9 @@ paths: $ref: '#/responses/notFoundResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' + delete: summary: Delete a circuit description: Delete a circuit by id. Requires admin access. @@ -542,6 +614,8 @@ paths: $ref: '#/responses/unauthorizedResponse' '409': $ref: '#/responses/cannotDeleteReferencedResourceResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Inspections @@ -566,6 +640,8 @@ paths: $ref: '#/responses/inspectResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Database @@ -653,6 +729,8 @@ paths: $ref: '#/responses/dataIntegrityCheckResult' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ################################################################### # Raft @@ -669,6 +747,8 @@ paths: $ref: '#/responses/raftListMembersResponse' '401': $ref: '#/responses/unauthorizedResponse' + '429': + $ref: '#/responses/rateLimitedResponse' ####################################################################################################################### # diff --git a/controller/sync_strats/sync_instant.go b/controller/sync_strats/sync_instant.go index 202780ae2..8d800abc4 100644 --- a/controller/sync_strats/sync_instant.go +++ b/controller/sync_strats/sync_instant.go @@ -22,17 +22,17 @@ import ( "github.com/lucsky/cuid" "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" + "github.com/openziti/foundation/v2/debugz" + "github.com/openziti/foundation/v2/genext" + "github.com/openziti/storage/ast" + "github.com/openziti/ziti/common/build" "github.com/openziti/ziti/common/pb/edge_ctrl_pb" "github.com/openziti/ziti/controller/env" + "github.com/openziti/ziti/controller/event" "github.com/openziti/ziti/controller/handler_edge_ctrl" "github.com/openziti/ziti/controller/model" - "github.com/openziti/ziti/controller/persistence" - "github.com/openziti/ziti/common/build" "github.com/openziti/ziti/controller/network" - "github.com/openziti/ziti/controller/event" - "github.com/openziti/foundation/v2/debugz" - "github.com/openziti/foundation/v2/genext" - "github.com/openziti/storage/ast" + "github.com/openziti/ziti/controller/persistence" cmap "github.com/orcaman/concurrent-map/v2" "go.etcd.io/bbolt" "google.golang.org/protobuf/proto" @@ -431,14 +431,18 @@ func (strategy *InstantStrategy) sendHello(rtx *RouterSender) { } } -func (strategy *InstantStrategy) ReceiveResync(r *network.Router, _ *edge_ctrl_pb.RequestClientReSync) { - rtx := strategy.rtxMap.Get(r.Id) +func (strategy *InstantStrategy) ReceiveResync(routerId string, _ *edge_ctrl_pb.RequestClientReSync) { + rtx := strategy.rtxMap.Get(routerId) if rtx == nil { + routerName := "" + if router, _ := strategy.ae.Managers.Router.Read(routerId); router != nil { + routerName = router.Name + } pfxlog.Logger(). WithField("strategy", strategy.Type()). - WithField("routerId", r.Id). - WithField("routerName", r.Name). + WithField("routerId", routerId). + WithField("routerName", routerName). Error("received resync from router that is currently not tracked by the strategy, dropping resync") return } @@ -450,14 +454,18 @@ func (strategy *InstantStrategy) ReceiveResync(r *network.Router, _ *edge_ctrl_p strategy.receivedClientHelloQueue <- rtx } -func (strategy *InstantStrategy) ReceiveClientHello(r *network.Router, respHello *edge_ctrl_pb.ClientHello) { - rtx := strategy.rtxMap.Get(r.Id) +func (strategy *InstantStrategy) ReceiveClientHello(routerId string, respHello *edge_ctrl_pb.ClientHello) { + rtx := strategy.rtxMap.Get(routerId) if rtx == nil { + routerName := "" + if router, _ := strategy.ae.Managers.Router.Read(routerId); router != nil { + routerName = router.Name + } pfxlog.Logger(). WithField("strategy", strategy.Type()). - WithField("routerId", r.Id). - WithField("routerName", r.Name). + WithField("routerId", routerId). + WithField("routerName", routerName). Error("received hello from router that is currently not tracked by the strategy, dropping hello") return } @@ -467,17 +475,12 @@ func (strategy *InstantStrategy) ReceiveClientHello(r *network.Router, respHello WithField("protocols", respHello.Protocols). WithField("protocolPorts", respHello.ProtocolPorts). WithField("listeners", respHello.Listeners). - WithField("data", respHello.Data) - - serverVersion := build.GetBuildInfo().Version() - - if r.VersionInfo != nil { - logger = logger.WithField("version", r.VersionInfo.Version). - WithField("revision", r.VersionInfo.Revision). - WithField("buildDate", r.VersionInfo.BuildDate). - WithField("os", r.VersionInfo.OS). - WithField("arch", r.VersionInfo.Arch) - } + WithField("data", respHello.Data). + WithField("version", rtx.Router.VersionInfo.Version). + WithField("revision", rtx.Router.VersionInfo.Revision). + WithField("buildDate", rtx.Router.VersionInfo.BuildDate). + WithField("os", rtx.Router.VersionInfo.OS). + WithField("arch", rtx.Router.VersionInfo.Arch) protocols := map[string]string{} @@ -497,8 +500,9 @@ func (strategy *InstantStrategy) ReceiveClientHello(r *network.Router, respHello rtx.SetHostname(respHello.Hostname) rtx.SetProtocols(protocols) - rtx.SetVersionInfo(*r.VersionInfo) + rtx.SetVersionInfo(*rtx.Router.VersionInfo) + serverVersion := build.GetBuildInfo().Version() logger.Infof("edge router sent hello with version [%s] to controller with version [%s]", respHello.Version, serverVersion) strategy.receivedClientHelloQueue <- rtx } diff --git a/dist/cloudfront/get.openziti.io/routes.yml b/dist/cloudfront/get.openziti.io/routes.yml index f2c16c2f1..7c80f09f7 100644 --- a/dist/cloudfront/get.openziti.io/routes.yml +++ b/dist/cloudfront/get.openziti.io/routes.yml @@ -28,3 +28,7 @@ - get: /pack/ raw: /openziti/ziti-tunnel-sdk-c/main/ file: package-repos.gpg + +- get: /zdew/ + raw: /openziti/desktop-edge-win/release-next/ + file: version-check.json diff --git a/dist/docker-images/ziti-cli/Dockerfile b/dist/docker-images/ziti-cli/Dockerfile index 0a006e7ce..8508e5b72 100644 --- a/dist/docker-images/ziti-cli/Dockerfile +++ b/dist/docker-images/ziti-cli/Dockerfile @@ -31,7 +31,7 @@ LABEL name="openziti/ziti-cli" \ USER root ### install packages -RUN INSTALL_PKGS="python38 python38-pip tar bash-completion vim-minimal less shadow-utils" && \ +RUN INSTALL_PKGS="python3.11 python3.11-pip tar bash-completion vim-minimal less shadow-utils jq" && \ microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \ microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS} diff --git a/etc/ctrl.with.edge.yml b/etc/ctrl.with.edge.yml index 98f7fd846..7e99f9678 100644 --- a/etc/ctrl.with.edge.yml +++ b/etc/ctrl.with.edge.yml @@ -233,3 +233,6 @@ web: - binding: edge-client options: { } +commandRateLimiter: + enabled: true + maxQueued: 100 diff --git a/go.mod b/go.mod index 800655f84..45476153a 100644 --- a/go.mod +++ b/go.mod @@ -24,11 +24,11 @@ require ( github.com/go-openapi/strfmt v0.21.7 github.com/go-openapi/swag v0.22.4 github.com/go-openapi/validate v0.22.1 - github.com/go-resty/resty/v2 v2.9.1 + github.com/go-resty/resty/v2 v2.10.0 github.com/golang-jwt/jwt/v5 v5.0.0 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/google/gopacket v1.1.19 - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.4.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 @@ -46,18 +46,18 @@ require ( github.com/miekg/dns v1.1.56 github.com/mitchellh/mapstructure v1.5.0 github.com/natefinch/lumberjack v2.0.0+incompatible - github.com/openziti/agent v1.0.15 - github.com/openziti/channel/v2 v2.0.101 - github.com/openziti/edge-api v0.25.38 + github.com/openziti/agent v1.0.16 + github.com/openziti/channel/v2 v2.0.105 + github.com/openziti/edge-api v0.26.0 github.com/openziti/foundation/v2 v2.0.33 - github.com/openziti/identity v1.0.64 + github.com/openziti/identity v1.0.66 github.com/openziti/jwks v1.0.3 - github.com/openziti/metrics v1.2.36 + github.com/openziti/metrics v1.2.37 github.com/openziti/runzmd v1.0.33 - github.com/openziti/sdk-golang v0.20.122 - github.com/openziti/secretstream v0.1.12 - github.com/openziti/storage v0.2.20 - github.com/openziti/transport/v2 v2.0.109 + github.com/openziti/sdk-golang v0.20.129 + github.com/openziti/secretstream v0.1.13 + github.com/openziti/storage v0.2.23 + github.com/openziti/transport/v2 v2.0.113 github.com/openziti/x509-claims v1.0.3 github.com/openziti/xweb/v2 v2.1.0 github.com/openziti/ziti-db-explorer v1.1.3 @@ -76,7 +76,7 @@ require ( github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 github.com/xeipuuv/gojsonschema v1.2.0 github.com/zitadel/oidc/v2 v2.7.0 - go.etcd.io/bbolt v1.3.7 + go.etcd.io/bbolt v1.3.8 golang.org/x/crypto v0.14.0 golang.org/x/net v0.17.0 golang.org/x/sync v0.4.0 @@ -95,7 +95,7 @@ require ( github.com/MichaelMure/go-term-markdown v0.1.4 // indirect github.com/MichaelMure/go-term-text v0.3.1 // indirect github.com/alecthomas/chroma v0.10.0 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect @@ -109,9 +109,9 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/eliukblau/pixterm/pkg/ansimage v0.0.0-20191210081756-9fb6cf8c2f75 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -129,15 +129,14 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.17.0 // indirect github.com/kr/pty v1.1.8 // indirect github.com/kyokomi/emoji/v2 v2.2.12 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect + github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-tty v0.0.3 // indirect github.com/mdlayher/socket v0.4.1 // indirect @@ -187,5 +186,5 @@ require ( google.golang.org/appengine v1.6.7 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - nhooyr.io/websocket v1.8.7 // indirect + nhooyr.io/websocket v1.8.10 // indirect ) diff --git a/go.sum b/go.sum index 4b7e21f74..ae3db55fa 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= @@ -192,16 +192,12 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/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/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-acme/lego/v4 v4.14.2 h1:/D/jqRgLi8Cbk33sLGtu2pX2jEg3bGJWHyV8kFuUHGM= github.com/go-acme/lego/v4 v4.14.2/go.mod h1:kBXxbeTg0x9AgaOYjPSwIeJy3Y33zTz+tMD16O4MO6c= @@ -217,8 +213,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -263,15 +259,8 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM= -github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= @@ -297,12 +286,6 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -363,8 +346,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -388,8 +372,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -404,7 +388,6 @@ github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -480,7 +463,6 @@ github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2C github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -494,10 +476,7 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -519,8 +498,6 @@ github.com/kyokomi/emoji/v2 v2.2.12 h1:sSVA5nH9ebR3Zji1o31wu3yOwD1zKXQA2z0zUyeit github.com/kyokomi/emoji/v2 v2.2.12/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -528,8 +505,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i github.com/lucsky/cuid v1.2.1 h1:MtJrL2OFhvYufUIn48d35QGXyeTC8tn0upumW9WwTHg= github.com/lucsky/cuid v1.2.1/go.mod h1:QaaJqckboimOmhRSJXSx/+IT+VTfxfPGSo/6mfgUfmE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= +github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0= +github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -567,8 +544,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.6/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/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -609,11 +586,9 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= @@ -639,32 +614,32 @@ github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openziti/agent v1.0.15 h1:NW4egpS3Mw1RQBZWfUEvrmBh9kn/SU/dU5fndsyyhZ4= -github.com/openziti/agent v1.0.15/go.mod h1:zfm53+PVWoGFzjGGgQdKby5749G6VRYHe+eQJmoVKy4= -github.com/openziti/channel/v2 v2.0.101 h1:UaveW/ogYKVtCQZfwRoMhsZhj/tvs1bD7SvH0aLaYNw= -github.com/openziti/channel/v2 v2.0.101/go.mod h1:b9CBWpH6tnLqCHInDKL6AzMGqXdbEjsul3yVQUGENVU= +github.com/openziti/agent v1.0.16 h1:9Saji+8hFE1NpzP2XzDhsVJbCrDlhixoLHfOpFt5Z+U= +github.com/openziti/agent v1.0.16/go.mod h1:zfm53+PVWoGFzjGGgQdKby5749G6VRYHe+eQJmoVKy4= +github.com/openziti/channel/v2 v2.0.105 h1:WT2zFF7krZkYUfuXA+4tQxhYiiVWlldD3mKX3qJU9Ww= +github.com/openziti/channel/v2 v2.0.105/go.mod h1:++bV6FFgGUNxaBu7iOkkCa6rSiueU34Kd6f2LSCrEtU= 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-api v0.25.38 h1:aijFEC4pMCi2gR6zL6FYQRkm59SQAwrF0tZS4LZsxi4= -github.com/openziti/edge-api v0.25.38/go.mod h1:5mmcMgqK1MsBb0K8V1CBfGbtRUji5KYdmhJJJkJBMqY= +github.com/openziti/edge-api v0.26.0 h1:082hXjj8rnyMBZHYiB6jb4n7mCXtdMXpF2iCqZOv4IM= +github.com/openziti/edge-api v0.26.0/go.mod h1:/e1pK92L471fvOAwE/hLX5sqBuuo+NwI8vmL04dUHsM= github.com/openziti/foundation/v2 v2.0.33 h1:8CP+fi4KsmzA4jDi54jibwFWWxKpd0rSiplzN9Z0Isw= github.com/openziti/foundation/v2 v2.0.33/go.mod h1:dWR0g3NOka3uKz9MgUHq6dmuRLmSvunkyeuOXEW/5qU= -github.com/openziti/identity v1.0.64 h1:HwALRY1J/rNNcIAlr1OwCwTHU/rlMRaUi5TXAfZotjw= -github.com/openziti/identity v1.0.64/go.mod h1:t/mW5mCpCbcRrssj4EpzfrmebI7+UKXGH2twll7IQIo= +github.com/openziti/identity v1.0.66 h1:wCIVNCoiHmeicC9yM15FC0xe6jSic879ztN63fSD6hM= +github.com/openziti/identity v1.0.66/go.mod h1:grReHVqBwhECrnrAZCxNw4ZpA2I1ox66tYfPkfGuKJY= github.com/openziti/jwks v1.0.3 h1:hf8wkb+Cg4nH/HM0KROFd7u+C3DkRVcFZJ7tDV+4icc= github.com/openziti/jwks v1.0.3/go.mod h1:t4xxq8vlXGsPn29kiQVnZBBDDnEoOFqtJoHibkJunQQ= -github.com/openziti/metrics v1.2.36 h1:oW5YM9H8IqtFuxIyo0rMC3mTpl3rdSnDKcHp+ZTn+JM= -github.com/openziti/metrics v1.2.36/go.mod h1:fjYG6sUC/n6VXe0nZbYGEBaopbRThBo/3xt7o9VatRQ= +github.com/openziti/metrics v1.2.37 h1:5yWvMwQT6X43LDlNVcUtqAPJQXfKtbWSYoCIiOfXztg= +github.com/openziti/metrics v1.2.37/go.mod h1:jIL9iilxby8tR98C18uZaSe6bRG15ItR8XF2hmMt8vs= github.com/openziti/runzmd v1.0.33 h1:tOyjRoUuVXIo1z1pNU32jALWkMmhzsSaDrhLtuOn3Ts= github.com/openziti/runzmd v1.0.33/go.mod h1:8c/uvZR/XWXQNllTq6LuTpfKL2DTNxfI2X2wYhgRwik= -github.com/openziti/sdk-golang v0.20.122 h1:fuxws2yFEFl4hdq4l96/N23ztC1oUiQIM/lePTI6rBY= -github.com/openziti/sdk-golang v0.20.122/go.mod h1:n6Ft+Gz7e2JO6DQ6Ixc9oIn06I1MjzkI3V9kilkOBIQ= -github.com/openziti/secretstream v0.1.12 h1:N78CHxtqWzSyNFOsYtYRWNNTfX1ZDAPkFgzHobpodZU= -github.com/openziti/secretstream v0.1.12/go.mod h1:gHMH1REH0r4VlmCtuWx8biU7j5ZfOivFjz9mLgwq7mk= -github.com/openziti/storage v0.2.20 h1:xpLczyF/czIw76M4Rrt2urYn/EvGNor+SPzoixuOkLs= -github.com/openziti/storage v0.2.20/go.mod h1:UO8D6h4AAf5OT1iJg1sppKoEPC2YWaBGZFLK7rPyk5M= -github.com/openziti/transport/v2 v2.0.109 h1:12ZdM9R7lETKP7cT2xsGlTX/4w2qBtC8nThxw8RG77Q= -github.com/openziti/transport/v2 v2.0.109/go.mod h1:r1jay/cSzkw15SJLtbk/I9YZtMIYjhueqAqfWtO5ioE= +github.com/openziti/sdk-golang v0.20.129 h1:FjvXsGFxEiHq89sNyLSvNymruACFW5tbhkgZ3VCg2pE= +github.com/openziti/sdk-golang v0.20.129/go.mod h1:ZpJ7HCcIQbp8XiSno3YXkfhoDIbgjCjS2ScK2bda8eo= +github.com/openziti/secretstream v0.1.13 h1:grp53Q5gCFPXv6okwWHDVvqBBk2BhD0ikHwfV3Adhnc= +github.com/openziti/secretstream v0.1.13/go.mod h1:M4DYavDc3TVF/eemNqp5Fa+zGuYTNa0HTGSz/GkgUzA= +github.com/openziti/storage v0.2.23 h1:R5ZBGDGC/LvOz3fE/GlevwbPZ3HL7VxYEvlhKuezvNU= +github.com/openziti/storage v0.2.23/go.mod h1:NZCrN2dLtRU73McVEflK5prDgYds9J54mMNz5DmgvZE= +github.com/openziti/transport/v2 v2.0.113 h1:xFPd1W00KqkFb62rRsRXmLqfgr9d9uk0CAVZegvtGhA= +github.com/openziti/transport/v2 v2.0.113/go.mod h1:TSDHV7RTGg/FinzfOP8cg86O53BCabXedANh3eUNics= github.com/openziti/x509-claims v1.0.3 h1:HNdQ8Nf1agB3lBs1gahcO6zfkeS4S5xoQ2/PkY4HRX0= github.com/openziti/x509-claims v1.0.3/go.mod h1:Z0WIpBm6c4ecrpRKrou6Gk2wrLWxJO/+tuUwKh8VewE= github.com/openziti/xweb/v2 v2.1.0 h1:Xhh3C2pZkq/Prr65V+SfFSibLDYteoc4f62KQCcTZF4= @@ -858,10 +833,6 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 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= @@ -896,8 +867,8 @@ github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ github.com/zitadel/oidc/v2 v2.7.0 h1:IGX4EDk6tegTjUSsZDWeTfLseFU0BdJ/Glf1tgys2lU= github.com/zitadel/oidc/v2 v2.7.0/go.mod h1:zkUkVJS0sDVy9m0UA9RgO3f8i/C0rtjvXU36UJj7T+0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -962,7 +933,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1065,7 +1035,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1181,7 +1150,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1195,7 +1163,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1217,8 +1184,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1456,8 +1423,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w= rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo= diff --git a/quickstart/docker/docker-compose.yml b/quickstart/docker/docker-compose.yml index c6e751bfa..75eda8236 100644 --- a/quickstart/docker/docker-compose.yml +++ b/quickstart/docker/docker-compose.yml @@ -2,6 +2,11 @@ version: '2.4' services: ziti-controller: image: "${ZITI_IMAGE}:${ZITI_VERSION}" + healthcheck: + test: curl -m 1 -s -k https://${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}:${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}/edge/client/v1/version + interval: 1s + timeout: 3s + retries: 30 env_file: - ./.env ports: @@ -32,7 +37,8 @@ services: ziti-controller-init-container: image: "${ZITI_IMAGE}:${ZITI_VERSION}" depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy environment: - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller} - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280} @@ -57,7 +63,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy ports: - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_PORT:-3022}:${ZITI_ROUTER_PORT:-3022} - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080} @@ -84,7 +91,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy ports: - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_WSS_PORT:-3023}:${ZITI_ROUTER_WSS_PORT:-3023} - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10081}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10081} @@ -113,7 +121,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy environment: - ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller} - ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-6262} @@ -135,7 +144,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy environment: - ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller} - ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-6262} @@ -156,7 +166,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy environment: - ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-ziti-controller} - ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-6262} @@ -194,7 +205,8 @@ services: - ZITI_CTRL_NAME=${ZITI_CTRL_NAME:-ziti-edge-controller} - PORTTLS=8443 depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy ports: - ${ZITI_INTERFACE:-0.0.0.0}:8443:8443 volumes: diff --git a/quickstart/docker/image/run-controller.sh b/quickstart/docker/image/run-controller.sh index 0ec35e252..40faea127 100755 --- a/quickstart/docker/image/run-controller.sh +++ b/quickstart/docker/image/run-controller.sh @@ -1,6 +1,14 @@ #!/bin/bash ziti_controller_cfg="${ZITI_HOME}/ziti-edge-controller.yaml" +# Global Variables +ASCI_RESTORE='\033[0m' +ASCI_RED='\033[00;31m' + +function RED { # Generally used for ERROR + echo "${ASCI_RED}${1-}${ASCI_RESTORE}" +} + if [[ "${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS-}" == "" ]]; then export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="ziti-edge-controller"; fi if [[ "${ZITI_CTRL_NAME-}" == "" ]]; then export ZITI_CTRL_NAME="${ZITI_NETWORK}-controller"; fi @@ -35,6 +43,10 @@ if [ ! -f "${ZITI_HOME}/access-control.init" ]; then # initialize the database with the admin user: "${ZITI_BIN_DIR}/ziti" controller edge init "${ZITI_HOME}/${ZITI_CTRL_NAME}.yaml" -u "${ZITI_USER}" -p "${ZITI_PWD}" + if [[ "$?" != 0 ]]; then + echo -e "$(RED " --- There was an error while initializing the controller ---")" + exit 1 + fi else echo "system has been initialized. starting the process." # don't move the sourcing of the file. yes it's duplicated but it needs to be here diff --git a/quickstart/docker/image/ziti-cli-functions.sh b/quickstart/docker/image/ziti-cli-functions.sh index a31d495a7..c71d0e896 100644 --- a/quickstart/docker/image/ziti-cli-functions.sh +++ b/quickstart/docker/image/ziti-cli-functions.sh @@ -405,7 +405,7 @@ function persistEnvironmentValues { # Store all ZITI_ variables in the environment file, creating the directory if necessary tmpfilepath="$(mktemp)" mkdir -p "$(dirname "${filepath}")" && echo "" > "${tmpfilepath}" - for zEnvVar in $(set | grep -e "^ZITI_" | sort); do + for zEnvVar in $(set | grep -e "^ZITI_" | sed "s/='\(.*\)'\$/=\1/" | sort); do envvar="$(echo "${zEnvVar}" | cut -d '=' -f1)" envval="$(echo "${zEnvVar}" | cut -d '=' -f2-1000)" echo 'if [[ "$'${envvar}'" == "" ]]; then export '${envvar}'="'${envval}'"; else echo "NOT OVERRIDING: env var '${envvar}' already set. using existing value"; fi' >> "${tmpfilepath}" @@ -717,10 +717,10 @@ function getZiti { if ! test -f "${ZITI_ENV_FILE}"; then echo -e " * $(YELLOW "WARN: The OpenZiti Environment file could not be found to update ziti binary related paths")" else - sed "s/export ZITI_BIN_DIR=.*/export ZITI_BIN_DIR=${ZITI_BIN_DIR}/g" - sed "s/export ZITI_BINARIES_VERSION=.*/export ZITI_BINARIES_VERSION=${ZITI_BINARIES_VERSION}/g" - sed "s/export ZITI_BINARIES_FILE=.*/export ZITI_BINARIES_FILE=${ZITI_BINARIES_FILE}/g" - sed "s/export ZITI_BINARIES_FILE_ABSPATH=.*/d" + sed -i.bak "s/export ZITI_BIN_DIR=.*/export ZITI_BIN_DIR=$(echo ${ZITI_BIN_DIR} | sed 's/\//\\\//g')/g" "${ZITI_ENV_FILE}" + sed -i.bak "s/export ZITI_BINARIES_VERSION=.*/export ZITI_BINARIES_VERSION=$(echo ${ZITI_BINARIES_VERSION} | sed 's/\//\\\//g')/g" "${ZITI_ENV_FILE}" + sed -i.bak "s/export ZITI_BINARIES_FILE=.*/export ZITI_BINARIES_FILE=$(echo ${ZITI_BINARIES_FILE} | sed 's/\//\\\//g')/g" "${ZITI_ENV_FILE}" + sed -i.bak "/export ZITI_BINARIES_FILE_ABSPATH=.*/d" "${ZITI_ENV_FILE}" fi echo -e "$(YELLOW 'Getting latest binaries ')$(BLUE "${ZITI_BIN_DIR}")" @@ -1024,6 +1024,11 @@ function initializeController { log_file="${ZITI_HOME-}/${ZITI_CTRL_NAME}-init.log" "${ZITI_BIN_DIR-}/ziti" controller edge init "${ZITI_HOME}/${ZITI_CTRL_NAME}.yaml" -u "${ZITI_USER-}" -p "${ZITI_PWD}" &> "${log_file}" + retVal=$? + if [[ "${retVal}" != 0 ]]; then + echo -e "$(RED " --- There was an error while initializing the controller, check the logs at ${log_file} ---")" + return 1 + fi echo -e "${ZITI_CTRL_NAME} initialized. See $(BLUE "${log_file}") for details" } @@ -1085,7 +1090,9 @@ function expressInstall { echo -e "$(PURPLE "******** Setting Up Controller ********")" createControllerConfig - initializeController + if ! initializeController; then + return 1 + fi startController echo "waiting for the controller to come online to allow the edge router to enroll" _wait_for_controller @@ -1553,31 +1560,33 @@ function performMigration { fi # Replace old Env Vars in the env file with new ones - # NOTE: the '' after -i is required for Mac, otherwise an error is thrown - sed -i '' 's/ZITI_CONTROLLER_HOSTNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CONTROLLER_INTERMEDIATE_NAME/ZITI_PKI_CTRL_INTERMEDIATE_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CONTROLLER_RAWNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CONTROLLER_ROOTCA_NAME/ZITI_PKI_CTRL_ROOTCA_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_EDGE_PORT/ZITI_CTRL_EDGE_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_IDENTITY_CA/ZITI_PKI_CTRL_CA/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_IDENTITY_CERT/ZITI_PKI_CTRL_CERT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_IDENTITY_KEY/ZITI_PKI_CTRL_KEY/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_IDENTITY_SERVER_CERT/ZITI_PKI_CTRL_SERVER_CERT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_CTRL_PORT/ZITI_CTRL_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CONTROLLER_HOSTNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CONTROLLER_INTERMEDIATE_NAME/ZITI_PKI_CTRL_EDGE_INTERMEDIATE_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CONTROLLER_PORT/ZITI_CTRL_EDGE_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CONTROLLER_RAWNAME/ZITI_CTRL_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CONTROLLER_ROOTCA_NAME/ZITI_PKI_CTRL_EDGE_ROOTCA_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CTRL_IDENTITY_CA/ZITI_PKI_EDGE_CA/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CTRL_IDENTITY_CERT/ZITI_PKI_EDGE_CERT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CTRL_IDENTITY_KEY/ZITI_PKI_EDGE_KEY/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_EDGE_CTRL_IDENTITY_SERVER_CERT/ZITI_PKI_EDGE_SERVER_CERT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_ROUTER_RAWNAME/ZITI_ROUTER_NAME/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_PKI_OS_SPECIFIC/ZITI_PKI/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_SIGNING_CERT/ZITI_PKI_SIGNER_CERT/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_SIGNING_KEY/ZITI_PKI_SIGNER_KEY/g' "${ZITI_ENV_FILE}" - sed -i '' 's/ZITI_ROUTER_HOSTNAME/ZITI_ROUTER_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" + # NOTE: use of -i behaves differently for Mac vs Linux. -i.bak is a workaround so the command works in both OSs + sed -i.bak 's/ZITI_CONTROLLER_HOSTNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CONTROLLER_INTERMEDIATE_NAME/ZITI_PKI_CTRL_INTERMEDIATE_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CONTROLLER_RAWNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CONTROLLER_ROOTCA_NAME/ZITI_PKI_CTRL_ROOTCA_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_EDGE_PORT/ZITI_CTRL_EDGE_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_IDENTITY_CA/ZITI_PKI_CTRL_CA/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_IDENTITY_CERT/ZITI_PKI_CTRL_CERT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_IDENTITY_KEY/ZITI_PKI_CTRL_KEY/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_IDENTITY_SERVER_CERT/ZITI_PKI_CTRL_SERVER_CERT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_CTRL_PORT/ZITI_CTRL_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CONTROLLER_HOSTNAME/ZITI_CTRL_EDGE_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CONTROLLER_INTERMEDIATE_NAME/ZITI_PKI_CTRL_EDGE_INTERMEDIATE_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CONTROLLER_PORT/ZITI_CTRL_EDGE_ADVERTISED_PORT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CONTROLLER_RAWNAME/ZITI_CTRL_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CONTROLLER_ROOTCA_NAME/ZITI_PKI_CTRL_EDGE_ROOTCA_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CTRL_IDENTITY_CA/ZITI_PKI_EDGE_CA/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CTRL_IDENTITY_CERT/ZITI_PKI_EDGE_CERT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CTRL_IDENTITY_KEY/ZITI_PKI_EDGE_KEY/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_EDGE_CTRL_IDENTITY_SERVER_CERT/ZITI_PKI_EDGE_SERVER_CERT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_ROUTER_RAWNAME/ZITI_ROUTER_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_PKI_OS_SPECIFIC/ZITI_PKI/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_SIGNING_CERT/ZITI_PKI_SIGNER_CERT/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_SIGNING_KEY/ZITI_PKI_SIGNER_KEY/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_ROUTER_HOSTNAME/ZITI_ROUTER_ADVERTISED_ADDRESS/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_SIGNING_ROOTCA_NAME/ZITI_PKI_SIGNER_ROOTCA_NAME/g' "${ZITI_ENV_FILE}" + sed -i.bak 's/ZITI_SIGNING_INTERMEDIATE_NAME/ZITI_PKI_SIGNER_INTERMEDIATE_NAME/g' "${ZITI_ENV_FILE}" # Update environment variables if currently set if [[ "${ZITI_EDGE_CONTROLLER_HOSTNAME-}" != "" ]]; then export ZITI_CTRL_EDGE_ADVERTISED_ADDRESS="${ZITI_EDGE_CONTROLLER_HOSTNAME}"; fi @@ -1600,14 +1609,16 @@ function performMigration { if [[ "${ZITI_SIGNING_CERT-}" != "" ]]; then export ZITI_PKI_SIGNER_CERT="${ZITI_SIGNING_CERT}"; fi if [[ "${ZITI_SIGNING_KEY-}" != "" ]]; then export ZITI_PKI_SIGNER_KEY="${ZITI_SIGNING_KEY}"; fi if [[ "${ZITI_ROUTER_HOSTNAME-}" != "" ]]; then export ZITI_ROUTER_ADVERTISED_ADDRESS="${ZITI_ROUTER_HOSTNAME}"; fi + if [[ "${ZITI_SIGNING_ROOTCA_NAME-}" != "" ]]; then export ZITI_PKI_SIGNER_ROOTCA_NAME="${ZITI_SIGNING_ROOTCA_NAME}"; fi + if [[ "${ZITI_SIGNING_INTERMEDIATE_NAME-}" != "" ]]; then export ZITI_PKI_SIGNER_INTERMEDIATE_NAME="${ZITI_SIGNING_INTERMEDIATE_NAME}"; fi # Update the necessary ziti binary references (others are not needed or are overwritten later) if [[ "${ZITI_BIN_DIR-}" != "" ]]; then - sed '/^export ZITI_BIN_DIR=/d' "${ZITI_ENV_FILE}" + sed -i.bak '/^export ZITI_BIN_DIR=/d' "${ZITI_ENV_FILE}" echo "export ZITI_BIN_DIR=${ZITI_BIN_DIR}" >> "${ZITI_ENV_FILE}" fi if [[ "${ZITI_BINARIES_VERSION-}" != "" ]]; then - sed '/^export ZITI_BINARIES_VERSION=/d' "${ZITI_ENV_FILE}" + sed -i.bak '/^export ZITI_BINARIES_VERSION=/d' "${ZITI_ENV_FILE}" echo "export ZITI_BINARIES_VERSION=${ZITI_BINARIES_VERSION}" >> "${ZITI_ENV_FILE}" fi diff --git a/quickstart/docker/simplified-docker-compose.yml b/quickstart/docker/simplified-docker-compose.yml index a4399cda5..c50429fa0 100644 --- a/quickstart/docker/simplified-docker-compose.yml +++ b/quickstart/docker/simplified-docker-compose.yml @@ -1,6 +1,11 @@ services: ziti-controller: image: "${ZITI_IMAGE}:${ZITI_VERSION}" + healthcheck: + test: curl -m 1 -s -k https://${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller}:${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280}/edge/client/v1/version + interval: 1s + timeout: 3s + retries: 30 env_file: - ./.env ports: @@ -28,7 +33,8 @@ services: ziti-controller-init-container: image: "${ZITI_IMAGE}:${ZITI_VERSION}" depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy environment: - ZITI_CTRL_EDGE_ADVERTISED_ADDRESS=${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS:-ziti-edge-controller} - ZITI_CTRL_EDGE_ADVERTISED_PORT=${ZITI_CTRL_EDGE_ADVERTISED_PORT:-1280} @@ -48,7 +54,8 @@ services: env_file: - ./.env depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy ports: - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_PORT:-3022}:${ZITI_ROUTER_PORT:-3022} - ${ZITI_INTERFACE:-0.0.0.0}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080}:${ZITI_ROUTER_LISTENER_BIND_PORT:-10080} @@ -80,7 +87,8 @@ services: - ZITI_CTRL_NAME=${ZITI_CTRL_NAME:-ziti-edge-controller} - PORTTLS=8443 depends_on: - - ziti-controller + ziti-controller: + condition: service_healthy ports: - ${ZITI_INTERFACE:-0.0.0.0}:8443:8443 volumes: diff --git a/router/forwarder/forwarder.go b/router/forwarder/forwarder.go index 1be4eff6a..3274d7270 100644 --- a/router/forwarder/forwarder.go +++ b/router/forwarder/forwarder.go @@ -18,14 +18,14 @@ package forwarder import ( "github.com/michaelquigley/pfxlog" + "github.com/openziti/foundation/v2/errorz" + "github.com/openziti/foundation/v2/info" + "github.com/openziti/metrics" "github.com/openziti/ziti/common/inspect" "github.com/openziti/ziti/common/pb/ctrl_pb" "github.com/openziti/ziti/common/trace" "github.com/openziti/ziti/router/xgress" "github.com/openziti/ziti/router/xlink" - "github.com/openziti/foundation/v2/errorz" - "github.com/openziti/foundation/v2/info" - "github.com/openziti/metrics" "github.com/pkg/errors" "github.com/sirupsen/logrus" "time" @@ -110,14 +110,12 @@ func (forwarder *Forwarder) HasDestination(address xgress.Address) bool { } func (forwarder *Forwarder) RegisterLink(link xlink.LinkDestination) error { - if !forwarder.destinations.addDestinationIfAbsent(xgress.Address(link.Id()), link) { - return errors.Errorf("unable to register link %v as it is already registered", link.Id()) - } + forwarder.destinations.addDestination(xgress.Address(link.Id()), link) return nil } func (forwarder *Forwarder) UnregisterLink(link xlink.LinkDestination) { - forwarder.destinations.removeDestination(xgress.Address(link.Id())) + forwarder.destinations.removeDestinationIfMatches(xgress.Address(link.Id()), link) } func (forwarder *Forwarder) Route(ctrlId string, route *ctrl_pb.Route) error { diff --git a/router/forwarder/tables.go b/router/forwarder/tables.go index a4ffdce5f..e80aa392e 100644 --- a/router/forwarder/tables.go +++ b/router/forwarder/tables.go @@ -115,10 +115,6 @@ func (dt *destinationTable) addDestination(addr xgress.Address, destination Dest dt.destinations.Set(string(addr), destination) } -func (dt *destinationTable) addDestinationIfAbsent(addr xgress.Address, destination Destination) bool { - return dt.destinations.SetIfAbsent(string(addr), destination) -} - func (dt *destinationTable) getDestination(addr xgress.Address) (Destination, bool) { if dst, found := dt.destinations.Get(string(addr)); found { return dst, true @@ -130,6 +126,12 @@ func (dt *destinationTable) removeDestination(addr xgress.Address) { dt.destinations.Remove(string(addr)) } +func (dt *destinationTable) removeDestinationIfMatches(addr xgress.Address, destination Destination) { + dt.destinations.RemoveCb(string(addr), func(key string, v Destination, exists bool) bool { + return exists && destination == v + }) +} + func (dt *destinationTable) linkDestinationToCircuit(circuitId string, address xgress.Address) { var addresses []xgress.Address if i, found := dt.xgress.Get(circuitId); found { diff --git a/router/handler_link/close.go b/router/handler_link/close.go index 4676ea696..8803fed9d 100644 --- a/router/handler_link/close.go +++ b/router/handler_link/close.go @@ -52,6 +52,8 @@ func (self *closeHandler) HandleClose(ch channel.Channel) { WithField("linkId", self.link.Id()). WithField("routerId", self.link.DestinationId()) + self.forwarder.UnregisterLink(self.link) + // ensure that both parts of a split link are closed, if one side closes go func() { _ = self.link.Close() @@ -72,7 +74,6 @@ func (self *closeHandler) HandleClose(ch channel.Channel) { }) }) - self.forwarder.UnregisterLink(self.link) close(self.closeNotify) } } diff --git a/router/link/link_events.go b/router/link/link_events.go index 6524e38cf..9392d7a44 100644 --- a/router/link/link_events.go +++ b/router/link/link_events.go @@ -19,11 +19,11 @@ package link import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" - "github.com/openziti/ziti/controller/idgen" + "github.com/openziti/foundation/v2/stringz" "github.com/openziti/ziti/common/inspect" "github.com/openziti/ziti/common/pb/ctrl_pb" + "github.com/openziti/ziti/controller/idgen" "github.com/openziti/ziti/router/xlink" - "github.com/openziti/foundation/v2/stringz" "github.com/pkg/errors" "sync/atomic" "time" @@ -255,7 +255,7 @@ func (self *updateLinkState) Handle(registry *linkRegistryImpl) { } state.status = self.status - if state.status == StatusQueueFailed || state.status == StatusDialFailed { + if state.status == StatusDialFailed { state.dialFailed(registry) } } diff --git a/router/link/link_registry.go b/router/link/link_registry.go index 84bd8fd79..3955c7704 100644 --- a/router/link/link_registry.go +++ b/router/link/link_registry.go @@ -22,11 +22,11 @@ import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" "github.com/openziti/channel/v2/protobufs" + "github.com/openziti/foundation/v2/goroutines" "github.com/openziti/ziti/common/inspect" "github.com/openziti/ziti/common/pb/ctrl_pb" "github.com/openziti/ziti/router/env" "github.com/openziti/ziti/router/xlink" - "github.com/openziti/foundation/v2/goroutines" "github.com/sirupsen/logrus" "sync" "sync/atomic" @@ -165,9 +165,9 @@ func (self *linkRegistryImpl) LinkClosed(link xlink.Xlink) { defer self.Unlock() if val := self.linkMap[link.Key()]; val == link { delete(self.linkMap, link.Key()) + self.updateLinkStateClosed(link) // only update link state to closed if this was the current link } delete(self.linkByIdMap, link.Id()) - self.updateLinkStateClosed(link) } func (self *linkRegistryImpl) Shutdown() { @@ -325,13 +325,33 @@ func (self *linkRegistryImpl) evaluateLinkStateQueue() { } func (self *linkRegistryImpl) evaluateDestinations() { - for _, dest := range self.destinations { - // TODO: When do we drop destinations? Should we ask the controller after the router has been - // unhealthy for a while and it doesn't have any established links? Do this on exponential backoff? - // Should the controller send router removed messages? + for destId, dest := range self.destinations { + hasEstablishedLinks := false for _, state := range dest.linkMap { + // verify that links marked as established have an open link. There's a small chance that a link established + // and link closed could be processed out of order if the event queue is full. This way, it will eventually + // get fixed. + if state.status == StatusEstablished { + link, _ := self.GetLink(state.linkKey) + if link == nil || link.IsClosed() { + // If the link is not valid, allow it to be re-dialed + state.retryDelay = time.Duration(0) + state.nextDial = time.Now() + state.status = StatusLinkFailed + } else { + hasEstablishedLinks = true + } + } + self.evaluateLinkState(state) } + + // we are notified of deleted routers. In case we're unreachable while a router is deleted, + // we will also stop trying to contact unhealthy routers after a period. If a destination + // has nothing to dial, it should also be removed + if len(dest.linkMap) == 0 || (!dest.healthy && !hasEstablishedLinks && time.Since(dest.unhealthyAt) > 48*time.Hour) { + delete(self.destinations, destId) + } } } @@ -343,14 +363,17 @@ func (self *linkRegistryImpl) evaluateLinkState(state *linkState) { if couldDial { state.status = StatusDialing state.dialAttempts++ + log.Info("queuing link to dial") err := self.env.GetLinkDialerPool().QueueOrError(func() { link, _ := self.GetLink(state.linkKey) if link != nil { - log.Warn("link already present, but link status still pending") + log.Info("link already present, attempting to mark established") + self.updateLinkStateEstablished(link) return } + log.Info("dialing link") link, err := state.dialer.Dial(state) if err != nil { log.WithError(err).Error("error dialing link") @@ -360,14 +383,23 @@ func (self *linkRegistryImpl) evaluateLinkState(state *linkState) { }) return } - self.DialSucceeded(link) + + existing, success := self.DialSucceeded(link) + if !success { + if existing != nil { + self.updateLinkStateEstablished(link) + } else { + self.queueEvent(&updateLinkState{ + linkState: state, + status: StatusDialFailed, + }) + } + } }) if err != nil { log.WithError(err).Error("unable to queue link dial, see pool error") - self.queueEvent(&updateLinkState{ - linkState: state, - status: StatusQueueFailed, - }) + state.status = StatusQueueFailed + state.dialFailed(self) } } } diff --git a/router/xgress_edge/certchecker_test.go b/router/xgress_edge/certchecker_test.go index 469821073..8741666cf 100644 --- a/router/xgress_edge/certchecker_test.go +++ b/router/xgress_edge/certchecker_test.go @@ -8,13 +8,13 @@ import ( "crypto/x509" "crypto/x509/pkix" "github.com/openziti/channel/v2" - "github.com/openziti/ziti/common/eid" - "github.com/openziti/ziti/router/internal/edgerouter" - "github.com/openziti/ziti/router/env" "github.com/openziti/foundation/v2/tlz" "github.com/openziti/foundation/v2/versions" "github.com/openziti/identity" "github.com/openziti/transport/v2" + "github.com/openziti/ziti/common/eid" + "github.com/openziti/ziti/router/env" + "github.com/openziti/ziti/router/internal/edgerouter" "github.com/pkg/errors" "github.com/stretchr/testify/require" "math/big" @@ -50,7 +50,7 @@ func Test_CertExpirationChecker(t *testing.T) { req := require.New(t) certChecker, _ := newCertChecker() - now := time.Now() + now := time.Now().UTC() notAfter := now.AddDate(0, 0, 7) certChecker.id.Cert().Leaf.NotAfter = notAfter @@ -210,7 +210,7 @@ func Test_CertExpirationChecker(t *testing.T) { req := require.New(t) certChecker, _ := newCertChecker() - now := time.Now() + now := time.Now().UTC() notAfter := now.AddDate(0, 0, 7) certChecker.id.ServerCert()[0].Leaf.NotAfter = notAfter diff --git a/router/xgress_edge/hosted.go b/router/xgress_edge/hosted.go index 26187677d..b7a6f0161 100644 --- a/router/xgress_edge/hosted.go +++ b/router/xgress_edge/hosted.go @@ -66,7 +66,7 @@ func (registry *hostedServiceRegistry) cleanupDuplicates(newest *edgeTerminator) registry.services.Range(func(key, value interface{}) bool { terminator := value.(*edgeTerminator) if terminator != newest && newest.token == terminator.token && newest.instance == terminator.instance { - terminator.close(true, "duplicate terminator") // don't notify, channel is already closed, we can't send messages + terminator.close(false, "duplicate terminator") // don't notify, channel is already closed, we can't send messages registry.services.Delete(key) pfxlog.Logger().WithField("routerId", terminator.edgeClientConn.listener.id.Token). WithField("sessionToken", terminator.token). diff --git a/tests/accept_manual_start_test.go b/tests/accept_manual_start_test.go index 1b2dab72f..ef88ce57f 100644 --- a/tests/accept_manual_start_test.go +++ b/tests/accept_manual_start_test.go @@ -20,9 +20,10 @@ package tests import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti/ziti/controller/xt" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" + "github.com/openziti/ziti/controller/change" + "github.com/openziti/ziti/controller/xt" "github.com/pkg/errors" "sync/atomic" "testing" @@ -34,7 +35,9 @@ func Test_ManualStart(t *testing.T) { defer ctx.Teardown() ctx.StartServer() - xt.GlobalRegistry().RegisterFactory(&testFailoverStrategyFactory{}) + xt.GlobalRegistry().RegisterFactory(&testFailoverStrategyFactory{ + ctx: ctx, + }) t.Run("creating service and edge router", func(t *testing.T) { ctx.testContextChanged(t) ctx.RequireAdminManagementApiLogin() @@ -165,25 +168,35 @@ func Test_ManualStart(t *testing.T) { }) } -type testFailoverStrategyFactory struct{} +type testFailoverStrategyFactory struct { + ctx *TestContext +} func (self *testFailoverStrategyFactory) GetStrategyName() string { return "test-failover" } func (self *testFailoverStrategyFactory) NewStrategy() xt.Strategy { - return &testFailoverStrategy{} + return &testFailoverStrategy{ + ctx: self.ctx, + } } type testFailoverStrategy struct { xt.DefaultEventVisitor failCount int32 + ctx *TestContext } func (self *testFailoverStrategy) VisitDialFailed(event xt.TerminatorEvent) { failCount := atomic.AddInt32(&self.failCount, 1) if failCount >= 3 { - xt.GlobalCosts().SetPrecedence(event.GetTerminator().GetId(), xt.Precedences.Failed) + mgr := self.ctx.EdgeController.AppEnv.Managers.Terminator + t, err := mgr.Read(event.GetTerminator().GetId()) + self.ctx.Req.NoError(err) + t.Precedence = xt.Precedences.Failed + err = mgr.Update(t, nil, change.New()) + self.ctx.Req.NoError(err) } } diff --git a/tests/addressable_terminators_test.go b/tests/addressable_terminators_test.go index 648250a97..c524ee0f3 100644 --- a/tests/addressable_terminators_test.go +++ b/tests/addressable_terminators_test.go @@ -19,9 +19,9 @@ package tests import ( - "github.com/openziti/ziti/controller/xt_smartrouting" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" + "github.com/openziti/ziti/controller/xt_smartrouting" "github.com/pkg/errors" "net" "strings" @@ -142,7 +142,9 @@ func Test_AddressableTerminatorSameIdentity(t *testing.T) { listener.(edge.SessionListener).SetErrorEventHandler(errorHandler) defer func() { _ = listener.Close() }() - context2 := ziti.NewContext(identity.config) + context2, err := ziti.NewContext(identity.config) + ctx.Req.NoError(err) + listener2, err := context2.ListenWithOptions(service.Name, &ziti.ListenOptions{ BindUsingEdgeIdentity: true, ConnectTimeout: 5 * time.Second, diff --git a/tests/data_flow_close_test.go b/tests/data_flow_close_test.go index 20bbb775c..b613169c1 100644 --- a/tests/data_flow_close_test.go +++ b/tests/data_flow_close_test.go @@ -22,8 +22,8 @@ package tests import ( "errors" "fmt" - "github.com/openziti/ziti/common/eid" "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/ziti/common/eid" "io" "testing" "time" @@ -69,7 +69,9 @@ func Test_ServerConnClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -134,7 +136,9 @@ func Test_ServerContextClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -202,7 +206,9 @@ func Test_ServerCloseListenerPropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -234,7 +240,9 @@ func Test_ClientConnClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) errC := make(chan error, 1) @@ -296,7 +304,9 @@ func Test_ClientContextClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) errC := make(chan error, 1) @@ -359,7 +369,9 @@ func Test_ServerConnCloseWritePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) errC := make(chan error, 1) @@ -453,7 +465,9 @@ func Test_ClientConnCloseWritePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) conn := ctx.WrapConn(clientContext.Dial(service.Name)) name := eid.New() diff --git a/tests/data_flow_hs_rotating_test.go b/tests/data_flow_hs_rotating_test.go index d860d4406..6966e37ac 100644 --- a/tests/data_flow_hs_rotating_test.go +++ b/tests/data_flow_hs_rotating_test.go @@ -21,9 +21,9 @@ package tests import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti/ziti/common/eid" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" + "github.com/openziti/ziti/common/eid" "github.com/pkg/errors" "math/rand" "sync" @@ -122,7 +122,9 @@ func testClientFirstWithStrategy(t *testing.T, strategy string) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) logger := pfxlog.Logger() @@ -265,7 +267,9 @@ func testServerFirstWithStrategy(t *testing.T, strategy string) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) ticker := time.NewTicker(time.Millisecond * 500) defer ticker.Stop() diff --git a/tests/data_flow_hs_test.go b/tests/data_flow_hs_test.go index 5a8295757..83d43ff5a 100644 --- a/tests/data_flow_hs_test.go +++ b/tests/data_flow_hs_test.go @@ -21,8 +21,8 @@ package tests import ( "github.com/michaelquigley/pfxlog" - "github.com/openziti/ziti/common/eid" "github.com/openziti/sdk-golang/ziti" + "github.com/openziti/ziti/common/eid" "sync/atomic" "testing" "time" @@ -76,7 +76,9 @@ func Test_HSDataflow(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContext(clientConfig) + + clientContext, err := ziti.NewContext(clientConfig) + ctx.Req.NoError(err) for i := 0; i < 100; i++ { conn := ctx.WrapConn(clientContext.Dial(service.Name)) diff --git a/version b/version index f7c6c31b6..48b9990e0 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.30 +0.31 diff --git a/ziti/cmd/api/delete.go b/ziti/cmd/api/delete.go index b245907b6..e846996e8 100644 --- a/ziti/cmd/api/delete.go +++ b/ziti/cmd/api/delete.go @@ -26,7 +26,7 @@ import ( 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) + 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 diff --git a/ziti/cmd/create/create_config_controller.go b/ziti/cmd/create/create_config_controller.go index e4f10aaf4..bd21f570f 100644 --- a/ziti/cmd/create/create_config_controller.go +++ b/ziti/cmd/create/create_config_controller.go @@ -173,10 +173,12 @@ func (options *CreateConfigControllerOptions) run(data *ConfigTemplateValues) er if err != nil { return errors.Wrapf(err, "unable to create config file: %s", options.Output) } + + //only close things we open + defer func() { _ = f.Close() }() } else { f = os.Stdout } - defer func() { _ = f.Close() }() if err := tmpl.Execute(f, data); err != nil { return errors.Wrap(err, "unable to execute template") diff --git a/ziti/cmd/create/create_config_controller_test.go b/ziti/cmd/create/create_config_controller_test.go index 5f319f4ad..925b18dc3 100644 --- a/ziti/cmd/create/create_config_controller_test.go +++ b/ziti/cmd/create/create_config_controller_test.go @@ -3,10 +3,12 @@ package create import ( "fmt" cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" "os" "strings" + "syscall" "testing" "time" ) @@ -111,15 +113,15 @@ func init() { } func TestControllerOutputPathDoesNotExist(t *testing.T) { - expectedErrorMsg := "stat /IDoNotExist: no such file or directory" - // Create the options with non-existent path options := &CreateConfigControllerOptions{} options.Output = "/IDoNotExist/MyController.yaml" err := options.run(&ConfigTemplateValues{}) - assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) + //check wrapped error type and not internal strings as they vary between operating systems + assert.Error(t, err) + assert.Equal(t, errors.Unwrap(err), syscall.ENOENT) } func TestCreateConfigControllerTemplateValues(t *testing.T) { diff --git a/ziti/cmd/create/create_config_router_edge_test.go b/ziti/cmd/create/create_config_router_edge_test.go index c43a471f7..7a432d163 100644 --- a/ziti/cmd/create/create_config_router_edge_test.go +++ b/ziti/cmd/create/create_config_router_edge_test.go @@ -2,11 +2,13 @@ package create import ( "github.com/openziti/ziti/ziti/constants" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "os" "strconv" "strings" + "syscall" "testing" "time" ) @@ -215,8 +217,6 @@ func TestEdgeRouterCannotBeWSSAndPrivate(t *testing.T) { } func TestEdgeRouterOutputPathDoesNotExist(t *testing.T) { - expectedErrorMsg := "stat /IDoNotExist: no such file or directory" - // Set the router options routerOptions := clearEnvAndInitializeTestData() routerOptions.TunnelerMode = defaultTunnelerMode @@ -225,7 +225,8 @@ func TestEdgeRouterOutputPathDoesNotExist(t *testing.T) { err := routerOptions.runEdgeRouter(&ConfigTemplateValues{}) - assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) + assert.Error(t, err) + assert.Equal(t, errors.Unwrap(err), syscall.ENOENT) } func TestExecuteCreateConfigRouterEdgeHasNonBlankTemplateValues(t *testing.T) { diff --git a/ziti/cmd/create/create_config_router_fabric_test.go b/ziti/cmd/create/create_config_router_fabric_test.go index 1083c29da..3269d58b1 100644 --- a/ziti/cmd/create/create_config_router_fabric_test.go +++ b/ziti/cmd/create/create_config_router_fabric_test.go @@ -2,10 +2,12 @@ package create import ( "github.com/openziti/ziti/ziti/constants" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" "os" "strconv" "strings" + "syscall" "testing" "time" ) @@ -94,7 +96,6 @@ func TestBlankFabricRouterNameBecomesHostname(t *testing.T) { func TestFabricRouterOutputPathDoesNotExist(t *testing.T) { routerOptions := clearEnvAndInitializeTestData() - expectedErrorMsg := "stat /IDoNotExist: no such file or directory" // Set the router options clearEnvAndInitializeTestData() @@ -103,7 +104,8 @@ func TestFabricRouterOutputPathDoesNotExist(t *testing.T) { err := routerOptions.runFabricRouter(&ConfigTemplateValues{}) - assert.EqualError(t, err, expectedErrorMsg, "Error does not match, expected %s but got %s", expectedErrorMsg, err) + assert.Error(t, err) + assert.Equal(t, errors.Unwrap(err), syscall.ENOENT) } func TestDefaultZitiFabricRouterListenerBindPort(t *testing.T) { diff --git a/ziti/cmd/create/create_config_test.go b/ziti/cmd/create/create_config_test.go index 69cbb777e..0c06d231e 100644 --- a/ziti/cmd/create/create_config_test.go +++ b/ziti/cmd/create/create_config_test.go @@ -1,7 +1,6 @@ package create import ( - "bytes" "fmt" "github.com/stretchr/testify/assert" "io" @@ -247,18 +246,61 @@ func contains(s []string, str string) bool { return false } +// captureOutput hot-swaps os.Stdout in order to redirect all output to a memory buffer. Where possible, do not use +// this function and instead create optional arguments/configuration to redirect output to io.Writer instances. This +// should only be used for functionality that we do not control. Many instances of its usage are unnecessary and should +// be remedied with the aforementioned solution where possible. func captureOutput(function func()) string { - var buffer bytes.Buffer oldStdOut := os.Stdout r, w, _ := os.Pipe() os.Stdout = w + defer func() { + _ = r.Close() + }() + + type readResult struct { + out []byte + err error + } + + defer func() { + os.Stdout = oldStdOut + }() + + var output []byte + var outputErr error + + outChan := make(chan *readResult, 1) + + // Start reading before writing, so we do not create backpressure that is never relieved in OSs with smaller buffers + // than the resulting configuration file (i.e. Windows). Go will not yield to other routines unless there is + // a system call. The fake os.Stdout will never yield and some code paths executed as `function()` may not + // have syscalls. + go func() { + output, outputErr = io.ReadAll(r) + outChan <- &readResult{ + output, + outputErr, + } + }() + function() - _ = w.Close() os.Stdout = oldStdOut - _, _ = io.Copy(&buffer, r) - return buffer.String() + _ = w.Close() + + result := <-outChan + + if result == nil { + panic("no output") + } + + if result.err != nil { + panic(result.err) + } + + return string(result.out) } func setEnvByMap[K string, V string](m map[K]V) { diff --git a/ziti/cmd/edge/create_enrollment.go b/ziti/cmd/edge/create_enrollment.go index 4c9dd3952..aa37ea440 100644 --- a/ziti/cmd/edge/create_enrollment.go +++ b/ziti/cmd/edge/create_enrollment.go @@ -45,7 +45,8 @@ func newCreateEnrollmentCmd(out io.Writer, errOut io.Writer) *cobra.Command { type createEnrollmentOptions struct { api.Options - duration int64 + jwtOutputFile string + duration int64 } func newCreateEnrollmentOtt(out io.Writer, errOut io.Writer) *cobra.Command { @@ -76,6 +77,7 @@ func newCreateEnrollmentOtt(out io.Writer, errOut io.Writer) *cobra.Command { cmd.Flags().SetInterspersed(true) options.AddCommonFlags(cmd) cmd.Flags().Int64VarP(&options.duration, "duration", "d", 30, "the duration of time the enrollment should valid for") + cmd.Flags().StringVarP(&options.jwtOutputFile, "jwt-output-file", "o", "", "File to which to output the enrollment JWT ") return cmd } @@ -149,6 +151,11 @@ func runCreateEnrollmentOtt(options *createEnrollmentOptions) error { panic(err) } + if options.jwtOutputFile != "" { + if err = getIdentityJwt(&options.Options, identityId, options.jwtOutputFile, "ott", options.Options.Timeout, options.Options.Verbose); err != nil { + return err + } + } return err } diff --git a/ziti/cmd/edge/create_identity.go b/ziti/cmd/edge/create_identity.go index e6a675b12..00a2e0977 100644 --- a/ziti/cmd/edge/create_identity.go +++ b/ziti/cmd/edge/create_identity.go @@ -18,6 +18,7 @@ package edge import ( "fmt" + "github.com/openziti/ziti/controller/persistence" "github.com/openziti/ziti/ziti/cmd/api" cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers" "github.com/pkg/errors" @@ -109,9 +110,9 @@ func runCreateIdentity(o *createIdentityOptions) error { o.username = strings.TrimSpace(o.username) if o.username != "" { - api.SetJSONValue(entityData, o.username, "enrollment", "updb") + api.SetJSONValue(entityData, o.username, "enrollment", persistence.MethodEnrollUpdb) } else { - api.SetJSONValue(entityData, true, "enrollment", "ott") + api.SetJSONValue(entityData, true, "enrollment", persistence.MethodEnrollOtt) } api.SetJSONValue(entityData, o.isAdmin, "isAdmin") api.SetJSONValue(entityData, o.roleAttributes, "roleAttributes") @@ -183,15 +184,18 @@ func runCreateIdentity(o *createIdentityOptions) error { if o.jwtOutputFile != "" { id := result.S("data", "id").Data().(string) - if err := getIdentityJwt(o, id, o.Options.Timeout, o.Options.Verbose); err != nil { + enrollmentType := persistence.MethodEnrollOtt + if o.username != "" { + enrollmentType = persistence.MethodEnrollUpdb + } + if err = getIdentityJwt(&o.Options, id, o.jwtOutputFile, enrollmentType, o.Options.Timeout, o.Options.Verbose); err != nil { return err } } return err } -func getIdentityJwt(o *createIdentityOptions, id string, timeout int, verbose bool) error { - +func getIdentityJwt(o *api.Options, id string, outputFile string, enrollmentType string, timeout int, verbose bool) error { newIdentity, err := DetailEntityOfType("identities", id, o.OutputJSONResponse, o.Out, timeout, verbose) if err != nil { return err @@ -202,10 +206,12 @@ func getIdentityJwt(o *createIdentityOptions, id string, timeout int, verbose bo } var dataContainer *gabs.Container - if o.username != "" { + if enrollmentType == persistence.MethodEnrollUpdb { dataContainer = newIdentity.Path("enrollment.updb.jwt") - } else { + } else if enrollmentType == persistence.MethodEnrollOtt { dataContainer = newIdentity.Path("enrollment.ott.jwt") + } else { + return errors.Errorf("unsupported enrollment type '%s'", enrollmentType) } data := dataContainer.Data() @@ -219,8 +225,8 @@ func getIdentityJwt(o *createIdentityOptions, id string, timeout int, verbose bo return fmt.Errorf("enrollment JWT not present for new identity") } - if err := os.WriteFile(o.jwtOutputFile, []byte(jwt), 0600); err != nil { - fmt.Printf("Failed to write JWT to file(%v)\n", o.jwtOutputFile) + if err = os.WriteFile(outputFile, []byte(jwt), 0600); err != nil { + fmt.Printf("Failed to write JWT to file(%v)\n", outputFile) return err } diff --git a/ziti/cmd/edge/delete.go b/ziti/cmd/edge/delete.go index 526a2f5e3..38205b546 100644 --- a/ziti/cmd/edge/delete.go +++ b/ziti/cmd/edge/delete.go @@ -30,6 +30,11 @@ import ( "github.com/spf13/cobra" ) +type deleteOptions struct { + *api.Options + ignoreMissing bool +} + // newDeleteCmd creates a command object for the "edge controller delete" command func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command { cmd := &cobra.Command{ @@ -42,11 +47,13 @@ func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command { }, } - newOptions := func() *api.Options { - return &api.Options{ - CommonOptions: common.CommonOptions{ - Out: out, - Err: errOut, + newOptions := func() *deleteOptions { + return &deleteOptions{ + Options: &api.Options{ + CommonOptions: common.CommonOptions{ + Out: out, + Err: errOut, + }, }, } } @@ -74,7 +81,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 *api.Options, aliases ...string) *cobra.Command { +func newDeleteCmdForEntityType(entityType string, options *deleteOptions, aliases ...string) *cobra.Command { cmd := &cobra.Command{ Use: entityType + " ", Short: "deletes " + getPlural(entityType) + " managed by the Ziti Edge Controller", @@ -92,13 +99,14 @@ func newDeleteCmdForEntityType(entityType string, options *api.Options, aliases // allow interspersing positional args and flags cmd.Flags().SetInterspersed(true) options.AddCommonFlags(cmd) + cmd.Flags().BoolVar(&options.ignoreMissing, "ignore-missing", false, "don't error if the entity can't be found to be deleted") cmd.AddCommand(newDeleteWhereCmdForEntityType(entityType, options)) return cmd } -func newDeleteWhereCmdForEntityType(entityType string, options *api.Options) *cobra.Command { +func newDeleteWhereCmdForEntityType(entityType string, options *deleteOptions) *cobra.Command { cmd := &cobra.Command{ Use: "where ", Short: "deletes " + getPlural(entityType) + " matching the filter managed by the Ziti Edge Controller", @@ -120,21 +128,25 @@ func newDeleteWhereCmdForEntityType(entityType string, options *api.Options) *co } // runDeleteEntityOfType implements the commands to delete various entity types -func runDeleteEntityOfType(o *api.Options, entityType string) error { +func runDeleteEntityOfType(o *deleteOptions, entityType string) error { var err error ids := o.Args if entityType != "terminators" && entityType != "api-sessions" && entityType != "sessions" && entityType != "authenticators" && entityType != "enrollments" { - if ids, err = mapNamesToIDs(entityType, *o, true, ids...); err != nil { + if ids, err = mapNamesToIDs(entityType, *o.Options, true, ids...); err != nil { return err } } return deleteEntitiesOfType(o, entityType, ids) } -func deleteEntitiesOfType(o *api.Options, entityType string, ids []string) error { +func deleteEntitiesOfType(o *deleteOptions, entityType string, ids []string) error { for _, id := range ids { - err := util.ControllerDelete("edge", entityType, id, "", o.Out, o.OutputJSONRequest, o.OutputJSONResponse, o.Timeout, o.Verbose) + err, statusCode := util.ControllerDelete("edge", entityType, id, "", o.Out, o.OutputJSONRequest, o.OutputJSONResponse, o.Timeout, o.Verbose) if err != nil { + if statusCode != nil && o.ignoreMissing { + o.Printf("delete of %v with id %v: %v\n", boltz.GetSingularEntityType(entityType), id, color.New(color.FgYellow, color.Bold).Sprint("NOT FOUND")) + return 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 } @@ -144,7 +156,7 @@ func deleteEntitiesOfType(o *api.Options, entityType string, ids []string) error } // runDeleteEntityOfType implements the commands to delete various entity types -func runDeleteEntityOfTypeWhere(options *api.Options, entityType string) error { +func runDeleteEntityOfTypeWhere(options *deleteOptions, entityType string) error { filter := strings.Join(options.Args, " ") params := url.Values{} @@ -156,7 +168,7 @@ func runDeleteEntityOfTypeWhere(options *api.Options, entityType string) error { } options.Printf("filter returned ") - pageInfo.Output(options) + pageInfo.Output(options.Options) var ids []string for _, entity := range children { diff --git a/ziti/cmd/helpers/env_helpers.go b/ziti/cmd/helpers/env_helpers.go index b5e8f2a5c..78c90105d 100644 --- a/ziti/cmd/helpers/env_helpers.go +++ b/ziti/cmd/helpers/env_helpers.go @@ -28,7 +28,7 @@ import ( func HomeDir() string { if h := os.Getenv("HOME"); h != "" { - return h + return NormalizePath(h) } h := os.Getenv("USERPROFILE") // windows if h == "" { diff --git a/ziti/util/rest.go b/ziti/util/rest.go index 6e4a1b16f..5919e01d8 100644 --- a/ziti/util/rest.go +++ b/ziti/util/rest.go @@ -28,8 +28,8 @@ import ( "github.com/go-openapi/strfmt" "github.com/openziti/edge-api/rest_management_api_client" "github.com/openziti/edge-api/rest_model" - fabric_rest_client "github.com/openziti/ziti/controller/rest_client" "github.com/openziti/ziti/common/version" + fabric_rest_client "github.com/openziti/ziti/controller/rest_client" cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers" c "github.com/openziti/ziti/ziti/constants" "gopkg.in/resty.v1" @@ -546,6 +546,7 @@ func (edgeTransport *edgeTransport) RoundTrip(r *http.Request) (*http.Response, } type ApiErrorPayload interface { + Error() string GetPayload() *rest_model.APIErrorEnvelope } @@ -573,12 +574,12 @@ func (a RestApiError) Error() string { if payload := a.ApiErrorPayload.GetPayload(); payload != nil { if payload.Error == nil { - return fmt.Sprintf("could not read API error, payload.error was nil: %v", a.Error()) + return fmt.Sprintf("could not read API error, payload.error was nil: %v", a.ApiErrorPayload.Error()) } return formatApiError(payload.Error) } - return fmt.Sprintf("could not read API error, payload was nil: %v", a.Error()) + return fmt.Sprintf("could not read API error, payload was nil: %v", a.ApiErrorPayload.Error()) } func WrapIfApiError(err error) error { @@ -669,20 +670,20 @@ func ControllerCreate(api API, entityType string, body string, out io.Writer, lo } // 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 { +func ControllerDelete(api API, entityType string, id string, body string, out io.Writer, logRequestJson bool, logResponseJson bool, timeout int, verbose bool) (error, *int) { restClientIdentity, err := LoadSelectedRWIdentityForApi(api) if err != nil { - return err + return err, nil } baseUrl, err := restClientIdentity.GetBaseUrlForApi(api) if err != nil { - return err + return err, nil } req, err := NewRequest(restClientIdentity, timeout, verbose) if err != nil { - return err + return err, nil } entityPath := entityType + "/" + id @@ -701,19 +702,20 @@ func ControllerDelete(api API, entityType string, id string, body string, out io resp, err := req.Delete(fullUrl) if err != nil { - return fmt.Errorf("unable to delete %v instance in Ziti Edge Controller at %v. Error: %v", entityPath, baseUrl, err) + return fmt.Errorf("unable to delete %v instance in Ziti Edge Controller at %v. Error: %v", entityPath, baseUrl, err), nil } if resp.StatusCode() != http.StatusOK { + statusCode := resp.StatusCode() 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)) + entityPath, baseUrl, resp.Status(), PrettyPrintResponse(resp)), &statusCode } if logResponseJson { OutputJson(out, resp.Body()) } - return nil + return nil, nil } // ControllerUpdate will update entities of the given type in the given Edge Controller diff --git a/zititest/ami/README.md b/zititest/ami/README.md deleted file mode 100644 index 4f0bd3816..000000000 --- a/zititest/ami/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Ziti AMI - -This folder shows how to use [Packer](https://www.packer.io/) to create an [Amazon Machine -Image (AMI)](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) that has the necessary prerequisites for running fablab based OpenZiti smoketests installed on top of Ubuntu 22.04. - -## Quick start - -To build the Ziti AMI: - -1. `git clone` this repo to your computer. -1. Install [Packer](https://www.packer.io/). -1. Configure your AWS credentials using one of the [options supported by the AWS - SDK](http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html). Usually, the easiest option is to - set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. -1. Run `packer build ziti-ami.pkr.hcl`. - -When the build finishes, it will output the ID of the new AMI. \ No newline at end of file diff --git a/zititest/ami/cleanup-old-images.sh b/zititest/ami/cleanup-old-images.sh deleted file mode 100755 index 0162bce93..000000000 --- a/zititest/ami/cleanup-old-images.sh +++ /dev/null @@ -1,18 +0,0 @@ -regions=( -"us-east-1" -"us-east-2" -"us-west-1" -"us-west-2" -"ca-central-1" -"ap-northeast-1" -"ap-southeast-2" -"sa-east-1" -"eu-central-1" -"af-south-1" -) - - -for region in ${regions[@]}; -do - aws ec2 describe-images --region ${region} --owners self --filters Name="name",Values="ziti-tests-*" | jq '[.Images[] | { Id: .ImageId, Date: .CreationDate}] | sort_by(.Date)' | jq -r '.[] | .Id ' | head -n -1 | xargs -t -r -n 1 aws ec2 deregister-image --region ${region} --image-id -done diff --git a/zititest/ami/etc/apt/apt.conf.d/99remote-not-fancy b/zititest/ami/etc/apt/apt.conf.d/99remote-not-fancy deleted file mode 100644 index ce12e07e0..000000000 --- a/zititest/ami/etc/apt/apt.conf.d/99remote-not-fancy +++ /dev/null @@ -1,2 +0,0 @@ -Binary::apt::APT::Color "0"; -Binary::apt::DPkg::Progress-Fancy "0"; \ No newline at end of file diff --git a/zititest/ami/etc/sysctl.d/51-network-tuning.conf b/zititest/ami/etc/sysctl.d/51-network-tuning.conf deleted file mode 100644 index edc76a389..000000000 --- a/zititest/ami/etc/sysctl.d/51-network-tuning.conf +++ /dev/null @@ -1,9 +0,0 @@ -# adjust the socket buffer sizes -net.core.rmem_max = 16777216 -net.core.wmem_max = 16777216 -net.core.rmem_default = 16777216 -net.core.wmem_default = 16777216 -net.ipv4.tcp_rmem = 4096 87380 16777216 -net.ipv4.tcp_wmem = 4096 65536 16777216 -net.ipv4.tcp_mem = 8388608 8388608 16777216 -net.ipv4.udp_mem = 8388608 8388608 16777216 \ No newline at end of file diff --git a/zititest/ami/etc/systemd/resolved.conf.d/ziti-tunnel.conf b/zititest/ami/etc/systemd/resolved.conf.d/ziti-tunnel.conf deleted file mode 100644 index 0f05e31cc..000000000 --- a/zititest/ami/etc/systemd/resolved.conf.d/ziti-tunnel.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Resolve] -DNS=127.0.0.1 diff --git a/zititest/ami/list-images.sh b/zititest/ami/list-images.sh deleted file mode 100755 index 11c49393b..000000000 --- a/zititest/ami/list-images.sh +++ /dev/null @@ -1,11 +0,0 @@ -regions=( -"us-east-1" -"us-west-2" -) - - -for region in ${regions[@]}; -do - echo "Region: ${region}" - aws ec2 describe-images --region ${region} --owners self --filters Name="name",Values="ziti-tests-*" | jq '[.Images[] | { Id: .ImageId, Date: .CreationDate}] | sort_by(.Date)' | jq -r '.[] | (.Id + " " + .Date) ' -done diff --git a/zititest/ami/ziti-ami.pkr.hcl b/zititest/ami/ziti-ami.pkr.hcl deleted file mode 100644 index 295da7fe9..000000000 --- a/zititest/ami/ziti-ami.pkr.hcl +++ /dev/null @@ -1,76 +0,0 @@ -packer { - required_version = ">= 1.6.0" - - required_plugins { - amazon = { - version = ">= 1.1.1" - source = "github.com/hashicorp/amazon" - } - } -} - -source "amazon-ebs" "ziti-tests-ubuntu-ami" { - ami_description = "An Ubuntu AMI that has everything needed for running fablab smoketests." - ami_name = "ziti-tests-{{ timestamp }}" - ami_regions = ["us-east-1", "us-east-2", "us-west-1", "us-west-2", "ca-central-1", "ap-northeast-1", "ap-southeast-2", "sa-east-1", "eu-central-1", "af-south-1"] - instance_type = "t2.micro" - region = "us-east-1" - source_ami_filter { - filters = { - architecture = "x86_64" - name = "ubuntu/images/*/ubuntu-jammy-22.04-amd64-server-*" - root-device-type = "ebs" - virtualization-type = "hvm" - } - most_recent = true - owners = ["099720109477"] - } - ssh_username = "ubuntu" -} - -build { - sources = ["source.amazon-ebs.ziti-tests-ubuntu-ami"] - - provisioner "file" { - source = "etc/apt/apt.conf.d/99remote-not-fancy" - destination = "/home/ubuntu/99remote-not-fancy" - } - - provisioner "file" { - source = "etc/sysctl.d/51-network-tuning.conf" - destination = "/home/ubuntu/51-network-tuning.conf" - } - - provisioner "file" { - source = "etc/systemd/resolved.conf.d/ziti-tunnel.conf" - destination = "/home/ubuntu/ziti-tunnel.conf" - } - - provisioner "shell" { - inline = [ - "sudo mv /home/ubuntu/99remote-not-fancy /etc/apt/apt.conf.d/", - "sudo mv /home/ubuntu/51-network-tuning.conf /etc/sysctl.d/", - "sudo mkdir /etc/systemd/resolved.conf.d", - "sudo mv /home/ubuntu/ziti-tunnel.conf /etc/systemd/resolved.conf.d/", - "sudo chown root.root /etc/systemd/resolved.conf.d/*", - - "cloud-init status --wait", - - # add metricsbeat sources - "curl --fail --silent --show-error --location https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor | sudo dd of=/usr/share/keyrings/elasticsearch-archive-keyring.gpg", - "echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/elasticsearch-archive-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main\" | sudo tee -a /etc/apt/sources.list.d/elastic-8.x.list", - - # add consul sources - "curl --fail --silent --show-error --location https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo dd of=/usr/share/keyrings/hashicorp-archive-keyring.gpg", - "echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee -a /etc/apt/sources.list.d/hashicorp.list", - - "sudo apt update", - "sudo apt upgrade -y", - "sudo apt install -y iperf3 tcpdump sysstat", - "sudo apt install -y metricbeat=8.3.2", - "sudo apt install -y consul", - "sudo bash -c \"echo 'ubuntu soft nofile 40960' >> /etc/security/limits.conf\"", - "sudo sed -i 's/ENABLED=\"false\"/ENABLED=\"true\"/g' /etc/default/sysstat", - ] - } -} diff --git a/zititest/go.mod b/zititest/go.mod index 93f8522f2..b16ad44e8 100644 --- a/zititest/go.mod +++ b/zititest/go.mod @@ -7,24 +7,24 @@ replace github.com/openziti/ziti => ../ require ( github.com/Jeffail/gabs v1.4.0 github.com/Jeffail/gabs/v2 v2.7.0 - github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.1 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.4.0 github.com/michaelquigley/pfxlog v0.6.10 - github.com/openziti/agent v1.0.15 - github.com/openziti/channel/v2 v2.0.101 - github.com/openziti/fablab v0.5.16 + github.com/openziti/agent v1.0.16 + github.com/openziti/channel/v2 v2.0.105 + github.com/openziti/fablab v0.5.25 github.com/openziti/foundation/v2 v2.0.33 - github.com/openziti/identity v1.0.64 - github.com/openziti/sdk-golang v0.20.122 - github.com/openziti/storage v0.2.20 - github.com/openziti/transport/v2 v2.0.109 + github.com/openziti/identity v1.0.66 + github.com/openziti/sdk-golang v0.20.129 + github.com/openziti/storage v0.2.23 + github.com/openziti/transport/v2 v2.0.113 github.com/openziti/ziti v0.28.3 github.com/pkg/errors v0.9.1 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - go.etcd.io/bbolt v1.3.7 + go.etcd.io/bbolt v1.3.8 golang.org/x/net v0.17.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 @@ -36,11 +36,11 @@ require ( github.com/MichaelMure/go-term-markdown v0.1.4 // indirect github.com/MichaelMure/go-term-text v0.3.1 // indirect github.com/alecthomas/chroma v0.10.0 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.45.13 // indirect + github.com/aws/aws-sdk-go v1.47.0 // indirect github.com/biogo/store v0.0.0-20200525035639-8c94ae1e7c9c // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/boltdb/bolt v1.3.1 // indirect @@ -58,11 +58,11 @@ require ( github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect github.com/go-acme/lego/v4 v4.14.2 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -75,7 +75,7 @@ require ( github.com/go-openapi/strfmt v0.21.7 // indirect github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/validate v0.22.1 // indirect - github.com/go-resty/resty/v2 v2.9.1 // indirect + github.com/go-resty/resty/v2 v2.10.0 // indirect github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/gomarkdown/markdown v0.0.0-20230922112808-5421fefb8386 // indirect @@ -94,7 +94,7 @@ require ( github.com/hashicorp/raft-boltdb v0.0.0-20220329195025-15018e9b97e0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d // indirect - github.com/jedib0t/go-pretty/v6 v6.4.8 // indirect + github.com/jedib0t/go-pretty/v6 v6.4.9 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -102,16 +102,15 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/kataras/go-events v0.0.3 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.17.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/kyokomi/emoji/v2 v2.2.12 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucsky/cuid v1.2.1 // indirect - github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect + github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-tty v0.0.3 // indirect github.com/mdlayher/netlink v1.7.2 // indirect @@ -129,11 +128,11 @@ require ( github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/openziti/dilithium v0.3.3 // indirect - github.com/openziti/edge-api v0.25.38 // indirect + github.com/openziti/edge-api v0.26.0 // indirect github.com/openziti/jwks v1.0.3 // indirect - github.com/openziti/metrics v1.2.36 // indirect + github.com/openziti/metrics v1.2.37 // indirect github.com/openziti/runzmd v1.0.33 // indirect - github.com/openziti/secretstream v0.1.12 // indirect + github.com/openziti/secretstream v0.1.13 // indirect github.com/openziti/x509-claims v1.0.3 // indirect github.com/openziti/xweb/v2 v2.1.0 // indirect github.com/openziti/ziti-db-explorer v1.1.3 // indirect @@ -194,6 +193,6 @@ require ( gopkg.in/resty.v1 v1.12.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - nhooyr.io/websocket v1.8.7 // indirect + nhooyr.io/websocket v1.8.10 // indirect rsc.io/goversion v1.2.0 // indirect ) diff --git a/zititest/go.sum b/zititest/go.sum index 80ab4139e..bd8d036db 100644 --- a/zititest/go.sum +++ b/zititest/go.sum @@ -80,8 +80,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= @@ -96,8 +96,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.45.13 h1:LwD/G+PX7FQnbU8wXekx12e90i1GuKJQC2+pl4IlPAs= -github.com/aws/aws-sdk-go v1.45.13/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.47.0 h1:/JUg9V1+xh+qBn8A6ec/l15ETPaMaBqxkjz+gg63dNk= +github.com/aws/aws-sdk-go v1.47.0/go.mod h1:DlEaEbWKZmsITVbqlSVvekPARM1HzeV9PMYg15ymSDA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -192,16 +192,12 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/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/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-acme/lego/v4 v4.14.2 h1:/D/jqRgLi8Cbk33sLGtu2pX2jEg3bGJWHyV8kFuUHGM= github.com/go-acme/lego/v4 v4.14.2/go.mod h1:kBXxbeTg0x9AgaOYjPSwIeJy3Y33zTz+tMD16O4MO6c= @@ -217,8 +213,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -263,15 +259,8 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM= -github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4= +github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= +github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= @@ -297,12 +286,6 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -363,8 +346,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -386,8 +370,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -402,7 +386,6 @@ github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -464,8 +447,8 @@ github.com/influxdata/influxdb-client-go/v2 v2.2.2/go.mod h1:fa/d1lAdUHxuc1jedx3 github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d h1:/WZQPMZNsjZ7IlCpsLGdQBINg5bxKQ1K1sh6awxLtkA= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/jedib0t/go-pretty/v6 v6.4.8 h1:HiNzyMSEpsBaduKhmK+CwcpulEeBrTmxutz4oX/oWkg= -github.com/jedib0t/go-pretty/v6 v6.4.8/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= +github.com/jedib0t/go-pretty/v6 v6.4.9 h1:vZ6bjGg2eBSrJn365qlxGcaWu09Id+LHtrfDWlB2Usc= +github.com/jedib0t/go-pretty/v6 v6.4.9/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= @@ -484,7 +467,6 @@ github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2C github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -498,10 +480,7 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -523,8 +502,6 @@ github.com/kyokomi/emoji/v2 v2.2.12 h1:sSVA5nH9ebR3Zji1o31wu3yOwD1zKXQA2z0zUyeit github.com/kyokomi/emoji/v2 v2.2.12/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -532,8 +509,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i github.com/lucsky/cuid v1.2.1 h1:MtJrL2OFhvYufUIn48d35QGXyeTC8tn0upumW9WwTHg= github.com/lucsky/cuid v1.2.1/go.mod h1:QaaJqckboimOmhRSJXSx/+IT+VTfxfPGSo/6mfgUfmE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= +github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0= +github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -571,8 +548,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.6/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/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= @@ -615,11 +592,9 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= @@ -649,34 +624,34 @@ github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openziti/agent v1.0.15 h1:NW4egpS3Mw1RQBZWfUEvrmBh9kn/SU/dU5fndsyyhZ4= -github.com/openziti/agent v1.0.15/go.mod h1:zfm53+PVWoGFzjGGgQdKby5749G6VRYHe+eQJmoVKy4= -github.com/openziti/channel/v2 v2.0.101 h1:UaveW/ogYKVtCQZfwRoMhsZhj/tvs1bD7SvH0aLaYNw= -github.com/openziti/channel/v2 v2.0.101/go.mod h1:b9CBWpH6tnLqCHInDKL6AzMGqXdbEjsul3yVQUGENVU= +github.com/openziti/agent v1.0.16 h1:9Saji+8hFE1NpzP2XzDhsVJbCrDlhixoLHfOpFt5Z+U= +github.com/openziti/agent v1.0.16/go.mod h1:zfm53+PVWoGFzjGGgQdKby5749G6VRYHe+eQJmoVKy4= +github.com/openziti/channel/v2 v2.0.105 h1:WT2zFF7krZkYUfuXA+4tQxhYiiVWlldD3mKX3qJU9Ww= +github.com/openziti/channel/v2 v2.0.105/go.mod h1:++bV6FFgGUNxaBu7iOkkCa6rSiueU34Kd6f2LSCrEtU= 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-api v0.25.38 h1:aijFEC4pMCi2gR6zL6FYQRkm59SQAwrF0tZS4LZsxi4= -github.com/openziti/edge-api v0.25.38/go.mod h1:5mmcMgqK1MsBb0K8V1CBfGbtRUji5KYdmhJJJkJBMqY= -github.com/openziti/fablab v0.5.16 h1:+tqqDR5Sl4qLT3fSC+Dv1AGZuOeeX87h9LNKa1KJS5Y= -github.com/openziti/fablab v0.5.16/go.mod h1:KiU/NxThNtH9U803Ep0WcSrbov3moZso2oRgIpQq0S0= +github.com/openziti/edge-api v0.26.0 h1:082hXjj8rnyMBZHYiB6jb4n7mCXtdMXpF2iCqZOv4IM= +github.com/openziti/edge-api v0.26.0/go.mod h1:/e1pK92L471fvOAwE/hLX5sqBuuo+NwI8vmL04dUHsM= +github.com/openziti/fablab v0.5.25 h1:KxbhNFeX40TlB1Ot+KnEZos0LYtTs77dNekIMRDLvEg= +github.com/openziti/fablab v0.5.25/go.mod h1:uUY3gr4IcGL6vsxBX7gA/b/StF0mHsICkW8HZBvkx9o= github.com/openziti/foundation/v2 v2.0.33 h1:8CP+fi4KsmzA4jDi54jibwFWWxKpd0rSiplzN9Z0Isw= github.com/openziti/foundation/v2 v2.0.33/go.mod h1:dWR0g3NOka3uKz9MgUHq6dmuRLmSvunkyeuOXEW/5qU= -github.com/openziti/identity v1.0.64 h1:HwALRY1J/rNNcIAlr1OwCwTHU/rlMRaUi5TXAfZotjw= -github.com/openziti/identity v1.0.64/go.mod h1:t/mW5mCpCbcRrssj4EpzfrmebI7+UKXGH2twll7IQIo= +github.com/openziti/identity v1.0.66 h1:wCIVNCoiHmeicC9yM15FC0xe6jSic879ztN63fSD6hM= +github.com/openziti/identity v1.0.66/go.mod h1:grReHVqBwhECrnrAZCxNw4ZpA2I1ox66tYfPkfGuKJY= github.com/openziti/jwks v1.0.3 h1:hf8wkb+Cg4nH/HM0KROFd7u+C3DkRVcFZJ7tDV+4icc= github.com/openziti/jwks v1.0.3/go.mod h1:t4xxq8vlXGsPn29kiQVnZBBDDnEoOFqtJoHibkJunQQ= -github.com/openziti/metrics v1.2.36 h1:oW5YM9H8IqtFuxIyo0rMC3mTpl3rdSnDKcHp+ZTn+JM= -github.com/openziti/metrics v1.2.36/go.mod h1:fjYG6sUC/n6VXe0nZbYGEBaopbRThBo/3xt7o9VatRQ= +github.com/openziti/metrics v1.2.37 h1:5yWvMwQT6X43LDlNVcUtqAPJQXfKtbWSYoCIiOfXztg= +github.com/openziti/metrics v1.2.37/go.mod h1:jIL9iilxby8tR98C18uZaSe6bRG15ItR8XF2hmMt8vs= github.com/openziti/runzmd v1.0.33 h1:tOyjRoUuVXIo1z1pNU32jALWkMmhzsSaDrhLtuOn3Ts= github.com/openziti/runzmd v1.0.33/go.mod h1:8c/uvZR/XWXQNllTq6LuTpfKL2DTNxfI2X2wYhgRwik= -github.com/openziti/sdk-golang v0.20.122 h1:fuxws2yFEFl4hdq4l96/N23ztC1oUiQIM/lePTI6rBY= -github.com/openziti/sdk-golang v0.20.122/go.mod h1:n6Ft+Gz7e2JO6DQ6Ixc9oIn06I1MjzkI3V9kilkOBIQ= -github.com/openziti/secretstream v0.1.12 h1:N78CHxtqWzSyNFOsYtYRWNNTfX1ZDAPkFgzHobpodZU= -github.com/openziti/secretstream v0.1.12/go.mod h1:gHMH1REH0r4VlmCtuWx8biU7j5ZfOivFjz9mLgwq7mk= -github.com/openziti/storage v0.2.20 h1:xpLczyF/czIw76M4Rrt2urYn/EvGNor+SPzoixuOkLs= -github.com/openziti/storage v0.2.20/go.mod h1:UO8D6h4AAf5OT1iJg1sppKoEPC2YWaBGZFLK7rPyk5M= -github.com/openziti/transport/v2 v2.0.109 h1:12ZdM9R7lETKP7cT2xsGlTX/4w2qBtC8nThxw8RG77Q= -github.com/openziti/transport/v2 v2.0.109/go.mod h1:r1jay/cSzkw15SJLtbk/I9YZtMIYjhueqAqfWtO5ioE= +github.com/openziti/sdk-golang v0.20.129 h1:FjvXsGFxEiHq89sNyLSvNymruACFW5tbhkgZ3VCg2pE= +github.com/openziti/sdk-golang v0.20.129/go.mod h1:ZpJ7HCcIQbp8XiSno3YXkfhoDIbgjCjS2ScK2bda8eo= +github.com/openziti/secretstream v0.1.13 h1:grp53Q5gCFPXv6okwWHDVvqBBk2BhD0ikHwfV3Adhnc= +github.com/openziti/secretstream v0.1.13/go.mod h1:M4DYavDc3TVF/eemNqp5Fa+zGuYTNa0HTGSz/GkgUzA= +github.com/openziti/storage v0.2.23 h1:R5ZBGDGC/LvOz3fE/GlevwbPZ3HL7VxYEvlhKuezvNU= +github.com/openziti/storage v0.2.23/go.mod h1:NZCrN2dLtRU73McVEflK5prDgYds9J54mMNz5DmgvZE= +github.com/openziti/transport/v2 v2.0.113 h1:xFPd1W00KqkFb62rRsRXmLqfgr9d9uk0CAVZegvtGhA= +github.com/openziti/transport/v2 v2.0.113/go.mod h1:TSDHV7RTGg/FinzfOP8cg86O53BCabXedANh3eUNics= github.com/openziti/x509-claims v1.0.3 h1:HNdQ8Nf1agB3lBs1gahcO6zfkeS4S5xoQ2/PkY4HRX0= github.com/openziti/x509-claims v1.0.3/go.mod h1:Z0WIpBm6c4ecrpRKrou6Gk2wrLWxJO/+tuUwKh8VewE= github.com/openziti/xweb/v2 v2.1.0 h1:Xhh3C2pZkq/Prr65V+SfFSibLDYteoc4f62KQCcTZF4= @@ -872,10 +847,6 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 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= @@ -910,8 +881,8 @@ github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ github.com/zitadel/oidc/v2 v2.7.0 h1:IGX4EDk6tegTjUSsZDWeTfLseFU0BdJ/Glf1tgys2lU= github.com/zitadel/oidc/v2 v2.7.0/go.mod h1:zkUkVJS0sDVy9m0UA9RgO3f8i/C0rtjvXU36UJj7T+0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -976,7 +947,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1079,7 +1049,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1195,7 +1164,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1209,7 +1177,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1231,8 +1198,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1470,8 +1437,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w= rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo= diff --git a/zititest/models/db-creation/README.md b/zititest/models/db-creation/README.md new file mode 100644 index 000000000..b5f37c990 --- /dev/null +++ b/zititest/models/db-creation/README.md @@ -0,0 +1,50 @@ +# db-creation model + +### This model is designed to be used for GitHub Actions to create a test DB and export the pki/identities/DB to s3 buckets for later testing usage. ### + +- Only setup for AWS. +- Designed to work with the pete-iperf branch of fablab. +- You will need to supply your own keys/secrets. +- Infrastructure is configured in the main.go in the model. +- This is a very alpha release, minimal features. + +### There are several files that will likely need to be customized for your setup: ### + +- ziti/zititest/models/db-creation/main.go - mainly used to alter the model and also your Rsync and Disposal Actions (removing Route 53 A Record) +- ziti/zititest/models/db-creation/actions/bootstrap.go - This is where the meat of the actions take place. Sets up AWS remotely from the GH Runner (using Fablab executable), then runs the DB Creation Script. +- ziti/zititest/models/db-creation/resources/db_creator_script_external.sh - This is the script that interacts with Ziti and creates all the identities, services and policies. +- ziti/zititest/models/db-creation/resources/aws_setup.sh - This will default to us-east-1 region and use JSON output, if you want to change those values do that here. +- ziti/.github/workflows/fablab-db-creation.yml - This is where you will setup your GitHub workflow specifics, inserting your custom secret variable names, etc. As you can see at the end, the following 3 Fablab commands are all that is needed to run this: + - ```./db-creation create db-creation``` + - ```./db-creation up``` + - ```./db-creation dispose``` + +### Once the DB is saved in s3, you will need to pull that and the pki from the proper buckets via the following steps: + +#### Non Fablab import (manual) or something designed by you #### +- Make sure AWS CLI is configured on the machine you want the DB imported to. +- cd to the /home/ubuntu/fablab directory which is where the DB lies. +- Stop any existing Ziti processes. +- Simply delete the old DB file or rename it. +- Run the following AWS CLI command to import DB: + - ```aws s3 cp s3://db-bucket-name/ctrl.db-filename ctrl.db ``` +- Remove the contents of the entire pki directory using the following: + - ```cd pki``` + - ```sudo rm -rf *``` + - ```cd ..``` +- Run the following to import the pki directory (replacing pki-s3-bucket-name/pki-folder-name with your names) : + - ```aws s3 cp --recursive s3://pki-s3-bucket-name/pki-s3-folder-name/ pki/``` +- Run the following command while replacing the ziti version number in filename to start the controller: + - ```nohup /home/ubuntu/fablab/bin/ziti-v0.28.4 controller run --log-formatter pfxlog /home/ubuntu/fablab/cfg/ctrl.yml --cli-agent-alias ctrl > /home/ubuntu/logs/ctrl.log 2>&1 & ``` + +#### Fablab import #### +- cd into your local ziti/zititest/models/db-creation/resources folder and then import both the DB and PKI from your s3 buckets: + - Command to run for your DB import: + - ```aws s3 cp s3://s3-db-bucket-name/s3-ctrl.db-filename ctrl.db``` + - Commands to run for your PKI import: + - ```mkdir pki``` + - ```aws s3 cp --recursive s3://pki-s3-bucket-name/pki-s3-folder-name/ pki/``` +- Within your main.go for the db-creation model, you should uncomment the 2 following lines within the Distribution portion of the model, around line 123 or so: + - ```rsync.NewRsyncHost("#ctrl", "resources/ctrl.db", "/home/ubuntu/fablab/ctrl.db"),``` + - ```rsync.NewRsyncHost("#ctrl", "resources/pki/", "/home/ubuntu/fablab/pki/"),``` +- Now you should be able to create a fresh db-creation executable by building and run that, which should have the new DB/PKI. \ No newline at end of file diff --git a/zititest/models/db-creation/actions/bootstrap.go b/zititest/models/db-creation/actions/bootstrap.go new file mode 100644 index 000000000..c532913b5 --- /dev/null +++ b/zititest/models/db-creation/actions/bootstrap.go @@ -0,0 +1,178 @@ +/* + (c) 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 actions + +import ( + "encoding/json" + "fmt" + "github.com/openziti/fablab/kernel/lib/actions" + "github.com/openziti/fablab/kernel/lib/actions/component" + "github.com/openziti/fablab/kernel/lib/actions/host" + "github.com/openziti/fablab/kernel/lib/actions/semaphore" + "github.com/openziti/fablab/kernel/model" + "github.com/openziti/ziti/zititest/zitilab" + zitilib_actions "github.com/openziti/ziti/zititest/zitilab/actions" + "github.com/openziti/ziti/zititest/zitilab/actions/edge" + "github.com/openziti/ziti/zititest/zitilab/models" + "os" + "time" +) + +const DomainName = "controller.testing.openziti.org" +const Create = "CREATE" +const Delete = "DELETE" + +type bootstrapAction struct{} + +// Define a struct to represent the nested "ResourceRecordSet" object +type ResourceRecordSet struct { + Name string `json:"Name"` + Type string `json:"Type"` + TTL int `json:"TTL"` + ResourceRecords []struct { + Value string `json:"Value"` + } `json:"ResourceRecords"` +} + +// Define a struct to represent the nested "Changes" object +type Change struct { + Action string `json:"Action"` + ResourceRecordSet ResourceRecordSet `json:"ResourceRecordSet"` +} + +// Define the main Payload struct to represent the entire JSON payload +type Payload struct { + Changes []Change `json:"Changes"` +} + +func NewBootstrapAction() model.ActionBinder { + action := &bootstrapAction{} + return action.bind +} + +func Route53StringCreator(m *model.Model, action string) string { + var payload = Payload{ + Changes: []Change{ + { + Action: action, + ResourceRecordSet: ResourceRecordSet{ + Name: DomainName, // The DNS record name + Type: "A", // Type A represents an IPv4 address + TTL: 300, // TTL value in seconds + ResourceRecords: []struct { + Value string `json:"Value"` + }{ + {Value: m.MustSelectHost("#ctrl").PublicIp}, + }, + }, + }, + }, + } + jsonData, err := json.MarshalIndent(payload, "", " ") + if err != nil { + fmt.Println("Error marshaling struct to JSON:", err) + } + dnsAddJsonData := string(jsonData) + s := "aws route53 change-resource-record-sets --hosted-zone-id Z09612893W445K5ME8MYS --change-batch '" + dnsAddJsonData + "'" + return s +} + +func (a *bootstrapAction) bind(m *model.Model) model.Action { + workflow := actions.Workflow() + // Set AWS config remotely + accessKey := os.Getenv("S3_KEY") + if accessKey != "" { + fmt.Println("S3_KEY", accessKey) + } else { + fmt.Println("S3_KEY missing") + } + accessSecret := os.Getenv("S3_SECRET") + if accessSecret != "" { + fmt.Println("S3_SECRET", accessSecret) + } else { + fmt.Println("S3_SECRET missing") + } + accessKeyIDString := "export AWS_ACCESS_KEY_ID=" + accessKey + accessSecretString := "export AWS_SECRET_ACCESS_KEY=" + accessSecret + setAccessKeyIDString := "aws configure set aws_access_key_id " + accessKey + setAccessSecretString := "aws configure set aws_secret_access_key " + accessSecret + workflow.AddAction(host.GroupExec("#ctrl", 1, accessKeyIDString)) + workflow.AddAction(host.GroupExec("#ctrl", 1, accessSecretString)) + workflow.AddAction(host.GroupExec("#ctrl", 1, setAccessKeyIDString)) + workflow.AddAction(host.GroupExec("#ctrl", 1, setAccessSecretString)) + workflow.AddAction(host.GroupExec("#ctrl", 1, "aws configure set default.region us-east-1")) + workflow.AddAction(host.GroupExec("#ctrl", 1, "aws configure set default.output json")) + + // Run aws_setup script - passing in AWS Key and Secret + awsScriptExecutionText := "sudo /home/ubuntu/fablab/bin/aws_setup.sh " + accessKey + " " + accessSecret + workflow.AddAction(host.GroupExec("#ctrl", 1, "sudo chmod 0755 /home/ubuntu/fablab/bin/aws_setup.sh")) + workflow.AddAction(host.GroupExec("#ctrl", 1, awsScriptExecutionText)) + + //Add Route53 DNS A Record + workflow.AddAction(model.ActionFunc(func(run model.Run) error { + m := run.GetModel() + s := Route53StringCreator(m, Create) + return host.Exec(m.MustSelectHost("#ctrl"), s).Execute(run) + })) + + //Start Ziti Controller + workflow.AddAction(host.GroupExec("#ctrl", 1, "rm -f logs/*")) + workflow.AddAction(component.Stop("#ctrl")) + workflow.AddAction(component.Exec("#ctrl", zitilab.ControllerActionInitStandalone)) + workflow.AddAction(component.Start("#ctrl")) + workflow.AddAction(edge.ControllerAvailable("#ctrl", 30*time.Second)) + + // Login to Ziti Controller + workflow.AddAction(edge.Login("#ctrl")) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + + // Setup Ziti Routers + workflow.AddAction(component.StopInParallel(models.EdgeRouterTag, 25)) + workflow.AddAction(edge.InitEdgeRouters(models.EdgeRouterTag, 2)) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + + // Init Identities + workflow.AddAction(edge.InitIdentities(models.SdkAppTag, 2)) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + + // Create Configs + workflow.AddAction(zitilib_actions.Edge("create", "config", "iperf-server", "host.v1", ` + { + "address" : "localhost", + "port" : 7001, + "protocol" : "tcp" + }`)) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + workflow.AddAction(zitilib_actions.Edge("create", "config", "iperf-intercept", "intercept.v1", ` + { + "addresses": ["iperf.service"], + "portRanges" : [ + { "low": 7001, "high": 7001 } + ], + "protocols": ["tcp"] + }`)) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + + // Start Beats Services + workflow.AddAction(host.GroupExec("ctrl", 25, "sudo service filebeat stop; sleep 5; sudo service filebeat start")) + workflow.AddAction(host.GroupExec("ctrl", 25, "sudo service metricbeat stop; sleep 5; sudo service metricbeat start")) + + // Run DB Creation Shell script + workflow.AddAction(host.GroupExec("ctrl", 1, "sudo chmod 0755 /home/ubuntu/fablab/bin/db_creator_script_external.sh")) + workflow.AddAction(host.GroupExec("ctrl", 1, "sudo /home/ubuntu/fablab/bin/db_creator_script_external.sh")) + return workflow +} diff --git a/zititest/models/db-creation/configs/ctrl.yml.tmpl b/zititest/models/db-creation/configs/ctrl.yml.tmpl new file mode 100644 index 000000000..8e2f46c7b --- /dev/null +++ b/zititest/models/db-creation/configs/ctrl.yml.tmpl @@ -0,0 +1,194 @@ +v: 3 + +db: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/ctrl.db + +identity: + cert: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/pki/ctrl/certs/{{ .Component.Id }}-server.cert + key: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/pki/ctrl/keys/{{ .Component.Id }}-server.key + ca: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/pki/ctrl/certs/{{ .Component.Id }}-server.chain.pem + +# the endpoint that routers will connect to the controller over. +ctrl: + listener: tls:0.0.0.0:6262 + options: + advertiseAddress: tls:{{.Host.PublicIp}}:6262 + # (optional) settings + # set the maximum number of connect requests that are buffered and waiting to be acknowledged (1 to 5000, default 1000) + #maxQueuedConnects: 50 + + # the maximum number of connects that have begun hello synchronization (1 to 1000, default 16) + #maxOutstandingConnects: 100 + + # the number of milliseconds to wait before a hello synchronization fails and closes the connection (30ms to 60000ms, default: 1000ms) + #connectTimeoutMs: 3000 + + # Sets the control channel write timeout. A write timeout will close the control channel, so the router will reconnect + #writeTimeout: 15s + + # A listener address which will be sent to connecting routers in order to change their configured controller + # address. If defined, routers will update address configuration to immediately use the new address for future + # connections. The value of newListener must be resolvable both via DNS and validate via certificates + #newListener: tls:localhost:6262 + +#events: +# jsonLogger: +# subscriptions: +# - type: fabric.routers +# - type: fabric.terminators +# - type: metrics +# sourceFilter: .* +# metricFilter: .*egress.*m1_rate* +# - type: fabric.circuits +# include: +# - created +# - type: edge.sessions +# include: +# - created +# - type: edge.apiSessions +# - type: fabric.usage +# - type: services +# - type: fabric.usage +# - type: edge.entityCounts +# interval: 5s +# handler: +# type: file +# format: json +# path: /tmp/ziti-events.log + +healthChecks: + boltCheck: + # How often to try entering a bolt read tx. Defaults to 30 seconds + interval: 30s + # When to timeout the check. Defaults to 15 seconds + timeout: 15s + # How long to wait before starting the check. Defaults to 15 seconds + initialDelay: 15s + +# By having an 'edge' section defined, the ziti-controller will attempt to parse the edge configuration. Removing this +# section, commenting out, or altering the name of the section will cause the edge to not run. +edge: + # This section represents the configuration of the Edge API that is served over HTTPS + api: + #(optional, default 90s) Alters how frequently heartbeat and last activity values are persisted + # activityUpdateInterval: 90s + #(optional, default 250) The number of API Sessions updated for last activity per transaction + # activityUpdateBatchSize: 250 + # sessionTimeout - optional, default 10m + # The number of minutes before an Edge API session will timeout. Timeouts are reset by + # API requests and connections that are maintained to Edge Routers + sessionTimeout: 30m + # address - required + # The default address (host:port) to use for enrollment for the Client API. This value must match one of the addresses + # defined in a bind point's address field for the `edge-client` API in the web section. + address: {{.Host.PublicIp}}:1280 + # enrollment - required + # A section containing settings pertaining to enrollment. + enrollment: + # signingCert - required + # A Ziti Identity configuration section that specifically makes use of the cert and key fields to define + # a signing certificate from the PKI that the Ziti environment is using to sign certificates. The signingCert.cert + # will be added to the /.well-known CA store that is used to bootstrap trust with the Ziti Controller. + signingCert: + cert: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/pki/ctrl/certs/ctrl.cert + key: /home/{{ .Model.MustVariable "credentials.ssh.username" }}/fablab/pki/ctrl/keys/ctrl.key + + # edgeIdentity - optional + # A section for identity enrollment specific settings + edgeIdentity: + # duration - optional, default 5m + # The length of time that a Ziti Edge Identity enrollment should remain valid. After + # this duration, the enrollment will expire and not longer be usable. + duration: 5m + # edgeRouter - Optional + # A section for edge router enrollment specific settings. + edgeRouter: + # duration - optional, default 5m + # The length of time that a Ziti Edge Router enrollment should remain valid. After + # this duration, the enrollment will expire and not longer be usable. + duration: 5m + + +# web - optional +# Defines webListeners that will be hosted by the controller. Each webListener can host many APIs and be bound to many +# bind points. +web: + # name - required + # Provides a name for this listener, used for logging output. Not required to be unique, but is highly suggested. + - name: all-apis-localhost + # bindPoints - required + # One or more bind points are required. A bind point specifies an interface (interface:port string) that defines + # where on the host machine the webListener will listen and the address (host:port) that should be used to + # publicly address the webListener(i.e. mydomain.com, localhost, 127.0.0.1). This public address may be used for + # incoming address resolution as well as used in responses in the API. + bindPoints: + #interface - required + # A host:port string on which network interface to listen on. 0.0.0.0 will listen on all interfaces + - interface: 0.0.0.0:1280 + + # address - required + # The public address that external incoming requests will be able to resolve. Used in request processing and + # response content that requires full host:port/path addresses. + address: {{.Host.PublicIp}}:1280 + + # newAddress - optional + # A host:port string which will be sent out as an HTTP header "ziti-new-address" if specified. If the header + # is present, clients should update location configuration to immediately use the new address for future + # connections. The value of newAddress must be resolvable both via DNS and validate via certificates + #newAddress: localhost:1280 + # identity - optional + # Allows the webListener to have a specific identity instead of defaulting to the root `identity` section. + # identity: + # cert: ${ZITI_SOURCE}/ziti/etc/ca/intermediate/certs/ctrl-client.cert.pem + # server_cert: ${ZITI_SOURCE}/ziti/etc/ca/intermediate/certs/ctrl-server.cert.pem + # key: ${ZITI_SOURCE}/ziti/etc/ca/intermediate/private/ctrl.key.pem + # ca: ${ZITI_SOURCE}/ziti/etc/ca/intermediate/certs/ca-chain.cert.pem + # options - optional + # Allows the specification of webListener level options - mainly dealing with HTTP/TLS settings. These options are + # used for all http servers started by the current webListener. + options: + # idleTimeout - optional, default 5000ms + # The maximum amount of idle time in milliseconds allowed for pipelined HTTP requests. Setting this too high + # can cause resources on the host to be consumed as clients remain connected and idle. Lowering this value + # will cause clients to reconnect on subsequent HTTPs requests. + idleTimeout: 5000ms #http timeouts, new + + # readTimeout - optional, default 5000ms + # The maximum amount of time in milliseconds http servers will wait to read the first incoming requests. A higher + # value risks consuming resources on the host with clients that are acting bad faith or suffering from high latency + # or packet loss. A lower value can risk losing connections to high latency/packet loss clients. + + readTimeout: 5000ms + # writeTimeout - optional, default 10000ms + # The total maximum time in milliseconds that the http server will wait for a single requests to be received and + # responded too. A higher value can allow long running requests to consume resources on the host. A lower value + # can risk ending requests before the server has a chance to respond. + + writeTimeout: 100000ms + # minTLSVersion - optional, default TSL1.2 + # The minimum version of TSL to support + + minTLSVersion: TLS1.2 + # maxTLSVersion - optional, default TSL1.3 + # The maximum version of TSL to support + + maxTLSVersion: TLS1.3 + # apis - required + # Allows one or more APIs to be bound to this webListener + apis: + # binding - required + # Specifies an API to bind to this webListener. Built-in APIs are + # - health-checks + # - edge-management + # - edge-client + # - 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. + # These settings are per API. The example below is for the `edge-api` and contains both optional values and + # required values. + options: {} + - binding: edge-client + options: {} diff --git a/zititest/models/db-creation/configs/router.yml.tmpl b/zititest/models/db-creation/configs/router.yml.tmpl new file mode 100644 index 000000000..788799f78 --- /dev/null +++ b/zititest/models/db-creation/configs/router.yml.tmpl @@ -0,0 +1,70 @@ +{{$ssh_username := .Model.MustVariable "credentials.ssh.username"}} +{{$identity := .Component.Id}} +{{$ctrl_ip := publicIp "component#ctrl"}} +{{$router_ip := .Host.PublicIp}} + +v: 3 + +enableDebugOps: true + +identity: + cert: /home/{{$ssh_username}}/fablab/cfg/{{$identity}}-client.cert + server_cert: /home/{{$ssh_username}}/fablab/cfg/{{$identity}}-server.cert + key: /home/{{$ssh_username}}/fablab/cfg/{{$identity}}.key + ca: /home/{{$ssh_username}}/fablab/cfg/{{$identity}}-server.chain.pem + +ctrl: + endpoint: tls:{{$ctrl_ip}}:6262 + +healthChecks: + ctrlPingCheck: + # How often to ping the controller over the control channel. Defaults to 30 seconds + interval: 30s + # When to timeout the ping. Defaults to 15 seconds + timeout: 15s + # How long to wait before pinging the controller. Defaults to 15 seconds + initialDelay: 15s + +metrics: + reportInterval: 15s + messageQueueSize: 10 + +link: + listeners: + - binding: transport + bind: tls:0.0.0.0:6000 + advertise: tls:{{$router_ip}}:6000 + dialers: + - binding: transport + +listeners: +{{if .Component.HasTag "tunneler"}} + - binding: tunnel + options: + mode: tproxy +{{end}} + - binding: edge + address: tls:0.0.0.0:6262 + options: + # (required) The public hostname and port combination that Ziti SDKs should connect on. Previously this was in the chanIngress section. + advertise: {{ .Host.PublicIp }}:6262 + +# By having an 'edge' section defined, the ziti-router will attempt to parse the edge configuration. Removing this +# section, commenting out, or altering the name of the section will cause the router to no longer operate as an Edge +# Router. +edge: + # (required) Information used to generate the initial registration CSR. For documentation on these fields please + # refer to the openssl documentation. These values MUST be supplied and have no defaults. + csr: + country: US + province: NC + locality: Charlotte + organization: NetFoundry + organizationalUnit: Ziti + + # (required) SANs that this Gateways certs should contain. At least one IP or DNS SAN should be defined that matches + # the edge listeners "advertise" value from the "listeners" section. + sans: + ip: + - {{ .Host.PublicIp }} + diff --git a/zititest/models/simple/configs/ziti.hcl b/zititest/models/db-creation/configs/ziti.hcl similarity index 100% rename from zititest/models/simple/configs/ziti.hcl rename to zititest/models/db-creation/configs/ziti.hcl diff --git a/zititest/models/db-creation/main.go b/zititest/models/db-creation/main.go new file mode 100644 index 000000000..10d8b4146 --- /dev/null +++ b/zititest/models/db-creation/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "embed" + "github.com/openziti/fablab" + "github.com/openziti/fablab/kernel/lib/actions/component" + "github.com/openziti/fablab/kernel/lib/actions/host" + "github.com/openziti/fablab/kernel/lib/binding" + "github.com/openziti/fablab/kernel/lib/runlevel/0_infrastructure/aws_ssh_key" + semaphore_0 "github.com/openziti/fablab/kernel/lib/runlevel/0_infrastructure/semaphore" + terraform_0 "github.com/openziti/fablab/kernel/lib/runlevel/0_infrastructure/terraform" + distribution "github.com/openziti/fablab/kernel/lib/runlevel/3_distribution" + "github.com/openziti/fablab/kernel/lib/runlevel/3_distribution/rsync" + aws_ssh_key2 "github.com/openziti/fablab/kernel/lib/runlevel/6_disposal/aws_ssh_key" + "github.com/openziti/fablab/kernel/lib/runlevel/6_disposal/terraform" + "github.com/openziti/fablab/kernel/model" + "github.com/openziti/fablab/resources" + "github.com/openziti/ziti/zititest/models/db-creation/actions" + "github.com/openziti/ziti/zititest/models/test_resources" + "github.com/openziti/ziti/zititest/zitilab" + "github.com/openziti/ziti/zititest/zitilab/actions/edge" + "os" + "path" + "time" +) + +//go:embed configs +var configResource embed.FS + +// Definition of the model, which houses most you need to run things. +var m = &model.Model{ + Id: "db-creation", + Scope: model.Scope{ + Defaults: model.Variables{ + "environment": "db-creation", + "credentials": model.Variables{ + "ssh": model.Variables{ + "username": "ubuntu", + }, + "edge": model.Variables{ + "username": "admin", + "password": "admin", + }, + "aws": model.Variables{ + "managed_key": true, + }, + }, + }, + }, + + StructureFactories: []model.Factory{ + //model.NewScaleFactoryWithDefaultEntityFactory(scaleStrategy{}), + }, + + Factories: []model.Factory{ + //newStageFactory(), + }, + + Resources: model.Resources{ + resources.Configs: resources.SubFolder(configResource, "configs"), + resources.Binaries: os.DirFS(path.Join(os.Getenv("GOPATH"), "bin")), + resources.Terraform: test_resources.TerraformResources(), + }, + + Regions: model.Regions{ + "us-east-1": { + Region: "us-east-1", + Site: "us-east-1a", + Hosts: model.Hosts{ + "ctrl": { + InstanceType: "t3.micro", + Components: model.Components{ + "ctrl": { + Scope: model.Scope{Tags: model.Tags{"ctrl"}}, + Type: &zitilab.ControllerType{ + ConfigSourceFS: nil, + ConfigSource: "", + ConfigName: "", + Version: os.Getenv("ZITI_VERSION"), + LocalPath: "", + DNSNames: []string{actions.DomainName}, + }, + }, + }, + }, + }, + }, + }, + + Actions: model.ActionBinders{ + "bootstrap": actions.NewBootstrapAction(), + "stop": model.Bind(component.StopInParallel("ctrl", 1)), + "login": model.Bind(edge.Login("#ctrl")), + }, + + Infrastructure: model.Stages{ + aws_ssh_key.Express(), + terraform_0.Express(), + semaphore_0.Restart(90 * time.Second), + }, + + Distribution: model.Stages{ + distribution.DistributeSshKey("*"), + distribution.Locations("*", "logs"), + rsync.RsyncStaged(), + //rsync.NewRsyncHost("#ctrl", "resources/ctrl.db", "/home/ubuntu/fablab/ctrl.db"), + //rsync.NewRsyncHost("#ctrl", "resources/pki/", "/home/ubuntu/fablab/pki/"), + rsync.NewRsyncHost("#ctrl", "resources/aws_setup.sh", "/home/ubuntu/fablab/bin/aws_setup.sh"), + rsync.NewRsyncHost("#ctrl", "resources/db_creator_script_external.sh", "/home/ubuntu/fablab/bin/db_creator_script_external.sh"), + }, + + Disposal: model.Stages{ + model.StageActionF(func(run model.Run) error { + m := run.GetModel() + s := actions.Route53StringCreator(m, actions.Delete) + return host.Exec(m.MustSelectHost("#ctrl"), s).Execute(run) + }), + terraform.Dispose(), + aws_ssh_key2.Dispose(), + }, +} + +func main() { + m.AddActivationActions("stop", "bootstrap") + model.AddBootstrapExtension(binding.AwsCredentialsLoader) + model.AddBootstrapExtension(aws_ssh_key.KeyManager) + fablab.InitModel(m) + fablab.Run() +} diff --git a/zititest/models/db-creation/resources/aws_setup.sh b/zititest/models/db-creation/resources/aws_setup.sh new file mode 100644 index 000000000..c6a2f6bc9 --- /dev/null +++ b/zititest/models/db-creation/resources/aws_setup.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +AWS_ACCESS_KEY="$1" +AWS_SECRET_KEY="$2" + +export AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY" +export AWS_SECRET_ACCESS_KEY="$AWS_SECRET_KEY" + +aws configure set aws_access_key_id "${AWS_ACCESS_KEY_ID}" +aws configure set aws_secret_access_key "${AWS_SECRET_ACCESS_KEY}" +aws configure set default.region us-east-1 +aws configure set default.output json diff --git a/zititest/models/db-creation/resources/db_creator_script_external.sh b/zititest/models/db-creation/resources/db_creator_script_external.sh new file mode 100644 index 000000000..c210740fa --- /dev/null +++ b/zititest/models/db-creation/resources/db_creator_script_external.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +exec >> bashlog.txt 2>&1 + +# Initial sleep to hopefully allow for pulling of ziti exe filename +sleep 10 + +# Set Sleep time easily for quick changes +sleep_time=.01625 + +# Set the directory path where ziti executable is +directory="/home/ubuntu/fablab/bin" + +# Set search string for 'ziti-' +search_string="ziti-" + +# Search for the file that contains the specified string +file=$(find "$directory" -type f -name "*$search_string*" -print -quit) + +# Check if a file was found +if [[ -n "$file" ]]; then + echo "File found: $file" + # Extract the file name from the full path and save it to a variable + filename=$(basename "$file") + echo "File name: $filename" +else + echo "File not found." +fi + +# cd to ziti bin dir +cd $directory || exit +ls -lsa + +# Get ziti_version +ziti_version=$(./${filename} -v) +echo "ziti_version: $ziti_version" +# Retrieve the instance metadata to get the public IP +public_ip=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4) +echo ${public_ip} + +# Login to ziti: +echo "Logging in to Ziti" +./ziti-${ziti_version} edge login ${public_ip}:1280 -y -u admin -p admin +echo "Ziti Edge Login Completed" + +# Add config variables for the intercept.v1 and host.v1 config types +json_response=$(./ziti-${ziti_version} edge list configs -j) +interceptv1=$(echo "$json_response" | jq -r '.data[0].id') +hostv1=$(echo "$json_response" | jq -r '.data[1].id') + +# Create some folder and bucket names + +BUCKET_NAME_IDENTITIES="fablab-ziti-identities" +FOLDER_NAME_IDENTITIES="identities-${ziti_version}" +BUCKET_NAME_PKI="fablab-ziti-pki" +FOLDER_NAME_PKI="pki-${ziti_version}" + +#Create folders with code version as suffix: +aws s3api put-object --bucket "$BUCKET_NAME_IDENTITIES" --key "$FOLDER_NAME_IDENTITIES"/ +aws s3api put-object --bucket "$BUCKET_NAME_PKI" --key "$FOLDER_NAME_PKI"/ + +#Copy the full pki directory into s3: +# aws s3 sync s3:/// +aws s3 sync /home/ubuntu/fablab/pki s3://$BUCKET_NAME_PKI/$FOLDER_NAME_PKI + +# Make directory to store identities +mkdir identities-${ziti_version}; chmod 0755 identities-${ziti_version} + +# Set the name of your S3 buckets and folder +BUCKET_NAME_DB="fablab-ziti-databases" + +# Set document path and s3 key of ziti-db +DOCUMENT_PATH_DB="/home/ubuntu/fablab/ctrl.db" +S3_KEY_DB="ctrl.db-${ziti_version}" + +for i in {20000..24000}; do + ./ziti-${ziti_version} edge create service service$i -c ${interceptv1},${hostv1} + ./ziti-${ziti_version} edge create service-policy service${i}Bind Bind --service-roles @service${i} --identity-roles '#iperf-server' + ./ziti-${ziti_version} edge create service-policy service${i}Dial Dial --service-roles @service${i} --identity-roles '#iperf-client' + ./ziti-${ziti_version} edge create serp service${i} --service-roles @service${i} --edge-router-roles '#all' + DOCUMENT_PATH_IDENTITIES="identities-${ziti_version}/identity${i}.json" + S3_KEY_IDENTITIES="identity${i}.json" + if ((i < 20100)); then + ./ziti-${ziti_version} edge create identity user identity${i} -o identities-${ziti_version}/identity${i}.jwt -a 'iperf.service.client.dial.100,iperf.service.client.dial.200,iperf.service.client.dial.300,iperf.service.client.dial.400,iperf.service.client.dial.500,iperf.service.client.dial.1000,iperf.service.client.dial.2000,iperf.service.client.dial.3000,iperf.service.client.dial.4000,iperf.service.client.dial.5000' + ./ziti-${ziti_version} edge enroll identities-${ziti_version}/identity${i}.jwt + aws s3 cp $DOCUMENT_PATH_IDENTITIES s3://$BUCKET_NAME_IDENTITIES/$FOLDER_NAME_IDENTITIES/$S3_KEY_IDENTITIES + sleep ${sleep_time} + elif ((20101 < i < 20200)); then + ./ziti-${ziti_version} edge create identity user identity${i} -o identities-${ziti_version}/identity${i}.jwt -a 'iperf.service.client.dial.200,iperf.service.client.dial.300,iperf.service.client.dial.400,iperf.service.client.dial.500,iperf.service.client.dial.1000,iperf.service.client.dial.2000,iperf.service.client.dial.3000,iperf.service.client.dial.4000,iperf.service.client.dial.5000' + ./ziti-${ziti_version} edge enroll identities-${ziti_version}/identity${i}.jwt + aws s3 cp $DOCUMENT_PATH_IDENTITIES s3://$BUCKET_NAME_IDENTITIES/$FOLDER_NAME_IDENTITIES/$S3_KEY_IDENTITIES + sleep ${sleep_time} + elif ((20201 < i < 20300)); then + ./ziti-${ziti_version} edge create identity user identity${i} -o identities-${ziti_version}/identity${i}.jwt -a 'iperf.service.client.dial.300,iperf.service.client.dial.400,iperf.service.client.dial.500,iperf.service.client.dial.1000,iperf.service.client.dial.2000,iperf.service.client.dial.3000,iperf.service.client.dial.4000,iperf.service.client.dial.5000' + ./ziti-${ziti_version} edge enroll identities-${ziti_version}/identity${i}.jwt + aws s3 cp $DOCUMENT_PATH_IDENTITIES s3://$BUCKET_NAME_IDENTITIES/$FOLDER_NAME_IDENTITIES/$S3_KEY_IDENTITIES + sleep ${sleep_time} + elif ((20301 < i < 20400)); then + ./ziti-${ziti_version} edge create identity user identity${i} -o identities-${ziti_version}/identity${i}.jwt -a 'iperf.service.client.dial.400,iperf.service.client.dial.500,iperf.service.client.dial.1000,iperf.service.client.dial.2000,iperf.service.client.dial.3000,iperf.service.client.dial.4000,iperf.service.client.dial.5000' + ./ziti-${ziti_version} edge enroll identities-${ziti_version}/identity${i}.jwt + aws s3 cp $DOCUMENT_PATH_IDENTITIES s3://$BUCKET_NAME_IDENTITIES/$FOLDER_NAME_IDENTITIES/$S3_KEY_IDENTITIES + sleep ${sleep_time} + elif ((20401 < i < 20500)); then + ./ziti-${ziti_version} edge create identity user identity${i} -o identities-${ziti_version}/identity${i}.jwt -a 'iperf.service.client.dial.500,iperf.service.client.dial.1000,iperf.service.client.dial.2000,iperf.service.client.dial.3000,iperf.service.client.dial.4000,iperf.service.client.dial.5000' + ./ziti-${ziti_version} edge enroll identities-${ziti_version}/identity${i}.jwt + aws s3 cp $DOCUMENT_PATH_IDENTITIES s3://$BUCKET_NAME_IDENTITIES/$FOLDER_NAME_IDENTITIES/$S3_KEY_IDENTITIES + sleep ${sleep_time} + elif ((20501 0 { + servicesCount += identityServiceCount + hostingIdentities[identityId] = identityServiceCount + } + } + + regionCount := len(m.Regions) + + perRegion := servicesCount / regionCount + idIdx := 0 + + avgTunnelsPerHost := 15 + + m.RangeSortedRegions(func(regionId string, region *model.Region) { + regionServiceCount := 0 + + var regionIdentityIds []string + + for { + if idIdx >= len(ids) { + break + } + identityId := ids[idIdx] + idIdx++ + + svcCount, found := hostingIdentities[identityId] + if !found { + continue + } + regionServiceCount += svcCount + regionIdentityIds = append(regionIdentityIds, identityId) + if regionServiceCount > perRegion { + break + } + } + + hostCount := len(regionIdentityIds) / avgTunnelsPerHost + var hosts []*model.Host + + for i := 0; i < hostCount; i++ { + tunnelsHost := &model.Host{ + Scope: model.Scope{Tags: model.Tags{}}, + Region: region, + Components: model.Components{}, + InstanceType: "t3.medium", + } + hostId := fmt.Sprintf("%s_svc_hosts_%v", regionId, i) + region.Hosts[hostId] = tunnelsHost + hosts = append(hosts, tunnelsHost) + } + + hostIdx := 0 + for _, identityId := range regionIdentityIds { + tunnelHost := hosts[hostIdx%len(hosts)] + hostIdx++ + + svcCount := hostingIdentities[identityId] + + tunnelComponent := &model.Component{ + Scope: model.Scope{Tags: model.Tags{"sdk-tunneler", "pre-created", fmt.Sprintf("serviceCount=%v", svcCount)}}, + Type: &zitilab.ZitiTunnelType{ + Mode: zitilab.ZitiTunnelModeHost, + Version: TargetZitiVersion, + }, + Host: tunnelHost, + } + tunnelHost.Components[identityId] = tunnelComponent + } + }) + + return nil +} + +var dbStrategyInstance = dbStrategy{} + +var m = &model.Model{ + Id: "router-test", + Scope: model.Scope{ + Defaults: model.Variables{ + "environment": "sdk-hosting-test", + "credentials": model.Variables{ + "aws": model.Variables{ + "managed_key": true, + }, + "ssh": model.Variables{ + "username": "ubuntu", + }, + "edge": model.Variables{ + "username": "admin", + "password": "admin", + }, + }, + "metrics": model.Variables{ + "influxdb": model.Variables{ + "url": "http://localhost:8086", + "db": "ziti", + }, + }, + }, + }, + StructureFactories: []model.Factory{ + model.NewScaleFactoryWithDefaultEntityFactory(scaleStrategy{}), + &models.ZitiDbBuilder{Strategy: dbStrategyInstance}, + }, + Resources: model.Resources{ + resources.Configs: resources.SubFolder(configResource, "configs"), + resources.Binaries: os.DirFS(path.Join(os.Getenv("GOPATH"), "bin")), + resources.Terraform: test_resources.TerraformResources(), + }, + Regions: model.Regions{ + "us-east-1": { + Region: "us-east-1", + Site: "us-east-1a", + Hosts: model.Hosts{ + "ctrl": { + InstanceType: "c5.large", + Components: model.Components{ + "ctrl": { + Scope: model.Scope{Tags: model.Tags{"ctrl"}}, + Type: &zitilab.ControllerType{ + Version: TargetZitiVersion, + }, + }, + }, + }, + }, + }, + }, + + Actions: model.ActionBinders{ + "bootstrap": model.ActionBinder(func(m *model.Model) model.Action { + workflow := actions.Workflow() + + //workflow.AddAction(component.Stop("*")) + //workflow.AddAction(host.GroupExec("*", 25, "rm -f logs/*")) + + workflow.AddAction(component.Start("#ctrl")) + workflow.AddAction(semaphore.Sleep(2 * time.Second)) + + workflow.AddAction(edge.Login("#ctrl")) + + workflow.AddAction(edge.ReEnrollEdgeRouters(".edge-router .pre-created", 2)) + workflow.AddAction(edge.ReEnrollIdentities(".sdk-tunneler .pre-created", 10)) + return workflow + }), + "stop": model.Bind(component.StopInParallelHostExclusive("*", 15)), + "clean": model.Bind(actions.Workflow( + component.StopInParallelHostExclusive("*", 15), + host.GroupExec("*", 25, "rm -f logs/*"), + )), + "login": model.Bind(edge.Login("#ctrl")), + }, + + Infrastructure: model.Stages{ + aws_ssh_key.Express(), + &terraform_0.Terraform{ + Retries: 3, + ReadyCheck: &semaphore_0.ReadyStage{ + MaxWait: 90 * time.Second, + }, + }, + }, + + Distribution: model.Stages{ + distribution.DistributeSshKey("*"), + distribution.Locations("*", "logs"), + rsync.RsyncStaged(), + model.StageActionF(func(run model.Run) error { + dbFile := dbStrategyInstance.GetDbFile(run.GetModel()) + deferred := rsync.NewRsyncHost("#ctrl", dbFile, "/home/ubuntu/fablab/ctrl.db") + return deferred.Execute(run) + }), + }, + + Disposal: model.Stages{ + terraform.Dispose(), + aws_ssh_key2.Dispose(), + }, +} + +func main() { + m.AddActivationActions("stop", "bootstrap") + + model.AddBootstrapExtension(binding.AwsCredentialsLoader) + model.AddBootstrapExtension(aws_ssh_key.KeyManager) + + fablab.InitModel(m) + fablab.Run() +} diff --git a/zititest/models/simple/actions/start.go b/zititest/models/simple/actions/start.go index a1220c129..e26447762 100644 --- a/zititest/models/simple/actions/start.go +++ b/zititest/models/simple/actions/start.go @@ -28,11 +28,8 @@ import ( "github.com/openziti/ziti/zititest/zitilab/models" ) -func NewStartAction(metricbeat MetricbeatConfig, consul ConsulConfig) model.ActionBinder { - action := &startAction{ - Metricbeat: metricbeat, - Consul: consul, - } +func NewStartAction() model.ActionBinder { + action := &startAction{} return action.bind } @@ -43,9 +40,6 @@ func (a *startAction) bind(m *model.Model) model.Action { workflow.AddAction(component.StartInParallel(models.EdgeRouterTag, 25)) workflow.AddAction(component.StartInParallel(".iperf", 5)) - workflow.AddAction(semaphore.Sleep(2 * time.Second)) - workflow.AddAction(zitilib_actions.StartMetricbeat("*", a.Metricbeat.ConfigPath, a.Metricbeat.DataPath, a.Metricbeat.LogPath)) - workflow.AddAction(zitilib_actions.StartConsul("*", a.Consul.ServerAddr, a.Consul.ConfigDir, a.Consul.DataPath, a.Consul.LogPath)) workflow.AddAction(semaphore.Sleep(2 * time.Second)) workflow.AddAction(component.StartInParallel(".sdk-app", 5)) @@ -56,20 +50,4 @@ func (a *startAction) bind(m *model.Model) model.Action { return workflow } -type startAction struct { - Metricbeat MetricbeatConfig - Consul ConsulConfig -} - -type MetricbeatConfig struct { - ConfigPath string - DataPath string - LogPath string -} - -type ConsulConfig struct { - ConfigDir string - ServerAddr string - DataPath string - LogPath string -} +type startAction struct{} diff --git a/zititest/models/simple/configs/consul.hcl b/zititest/models/simple/configs/consul.hcl deleted file mode 100644 index 0f333bb3b..000000000 --- a/zititest/models/simple/configs/consul.hcl +++ /dev/null @@ -1,24 +0,0 @@ -datacenter = "ziti-build-metrics" -data_dir = "/opt/consul" -encrypt = "${encryption_key}" -advertise_addr="${public_ip}" - - -tls { - defaults { - verify_incoming = false - verify_outgoing = true - - ca_file="consul/consul-agent-ca.pem" - } -} - -auto_encrypt { - tls = true -} - -acl { - enabled = true - default_policy = "allow" - enable_token_persistence = true -} diff --git a/zititest/models/simple/configs/elasticsearch.repo b/zititest/models/simple/configs/elasticsearch.repo deleted file mode 100644 index e90d3f65d..000000000 --- a/zititest/models/simple/configs/elasticsearch.repo +++ /dev/null @@ -1,8 +0,0 @@ -[logstash-6.x] -name=Elastic repository for 6.x packages -baseurl=https://artifacts.elastic.co/packages/6.x/yum -gpgcheck=1 -gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch -enabled=1 -autorefresh=1 -type=rpm-md \ No newline at end of file diff --git a/zititest/models/simple/configs/metricbeat.yml b/zititest/models/simple/configs/metricbeat.yml deleted file mode 100644 index 35c1cc9f6..000000000 --- a/zititest/models/simple/configs/metricbeat.yml +++ /dev/null @@ -1,53 +0,0 @@ -fields_under_root: true -fields: - build_number: ${build_number} - ziti_version: ${ziti_version} - -processors: - - add_cloud_metadata: ~ - -metricbeat.modules: -- module: system - metricsets: - - cpu # CPU usage - - load # CPU load averages - - memory # Memory usage - - network # Network IO - enabled: true - period: 30s - cpu.metrics: ["percentages"] # The other available options are normalized_percentages and ticks. - core.metrics: ["percentages"] # The other available option is ticks. -#- module: docker -# metricsets: -# - "container" -# - "cpu" -# - "diskio" -# - "healthcheck" -# - "info" -# - "image" -# - "memory" -# - "network" -# hosts: ["unix:///var/run/docker.sock"] -# period: 30s -# enabled: true -# # If set to true, replace dots in labels with `_`. -# labels.dedot: true - - -output.elasticsearch: - # Array of hosts to connect to. - hosts: ["${host}"] - - # Optional protocol and basic auth credentials. - protocol: "https" - username: "${user}" - password: "${password}" - index: 'zt-%{[agent.version]}-%{+yyyy.MM.dd}' - -setup.template.enabled: true -setup.template.name: 'zt-%{[agent.version]}' -setup.template.pattern: 'zt-%{[agent.version]}-*' -setup.template.fields: "/etc/metricbeat/fields.yml" -setup.template.settings: - index.number_of_shards: 1 - index.codec: best_compression \ No newline at end of file diff --git a/zititest/models/simple/simple.go b/zititest/models/simple/simple.go index dee895868..880bee875 100644 --- a/zititest/models/simple/simple.go +++ b/zititest/models/simple/simple.go @@ -18,7 +18,6 @@ package simple import ( "embed" - "fmt" "github.com/michaelquigley/pfxlog" "github.com/openziti/fablab/kernel/lib/actions/component" "github.com/openziti/fablab/kernel/lib/binding" @@ -35,22 +34,15 @@ import ( "github.com/openziti/ziti/zititest/models/test_resources" "github.com/openziti/ziti/zititest/zitilab" "github.com/openziti/ziti/zititest/zitilab/actions/edge" - "github.com/sirupsen/logrus" "os" "time" ) +const ZitiEdgeTunnelVersion = "v0.22.12" + //go:embed configs var configResource embed.FS -func getConfigData(filePath string) []byte { - data, err := configResource.ReadFile(fmt.Sprintf("configs/%s", filePath)) - if err != nil { - logrus.Errorf("Unable to read config data from %s: [%s]", filePath, err) - } - return data -} - func getUniqueId() string { if runId := os.Getenv("GITHUB_RUN_ID"); runId != "" { return "-" + runId + "." + os.Getenv("GITHUB_RUN_ATTEMPT") @@ -101,6 +93,29 @@ var Model = &model.Model{ return nil }) }), + + model.FactoryFunc(func(m *model.Model) error { + zetPath, useLocalPath := m.GetStringVariable("local_zet_path") + return m.ForEachComponent("*", 1, func(c *model.Component) error { + if c.Type == nil { + return nil + } + + if zet, ok := c.Type.(*zitilab.ZitiEdgeTunnelType); ok { + if useLocalPath { + zet.Version = "" + zet.LocalPath = zetPath + } else { + zet.Version = ZitiEdgeTunnelVersion + zet.LocalPath = "" + } + zet.InitType(c) + return nil + } + + return nil + }) + }), }, Resources: model.Resources{ @@ -156,7 +171,7 @@ var Model = &model.Model{ "ziti-edge-tunnel-client": { Scope: model.Scope{Tags: model.Tags{"sdk-app", "client"}}, Type: &zitilab.ZitiEdgeTunnelType{ - Version: "v0.21.4", + Version: ZitiEdgeTunnelVersion, }, }, }, @@ -206,7 +221,7 @@ var Model = &model.Model{ "ziti-edge-tunnel-host": { Scope: model.Scope{Tags: model.Tags{"sdk-app", "host", "zet-host"}}, Type: &zitilab.ZitiEdgeTunnelType{ - Version: "v0.21.4", + Version: ZitiEdgeTunnelVersion, }, }, "iperf-server-zet": { @@ -235,19 +250,9 @@ var Model = &model.Model{ Actions: model.ActionBinders{ "bootstrap": actions.NewBootstrapAction(), - "start": actions.NewStartAction(actions.MetricbeatConfig{ - ConfigPath: "metricbeat", - DataPath: "metricbeat/data", - LogPath: "metricbeat/logs", - }, - actions.ConsulConfig{ - ServerAddr: os.Getenv("CONSUL_ENDPOINT"), - ConfigDir: "consul", - DataPath: "consul/data", - LogPath: "consul/log.out", - }), - "stop": model.Bind(component.StopInParallel("*", 15)), - "login": model.Bind(edge.Login("#ctrl1")), + "start": actions.NewStartAction(), + "stop": model.Bind(component.StopInParallel("*", 15)), + "login": model.Bind(edge.Login("#ctrl1")), }, Infrastructure: model.Stages{ @@ -262,68 +267,6 @@ var Model = &model.Model{ Distribution: model.Stages{ distribution.DistributeSshKey("*"), - distribution.Locations("*", "logs"), - distribution.DistributeDataWithReplaceCallbacks( - "*", - string(getConfigData("metricbeat.yml")), - "metricbeat/metricbeat.yml", - os.FileMode(0644), - map[string]func(*model.Host) string{ - "${host}": func(h *model.Host) string { - return os.Getenv("ELASTIC_ENDPOINT") - }, - "${user}": func(h *model.Host) string { - return os.Getenv("ELASTIC_USERNAME") - }, - "${password}": func(h *model.Host) string { - return os.Getenv("ELASTIC_PASSWORD") - }, - "${build_number}": func(h *model.Host) string { - return os.Getenv("BUILD_NUMBER") - }, - "${ziti_version}": func(h *model.Host) string { - return h.MustStringVariable("ziti_version") - }, - }, - ), - - distribution.DistributeDataWithReplaceCallbacks( - "*", - string(getConfigData("consul.hcl")), - "consul/consul.hcl", - os.FileMode(0644), - map[string]func(*model.Host) string{ - "${public_ip}": func(h *model.Host) string { - return h.PublicIp - }, - "${encryption_key}": func(h *model.Host) string { - return os.Getenv("CONSUL_ENCRYPTION_KEY") - }, - "${build_number}": func(h *model.Host) string { - return os.Getenv("BUILD_NUMBER") - }, - "${ziti_version}": func(h *model.Host) string { - return h.MustStringVariable("ziti_version") - }, - }, - ), - distribution.DistributeDataWithReplaceCallbacks( - "#ctrl", - string(getConfigData("ziti.hcl")), - "consul/ziti.hcl", - os.FileMode(0644), - map[string]func(*model.Host) string{ - "${build_number}": func(h *model.Host) string { - return os.Getenv("BUILD_NUMBER") - }, - "${ziti_version}": func(h *model.Host) string { - return h.MustStringVariable("ziti_version") - }, - }), - distribution.DistributeData( - "*", - []byte(os.Getenv("CONSUL_AGENT_CERT")), - "consul/consul-agent-ca.pem"), rsync.RsyncStaged(), }, diff --git a/zititest/tests/echo_test.go b/zititest/tests/echo_test.go index 4aa844f59..bed362f36 100644 --- a/zititest/tests/echo_test.go +++ b/zititest/tests/echo_test.go @@ -19,7 +19,6 @@ package tests import ( "fmt" "github.com/google/uuid" - "github.com/openziti/fablab/kernel/lib" "github.com/stretchr/testify/require" "strings" "testing" @@ -37,13 +36,12 @@ func TestSdkEcho(t *testing.T) { } for _, c := range components { - ssh := lib.NewSshConfigFactory(c.GetHost()) remoteConfigFile := "/home/ubuntu/fablab/cfg/" + c.Id + ".json" echoClientCmd := fmt.Sprintf(`echo "%s" | /home/%s/fablab/bin/ziti demo zcat --identity %s ziti:echo 2>&1`, - string(data), ssh.User(), remoteConfigFile) + string(data), c.GetHost().GetSshUser(), remoteConfigFile) - output, err := lib.RemoteExec(ssh, echoClientCmd) + output, err := c.GetHost().ExecLogged(echoClientCmd) t.Logf("test output:\n%s", output) req.NoError(err) //trim the newline ssh added diff --git a/zititest/tests/files_test.go b/zititest/tests/files_test.go index 562025bd4..660cb6027 100644 --- a/zititest/tests/files_test.go +++ b/zititest/tests/files_test.go @@ -18,7 +18,9 @@ package tests import ( "fmt" + "github.com/google/uuid" "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" "github.com/stretchr/testify/require" "testing" @@ -52,7 +54,7 @@ func TestDownloadFiles(t *testing.T) { t.Run("test-ert-downloads", func(t *testing.T) { t.Parallel() - for _, size := range []string{"1KB", "100KB", "20MB"} { + for _, size := range []string{"1KB" /* "100KB", "20MB"*/} { for _, hostType := range []string{"ert", "zet", "ziti-tunnel"} { for _, client := range []httpClient{ClientCurl, ClientWget} { for _, encrypted := range []bool{true, false} { @@ -117,7 +119,7 @@ func testFileDownload(t *testing.T, hostSelector string, client httpClient, host success := false - t.Run(fmt.Sprintf("%v-(%s->%s)-%s-%v", client, hostSelector, hostType, fileSize, encDesk), func(t *testing.T) { + t.Run(fmt.Sprintf("%v-(%s<-%s)-%s-%v", client, hostSelector, hostType, fileSize, encDesk), func(t *testing.T) { host, err := model.GetModel().SelectHost("." + hostSelector + "-client") req := require.New(t) req.NoError(err) @@ -130,15 +132,24 @@ func testFileDownload(t *testing.T, hostSelector string, client httpClient, host url := fmt.Sprintf("https://files-%s%s.s3-us-west-1.amazonaws.ziti/%s.zip", hostType, urlExtra, fileSize) sshConfigFactory := lib.NewSshConfigFactory(host) + filename := uuid.NewString() + + var cmds []string + cmds = append(cmds, fmt.Sprintf("echo '%s %s' > checksums", hashes[fileSize], filename)) + var cmd string if client == ClientCurl { - cmd = fmt.Sprintf(`set -o pipefail; curl -k --header "Host: ziti-smoketest-files.s3-us-west-1.amazonaws.com" -fSL -o - %s | md5sum`, url) + cmd = fmt.Sprintf(`set -o pipefail; curl -k --header "Host: ziti-smoketest-files.s3-us-west-1.amazonaws.com" --fail-early --fail-with-body -SL -o %s %s`, filename, url) } else if client == ClientWget { - cmd = fmt.Sprintf(`set -o pipefail; wget --no-check-certificate --header "Host: ziti-smoketest-files.s3-us-west-1.amazonaws.com" -O - -t 5 -T 5 %s | md5sum`, url) + cmd = fmt.Sprintf(`set -o pipefail; wget --no-check-certificate --header "Host: ziti-smoketest-files.s3-us-west-1.amazonaws.com" -O %s -t 5 -T 5 %s`, filename, url) } + cmds = append(cmds, cmd) + cmds = append(cmds, "md5sum -c checksums") timeout := timeouts[fileSize] - o, err := lib.RemoteExecAllWithTimeout(sshConfigFactory, timeout, cmd) + o, err := libssh.RemoteExecAllWithTimeout(sshConfigFactory, timeout, cmds...) + t.Log(o) + if hostType == "zet" && err != nil { t.Skipf("zet hosted file transfer failed [%v]", err.Error()) return @@ -149,9 +160,7 @@ func testFileDownload(t *testing.T, hostSelector string, client httpClient, host return } - t.Log(o) req.NoError(err) - req.Equal(hashes[fileSize], o[0:32]) success = true }) return success diff --git a/zititest/tests/iperf_test.go b/zititest/tests/iperf_test.go index 1d339b861..91d139843 100644 --- a/zititest/tests/iperf_test.go +++ b/zititest/tests/iperf_test.go @@ -19,6 +19,7 @@ package tests import ( "fmt" "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" "github.com/stretchr/testify/require" "testing" @@ -98,7 +99,7 @@ func testIPerf(t *testing.T, hostSelector string, hostType string, encrypted boo cmd := fmt.Sprintf(`set -o pipefail; iperf3 -c %s -P 1 -t 10 %s`, addr, extraOptions) sshConfigFactory := lib.NewSshConfigFactory(host) - o, err := lib.RemoteExecAllWithTimeout(sshConfigFactory, 20*time.Second, cmd) + o, err := libssh.RemoteExecAllWithTimeout(sshConfigFactory, 20*time.Second, cmd) if hostType == "zet" && err != nil { t.Skipf("zet hosted iperf test failed [%v]", err.Error()) return diff --git a/zititest/tests/scp_test.go b/zititest/tests/scp_test.go index 6cc39f7ae..cde67deb2 100644 --- a/zititest/tests/scp_test.go +++ b/zititest/tests/scp_test.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/google/uuid" "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" "github.com/stretchr/testify/require" "testing" @@ -75,9 +76,7 @@ func TestScp(t *testing.T) { req := require.New(t) req.False(allZetHostedFailed, "all zet hosted file transfer should not failed, indicates bigger issue") - - // TODO: fix once ZET client tests are working - req.True(allZetClientsFailed, "all zet client file transfers should not failed, indicates bigger issue") + req.False(allZetClientsFailed, "all zet client file transfers should not failed, indicates bigger issue") } func testScp(t *testing.T, hostSelector string, hostType string, encrypted bool) bool { @@ -88,40 +87,44 @@ func testScp(t *testing.T, hostSelector string, hostType string, encrypted bool) success := false - t.Run(fmt.Sprintf("(%s->%s)-%v", hostSelector, hostType, encDesk), func(t *testing.T) { - if hostSelector == "zet" { - t.Skipf("zet is currently failing as client") - } - host, err := model.GetModel().SelectHost("." + hostSelector + "-client") - req := require.New(t) - req.NoError(err) - - nameExtra := "" - if !encrypted { - nameExtra = "-unencrypted" - } - - sshConfigFactory := lib.NewSshConfigFactory(host) - - cmds := []string{ - fmt.Sprintf("scp -o StrictHostKeyChecking=no ssh-%s%s.ziti:./fablab/bin/ziti /tmp/ziti-%s", hostType, nameExtra, uuid.NewString()), - fmt.Sprintf("scp -o StrictHostKeyChecking=no ./fablab/bin/ziti ssh-%s%s.ziti:/tmp/ziti-%s", hostType, nameExtra, uuid.NewString()), - } - - o, err := lib.RemoteExecAllWithTimeout(sshConfigFactory, 30*time.Second, cmds...) - if hostType == "zet" && err != nil { - t.Skipf("zet hosted ssh failed [%v]", err.Error()) - return - } - - if hostSelector == "zet" && err != nil { - t.Skipf("zet client ssh failed [%v]", err.Error()) - return - } - - t.Log(o) - req.NoError(err) - success = true - }) + nameExtra := "" + if !encrypted { + nameExtra = "-unencrypted" + } + + tests := []struct { + direction string + cmd string + }{ + { + direction: "<-", + cmd: fmt.Sprintf("scp -o StrictHostKeyChecking=no scp://ssh-%s%s.ziti:2022/fablab/bin/ziti /tmp/ziti-%s", hostType, nameExtra, uuid.NewString()), + }, { + direction: "->", + cmd: fmt.Sprintf("scp -o StrictHostKeyChecking=no ./fablab/bin/ziti scp://ssh-%s%s.ziti:2022//tmp/ziti-%s", hostType, nameExtra, uuid.NewString()), + }, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("(%s%s%s)-%v", hostSelector, test.direction, hostType, encDesk), func(t *testing.T) { + host, err := model.GetModel().SelectHost("." + hostSelector + "-client") + req := require.New(t) + req.NoError(err) + + sshConfigFactory := lib.NewSshConfigFactory(host) + + o, err := libssh.RemoteExecAllWithTimeout(sshConfigFactory, 50*time.Second, test.cmd) + if hostType == "zet" && err != nil { + t.Skipf("zet hosted ssh failed [%v]", err.Error()) + } else if hostSelector == "zet" && err != nil { + t.Skipf("zet client ssh failed [%v]", err.Error()) + } else { + t.Log(o) + req.NoError(err) + success = true + } + }) + } + return success } diff --git a/zititest/zitilab/actions/consul.go b/zititest/zitilab/actions/consul.go index eef623a9b..883ef89a4 100644 --- a/zititest/zitilab/actions/consul.go +++ b/zititest/zitilab/actions/consul.go @@ -2,8 +2,8 @@ package zitilib_actions import ( "fmt" + "github.com/openziti/fablab/kernel/libssh" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" ) @@ -27,12 +27,12 @@ func StartConsul(hostSpec, consulServer, configDir, dataPath, logFile string) mo } func (cs *consulStart) Execute(run model.Run) error { - return run.GetModel().ForEachHost(cs.hostSpec, 24, func(c *model.Host) error { - ssh := lib.NewSshConfigFactory(c) + return run.GetModel().ForEachHost(cs.hostSpec, 24, func(host *model.Host) error { + ssh := host.NewSshConfigFactory() cmd := fmt.Sprintf("screen -d -m nohup consul agent -join %s -config-dir %s -data-dir %s -log-file %s 2>&1 &", cs.consulServer, cs.configDir, cs.dataPath, cs.logFile) - if output, err := lib.RemoteExec(ssh, cmd); err != nil { + if output, err := libssh.RemoteExec(ssh, cmd); err != nil { logrus.Errorf("error starting consul service [%s] (%v)", output, err) return err } diff --git a/zititest/zitilab/actions/edge/ctrl_init.go b/zititest/zitilab/actions/edge/ctrl_init.go index 823798de5..fa4cb0faf 100644 --- a/zititest/zitilab/actions/edge/ctrl_init.go +++ b/zititest/zitilab/actions/edge/ctrl_init.go @@ -2,7 +2,6 @@ package edge import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/lib/actions/component" "github.com/openziti/fablab/kernel/lib/actions/host" "github.com/openziti/fablab/kernel/model" @@ -44,7 +43,7 @@ func (init *raftInit) Execute(run model.Run) error { } for _, c := range m.SelectComponents(init.componentSpec) { - sshConfigFactory := lib.NewSshConfigFactory(c.GetHost()) + sshConfigFactory := c.GetHost().NewSshConfigFactory() tmpl := "set -o pipefail; /home/%s/fablab/bin/ziti agent controller init %s %s default.admin 2>&1 | tee logs/controller.edge.init.log" if err := host.Exec(c.GetHost(), fmt.Sprintf(tmpl, sshConfigFactory.User(), username, password)).Execute(run); err != nil { diff --git a/zititest/zitilab/actions/edge/init_identities.go b/zititest/zitilab/actions/edge/init_identities.go index 8c8192fc5..3eae38a20 100644 --- a/zititest/zitilab/actions/edge/init_identities.go +++ b/zititest/zitilab/actions/edge/init_identities.go @@ -1,7 +1,7 @@ package edge import ( - "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" zitilib_actions "github.com/openziti/ziti/zititest/zitilab/actions" "github.com/openziti/ziti/zititest/zitilab/cli" @@ -27,7 +27,7 @@ func (action *initIdentitiesAction) Execute(run model.Run) error { } func (action *initIdentitiesAction) createAndEnrollIdentity(run model.Run, c *model.Component) error { - ssh := lib.NewSshConfigFactory(c.GetHost()) + ssh := c.GetHost().NewSshConfigFactory() jwtFileName := filepath.Join(run.GetTmpDir(), c.Id+".jwt") @@ -48,7 +48,7 @@ func (action *initIdentitiesAction) createAndEnrollIdentity(run model.Run, c *mo } remoteConfigFile := "/home/ubuntu/fablab/cfg/" + c.Id + ".json" - return lib.SendFile(ssh, configFileName, remoteConfigFile) + return libssh.SendFile(ssh, configFileName, remoteConfigFile) } type initIdentitiesAction struct { diff --git a/zititest/zitilab/actions/edge/raft_join.go b/zititest/zitilab/actions/edge/raft_join.go index f3c3676f4..ffca42194 100644 --- a/zititest/zitilab/actions/edge/raft_join.go +++ b/zititest/zitilab/actions/edge/raft_join.go @@ -2,7 +2,6 @@ package edge import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/lib/actions/host" "github.com/openziti/fablab/kernel/model" "github.com/pkg/errors" @@ -24,7 +23,7 @@ func (self *raftJoin) Execute(run model.Run) error { return errors.Errorf("no controllers found with spec '%v'", self.componentSpec) } primary := ctrls[0] - sshConfigFactory := lib.NewSshConfigFactory(primary.GetHost()) + sshConfigFactory := primary.GetHost().NewSshConfigFactory() for _, c := range ctrls[1:] { tmpl := "/home/%s/fablab/bin/ziti agent cluster add %v --id %v" if err := host.Exec(primary.GetHost(), fmt.Sprintf(tmpl, sshConfigFactory.User(), "tls:"+c.Host.PublicIp+":6262", c.Id)).Execute(run); err != nil { diff --git a/zititest/zitilab/actions/edge/reenroll_identities.go b/zititest/zitilab/actions/edge/reenroll_identities.go new file mode 100644 index 000000000..67948d3b9 --- /dev/null +++ b/zititest/zitilab/actions/edge/reenroll_identities.go @@ -0,0 +1,23 @@ +package edge + +import ( + "github.com/openziti/fablab/kernel/lib/actions/component" + "github.com/openziti/fablab/kernel/model" + "github.com/openziti/ziti/zititest/zitilab" +) + +func ReEnrollIdentities(componentSpec string, concurrency int) model.Action { + return &reEnrollIdentitiesAction{ + componentSpec: componentSpec, + concurrency: concurrency, + } +} + +func (action *reEnrollIdentitiesAction) Execute(run model.Run) error { + return component.ExecInParallel(action.componentSpec, action.concurrency, zitilab.ZitiTunnelActionsReEnroll).Execute(run) +} + +type reEnrollIdentitiesAction struct { + componentSpec string + concurrency int +} diff --git a/zititest/zitilab/actions/logs.go b/zititest/zitilab/actions/logs.go index a51dadb62..b3b63d81c 100644 --- a/zititest/zitilab/actions/logs.go +++ b/zititest/zitilab/actions/logs.go @@ -18,10 +18,10 @@ package zitilib_actions import ( "fmt" + "github.com/openziti/fablab/kernel/libssh" "os" "path/filepath" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/openziti/foundation/v2/info" "github.com/sirupsen/logrus" @@ -39,7 +39,7 @@ func (self *logs) Execute(run model.Run) error { snapshot := fmt.Sprintf("%d", info.NowInMilliseconds()) for rn, r := range run.GetModel().Regions { for hn, h := range r.Hosts { - ssh := lib.NewSshConfigFactory(h) + ssh := h.NewSshConfigFactory() if err := self.forHost(snapshot, rn, hn, ssh); err != nil { return fmt.Errorf("error retrieving logs for [%s/%s] (%w)", rn, hn, err) } @@ -48,14 +48,14 @@ func (self *logs) Execute(run model.Run) error { return nil } -func (self *logs) forHost(snapshot, rn, hn string, ssh lib.SshConfigFactory) error { +func (self *logs) forHost(snapshot, rn, hn string, ssh libssh.SshConfigFactory) error { path := filepath.Join(model.AllocateForensicScenario(snapshot, "logs"), rn, hn) if err := os.MkdirAll(path, os.ModePerm); err != nil { return fmt.Errorf("error creating logs path [%s] for host [%s/%s] (%w)", path, rn, hn, err) } logrus.Infof("=> [%s]", path) - fis, err := lib.RemoteFileList(ssh, ".") + fis, err := libssh.RemoteFileList(ssh, ".") if err != nil { return fmt.Errorf("error retrieving home directory for host [%s/%s] (%w)", rn, hn, err) } @@ -76,8 +76,8 @@ func (self *logs) forHost(snapshot, rn, hn string, ssh lib.SshConfigFactory) err return nil } -func (self *logs) forHostDir(localPath, remotePath string, ssh lib.SshConfigFactory) error { - fis, err := lib.RemoteFileList(ssh, remotePath) +func (self *logs) forHostDir(localPath, remotePath string, ssh libssh.SshConfigFactory) error { + fis, err := libssh.RemoteFileList(ssh, remotePath) if err != nil { return err } @@ -97,7 +97,7 @@ func (self *logs) forHostDir(localPath, remotePath string, ssh lib.SshConfigFact paths = append(paths, filepath.Join(remotePath, fi.Name())) } } - if err := lib.RetrieveRemoteFiles(ssh, localPath, paths...); err != nil { + if err := libssh.RetrieveRemoteFiles(ssh, localPath, paths...); err != nil { return fmt.Errorf("error retrieving from [%s] (%w)", localPath, err) } return nil diff --git a/zititest/zitilab/actions/metricbeat.go b/zititest/zitilab/actions/metricbeat.go index 79ec78121..dd834e9dc 100644 --- a/zititest/zitilab/actions/metricbeat.go +++ b/zititest/zitilab/actions/metricbeat.go @@ -2,8 +2,8 @@ package zitilib_actions import ( "fmt" + "github.com/openziti/fablab/kernel/libssh" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" ) @@ -25,12 +25,12 @@ func StartMetricbeat(hostSpec, configPath, dataPath, logPath string) model.Actio } func (mbs *metricbeatStart) Execute(run model.Run) error { - return run.GetModel().ForEachHost(mbs.hostSpec, 24, func(c *model.Host) error { - ssh := lib.NewSshConfigFactory(c) + return run.GetModel().ForEachHost(mbs.hostSpec, 24, func(host *model.Host) error { + ssh := host.NewSshConfigFactory() cmd := fmt.Sprintf("screen -d -m nohup metricbeat --path.config %s --path.data %s --path.logs %s 2>&1 &", mbs.configPath, mbs.dataPath, mbs.logPath) - if output, err := lib.RemoteExec(ssh, cmd); err != nil { + if output, err := libssh.RemoteExec(ssh, cmd); err != nil { logrus.Errorf("error starting metricbeat service [%s] (%v)", output, err) return err } diff --git a/zititest/zitilab/actions/stop_all.go b/zititest/zitilab/actions/stop_all.go new file mode 100644 index 000000000..3e75a1268 --- /dev/null +++ b/zititest/zitilab/actions/stop_all.go @@ -0,0 +1,43 @@ +/* + Copyright 2019 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 zitilib_actions + +import ( + "github.com/openziti/fablab/kernel/model" +) + +func StopAll(hostSpec string) model.Action { + return StopAllInParallel(hostSpec, 1) +} + +func StopAllInParallel(hostSpec string, concurrency int) model.Action { + return &stopAll{ + hostSpec: hostSpec, + concurrency: concurrency, + } +} + +func (stop *stopAll) Execute(run model.Run) error { + return run.GetModel().ForEachHost(stop.hostSpec, stop.concurrency, func(c *model.Host) error { + return nil + }) +} + +type stopAll struct { + hostSpec string + concurrency int +} diff --git a/zititest/zitilab/component_common.go b/zititest/zitilab/component_common.go index f30216a9d..7d4df7474 100644 --- a/zititest/zitilab/component_common.go +++ b/zititest/zitilab/component_common.go @@ -18,9 +18,10 @@ package zitilab import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" + zitilib_actions "github.com/openziti/ziti/zititest/zitilab/actions" "github.com/sirupsen/logrus" + "path/filepath" "strings" ) @@ -39,11 +40,11 @@ func startZitiComponent(c *model.Component, zitiType string, version string, con binaryName += "-" + version } - factory := lib.NewSshConfigFactory(c.GetHost()) + user := c.GetHost().GetSshUser() - binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", factory.User(), binaryName) - configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s", factory.User(), configName) - logsPath := fmt.Sprintf("/home/%s/logs/%s.log", factory.User(), c.Id) + binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", user, binaryName) + configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s", user, configName) + logsPath := fmt.Sprintf("/home/%s/logs/%s.log", user, c.Id) useSudo := "" if zitiType == "tunnel" || c.HasTag("tunneler") { @@ -53,7 +54,7 @@ func startZitiComponent(c *model.Component, zitiType string, version string, con serviceCmd := fmt.Sprintf("nohup %s %s %s run --log-formatter pfxlog %s --cli-agent-alias %s > %s 2>&1 &", useSudo, binaryPath, zitiType, configPath, c.Id, logsPath) - value, err := lib.RemoteExec(factory, serviceCmd) + value, err := c.GetHost().ExecLogged(serviceCmd) if err != nil { return err } @@ -71,3 +72,31 @@ func getPrefixVersion(version string) string { } return "v" + version } + +func reEnrollIdentity(run model.Run, c *model.Component, binaryName string, configName string) error { + if err := zitilib_actions.EdgeExec(run.GetModel(), "delete", "authenticator", "where", fmt.Sprintf("identity=\"%v\"", c.Id)); err != nil { + return err + } + + if err := zitilib_actions.EdgeExec(run.GetModel(), "delete", "enrollment", "where", fmt.Sprintf("identity=\"%v\"", c.Id)); err != nil { + return err + } + + jwtFileName := filepath.Join(model.ConfigBuild(), c.Id+".jwt") + + args := []string{"create", "enrollment", "ott", "--jwt-output-file", jwtFileName, "--", c.Id} + + if err := zitilib_actions.EdgeExec(c.GetModel(), args...); err != nil { + return err + } + + remoteJwt := "/home/ubuntu/fablab/cfg/" + c.Id + ".jwt" + if err := c.GetHost().SendFile(jwtFileName, remoteJwt); err != nil { + return err + } + + tmpl := "set -o pipefail; /home/ubuntu/fablab/bin/%s edge enroll %s 2>&1 | tee /home/ubuntu/logs/%s.identity.enroll.log " + cmd := fmt.Sprintf(tmpl, binaryName, remoteJwt, c.Id) + + return c.GetHost().ExecLogOnlyOnError(cmd) +} diff --git a/zititest/zitilab/component_controller.go b/zititest/zitilab/component_controller.go index b47a94f72..65e6382c7 100644 --- a/zititest/zitilab/component_controller.go +++ b/zititest/zitilab/component_controller.go @@ -47,7 +47,7 @@ type ControllerType struct { } func (self *ControllerType) InitType(*model.Component) { - if self.Version != "" && !strings.HasPrefix(self.Version, "v") { + if self.Version != "" && self.Version != "latest" && !strings.HasPrefix(self.Version, "v") { self.Version = "v" + self.Version } } @@ -100,8 +100,7 @@ func (self *ControllerType) getProcessFilter(c *model.Component) func(string) bo } func (self *ControllerType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter(c)) if err != nil { return false, err } @@ -113,8 +112,7 @@ func (self *ControllerType) Start(_ model.Run, c *model.Component) error { } func (self *ControllerType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter(c)) } func (self *ControllerType) InitStandalone(run model.Run, c *model.Component) error { @@ -129,7 +127,7 @@ func (self *ControllerType) InitStandalone(run model.Run, c *model.Component) er return errors.New("variable credentials/edge/password must be a string") } - factory := lib.NewSshConfigFactory(c.GetHost()) + factory := c.GetHost().NewSshConfigFactory() binaryName := "ziti" if self.Version != "" { diff --git a/zititest/zitilab/component_echo_server.go b/zititest/zitilab/component_echo_server.go index 0518aa271..b0425c42d 100644 --- a/zititest/zitilab/component_echo_server.go +++ b/zititest/zitilab/component_echo_server.go @@ -2,7 +2,6 @@ package zitilab import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/openziti/ziti/zititest/zitilab/stageziti" "github.com/sirupsen/logrus" @@ -19,7 +18,7 @@ type EchoServerType struct { } func (self *EchoServerType) InitType(*model.Component) { - if self.Version != "" && !strings.HasPrefix(self.Version, "v") { + if self.Version != "" && self.Version != "latest" && !strings.HasPrefix(self.Version, "v") { self.Version = "v" + self.Version } } @@ -41,8 +40,7 @@ func (self *EchoServerType) getProcessFilter(c *model.Component) func(string) bo } func (self *EchoServerType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter(c)) if err != nil { return false, err } @@ -55,16 +53,16 @@ func (self *EchoServerType) Start(_ model.Run, c *model.Component) error { binaryName += "-" + self.Version } - factory := lib.NewSshConfigFactory(c.GetHost()) + user := c.GetHost().GetSshUser() - binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", factory.User(), binaryName) - configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s.json", factory.User(), c.Id) - logsPath := fmt.Sprintf("/home/%s/logs/%s.log", factory.User(), c.Id) + binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", user, binaryName) + configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s.json", user, c.Id) + logsPath := fmt.Sprintf("/home/%s/logs/%s.log", user, c.Id) serviceCmd := fmt.Sprintf("nohup %s demo echo-server -i %s --cli-agent-alias %s > %s 2>&1 &", binaryPath, configPath, c.Id, logsPath) - value, err := lib.RemoteExec(factory, serviceCmd) + value, err := c.GetHost().ExecLogged(serviceCmd) if err != nil { return err } @@ -77,6 +75,5 @@ func (self *EchoServerType) Start(_ model.Run, c *model.Component) error { } func (self *EchoServerType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter(c)) } diff --git a/zititest/zitilab/component_iperf.go b/zititest/zitilab/component_iperf.go index af20df11d..eedac0073 100644 --- a/zititest/zitilab/component_iperf.go +++ b/zititest/zitilab/component_iperf.go @@ -18,7 +18,6 @@ package zitilab import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" "strings" @@ -44,15 +43,14 @@ func (self *IPerfServerType) GetPort() uint16 { return self.Port } -func (self *IPerfServerType) getProcessFilter(*model.Component) func(string) bool { +func (self *IPerfServerType) getProcessFilter() func(string) bool { return func(s string) bool { return strings.Contains(s, fmt.Sprintf("iperf3 -s -p %v", self.GetPort())) } } func (self *IPerfServerType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter()) if err != nil { return false, err } @@ -60,12 +58,11 @@ func (self *IPerfServerType) IsRunning(_ model.Run, c *model.Component) (bool, e } func (self *IPerfServerType) Start(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - - logsPath := fmt.Sprintf("/home/%s/logs/%s.log", factory.User(), c.Id) + user := c.GetHost().GetSshUser() + logsPath := fmt.Sprintf("/home/%s/logs/%s.log", user, c.Id) serviceCmd := fmt.Sprintf("nohup iperf3 -s -p %v > %s 2>&1 &", self.GetPort(), logsPath) - value, err := lib.RemoteExec(factory, serviceCmd) + value, err := c.GetHost().ExecLogged(serviceCmd) if err != nil { return err } @@ -78,6 +75,5 @@ func (self *IPerfServerType) Start(_ model.Run, c *model.Component) error { } func (self *IPerfServerType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter()) } diff --git a/zititest/zitilab/component_router.go b/zititest/zitilab/component_router.go index 965c44447..73d1f1f3f 100644 --- a/zititest/zitilab/component_router.go +++ b/zititest/zitilab/component_router.go @@ -45,7 +45,7 @@ type RouterType struct { } func (self *RouterType) InitType(*model.Component) { - if self.Version != "" && !strings.HasPrefix(self.Version, "v") { + if self.Version != "" && self.Version != "latest" && !strings.HasPrefix(self.Version, "v") { self.Version = "v" + self.Version } } @@ -120,8 +120,7 @@ func (self *RouterType) getProcessFilter(c *model.Component) func(string) bool { } func (self *RouterType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter(c)) if err != nil { return false, err } @@ -133,8 +132,7 @@ func (self *RouterType) Start(_ model.Run, c *model.Component) error { } func (self *RouterType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter(c)) } func (self *RouterType) CreateAndEnroll(run model.Run, c *model.Component) error { @@ -145,8 +143,6 @@ func (self *RouterType) CreateAndEnroll(run model.Run, c *model.Component) error Warn("unable to delete router (may not be present") } - ssh := lib.NewSshConfigFactory(c.GetHost()) - jwtFileName := filepath.Join(run.GetTmpDir(), c.Id+".jwt") attributes := strings.Join(c.Tags, ",") @@ -173,19 +169,17 @@ func (self *RouterType) CreateAndEnroll(run model.Run, c *model.Component) error } remoteJwt := "/home/ubuntu/fablab/cfg/" + c.Id + ".jwt" - if err := lib.SendFile(ssh, jwtFileName, remoteJwt); err != nil { + if err := c.GetHost().SendFile(jwtFileName, remoteJwt); err != nil { return err } tmpl := "set -o pipefail; /home/ubuntu/fablab/bin/%v router enroll /home/ubuntu/fablab/cfg/%s -j %s 2>&1 | tee /home/ubuntu/logs/%s.router.enroll.log " cmd := fmt.Sprintf(tmpl, self.getBinaryName(), self.getConfigName(c), remoteJwt, c.Id) - return host.Exec(c.GetHost(), cmd).Execute(run) + return c.GetHost().ExecLogOnlyOnError(cmd) } -func (self *RouterType) ReEnroll(run model.Run, c *model.Component) error { - ssh := lib.NewSshConfigFactory(c.GetHost()) - +func (self *RouterType) ReEnroll(_ model.Run, c *model.Component) error { jwtFileName := filepath.Join(model.ConfigBuild(), c.Id+".jwt") args := []string{"re-enroll", "edge-router", c.Id, "-j", "--jwt-output-file", jwtFileName} @@ -195,12 +189,12 @@ func (self *RouterType) ReEnroll(run model.Run, c *model.Component) error { } remoteJwt := "/home/ubuntu/fablab/cfg/" + c.Id + ".jwt" - if err := lib.SendFile(ssh, jwtFileName, remoteJwt); err != nil { + if err := c.GetHost().SendFile(jwtFileName, remoteJwt); err != nil { return err } - tmpl := "set -o pipefail; /home/ubuntu/fablab/bin/%s enroll /home/ubuntu/fablab/cfg/%s -j %s 2>&1 | tee /home/ubuntu/logs/%s.router.enroll.log " + tmpl := "set -o pipefail; /home/ubuntu/fablab/bin/%s router enroll /home/ubuntu/fablab/cfg/%s -j %s 2>&1 | tee /home/ubuntu/logs/%s.router.enroll.log " cmd := fmt.Sprintf(tmpl, self.getBinaryName(), self.getConfigName(c), remoteJwt, c.Id) - return host.Exec(c.GetHost(), cmd).Execute(run) + return c.GetHost().ExecLogOnlyOnError(cmd) } diff --git a/zititest/zitilab/component_zcat.go b/zititest/zitilab/component_zcat.go index 84923ec82..d7e5f3645 100644 --- a/zititest/zitilab/component_zcat.go +++ b/zititest/zitilab/component_zcat.go @@ -1,7 +1,6 @@ package zitilab import ( - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/openziti/ziti/zititest/zitilab/stageziti" "strings" @@ -17,7 +16,7 @@ type ZCatType struct { } func (self *ZCatType) InitType(*model.Component) { - if self.Version != "" && !strings.HasPrefix(self.Version, "v") { + if self.Version != "" && self.Version != "latest" && !strings.HasPrefix(self.Version, "v") { self.Version = "v" + self.Version } } @@ -34,15 +33,14 @@ func (self *ZCatType) StageFiles(r model.Run, c *model.Component) error { return stageziti.StageZitiOnce(r, c, self.Version, self.LocalPath) } -func (self *ZCatType) getProcessFilter(c *model.Component) func(string) bool { +func (self *ZCatType) getProcessFilter() func(string) bool { return func(s string) bool { return strings.Contains(s, "ziti") && strings.Contains(s, "zcat ") } } func (self *ZCatType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter()) if err != nil { return false, err } @@ -50,6 +48,5 @@ func (self *ZCatType) IsRunning(_ model.Run, c *model.Component) (bool, error) { } func (self *ZCatType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter()) } diff --git a/zititest/zitilab/component_ziti_edge_tunnel.go b/zititest/zitilab/component_ziti_edge_tunnel.go index eee4694db..b0948b52d 100644 --- a/zititest/zitilab/component_ziti_edge_tunnel.go +++ b/zititest/zitilab/component_ziti_edge_tunnel.go @@ -18,7 +18,6 @@ package zitilab import ( "fmt" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/openziti/ziti/zititest/zitilab/stageziti" "github.com/sirupsen/logrus" @@ -68,8 +67,7 @@ func (self *ZitiEdgeTunnelType) getProcessFilter(c *model.Component) func(string } func (self *ZitiEdgeTunnelType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter(c)) if err != nil { return false, err } @@ -77,15 +75,15 @@ func (self *ZitiEdgeTunnelType) IsRunning(_ model.Run, c *model.Component) (bool } func (self *ZitiEdgeTunnelType) Start(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) + user := c.GetHost().GetSshUser() - binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", factory.User(), self.getBinaryName()) - configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s.json", factory.User(), c.Id) - logsPath := fmt.Sprintf("/home/%s/logs/%s.log", factory.User(), c.Id) + binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", user, self.getBinaryName()) + configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s.json", user, c.Id) + logsPath := fmt.Sprintf("/home/%s/logs/%s.log", user, c.Id) - serviceCmd := fmt.Sprintf("nohup sudo %s run -i %s > %s 2>&1 &", binaryPath, configPath, logsPath) + serviceCmd := fmt.Sprintf("sudo %s run -i %s > %s 2>&1 &", binaryPath, configPath, logsPath) - value, err := lib.RemoteExec(factory, serviceCmd) + value, err := c.GetHost().ExecLogged(serviceCmd) if err != nil { return err } @@ -98,6 +96,5 @@ func (self *ZitiEdgeTunnelType) Start(_ model.Run, c *model.Component) error { } func (self *ZitiEdgeTunnelType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillFilterF(factory, self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-TERM", self.getProcessFilter(c)) } diff --git a/zititest/zitilab/component_ziti_tunnel.go b/zititest/zitilab/component_ziti_tunnel.go index 6036e3b84..b76151db0 100644 --- a/zititest/zitilab/component_ziti_tunnel.go +++ b/zititest/zitilab/component_ziti_tunnel.go @@ -18,8 +18,6 @@ package zitilab import ( "fmt" - "github.com/openziti/fablab/kernel/lib" - "github.com/openziti/fablab/kernel/lib/actions/host" "github.com/openziti/fablab/kernel/model" "github.com/openziti/ziti/zititest/zitilab/stageziti" "github.com/sirupsen/logrus" @@ -34,6 +32,8 @@ const ( ZitiTunnelModeTproxy ZitiTunnelMode = 0 ZitiTunnelModeProxy ZitiTunnelMode = 1 ZitiTunnelModeHost ZitiTunnelMode = 2 + + ZitiTunnelActionsReEnroll = "reEnroll" ) func (self ZitiTunnelMode) String() string { @@ -55,8 +55,14 @@ type ZitiTunnelType struct { LocalPath string } +func (self *ZitiTunnelType) GetActions() map[string]model.ComponentAction { + return map[string]model.ComponentAction{ + ZitiTunnelActionsReEnroll: model.ComponentActionF(self.ReEnroll), + } +} + func (self *ZitiTunnelType) InitType(*model.Component) { - if self.Version != "" && !strings.HasPrefix(self.Version, "v") { + if self.Version != "" && self.Version != "latest" && !strings.HasPrefix(self.Version, "v") { self.Version = "v" + self.Version } } @@ -73,15 +79,15 @@ func (self *ZitiTunnelType) StageFiles(r model.Run, c *model.Component) error { return stageziti.StageZitiOnce(r, c, self.Version, self.LocalPath) } -func (self *ZitiTunnelType) InitializeHost(run model.Run, c *model.Component) error { - cmds := []string{"mkdir -p /home/ubuntu/logs"} +func (self *ZitiTunnelType) InitializeHost(_ model.Run, c *model.Component) error { if self.Mode == ZitiTunnelModeTproxy { - cmds = append(cmds, + cmds := []string{ "sudo sed -i 's/#DNS=/DNS=127.0.0.1/g' /etc/systemd/resolved.conf", "sudo systemctl restart systemd-resolved", - ) + } + return c.Host.ExecLogOnlyOnError(cmds...) } - return host.Exec(c.GetHost(), cmds...).Execute(run) + return nil } func (self *ZitiTunnelType) getProcessFilter(c *model.Component) func(string) bool { @@ -89,37 +95,45 @@ func (self *ZitiTunnelType) getProcessFilter(c *model.Component) func(string) bo } func (self *ZitiTunnelType) IsRunning(_ model.Run, c *model.Component) (bool, error) { - factory := lib.NewSshConfigFactory(c.GetHost()) - pids, err := lib.FindProcesses(factory, self.getProcessFilter(c)) + pids, err := c.GetHost().FindProcesses(self.getProcessFilter(c)) if err != nil { return false, err } return len(pids) > 0, nil } -func (self *ZitiTunnelType) Start(_ model.Run, c *model.Component) error { +func (self *ZitiTunnelType) GetBinaryName() string { binaryName := "ziti" if self.Version != "" { binaryName += "-" + self.Version } + return binaryName +} + +func (self *ZitiTunnelType) GetConfigName(c *model.Component) string { + return fmt.Sprintf("%s.json", c.Id) +} +func (self *ZitiTunnelType) Start(_ model.Run, c *model.Component) error { mode := self.Mode - factory := lib.NewSshConfigFactory(c.GetHost()) + user := c.GetHost().GetSshUser() - binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", factory.User(), binaryName) - configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s.json", factory.User(), c.Id) - logsPath := fmt.Sprintf("/home/%s/logs/%s.log", factory.User(), c.Id) + binaryPath := fmt.Sprintf("/home/%s/fablab/bin/%s", user, self.GetBinaryName()) + configPath := fmt.Sprintf("/home/%s/fablab/cfg/%s", user, self.GetConfigName(c)) + logsPath := fmt.Sprintf("/home/%s/logs/%s.log", user, c.Id) useSudo := "" if mode == ZitiTunnelModeTproxy { useSudo = "sudo" } - serviceCmd := fmt.Sprintf("nohup %s %s tunnel %s --log-formatter pfxlog -i %s --cli-agent-alias %s > %s 2>&1 &", + serviceCmd := fmt.Sprintf("%s %s tunnel %s --log-formatter pfxlog -i %s --cli-agent-alias %s > %s 2>&1 &", useSudo, binaryPath, mode.String(), configPath, c.Id, logsPath) - value, err := lib.RemoteExec(factory, serviceCmd) + value, err := c.Host.ExecLogged( + "rm -f "+logsPath, + serviceCmd) if err != nil { return err } @@ -132,6 +146,9 @@ func (self *ZitiTunnelType) Start(_ model.Run, c *model.Component) error { } func (self *ZitiTunnelType) Stop(_ model.Run, c *model.Component) error { - factory := lib.NewSshConfigFactory(c.GetHost()) - return lib.RemoteKillSignalFilterF(factory, "-KILL", self.getProcessFilter(c)) + return c.GetHost().KillProcesses("-KILL", self.getProcessFilter(c)) +} + +func (self *ZitiTunnelType) ReEnroll(run model.Run, c *model.Component) error { + return reEnrollIdentity(run, c, self.GetBinaryName(), self.GetConfigName(c)) } diff --git a/zititest/zitilab/models/db_builder.go b/zititest/zitilab/models/db_builder.go index 86a358149..e78375707 100644 --- a/zititest/zitilab/models/db_builder.go +++ b/zititest/zitilab/models/db_builder.go @@ -2,11 +2,11 @@ package models import ( "fmt" - "github.com/openziti/ziti/controller/persistence" "github.com/openziti/fablab/kernel/model" + "github.com/openziti/storage/boltz" "github.com/openziti/ziti/controller/db" "github.com/openziti/ziti/controller/network" - "github.com/openziti/storage/boltz" + "github.com/openziti/ziti/controller/persistence" "github.com/openziti/ziti/zititest/zitilab" "github.com/pkg/errors" "go.etcd.io/bbolt" @@ -14,118 +14,120 @@ import ( ) type ZitiDbBuilderStrategy interface { - GetDbFile() string + GetDbFile(m *model.Model) string GetSite(router *persistence.EdgeRouter) (string, bool) PostProcess(router *persistence.EdgeRouter, c *model.Component) + ProcessDbModel(tx *bbolt.Tx, m *model.Model, builder *ZitiDbBuilder) error } type ZitiDbBuilder struct { - Strategy ZitiDbBuilderStrategy + Strategy ZitiDbBuilderStrategy + zitiDb boltz.Db + stores *db.Stores + edgeStores *persistence.Stores } -type dbProvider struct { - zitiDb boltz.Db - stores *db.Stores -} - -func (self *dbProvider) GetDb() boltz.Db { +func (self *ZitiDbBuilder) GetDb() boltz.Db { return self.zitiDb } -func (self *dbProvider) GetStores() *db.Stores { +func (self *ZitiDbBuilder) GetStores() *db.Stores { return self.stores } -func (self *dbProvider) GetManagers() *network.Managers { +func (self *ZitiDbBuilder) GetEdgeStores() *persistence.Stores { + return self.edgeStores +} + +func (self *ZitiDbBuilder) GetManagers() *network.Managers { panic("should not be needed") } func (self *ZitiDbBuilder) Build(m *model.Model) error { - dbFile := self.Strategy.GetDbFile() - zitiDb, err := db.Open(dbFile) + dbFile := self.Strategy.GetDbFile(m) + + var err error + self.zitiDb, err = db.Open(dbFile) if err != nil { return errors.Wrapf(err, "unable to open ziti bbolt db [%v]", dbFile) } defer func() { - if err = zitiDb.Close(); err != nil { + if err = self.zitiDb.Close(); err != nil { panic(err) } }() - fabricStore, err := db.InitStores(zitiDb) + self.stores, err = db.InitStores(self.zitiDb) if err != nil { return errors.Wrapf(err, "unable to init fabric stores using db [%v]", dbFile) } - provider := &dbProvider{ - zitiDb: zitiDb, - stores: fabricStore, + self.edgeStores, err = persistence.NewBoltStores(self) + if err != nil { + return errors.Wrapf(err, "unable to init edge stores using db [%v]", dbFile) } - edgeStores, err := persistence.NewBoltStores(provider) + return self.zitiDb.View(func(tx *bbolt.Tx) error { + return self.Strategy.ProcessDbModel(tx, m, self) + }) +} + +func (self *ZitiDbBuilder) CreateEdgeRouterHosts(tx *bbolt.Tx, m *model.Model) error { + ids, _, err := self.edgeStores.EdgeRouter.QueryIds(tx, "true limit none") if err != nil { - return errors.Wrapf(err, "unable to init edge stores using db [%v]", dbFile) + return err } - err = zitiDb.View(func(tx *bbolt.Tx) error { - ids, _, err := edgeStores.EdgeRouter.QueryIds(tx, "true limit none") + for _, id := range ids { + er, err := self.edgeStores.EdgeRouter.LoadOneById(tx, id) if err != nil { return err } - for _, id := range ids { - er, err := edgeStores.EdgeRouter.LoadOneById(tx, id) - if err != nil { - return err - } - - if site, useEdgeRouter := self.Strategy.GetSite(er); useEdgeRouter { - regionId := site[:len(site)-1] + if site, useEdgeRouter := self.Strategy.GetSite(er); useEdgeRouter { + regionId := site[:len(site)-1] - var region *model.Region - for _, r := range m.Regions { - if r.Site == site { - region = r - break - } + var region *model.Region + for _, r := range m.Regions { + if r.Site == site { + region = r + break } + } - if region == nil { - if _, found := m.Regions[site]; found { - return errors.Errorf("trying to add region for site %v, but one exists, with different site", site) - } - region = &model.Region{ - Scope: model.Scope{Tags: model.Tags{}}, - Region: regionId, - Site: site, - Hosts: model.Hosts{}, - } - m.Regions[site] = region + if region == nil { + if _, found := m.Regions[site]; found { + return errors.Errorf("trying to add region for site %v, but one exists, with different site", site) } - - host := &model.Host{ - Scope: model.Scope{Tags: model.Tags{}}, - Region: region, - Components: model.Components{}, + region = &model.Region{ + Scope: model.Scope{Tags: model.Tags{}}, + Region: regionId, + Site: site, + Hosts: model.Hosts{}, } - id := strings.ReplaceAll(er.Id, ".", "_") - region.Hosts["router_"+id] = host + m.Regions[site] = region + } - component := &model.Component{ - Scope: model.Scope{Tags: model.Tags{}}, - Type: &zitilab.RouterType{}, - Host: host, - } + host := &model.Host{ + Scope: model.Scope{Tags: model.Tags{}}, + Region: region, + Components: model.Components{}, + } + id = strings.ReplaceAll(er.Id, ".", "_") + region.Hosts["router_"+id] = host - host.Components[er.Id] = component - self.Strategy.PostProcess(er, component) + component := &model.Component{ + Scope: model.Scope{Tags: model.Tags{}}, + Type: &zitilab.RouterType{}, + Host: host, } - } - return nil - }) - return err + host.Components[er.Id] = component + self.Strategy.PostProcess(er, component) + } + } + return nil } func (self *ZitiDbBuilder) DefaultGetSite(er *persistence.EdgeRouter) (string, bool) { diff --git a/zititest/zitilab/runlevel/0_infrastructure/consul.go b/zititest/zitilab/runlevel/0_infrastructure/consul.go index beb72a0db..95b76ac62 100644 --- a/zititest/zitilab/runlevel/0_infrastructure/consul.go +++ b/zititest/zitilab/runlevel/0_infrastructure/consul.go @@ -2,8 +2,8 @@ package zitilib_runlevel_0_infrastructure import ( "fmt" + "github.com/openziti/fablab/kernel/libssh" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" ) @@ -20,19 +20,19 @@ func InstallConsul(hostSpec string) model.Stage { func (imb *installConsul) Execute(run model.Run) error { return run.GetModel().ForEachHost(imb.hostSpec, 25, func(host *model.Host) error { - ssh := lib.NewSshConfigFactory(host) + ssh := host.NewSshConfigFactory() - if output, err := lib.RemoteExec(ssh, "curl --fail --silent --show-error --location https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo dd of=/usr/share/keyrings/hashicorp-archive-keyring.gpg"); err != nil { + if output, err := libssh.RemoteExec(ssh, "curl --fail --silent --show-error --location https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo dd of=/usr/share/keyrings/hashicorp-archive-keyring.gpg"); err != nil { return fmt.Errorf("error getting hashicorp gpg key on host [%s] %s (%s)", host.PublicIp, output, err) } - if output, err := lib.RemoteExec(ssh, "echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee -a /etc/apt/sources.list.d/hashicorp.list"); err != nil { + if output, err := libssh.RemoteExec(ssh, "echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee -a /etc/apt/sources.list.d/hashicorp.list"); err != nil { return fmt.Errorf("error adding hashicorp repo to apt on host [%s] %s (%s)", host.PublicIp, output, err) } cmd := "sudo apt-get update && sudo apt-get install consul -y" - if output, err := lib.RemoteExec(ssh, cmd); err != nil { + if output, err := libssh.RemoteExec(ssh, cmd); err != nil { return fmt.Errorf("error installing Consul on host [%s] %s (%s)", host.PublicIp, output, err) } logrus.Infof("%s => %s", host.PublicIp, "installing Consul") diff --git a/zititest/zitilab/runlevel/0_infrastructure/metricbeat.go b/zititest/zitilab/runlevel/0_infrastructure/metricbeat.go index 24f3ab9ba..575aabc5f 100644 --- a/zititest/zitilab/runlevel/0_infrastructure/metricbeat.go +++ b/zititest/zitilab/runlevel/0_infrastructure/metricbeat.go @@ -2,8 +2,8 @@ package zitilib_runlevel_0_infrastructure import ( "fmt" + "github.com/openziti/fablab/kernel/libssh" - "github.com/openziti/fablab/kernel/lib" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" ) @@ -24,13 +24,13 @@ func InstallMetricbeat(hostSpec, version string) model.Stage { func (imb *installMetricbeat) Execute(run model.Run) error { return run.GetModel().ForEachHost(imb.hostSpec, 25, func(host *model.Host) error { - ssh := lib.NewSshConfigFactory(host) + ssh := host.NewSshConfigFactory() - if output, err := lib.RemoteExec(ssh, "wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -"); err != nil { + if output, err := libssh.RemoteExec(ssh, "wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -"); err != nil { return fmt.Errorf("error getting elastic gpg key on host [%s] %s (%s)", host.PublicIp, output, err) } - if output, err := lib.RemoteExec(ssh, "echo \"deb https://artifacts.elastic.co/packages/8.x/apt stable main\" | sudo tee -a /etc/apt/sources.list.d/elastic-8.x.list"); err != nil { + if output, err := libssh.RemoteExec(ssh, "echo \"deb https://artifacts.elastic.co/packages/8.x/apt stable main\" | sudo tee -a /etc/apt/sources.list.d/elastic-8.x.list"); err != nil { return fmt.Errorf("error adding elastic repo to apt on host [%s] %s (%s)", host.PublicIp, output, err) } @@ -41,7 +41,7 @@ func (imb *installMetricbeat) Execute(run model.Run) error { return "" }()) - if output, err := lib.RemoteExec(ssh, cmd); err != nil { + if output, err := libssh.RemoteExec(ssh, cmd); err != nil { return fmt.Errorf("error installing metricbeat on host [%s] %s (%s)", host.PublicIp, output, err) } logrus.Infof("%s => %s", host.PublicIp, "installing metricbeat") diff --git a/zititest/zitilab/runlevel/5_operation/loop_dialer.go b/zititest/zitilab/runlevel/5_operation/loop_dialer.go index 1fe6402a5..a1444ff46 100644 --- a/zititest/zitilab/runlevel/5_operation/loop_dialer.go +++ b/zititest/zitilab/runlevel/5_operation/loop_dialer.go @@ -18,7 +18,7 @@ package zitilib_runlevel_5_operation import ( "fmt" - "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" "strings" @@ -47,8 +47,8 @@ func LoopDialer(host *model.Host, scenario, endpoint string, joiner chan struct{ } func (self *loopDialer) Execute(run model.Run) error { - ssh := lib.NewSshConfigFactory(self.host) - if err := lib.RemoteKill(ssh, fmt.Sprintf("ziti-fabric-test %v dialer", self.subcmd)); err != nil { + ssh := self.host.NewSshConfigFactory() + if err := libssh.RemoteKill(ssh, fmt.Sprintf("ziti-fabric-test %v dialer", self.subcmd)); err != nil { return fmt.Errorf("error killing %v listeners (%w)", self.subcmd, err) } @@ -64,11 +64,11 @@ func (self *loopDialer) run(ctx model.Run) { } }() - ssh := lib.NewSshConfigFactory(self.host) + ssh := self.host.NewSshConfigFactory() logFile := fmt.Sprintf("/home/%s/logs/%v-dialer-%s.log", ssh.User(), self.subcmd, ctx.GetId()) dialerCmd := fmt.Sprintf("/home/%s/fablab/bin/ziti-fabric-test %v dialer /home/%s/fablab/cfg/%s -e %s -s %s %s >> %s 2>&1", ssh.User(), self.subcmd, ssh.User(), self.scenario, self.endpoint, self.host.GetId(), strings.Join(self.extraArgs, " "), logFile) - if output, err := lib.RemoteExec(ssh, dialerCmd); err != nil { + if output, err := libssh.RemoteExec(ssh, dialerCmd); err != nil { logrus.Errorf("error starting loop dialer [%s] (%v)", output, err) } } diff --git a/zititest/zitilab/runlevel/5_operation/loop_listener.go b/zititest/zitilab/runlevel/5_operation/loop_listener.go index efc85a087..b9cf8319c 100644 --- a/zititest/zitilab/runlevel/5_operation/loop_listener.go +++ b/zititest/zitilab/runlevel/5_operation/loop_listener.go @@ -2,7 +2,7 @@ package zitilib_runlevel_5_operation import ( "fmt" - "github.com/openziti/fablab/kernel/lib" + "github.com/openziti/fablab/kernel/libssh" "github.com/openziti/fablab/kernel/model" "github.com/sirupsen/logrus" "strings" @@ -29,8 +29,8 @@ func LoopListener(host *model.Host, joiner chan struct{}, bindAddress string, ex } func (self *loopListener) Execute(run model.Run) error { - ssh := lib.NewSshConfigFactory(self.host) - if err := lib.RemoteKill(ssh, fmt.Sprintf("ziti-fabric-test %v listener", self.subcmd)); err != nil { + ssh := self.host.NewSshConfigFactory() + if err := libssh.RemoteKill(ssh, fmt.Sprintf("ziti-fabric-test %v listener", self.subcmd)); err != nil { return fmt.Errorf("error killing %v listeners (%w)", self.subcmd, err) } @@ -46,12 +46,12 @@ func (self *loopListener) run(run model.Run) { } }() - ssh := lib.NewSshConfigFactory(self.host) + ssh := self.host.NewSshConfigFactory() logFile := fmt.Sprintf("/home/%s/logs/%v-listener-%s.log", ssh.User(), self.subcmd, run.GetId()) listenerCmd := fmt.Sprintf("/home/%s/fablab/bin/ziti-fabric-test %v listener -b %v %v >> %s 2>&1", ssh.User(), self.subcmd, self.bindAddress, strings.Join(self.extraArgs, " "), logFile) - if output, err := lib.RemoteExec(ssh, listenerCmd); err != nil { + if output, err := libssh.RemoteExec(ssh, listenerCmd); err != nil { logrus.Errorf("error starting loop listener [%s] (%v)", output, err) } }