mirror of
https://github.com/openziti/zrok.git
synced 2025-06-19 17:27:54 +02:00
Merge branch 'main' into v1.next_canary
This commit is contained in:
commit
c3dd6ac116
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
|||||||
*.db
|
*.db
|
||||||
/automated-release-build/
|
/automated-release-build/
|
||||||
etc/dev.yml
|
etc/dev.yml
|
||||||
|
etc/dev-canary.yml
|
||||||
etc/dev-frontend.yml
|
etc/dev-frontend.yml
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
20
CHANGELOG.md
20
CHANGELOG.md
@ -1,5 +1,25 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.3
|
||||||
|
|
||||||
|
FEATURE: New `zrok admin unbootstrap` to remove zrok resources from the underlying OpenZiti instance (https://github.com/openziti/zrok/issues/935)
|
||||||
|
|
||||||
|
FEATURE: New InfluxDB metrics capture infrastructure for `zrok test canary` framework (https://github.com/openziti/zrok/issues/948)
|
||||||
|
|
||||||
|
FEATURE: New `zrok test canary enabler` to validate `enable`/`disable` operations and gather performance metrics around how those paths are operating (https://github.com/openziti/zrok/issues/771)
|
||||||
|
|
||||||
|
CHANGE: New _guard_ to prevent users from running potentially dangerous `zrok test canary` commands inadvertently without understanding what they do (https://github.com/openziti/zrok/issues/947)
|
||||||
|
|
||||||
|
## v1.0.2
|
||||||
|
|
||||||
|
FEATURE: "Auto-rebase" for enabled environments where the `apiEndpoint` is set to `https://api.zrok.io`. This will automatically migrate existing environments to the new `apiEndpoint` for the `v1.0.x` series (https://github.com/openziti/zrok/issues/936)
|
||||||
|
|
||||||
|
FEATURE: New `admin/new_account_link` configuration option to allow the insertion of "how do I register for an account?" links into the login form (https://github.com/openziti/zrok/issues/552)
|
||||||
|
|
||||||
|
CHANGE: The release environment, share, and access modals in the API console now have a better message letting the user know they will still need to clean up their `zrok` processes (https://github.com/openziti/zrok/issues/910)
|
||||||
|
|
||||||
|
CHANGE: The openziti/zrok Docker image has been updated to use the latest version of the ziti CLI, 1.4.3 (https://github.com/openziti/zrok/pull/917)
|
||||||
|
|
||||||
## v1.0.1
|
## v1.0.1
|
||||||
|
|
||||||
FEATURE: The zrok Agent now persists private accesses and reserved shares between executions. Any `zrok access private` instances or `zrok share reserved` instances created using the agent are now persisted to a registry stored in `${HOME}/.zrok`. When restarting the agent these accesses and reserved shares are re-created from the data in this registry (https://github.com/openziti/zrok/pull/922)
|
FEATURE: The zrok Agent now persists private accesses and reserved shares between executions. Any `zrok access private` instances or `zrok share reserved` instances created using the agent are now persisted to a registry stored in `${HOME}/.zrok`. When restarting the agent these accesses and reserved shares are re-created from the data in this registry (https://github.com/openziti/zrok/pull/922)
|
||||||
|
31
canary/config.go
Normal file
31
canary/config.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package canary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/michaelquigley/cf"
|
||||||
|
"github.com/openziti/zrok/controller/metrics"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ConfigVersion = 1
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
V int
|
||||||
|
Influx *metrics.InfluxConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultConfig() *Config {
|
||||||
|
return &Config{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig(path string) (*Config, error) {
|
||||||
|
cfg := DefaultConfig()
|
||||||
|
if err := cf.BindYaml(cfg, path, cf.DefaultOptions()); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error loading canary configuration '%v'", path)
|
||||||
|
}
|
||||||
|
if cfg.V != ConfigVersion {
|
||||||
|
return nil, errors.Errorf("expecting canary configuration version '%v', got '%v'", ConfigVersion, cfg.V)
|
||||||
|
}
|
||||||
|
logrus.Info(cf.Dump(cfg, cf.DefaultOptions()))
|
||||||
|
return cfg, nil
|
||||||
|
}
|
13
canary/dangerous.go
Normal file
13
canary/dangerous.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package canary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AcknowledgeDangerousCanary() error {
|
||||||
|
if _, ok := os.LookupEnv("ZROK_DANGEROUS_CANARY"); !ok {
|
||||||
|
return fmt.Errorf("this is a dangerous canary; see canary docs for details on enabling")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
92
canary/disabler.go
Normal file
92
canary/disabler.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package canary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/openziti/zrok/environment/env_core"
|
||||||
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DisablerOptions struct {
|
||||||
|
Environments chan *sdk.Environment
|
||||||
|
MinDwell time.Duration
|
||||||
|
MaxDwell time.Duration
|
||||||
|
MinPacing time.Duration
|
||||||
|
MaxPacing time.Duration
|
||||||
|
SnapshotQueue chan *Snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
type Disabler struct {
|
||||||
|
Id uint
|
||||||
|
Done chan struct{}
|
||||||
|
opt *DisablerOptions
|
||||||
|
root env_core.Root
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDisabler(id uint, opt *DisablerOptions, root env_core.Root) *Disabler {
|
||||||
|
return &Disabler{
|
||||||
|
Id: id,
|
||||||
|
Done: make(chan struct{}),
|
||||||
|
opt: opt,
|
||||||
|
root: root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Disabler) Run() {
|
||||||
|
defer logrus.Infof("#%d stopping", d.Id)
|
||||||
|
defer close(d.Done)
|
||||||
|
d.dwell()
|
||||||
|
d.iterate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Disabler) dwell() {
|
||||||
|
dwell := d.opt.MinDwell.Milliseconds()
|
||||||
|
dwelta := d.opt.MaxDwell.Milliseconds() - d.opt.MinDwell.Milliseconds()
|
||||||
|
if dwelta > 0 {
|
||||||
|
dwell = int64(rand.Intn(int(dwelta)) + int(d.opt.MinDwell.Milliseconds()))
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(dwell) * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Disabler) iterate() {
|
||||||
|
iteration := uint64(0)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case env, ok := <-d.opt.Environments:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot := NewSnapshot("disable", d.Id, iteration)
|
||||||
|
iteration++
|
||||||
|
|
||||||
|
if err := sdk.DisableEnvironment(env, d.root); err == nil {
|
||||||
|
snapshot.Completed = time.Now()
|
||||||
|
snapshot.Ok = true
|
||||||
|
|
||||||
|
logrus.Infof("#%d disabled environment '%v'", d.Id, env.ZitiIdentity)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
snapshot.Completed = time.Now()
|
||||||
|
snapshot.Ok = false
|
||||||
|
snapshot.Error = err
|
||||||
|
|
||||||
|
logrus.Errorf("error disabling canary (#%d) environment '%v': %v", d.Id, env.ZitiIdentity, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.opt.SnapshotQueue != nil {
|
||||||
|
d.opt.SnapshotQueue <- snapshot
|
||||||
|
} else {
|
||||||
|
logrus.Info(snapshot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pacingMs := d.opt.MaxPacing.Milliseconds()
|
||||||
|
pacingDelta := d.opt.MaxPacing.Milliseconds() - d.opt.MinPacing.Milliseconds()
|
||||||
|
if pacingDelta > 0 {
|
||||||
|
pacingMs = (rand.Int63() % pacingDelta) + d.opt.MinPacing.Milliseconds()
|
||||||
|
time.Sleep(time.Duration(pacingMs) * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
canary/enabler.go
Normal file
93
canary/enabler.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package canary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/openziti/zrok/environment/env_core"
|
||||||
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnablerOptions struct {
|
||||||
|
Iterations uint
|
||||||
|
MinDwell time.Duration
|
||||||
|
MaxDwell time.Duration
|
||||||
|
MinPacing time.Duration
|
||||||
|
MaxPacing time.Duration
|
||||||
|
SnapshotQueue chan *Snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
type Enabler struct {
|
||||||
|
Id uint
|
||||||
|
Done chan struct{}
|
||||||
|
opt *EnablerOptions
|
||||||
|
root env_core.Root
|
||||||
|
Environments chan *sdk.Environment
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnabler(id uint, opt *EnablerOptions, root env_core.Root) *Enabler {
|
||||||
|
return &Enabler{
|
||||||
|
Id: id,
|
||||||
|
Done: make(chan struct{}),
|
||||||
|
opt: opt,
|
||||||
|
root: root,
|
||||||
|
Environments: make(chan *sdk.Environment, opt.Iterations),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Enabler) Run() {
|
||||||
|
defer close(e.Environments)
|
||||||
|
defer close(e.Done)
|
||||||
|
defer logrus.Infof("#%d stopping", e.Id)
|
||||||
|
e.dwell()
|
||||||
|
e.iterate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Enabler) dwell() {
|
||||||
|
dwell := e.opt.MinDwell.Milliseconds()
|
||||||
|
dwelta := e.opt.MaxDwell.Milliseconds() - e.opt.MinDwell.Milliseconds()
|
||||||
|
if dwelta > 0 {
|
||||||
|
dwell = int64(rand.Intn(int(dwelta)) + int(e.opt.MinDwell.Milliseconds()))
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(dwell) * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Enabler) iterate() {
|
||||||
|
defer logrus.Info("done")
|
||||||
|
for i := uint(0); i < e.opt.Iterations; i++ {
|
||||||
|
snapshot := NewSnapshot("enable", e.Id, uint64(i))
|
||||||
|
|
||||||
|
env, err := sdk.EnableEnvironment(e.root, &sdk.EnableRequest{
|
||||||
|
Host: fmt.Sprintf("canary_%d_%d", e.Id, i),
|
||||||
|
Description: "canary.Enabler",
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
snapshot.Completed = time.Now()
|
||||||
|
snapshot.Ok = true
|
||||||
|
|
||||||
|
e.Environments <- env
|
||||||
|
logrus.Infof("#%d enabled environment '%v'", e.Id, env.ZitiIdentity)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
snapshot.Completed = time.Now()
|
||||||
|
snapshot.Ok = false
|
||||||
|
snapshot.Error = err
|
||||||
|
|
||||||
|
logrus.Errorf("error creating canary (#%d) environment: %v", e.Id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.opt.SnapshotQueue != nil {
|
||||||
|
e.opt.SnapshotQueue <- snapshot
|
||||||
|
} else {
|
||||||
|
logrus.Info(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
pacingMs := e.opt.MaxPacing.Milliseconds()
|
||||||
|
pacingDelta := e.opt.MaxPacing.Milliseconds() - e.opt.MinPacing.Milliseconds()
|
||||||
|
if pacingDelta > 0 {
|
||||||
|
pacingMs = (rand.Int63() % pacingDelta) + e.opt.MinPacing.Milliseconds()
|
||||||
|
time.Sleep(time.Duration(pacingMs) * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
canary/metrics.go
Normal file
102
canary/metrics.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package canary
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||||
|
"github.com/openziti/zrok/util"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"slices"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Snapshot struct {
|
||||||
|
Operation string
|
||||||
|
Instance uint
|
||||||
|
Iteration uint64
|
||||||
|
Started time.Time
|
||||||
|
Completed time.Time
|
||||||
|
Ok bool
|
||||||
|
Error error
|
||||||
|
Size uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSnapshot(operation string, instance uint, iteration uint64) *Snapshot {
|
||||||
|
return &Snapshot{Operation: operation, Instance: instance, Iteration: iteration, Started: time.Now()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Snapshot) String() string {
|
||||||
|
if s.Ok {
|
||||||
|
return fmt.Sprintf("[%v, %d, %d] (ok) %v, %v", s.Operation, s.Instance, s.Iteration, s.Completed.Sub(s.Started), util.BytesToSize(int64(s.Size)))
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("[%v, %d, %d] (err) %v, %v, (%v)", s.Operation, s.Instance, s.Iteration, s.Completed.Sub(s.Started), util.BytesToSize(int64(s.Size)), s.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SnapshotCollector struct {
|
||||||
|
InputQueue chan *Snapshot
|
||||||
|
Closed chan struct{}
|
||||||
|
ctx context.Context
|
||||||
|
cfg *Config
|
||||||
|
snapshots map[string][]*Snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSnapshotCollector(ctx context.Context, cfg *Config) *SnapshotCollector {
|
||||||
|
return &SnapshotCollector{
|
||||||
|
InputQueue: make(chan *Snapshot),
|
||||||
|
Closed: make(chan struct{}),
|
||||||
|
ctx: ctx,
|
||||||
|
cfg: cfg,
|
||||||
|
snapshots: make(map[string][]*Snapshot),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SnapshotCollector) Run() {
|
||||||
|
defer close(sc.Closed)
|
||||||
|
defer logrus.Info("stopping")
|
||||||
|
logrus.Info("starting")
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-sc.ctx.Done():
|
||||||
|
return
|
||||||
|
|
||||||
|
case snapshot := <-sc.InputQueue:
|
||||||
|
var snapshots []*Snapshot
|
||||||
|
if v, ok := sc.snapshots[snapshot.Operation]; ok {
|
||||||
|
snapshots = v
|
||||||
|
}
|
||||||
|
i := sort.Search(len(snapshots), func(i int) bool { return snapshots[i].Completed.After(snapshot.Started) })
|
||||||
|
snapshots = slices.Insert(snapshots, i, snapshot)
|
||||||
|
sc.snapshots[snapshot.Operation] = snapshots
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SnapshotCollector) Store() error {
|
||||||
|
idb := influxdb2.NewClient(sc.cfg.Influx.Url, sc.cfg.Influx.Token)
|
||||||
|
writeApi := idb.WriteAPIBlocking(sc.cfg.Influx.Org, sc.cfg.Influx.Bucket)
|
||||||
|
for key, arr := range sc.snapshots {
|
||||||
|
for _, snapshot := range arr {
|
||||||
|
tags := map[string]string{
|
||||||
|
"instance": fmt.Sprintf("%d", snapshot.Instance),
|
||||||
|
"iteration": fmt.Sprintf("%d", snapshot.Iteration),
|
||||||
|
"ok": fmt.Sprintf("%t", snapshot.Ok),
|
||||||
|
}
|
||||||
|
if snapshot.Error != nil {
|
||||||
|
tags["error"] = snapshot.Error.Error()
|
||||||
|
}
|
||||||
|
pt := influxdb2.NewPoint(snapshot.Operation, tags, map[string]interface{}{
|
||||||
|
"duration": snapshot.Completed.Sub(snapshot.Started).Milliseconds(),
|
||||||
|
"size": snapshot.Size,
|
||||||
|
}, snapshot.Started)
|
||||||
|
if err := writeApi.WritePoint(context.Background(), pt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logrus.Infof("wrote '%v' points for '%v'", len(arr), key)
|
||||||
|
}
|
||||||
|
idb.Close()
|
||||||
|
logrus.Infof("complete")
|
||||||
|
return nil
|
||||||
|
}
|
40
cmd/zrok/adminUnbootstrap.go
Normal file
40
cmd/zrok/adminUnbootstrap.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/michaelquigley/cf"
|
||||||
|
"github.com/openziti/zrok/controller"
|
||||||
|
"github.com/openziti/zrok/controller/config"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
adminCmd.AddCommand(newAdminUnbootstrap().cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
type adminUnbootstrap struct {
|
||||||
|
cmd *cobra.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAdminUnbootstrap() *adminUnbootstrap {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "unbootstrap <configPath>",
|
||||||
|
Short: "Unbootstrap the underlying Ziti network from zrok",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
command := &adminUnbootstrap{cmd: cmd}
|
||||||
|
cmd.Run = command.run
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *adminUnbootstrap) run(_ *cobra.Command, args []string) {
|
||||||
|
cfg, err := config.LoadConfig(args[0])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logrus.Infof(cf.Dump(cfg, cf.DefaultOptions()))
|
||||||
|
if err := controller.Unbootstrap(cfg); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logrus.Infof("unbootstrap complete!")
|
||||||
|
}
|
143
cmd/zrok/testCanaryEnabler.go
Normal file
143
cmd/zrok/testCanaryEnabler.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/openziti/zrok/canary"
|
||||||
|
"github.com/openziti/zrok/environment"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
testCanaryCmd.AddCommand(newTestCanaryEnabler().cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCanaryEnabler struct {
|
||||||
|
cmd *cobra.Command
|
||||||
|
enablers uint
|
||||||
|
iterations uint
|
||||||
|
minPreDelay time.Duration
|
||||||
|
maxPreDelay time.Duration
|
||||||
|
minDwell time.Duration
|
||||||
|
maxDwell time.Duration
|
||||||
|
minPacing time.Duration
|
||||||
|
maxPacing time.Duration
|
||||||
|
skipDisable bool
|
||||||
|
canaryConfig string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestCanaryEnabler() *testCanaryEnabler {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "enabler",
|
||||||
|
Short: "Enable a canary enabling environments",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
}
|
||||||
|
command := &testCanaryEnabler{cmd: cmd}
|
||||||
|
cmd.Run = command.run
|
||||||
|
cmd.Flags().UintVarP(&command.enablers, "enablers", "e", 1, "Number of concurrent enablers to start")
|
||||||
|
cmd.Flags().UintVarP(&command.iterations, "iterations", "i", 1, "Number of iterations")
|
||||||
|
cmd.Flags().DurationVar(&command.minDwell, "min-dwell", 0, "Minimum dwell time")
|
||||||
|
cmd.Flags().DurationVar(&command.maxDwell, "max-dwell", 0, "Maximum dwell time")
|
||||||
|
cmd.Flags().DurationVar(&command.minPacing, "min-pacing", 0, "Minimum pacing time")
|
||||||
|
cmd.Flags().DurationVar(&command.maxPacing, "max-pacing", 0, "Maximum pacing time")
|
||||||
|
cmd.Flags().BoolVar(&command.skipDisable, "skip-disable", false, "Disable (clean up) enabled environments")
|
||||||
|
cmd.Flags().StringVar(&command.canaryConfig, "canary-config", "", "Path to canary configuration file")
|
||||||
|
return command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *testCanaryEnabler) run(_ *cobra.Command, _ []string) {
|
||||||
|
if err := canary.AcknowledgeDangerousCanary(); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := environment.LoadRoot()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sc *canary.SnapshotCollector
|
||||||
|
var scCtx context.Context
|
||||||
|
var scCancel context.CancelFunc
|
||||||
|
if cmd.canaryConfig != "" {
|
||||||
|
cfg, err := canary.LoadConfig(cmd.canaryConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
scCtx, scCancel = context.WithCancel(context.Background())
|
||||||
|
sc = canary.NewSnapshotCollector(scCtx, cfg)
|
||||||
|
go sc.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
var enablers []*canary.Enabler
|
||||||
|
for i := uint(0); i < cmd.enablers; i++ {
|
||||||
|
preDelay := cmd.maxPreDelay.Milliseconds()
|
||||||
|
preDelayDelta := cmd.maxPreDelay.Milliseconds() - cmd.minPreDelay.Milliseconds()
|
||||||
|
if preDelayDelta > 0 {
|
||||||
|
preDelay = int64(rand.Intn(int(preDelayDelta))) + cmd.minPreDelay.Milliseconds()
|
||||||
|
time.Sleep(time.Duration(preDelay) * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
enablerOpts := &canary.EnablerOptions{
|
||||||
|
Iterations: cmd.iterations,
|
||||||
|
MinDwell: cmd.minDwell,
|
||||||
|
MaxDwell: cmd.maxDwell,
|
||||||
|
MinPacing: cmd.minPacing,
|
||||||
|
MaxPacing: cmd.maxPacing,
|
||||||
|
}
|
||||||
|
if sc != nil {
|
||||||
|
enablerOpts.SnapshotQueue = sc.InputQueue
|
||||||
|
}
|
||||||
|
enabler := canary.NewEnabler(i, enablerOpts, root)
|
||||||
|
enablers = append(enablers, enabler)
|
||||||
|
go enabler.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cmd.skipDisable {
|
||||||
|
var disablers []*canary.Disabler
|
||||||
|
for i := uint(0); i < cmd.enablers; i++ {
|
||||||
|
disablerOpts := &canary.DisablerOptions{
|
||||||
|
Environments: enablers[i].Environments,
|
||||||
|
}
|
||||||
|
if sc != nil {
|
||||||
|
disablerOpts.SnapshotQueue = sc.InputQueue
|
||||||
|
}
|
||||||
|
disabler := canary.NewDisabler(i, disablerOpts, root)
|
||||||
|
disablers = append(disablers, disabler)
|
||||||
|
go disabler.Run()
|
||||||
|
}
|
||||||
|
for _, disabler := range disablers {
|
||||||
|
logrus.Infof("waiting for disabler #%d", disabler.Id)
|
||||||
|
<-disabler.Done
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for _, enabler := range enablers {
|
||||||
|
enablerLoop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case env, ok := <-enabler.Environments:
|
||||||
|
if !ok {
|
||||||
|
break enablerLoop
|
||||||
|
}
|
||||||
|
logrus.Infof("enabler #%d: %v", enabler.Id, env.ZitiIdentity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, enabler := range enablers {
|
||||||
|
<-enabler.Done
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc != nil {
|
||||||
|
scCancel()
|
||||||
|
<-sc.Closed
|
||||||
|
if err := sc.Store(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("complete")
|
||||||
|
}
|
@ -38,6 +38,7 @@ type Config struct {
|
|||||||
type AdminConfig struct {
|
type AdminConfig struct {
|
||||||
Secrets []string `cf:"+secret"`
|
Secrets []string `cf:"+secret"`
|
||||||
TouLink string
|
TouLink string
|
||||||
|
NewAccountLink string
|
||||||
ProfileEndpoint string
|
ProfileEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ func (ch *configurationHandler) Handle(_ metadata.ConfigurationParams) middlewar
|
|||||||
}
|
}
|
||||||
if cfg.Admin != nil {
|
if cfg.Admin != nil {
|
||||||
data.TouLink = cfg.Admin.TouLink
|
data.TouLink = cfg.Admin.TouLink
|
||||||
|
data.NewAccountLink = cfg.Admin.NewAccountLink
|
||||||
}
|
}
|
||||||
if cfg.Invites != nil {
|
if cfg.Invites != nil {
|
||||||
data.InviteTokenContact = cfg.Invites.TokenContact
|
data.InviteTokenContact = cfg.Invites.TokenContact
|
||||||
|
284
controller/unbootstrap.go
Normal file
284
controller/unbootstrap.go
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client"
|
||||||
|
apiConfig "github.com/openziti/edge-api/rest_management_api_client/config"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client/edge_router_policy"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client/identity"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client/service"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client/service_edge_router_policy"
|
||||||
|
"github.com/openziti/edge-api/rest_management_api_client/service_policy"
|
||||||
|
"github.com/openziti/zrok/controller/config"
|
||||||
|
"github.com/openziti/zrok/controller/zrokEdgeSdk"
|
||||||
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Unbootstrap(cfg *config.Config) error {
|
||||||
|
edge, err := zrokEdgeSdk.Client(cfg.Ziti)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := unbootstrapServiceEdgeRouterPolicies(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping service edge router policies: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapServicePolicies(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping service policies: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapConfigs(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootrapping configs: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapServices(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping services: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapEdgeRouterPolicies(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping edge router policies: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapIdentities(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping identities: %v", err)
|
||||||
|
}
|
||||||
|
if err := unbootstrapConfigType(edge); err != nil {
|
||||||
|
logrus.Errorf("error unbootstrapping config type: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapServiceEdgeRouterPolicies(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &service_edge_router_policy.ListServiceEdgeRouterPoliciesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.ServiceEdgeRouterPolicy.ListServiceEdgeRouterPolicies(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, serp := range listResp.Payload.Data {
|
||||||
|
delReq := &service_edge_router_policy.DeleteServiceEdgeRouterPolicyParams{
|
||||||
|
ID: *serp.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.ServiceEdgeRouterPolicy.DeleteServiceEdgeRouterPolicy(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted service edge router policy '%v'", *serp.ID)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapServicePolicies(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &service_policy.ListServicePoliciesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.ServicePolicy.ListServicePolicies(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, sp := range listResp.Payload.Data {
|
||||||
|
delReq := &service_policy.DeleteServicePolicyParams{
|
||||||
|
ID: *sp.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.ServicePolicy.DeleteServicePolicy(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted service policy '%v'", *sp.ID)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapServices(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &service.ListServicesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.Service.ListServices(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, svc := range listResp.Payload.Data {
|
||||||
|
delReq := &service.DeleteServiceParams{
|
||||||
|
ID: *svc.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.Service.DeleteService(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted service '%v' (%v)", *svc.ID, *svc.Name)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapEdgeRouterPolicies(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &edge_router_policy.ListEdgeRouterPoliciesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.EdgeRouterPolicy.ListEdgeRouterPolicies(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, erp := range listResp.Payload.Data {
|
||||||
|
delReq := &edge_router_policy.DeleteEdgeRouterPolicyParams{
|
||||||
|
ID: *erp.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.EdgeRouterPolicy.DeleteEdgeRouterPolicy(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted edge router policy '%v'", *erp.ID)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapIdentities(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &identity.ListIdentitiesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.Identity.ListIdentities(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, i := range listResp.Payload.Data {
|
||||||
|
delReq := &identity.DeleteIdentityParams{
|
||||||
|
ID: *i.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.Identity.DeleteIdentity(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted identity '%v' (%v)", *i.ID, *i.Name)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapConfigs(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := "tags.zrok != null"
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &apiConfig.ListConfigsParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.Config.ListConfigs(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, listCfg := range listResp.Payload.Data {
|
||||||
|
delReq := &apiConfig.DeleteConfigParams{
|
||||||
|
ID: *listCfg.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.Config.DeleteConfig(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted config '%v'", *listCfg.ID)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unbootstrapConfigType(edge *rest_management_api_client.ZitiEdgeManagement) error {
|
||||||
|
for {
|
||||||
|
filter := fmt.Sprintf("name = \"%v\"", sdk.ZrokProxyConfig)
|
||||||
|
limit := int64(100)
|
||||||
|
offset := int64(0)
|
||||||
|
listReq := &apiConfig.ListConfigTypesParams{
|
||||||
|
Filter: &filter,
|
||||||
|
Limit: &limit,
|
||||||
|
Offset: &offset,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
listResp, err := edge.Config.ListConfigTypes(listReq, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(listResp.Payload.Data) < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for _, listCfgType := range listResp.Payload.Data {
|
||||||
|
delReq := &apiConfig.DeleteConfigTypeParams{
|
||||||
|
ID: *listCfgType.ID,
|
||||||
|
Context: context.Background(),
|
||||||
|
}
|
||||||
|
_, err := edge.Config.DeleteConfigType(delReq, nil)
|
||||||
|
if err == nil {
|
||||||
|
logrus.Infof("deleted config type '%v' (%v)", *listCfgType.ID, *listCfgType.Name)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
# this builds docker.io/openziti/zrok
|
# this builds docker.io/openziti/zrok
|
||||||
FROM docker.io/openziti/ziti-cli:1.3.3
|
FROM docker.io/openziti/ziti-cli:1.4.3
|
||||||
|
|
||||||
ARG ARTIFACTS_DIR=./dist
|
ARG ARTIFACTS_DIR=./dist
|
||||||
ARG DOCKER_BUILD_DIR=.
|
ARG DOCKER_BUILD_DIR=.
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
This formula is maintained by the Homebrew community.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
brew install zrok
|
brew install zrok
|
||||||
```
|
```
|
||||||
|
@ -19,7 +19,7 @@ import DownloadCardStyles from '@site/src/css/download-card.module.css';
|
|||||||
<DownloadCard
|
<DownloadCard
|
||||||
osName="Linux"
|
osName="Linux"
|
||||||
osLogo="/img/logo-linux.svg"
|
osLogo="/img/logo-linux.svg"
|
||||||
infoText="RPM/DEB or Homebrew"
|
infoText="RPM/DEB/AUR or Homebrew"
|
||||||
guideLink="/docs/guides/install/linux"
|
guideLink="/docs/guides/install/linux"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,9 +10,9 @@ import AnsibleRepoSetup from './_ansible_repo_setup.yaml'
|
|||||||
import ConcatenateYamlSnippets from '@site/src/components/cat-yaml.jsx'
|
import ConcatenateYamlSnippets from '@site/src/components/cat-yaml.jsx'
|
||||||
import Homebrew from './_homebrew.mdx';
|
import Homebrew from './_homebrew.mdx';
|
||||||
|
|
||||||
## Install `zrok` from the Repository
|
## Package Repository
|
||||||
|
|
||||||
This will configure the system to receive DEB or RPM package updates.
|
The RedHat (RPM) and Debian (DEB) packages are maintained by NetFoundry.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
curl -sSf https://get.openziti.io/install.bash | sudo bash -s zrok
|
curl -sSf https://get.openziti.io/install.bash | sudo bash -s zrok
|
||||||
@ -43,10 +43,6 @@ Check out [zrok frontdoor](/guides/frontdoor.mdx?os=Linux) for running `zrok` as
|
|||||||
|
|
||||||
</Details>
|
</Details>
|
||||||
|
|
||||||
## Homebrew
|
|
||||||
|
|
||||||
<Homebrew />
|
|
||||||
|
|
||||||
## Linux Binary
|
## Linux Binary
|
||||||
|
|
||||||
<AssetsProvider>
|
<AssetsProvider>
|
||||||
@ -94,7 +90,7 @@ Download the binary distribution for your Linux distribution's architecture or r
|
|||||||
/ /| | | (_) | <
|
/ /| | | (_) | <
|
||||||
/___|_| \___/|_|\_\
|
/___|_| \___/|_|\_\
|
||||||
|
|
||||||
v0.4.0 [c889005]
|
v1.0.0 [c889005]
|
||||||
```
|
```
|
||||||
|
|
||||||
</Details>
|
</Details>
|
||||||
@ -133,4 +129,12 @@ sudo install -o root -g root ./zrok /usr/local/bin/;
|
|||||||
zrok version;
|
zrok version;
|
||||||
```
|
```
|
||||||
|
|
||||||
</Details>
|
</Details>
|
||||||
|
|
||||||
|
## Arch User Repository
|
||||||
|
|
||||||
|
[An Arch User Repository (AUR) package](https://aur.archlinux.org/packages/zrok-bin) is maintained by the Arch community. As of April 2025, the AUR package includes the `zrok` CLI and [the `zrok-agent.service` systemd `--user` service](/guides/agent/linux-service.mdx).
|
||||||
|
|
||||||
|
## Homebrew Formula
|
||||||
|
|
||||||
|
<Homebrew />
|
||||||
|
@ -68,7 +68,7 @@ Create a `zrok` controller configuration file in `etc/ctrl.yml`. The controller
|
|||||||
# /___|_| \___/|_|\_\
|
# /___|_| \___/|_|\_\
|
||||||
# controller configuration
|
# controller configuration
|
||||||
|
|
||||||
v: 3
|
v: 4
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
# generate these admin tokens from a source of randomness, e.g.
|
# generate these admin tokens from a source of randomness, e.g.
|
||||||
|
32
docs/myzrok/limits.md
Normal file
32
docs/myzrok/limits.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
title: Limits
|
||||||
|
---
|
||||||
|
|
||||||
|
NetFoundry's public zrok instance implements various limits based on pricing tier,
|
||||||
|
as well as rate limits in order to protect the service for all users.
|
||||||
|
|
||||||
|
### Limits on Shares, Environments, or Bandwidth
|
||||||
|
|
||||||
|
The number of shares, enviroments, or allowed bandwidth is based on the limits outlined within your myzrok subscription.
|
||||||
|
These limits are defined on the [zrok pricing](https://zrok.io/pricing/) page.
|
||||||
|
Bandwidth limitations are based on a rolling 24 hour window. Note that if you exceed the daily bandwidth of your plan,
|
||||||
|
any running shares will be disabled, and the zrok API will prevent any new shares from being created until the bandwidth
|
||||||
|
falls back below the 24 hour limit.
|
||||||
|
|
||||||
|
### Rate Limitations For Public Shares
|
||||||
|
Public shares are subject to API rate limiting, both by IP address, as well as the individual share token.
|
||||||
|
These limits exist to protect the zrok service so that one user does not negatively impact the experience for others.
|
||||||
|
The rate limits for public shares are defined below:
|
||||||
|
|
||||||
|
#### Per IP Address
|
||||||
|
2000 requests per 300 seconds (average of 6.66 requests per second)
|
||||||
|
|
||||||
|
The rate limiter will allow a burst of requests in a shorter timespan up to 2000 requests, but once the rate limit has been exceeded,
|
||||||
|
new requests will be blocked until the request rate falls below the limit of the 300 second window.
|
||||||
|
|
||||||
|
#### Per Share
|
||||||
|
7500 requests per 300 seconds from *any number of IP addresses* (average of 25 requests per second)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
51
docs/myzrok/upgrading.md
Normal file
51
docs/myzrok/upgrading.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
title: Upgrading From 0.4 to 1.0
|
||||||
|
---
|
||||||
|
|
||||||
|
## Upgrading an existing 0.4 environment
|
||||||
|
If you have not already, [install the latest 1.x zrok binary](/docs/guides/install) into your environment.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
As of zrok `1.0.2`, the zrok rebase is automatic and the configuration will automatically be updated to the v1 API.
|
||||||
|
No action is necessary.
|
||||||
|
:::
|
||||||
|
|
||||||
|
If you are running version `1.0.0` or `1.0.1`, you can run the following to rebase your environment to use the new versioned API:
|
||||||
|
```
|
||||||
|
zrok rebase apiEndpoint https://api-v1.zrok.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Resume zrok API interactions as normal!
|
||||||
|
|
||||||
|
|
||||||
|
## Trouble after upgrade?
|
||||||
|
|
||||||
|
If you run into any issues after upgrading your environment, first verify your zrok version and review your current zrok configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
zrok version
|
||||||
|
```
|
||||||
|
Review the `apiEndpoint` configuration, if you are running version `1.0` or later, the `apiEndpoint` should be `https://api-v1.zrok.io`
|
||||||
|
```
|
||||||
|
zrok status
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're still having issues, we recommend you reach out to our community support team at our [zrok discourse](https://openziti.discourse.group/c/zrok/24) forum.
|
||||||
|
|
||||||
|
If you prefer to do a hard reset of your environment, you can also run the commands below:
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
Running `zrok disable` will delete any running environments or shares, and will release any reserved shares
|
||||||
|
:::
|
||||||
|
```
|
||||||
|
zrok disable
|
||||||
|
```
|
||||||
|
|
||||||
|
Reset the config back to the default API endpoint for the binary version
|
||||||
|
```
|
||||||
|
zrok config unset apiEndpoint
|
||||||
|
```
|
||||||
|
Create a fresh environment
|
||||||
|
```
|
||||||
|
zrok enable <your account token>
|
||||||
|
```
|
@ -6,8 +6,10 @@ import (
|
|||||||
"github.com/openziti/zrok/environment/env_core"
|
"github.com/openziti/zrok/environment/env_core"
|
||||||
"github.com/openziti/zrok/environment/env_v0_3"
|
"github.com/openziti/zrok/environment/env_v0_3"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const V = "v0.4"
|
const V = "v0.4"
|
||||||
@ -286,6 +288,13 @@ func loadEnvironment() (*env_core.Environment, error) {
|
|||||||
ZitiIdentity: env.ZId,
|
ZitiIdentity: env.ZId,
|
||||||
ApiEndpoint: env.ApiEndpoint,
|
ApiEndpoint: env.ApiEndpoint,
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(env.ApiEndpoint, "https://api.zrok.io") {
|
||||||
|
out.ApiEndpoint = "https://api-v1.zrok.io"
|
||||||
|
if err := saveEnvironment(out); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error auto-rebasing apiEndpoint")
|
||||||
|
}
|
||||||
|
logrus.Info("auto-rebased 'apiEndpoint' for v1.0.x")
|
||||||
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,15 @@ admin:
|
|||||||
secrets:
|
secrets:
|
||||||
- 77623cad-1847-4d6d-8ffe-37defc33c909
|
- 77623cad-1847-4d6d-8ffe-37defc33c909
|
||||||
#
|
#
|
||||||
# If `tou_link` is present, the frontend will display the "Terms of Use" link on the login and registration forms
|
# If `tou_link` is present, the API console will display the "Terms of Use" link on the login and registration forms
|
||||||
#
|
#
|
||||||
tou_link: '<a href="https://google.com" target="_">Terms and Conditions</a>'
|
tou_link: '<a href="https://google.com" target="_">Terms and Conditions</a>'
|
||||||
#
|
#
|
||||||
|
# If `new_account_link` is present, the API console will inject the contents of this setting into the login form; the
|
||||||
|
# intention is that it is used to present a "How do I get an account?" link.
|
||||||
|
#
|
||||||
|
new_account_link: '<a href="https://google.com" target="_">How do I get an account?</a>'
|
||||||
|
#
|
||||||
# If `profile_endpoint` is present, the controller will start a `net/http/pprof` endpoint at the specified host:port
|
# If `profile_endpoint` is present, the controller will start a `net/http/pprof` endpoint at the specified host:port
|
||||||
#
|
#
|
||||||
#profile_endpoint: localhost:6060
|
#profile_endpoint: localhost:6060
|
||||||
|
@ -23,6 +23,9 @@ type Configuration struct {
|
|||||||
// invites open
|
// invites open
|
||||||
InvitesOpen bool `json:"invitesOpen,omitempty"`
|
InvitesOpen bool `json:"invitesOpen,omitempty"`
|
||||||
|
|
||||||
|
// new account link
|
||||||
|
NewAccountLink string `json:"newAccountLink,omitempty"`
|
||||||
|
|
||||||
// requires invite token
|
// requires invite token
|
||||||
RequiresInviteToken bool `json:"requiresInviteToken,omitempty"`
|
RequiresInviteToken bool `json:"requiresInviteToken,omitempty"`
|
||||||
|
|
||||||
|
@ -1985,6 +1985,9 @@ func init() {
|
|||||||
"invitesOpen": {
|
"invitesOpen": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"newAccountLink": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"requiresInviteToken": {
|
"requiresInviteToken": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
@ -4298,6 +4301,9 @@ func init() {
|
|||||||
"invitesOpen": {
|
"invitesOpen": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"newAccountLink": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"requiresInviteToken": {
|
"requiresInviteToken": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
50
sdk/golang/sdk/environment.go
Normal file
50
sdk/golang/sdk/environment.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package sdk
|
||||||
|
|
||||||
|
import (
|
||||||
|
httptransport "github.com/go-openapi/runtime/client"
|
||||||
|
"github.com/openziti/zrok/environment/env_core"
|
||||||
|
restEnvironment "github.com/openziti/zrok/rest_client_zrok/environment"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnableEnvironment(root env_core.Root, request *EnableRequest) (*Environment, error) {
|
||||||
|
zrok, err := root.Client()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create zrok client")
|
||||||
|
}
|
||||||
|
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().AccountToken)
|
||||||
|
|
||||||
|
req := restEnvironment.NewEnableParams()
|
||||||
|
req.Body.Description = request.Description
|
||||||
|
req.Body.Host = request.Host
|
||||||
|
|
||||||
|
resp, err := zrok.Environment.Enable(req, auth)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Environment{
|
||||||
|
Host: request.Host,
|
||||||
|
Description: request.Description,
|
||||||
|
ZitiIdentity: resp.Payload.Identity,
|
||||||
|
ZitiConfig: resp.Payload.Cfg,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DisableEnvironment(env *Environment, root env_core.Root) error {
|
||||||
|
zrok, err := root.Client()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not create zrok client")
|
||||||
|
}
|
||||||
|
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().AccountToken)
|
||||||
|
|
||||||
|
req := restEnvironment.NewDisableParams()
|
||||||
|
req.Body.Identity = env.ZitiIdentity
|
||||||
|
|
||||||
|
_, err = zrok.Environment.Disable(req, auth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -2,6 +2,18 @@ package sdk
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
type EnableRequest struct {
|
||||||
|
Host string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Environment struct {
|
||||||
|
Host string
|
||||||
|
Description string
|
||||||
|
ZitiIdentity string
|
||||||
|
ZitiConfig string
|
||||||
|
}
|
||||||
|
|
||||||
type BackendMode string
|
type BackendMode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -31,6 +31,12 @@ export interface ModelConfiguration {
|
|||||||
* @memberof ModelConfiguration
|
* @memberof ModelConfiguration
|
||||||
*/
|
*/
|
||||||
touLink?: string;
|
touLink?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ModelConfiguration
|
||||||
|
*/
|
||||||
|
newAccountLink?: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@ -70,6 +76,7 @@ export function ModelConfigurationFromJSONTyped(json: any, ignoreDiscriminator:
|
|||||||
|
|
||||||
'version': json['version'] == null ? undefined : json['version'],
|
'version': json['version'] == null ? undefined : json['version'],
|
||||||
'touLink': json['touLink'] == null ? undefined : json['touLink'],
|
'touLink': json['touLink'] == null ? undefined : json['touLink'],
|
||||||
|
'newAccountLink': json['newAccountLink'] == null ? undefined : json['newAccountLink'],
|
||||||
'invitesOpen': json['invitesOpen'] == null ? undefined : json['invitesOpen'],
|
'invitesOpen': json['invitesOpen'] == null ? undefined : json['invitesOpen'],
|
||||||
'requiresInviteToken': json['requiresInviteToken'] == null ? undefined : json['requiresInviteToken'],
|
'requiresInviteToken': json['requiresInviteToken'] == null ? undefined : json['requiresInviteToken'],
|
||||||
'inviteTokenContact': json['inviteTokenContact'] == null ? undefined : json['inviteTokenContact'],
|
'inviteTokenContact': json['inviteTokenContact'] == null ? undefined : json['inviteTokenContact'],
|
||||||
@ -89,6 +96,7 @@ export function ModelConfigurationToJSONTyped(value?: ModelConfiguration | null,
|
|||||||
|
|
||||||
'version': value['version'],
|
'version': value['version'],
|
||||||
'touLink': value['touLink'],
|
'touLink': value['touLink'],
|
||||||
|
'newAccountLink': value['newAccountLink'],
|
||||||
'invitesOpen': value['invitesOpen'],
|
'invitesOpen': value['invitesOpen'],
|
||||||
'requiresInviteToken': value['requiresInviteToken'],
|
'requiresInviteToken': value['requiresInviteToken'],
|
||||||
'inviteTokenContact': value['inviteTokenContact'],
|
'inviteTokenContact': value['inviteTokenContact'],
|
||||||
|
@ -7,6 +7,7 @@ Name | Type | Description | Notes
|
|||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**version** | **str** | | [optional]
|
**version** | **str** | | [optional]
|
||||||
**tou_link** | **str** | | [optional]
|
**tou_link** | **str** | | [optional]
|
||||||
|
**new_account_link** | **str** | | [optional]
|
||||||
**invites_open** | **bool** | | [optional]
|
**invites_open** | **bool** | | [optional]
|
||||||
**requires_invite_token** | **bool** | | [optional]
|
**requires_invite_token** | **bool** | | [optional]
|
||||||
**invite_token_contact** | **str** | | [optional]
|
**invite_token_contact** | **str** | | [optional]
|
||||||
|
@ -37,6 +37,7 @@ class TestConfiguration(unittest.TestCase):
|
|||||||
return Configuration(
|
return Configuration(
|
||||||
version = '',
|
version = '',
|
||||||
tou_link = '',
|
tou_link = '',
|
||||||
|
new_account_link = '',
|
||||||
invites_open = True,
|
invites_open = True,
|
||||||
requires_invite_token = True,
|
requires_invite_token = True,
|
||||||
invite_token_contact = ''
|
invite_token_contact = ''
|
||||||
|
@ -28,10 +28,11 @@ class Configuration(BaseModel):
|
|||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
version: Optional[StrictStr] = None
|
version: Optional[StrictStr] = None
|
||||||
tou_link: Optional[StrictStr] = Field(default=None, alias="touLink")
|
tou_link: Optional[StrictStr] = Field(default=None, alias="touLink")
|
||||||
|
new_account_link: Optional[StrictStr] = Field(default=None, alias="newAccountLink")
|
||||||
invites_open: Optional[StrictBool] = Field(default=None, alias="invitesOpen")
|
invites_open: Optional[StrictBool] = Field(default=None, alias="invitesOpen")
|
||||||
requires_invite_token: Optional[StrictBool] = Field(default=None, alias="requiresInviteToken")
|
requires_invite_token: Optional[StrictBool] = Field(default=None, alias="requiresInviteToken")
|
||||||
invite_token_contact: Optional[StrictStr] = Field(default=None, alias="inviteTokenContact")
|
invite_token_contact: Optional[StrictStr] = Field(default=None, alias="inviteTokenContact")
|
||||||
__properties: ClassVar[List[str]] = ["version", "touLink", "invitesOpen", "requiresInviteToken", "inviteTokenContact"]
|
__properties: ClassVar[List[str]] = ["version", "touLink", "newAccountLink", "invitesOpen", "requiresInviteToken", "inviteTokenContact"]
|
||||||
|
|
||||||
model_config = ConfigDict(
|
model_config = ConfigDict(
|
||||||
populate_by_name=True,
|
populate_by_name=True,
|
||||||
@ -86,6 +87,7 @@ class Configuration(BaseModel):
|
|||||||
_obj = cls.model_validate({
|
_obj = cls.model_validate({
|
||||||
"version": obj.get("version"),
|
"version": obj.get("version"),
|
||||||
"touLink": obj.get("touLink"),
|
"touLink": obj.get("touLink"),
|
||||||
|
"newAccountLink": obj.get("newAccountLink"),
|
||||||
"invitesOpen": obj.get("invitesOpen"),
|
"invitesOpen": obj.get("invitesOpen"),
|
||||||
"requiresInviteToken": obj.get("requiresInviteToken"),
|
"requiresInviteToken": obj.get("requiresInviteToken"),
|
||||||
"inviteTokenContact": obj.get("inviteTokenContact")
|
"inviteTokenContact": obj.get("inviteTokenContact")
|
||||||
|
@ -1229,6 +1229,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
touLink:
|
touLink:
|
||||||
type: string
|
type: string
|
||||||
|
newAccountLink:
|
||||||
|
type: string
|
||||||
invitesOpen:
|
invitesOpen:
|
||||||
type: boolean
|
type: boolean
|
||||||
requiresInviteToken:
|
requiresInviteToken:
|
||||||
|
@ -13,14 +13,19 @@ const Login = ({ onLogin }: LoginProps) => {
|
|||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [tou, setTou] = useState(null as string);
|
const [tou, setTou] = useState<string>("");
|
||||||
|
const [newAccountLink, setNewAccountLink] = useState<string>("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
new MetadataApi()._configuration()
|
new MetadataApi()._configuration()
|
||||||
.then(d => {
|
.then(d => {
|
||||||
|
console.log("d", d);
|
||||||
if(d.touLink && d.touLink.trim() !== "") {
|
if(d.touLink && d.touLink.trim() !== "") {
|
||||||
setTou(d.touLink);
|
setTou(d.touLink);
|
||||||
}
|
}
|
||||||
|
if(d.newAccountLink && d.newAccountLink.trim() != "") {
|
||||||
|
setNewAccountLink(d.newAccountLink)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -86,6 +91,9 @@ const Login = ({ onLogin }: LoginProps) => {
|
|||||||
<Box component="div" style={{ textAlign: "center" }}>
|
<Box component="div" style={{ textAlign: "center" }}>
|
||||||
<Link to="/forgotPassword">Forgot Password?</Link>
|
<Link to="/forgotPassword">Forgot Password?</Link>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box component="div" style={{ textAlign: "center" }}>
|
||||||
|
<div dangerouslySetInnerHTML={{__html: newAccountLink}}></div>
|
||||||
|
</Box>
|
||||||
<Box component="div" style={{ textAlign: "center" }}>
|
<Box component="div" style={{ textAlign: "center" }}>
|
||||||
<div dangerouslySetInnerHTML={{__html: tou}}></div>
|
<div dangerouslySetInnerHTML={{__html: tou}}></div>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -70,6 +70,9 @@ const ReleaseAccessModal = ({ close, isOpen, user, access, detail }: ReleaseAcce
|
|||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<Typography variant="body1">Would you like to release the access <code>{frontendToken}</code> ?</Typography>
|
<Typography variant="body1">Would you like to release the access <code>{frontendToken}</code> ?</Typography>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
|
<Typography variant="h6" color="red">WARNING: This operation removes permissions and frees resources, but it does NOT terminate your <code>zrok access</code> process—you must do that manually.</Typography>
|
||||||
|
</Grid2>
|
||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{frontendToken}</code></p>} sx={{ mt: 2 }} />
|
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{frontendToken}</code></p>} sx={{ mt: 2 }} />
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
@ -69,7 +69,7 @@ const ReleaseEnvironmentModal = ({ close, isOpen, user, environment, detail }: R
|
|||||||
<Typography variant="body1">Would you like to release the environment <code>{description}</code> ?</Typography>
|
<Typography variant="body1">Would you like to release the environment <code>{description}</code> ?</Typography>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<Typography variant="body1">Releasing this environment will also release any shares and accesses that are associated with it.</Typography>
|
<Typography variant="h6" color="red">WARNING: Releasing this environment will also release any shares and accesses that are associated with it. This operation removes permissions and frees resources, but it does NOT terminate your <code>zrok share</code> or <code>zrok access</code> processes—you must do that manually.</Typography>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{description}</code></p>} sx={{ mt: 2 }} />
|
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{description}</code></p>} sx={{ mt: 2 }} />
|
||||||
|
@ -70,6 +70,9 @@ const ReleaseShareModal = ({ close, isOpen, user, share, detail }: ReleaseShareP
|
|||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<Typography variant="body1">Would you like to release the share <code>{shareToken}</code> ?</Typography>
|
<Typography variant="body1">Would you like to release the share <code>{shareToken}</code> ?</Typography>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
|
<Typography variant="h6" color="red">WARNING: This operation removes permissions and frees resources, but it does NOT terminate your <code>zrok share</code> process—you must do that manually.</Typography>
|
||||||
|
</Grid2>
|
||||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||||
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{shareToken}</code></p>} sx={{ mt: 2 }} />
|
<FormControlLabel control={<Checkbox checked={checked} onChange={toggleChecked} />} label={<p>I confirm the release of <code>{shareToken}</code></p>} sx={{ mt: 2 }} />
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
@ -31,6 +31,12 @@ export interface ModelConfiguration {
|
|||||||
* @memberof ModelConfiguration
|
* @memberof ModelConfiguration
|
||||||
*/
|
*/
|
||||||
touLink?: string;
|
touLink?: string;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ModelConfiguration
|
||||||
|
*/
|
||||||
|
newAccountLink?: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@ -70,6 +76,7 @@ export function ModelConfigurationFromJSONTyped(json: any, ignoreDiscriminator:
|
|||||||
|
|
||||||
'version': json['version'] == null ? undefined : json['version'],
|
'version': json['version'] == null ? undefined : json['version'],
|
||||||
'touLink': json['touLink'] == null ? undefined : json['touLink'],
|
'touLink': json['touLink'] == null ? undefined : json['touLink'],
|
||||||
|
'newAccountLink': json['newAccountLink'] == null ? undefined : json['newAccountLink'],
|
||||||
'invitesOpen': json['invitesOpen'] == null ? undefined : json['invitesOpen'],
|
'invitesOpen': json['invitesOpen'] == null ? undefined : json['invitesOpen'],
|
||||||
'requiresInviteToken': json['requiresInviteToken'] == null ? undefined : json['requiresInviteToken'],
|
'requiresInviteToken': json['requiresInviteToken'] == null ? undefined : json['requiresInviteToken'],
|
||||||
'inviteTokenContact': json['inviteTokenContact'] == null ? undefined : json['inviteTokenContact'],
|
'inviteTokenContact': json['inviteTokenContact'] == null ? undefined : json['inviteTokenContact'],
|
||||||
@ -89,6 +96,7 @@ export function ModelConfigurationToJSONTyped(value?: ModelConfiguration | null,
|
|||||||
|
|
||||||
'version': value['version'],
|
'version': value['version'],
|
||||||
'touLink': value['touLink'],
|
'touLink': value['touLink'],
|
||||||
|
'newAccountLink': value['newAccountLink'],
|
||||||
'invitesOpen': value['invitesOpen'],
|
'invitesOpen': value['invitesOpen'],
|
||||||
'requiresInviteToken': value['requiresInviteToken'],
|
'requiresInviteToken': value['requiresInviteToken'],
|
||||||
'inviteTokenContact': value['inviteTokenContact'],
|
'inviteTokenContact': value['inviteTokenContact'],
|
||||||
|
4373
website/package-lock.json
generated
4373
website/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,9 +14,9 @@
|
|||||||
"write-heading-ids": "docusaurus write-heading-ids"
|
"write-heading-ids": "docusaurus write-heading-ids"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "^3.6.0",
|
"@docusaurus/core": "^3.7.0",
|
||||||
"@docusaurus/plugin-client-redirects": "^3.6.0",
|
"@docusaurus/plugin-client-redirects": "^3.7.0",
|
||||||
"@docusaurus/preset-classic": "^3.6.0",
|
"@docusaurus/preset-classic": "^3.7.0",
|
||||||
"@mdx-js/react": "^3.0.1",
|
"@mdx-js/react": "^3.0.1",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"remark-math": "^5.1.1"
|
"remark-math": "^5.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^3.6.0",
|
"@docusaurus/module-type-aliases": "^3.7.0",
|
||||||
"yaml-loader": "^0.8.0"
|
"yaml-loader": "^0.8.0"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user