mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
Compare commits
11
Commits
v0.19.0
...
hub-landing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e698f6d06e | ||
|
|
03ff4cd51d | ||
|
|
519825c34a | ||
|
|
eebb7b51ed | ||
|
|
5ecd09aa2b | ||
|
|
34560470ce | ||
|
|
dd68079005 | ||
|
|
d23f1bdc00 | ||
|
|
4503b17046 | ||
|
|
4a12217e65 | ||
|
|
e7a62f6908 |
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/ucind"
|
"github.com/psviderski/uncloud/internal/ucind"
|
||||||
|
"github.com/psviderski/uncloud/internal/ucind/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,6 +27,12 @@ func NewRemoveCommand() *cobra.Command {
|
|||||||
fmt.Printf("Cluster '%s' removed.\n", name)
|
fmt.Printf("Cluster '%s' removed.\n", name)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
return completion.Clusters(cmd, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
composecli "github.com/compose-spec/compose-go/v2/cli"
|
composecli "github.com/compose-spec/compose-go/v2/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/pkg/client/compose"
|
"github.com/psviderski/uncloud/pkg/client/compose"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -50,6 +51,9 @@ to cluster machines or --push-registry to upload them to external registries.`,
|
|||||||
return runBuild(cmd.Context(), uncli, opts)
|
return runBuild(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: "service",
|
GroupID: "service",
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
return completion.ComposeServices(cmd.Context(), args, toComplete, opts.files, opts.profiles)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringArrayVar(&opts.BuildArgs, "build-arg", nil,
|
cmd.Flags().StringArrayVar(&opts.BuildArgs, "build-arg", nil,
|
||||||
@@ -76,6 +80,8 @@ to cluster machines or --push-registry to upload them to external registries.`,
|
|||||||
cmd.Flags().BoolVar(&opts.PushRegistry, "push-registry", false,
|
cmd.Flags().BoolVar(&opts.PushRegistry, "push-registry", false,
|
||||||
"Upload the built images to external registries (e.g., Docker Hub) after building.")
|
"Upload the built images to external registries (e.g., Docker Hub) after building.")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alecthomas/chroma/v2/quick"
|
"github.com/alecthomas/chroma/v2/quick"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +34,8 @@ func NewConfigCommand() *cobra.Command {
|
|||||||
cmd.Flags().BoolVar(&opts.noColor, "no-color", false,
|
cmd.Flags().BoolVar(&opts.noColor, "no-color", false,
|
||||||
"Disable syntax highlighting for the output.")
|
"Disable syntax highlighting for the output.")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -48,6 +49,8 @@ func NewDeployCommand() *cobra.Command {
|
|||||||
"Machine names or IDs to deploy to. Can be specified multiple times or as a comma-separated "+
|
"Machine names or IDs to deploy to. Can be specified multiple times or as a comma-separated "+
|
||||||
"list. (default is all machines)")
|
"list. (default is all machines)")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,8 +175,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
|
|||||||
return fmt.Errorf("confirm deployment: %w", err)
|
return fmt.Errorf("confirm deployment: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. No changes were made.")
|
return cli.Cancelled("Caddy deploy cancelled. No changes were made.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
err = progress.RunWithTitle(ctx, func(ctx context.Context) error {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,6 +30,13 @@ func NewUseCommand() *cobra.Command {
|
|||||||
|
|
||||||
return selectContext(uncli)
|
return selectContext(uncli)
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Contexts(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/logs"
|
"github.com/psviderski/uncloud/internal/cli/logs"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -48,6 +49,9 @@ func NewDeployCommand() *cobra.Command {
|
|||||||
return runDeploy(cmd.Context(), uncli, opts)
|
return runDeploy(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: "service",
|
GroupID: "service",
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
return completion.ComposeServices(cmd.Context(), args, toComplete, opts.files, opts.profiles)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringArrayVar(&opts.BuildServicesOptions.BuildArgs, "build-arg", nil,
|
cmd.Flags().StringArrayVar(&opts.BuildServicesOptions.BuildArgs, "build-arg", nil,
|
||||||
@@ -218,8 +222,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
|
|||||||
return fmt.Errorf("confirm deployment: %w", err)
|
return fmt.Errorf("confirm deployment: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. No changes were made.")
|
return cli.Cancelled("Deploy cancelled. No changes were made.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -62,6 +63,8 @@ func NewListCommand() *cobra.Command {
|
|||||||
"Filter images by machine name or ID. Can be specified multiple times or as a comma-separated list. "+
|
"Filter images by machine name or ID. Can be specified multiple times or as a comma-separated list. "+
|
||||||
"(default is include all machines)")
|
"(default is include all machines)")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/containerd/platforms"
|
"github.com/containerd/platforms"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -54,6 +55,8 @@ The image is uploaded to all cluster machines (default) or the specified machine
|
|||||||
"Local Docker must be configured to use containerd image store to support multi-platform images.",
|
"Local Docker must be configured to use containerd image store to support multi-platform images.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,11 +96,12 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||||
fmt.Sprintf("WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. "+
|
fmt.Sprintf("WireGuard endpoint address that other machines in the cluster should use to establish "+
|
||||||
"Default port %d is used if omitted.\n", network.WireGuardPort)+
|
"WireGuard connections\n"+
|
||||||
"Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.\n"+
|
"to this machine. This doesn't change the address/port WireGuard listens on the machine.\n"+
|
||||||
|
"Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is %d if omitted.\n", network.WireGuardPort)+
|
||||||
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.\n"+
|
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.\n"+
|
||||||
"If not specified, the machine's routable IPs and public IP are auto-detected and used as endpoints.",
|
"Defaults to the auto-detected public and routable machine IPs.",
|
||||||
)
|
)
|
||||||
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
||||||
"Auto-confirm prompts (e.g., resetting an already initialised machine).\n"+
|
"Auto-confirm prompts (e.g., resetting an already initialised machine).\n"+
|
||||||
@@ -231,8 +232,7 @@ func add(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteMachine,
|
|||||||
return fmt.Errorf("confirm deployment: %w", err)
|
return fmt.Errorf("confirm deployment: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. No changes were made.")
|
return cli.Cancelled("Caddy deploy cancelled. The machine has been added to the cluster.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,11 +135,12 @@ Connection methods:
|
|||||||
)
|
)
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||||
fmt.Sprintf("WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. "+
|
fmt.Sprintf("WireGuard endpoint address that other machines in the cluster should use to establish "+
|
||||||
"Default port %d is used if omitted.\n", network.WireGuardPort)+
|
"WireGuard connections\n"+
|
||||||
"Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.\n"+
|
"to this machine. This doesn't change the address/port WireGuard listens on the machine.\n"+
|
||||||
|
"Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is %d if omitted.\n", network.WireGuardPort)+
|
||||||
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.\n"+
|
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.\n"+
|
||||||
"If not specified, the machine's routable IPs and public IP are auto-detected and used as endpoints.",
|
"Defaults to the auto-detected public and routable machine IPs.",
|
||||||
)
|
)
|
||||||
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
||||||
"Auto-confirm prompts (e.g., resetting an already initialised machine).\n"+
|
"Auto-confirm prompts (e.g., resetting an already initialised machine).\n"+
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -37,6 +38,13 @@ func NewRmCommand() *cobra.Command {
|
|||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
return remove(cmd.Context(), uncli, args[0], opts)
|
return remove(cmd.Context(), uncli, args[0], opts)
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Machines(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -46,6 +47,13 @@ At least one flag must be specified to perform an update.`,
|
|||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
return update(cmd.Context(), uncli, cmd, opts, args[0])
|
return update(cmd.Context(), uncli, cmd, opts, args[0])
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Machines(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
@@ -59,9 +67,10 @@ At least one flag must be specified to perform an update.`,
|
|||||||
)
|
)
|
||||||
cmd.Flags().StringSliceVar(
|
cmd.Flags().StringSliceVar(
|
||||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||||
fmt.Sprintf("WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. "+
|
fmt.Sprintf("WireGuard endpoint address that other machines in the cluster should use to establish "+
|
||||||
"Default port %d is used if omitted.\n", network.WireGuardPort)+
|
"WireGuard connections\n"+
|
||||||
"Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.\n"+
|
"to this machine. This doesn't change the address/port WireGuard listens on the machine.\n"+
|
||||||
|
"Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is %d if omitted.\n", network.WireGuardPort)+
|
||||||
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.",
|
"Multiple endpoints can be specified by repeating the flag or using a comma-separated list.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -2,8 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
@@ -152,5 +154,11 @@ func main() {
|
|||||||
volume.NewRootCommand(),
|
volume.NewRootCommand(),
|
||||||
wg.NewRootCommand(),
|
wg.NewRootCommand(),
|
||||||
)
|
)
|
||||||
cobra.CheckErr(cmd.Execute())
|
if err := cmd.Execute(); err != nil {
|
||||||
|
if cancelled, ok := errors.AsType[*cli.CancelledError](err); ok {
|
||||||
|
fmt.Fprintln(os.Stderr, cancelled.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
cobra.CheckErr(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -55,6 +56,13 @@ If the service has multiple replicas and no container ID is specified, the comma
|
|||||||
return runExec(cmd.Context(), uncli, serviceName, command, opts)
|
return runExec(cmd.Context(), uncli, serviceName, command, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
execCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: run command in the background")
|
execCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: run command in the background")
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -30,6 +31,13 @@ func NewInspectCommand(groupID string) *cobra.Command {
|
|||||||
return inspect(cmd.Context(), uncli, opts)
|
return inspect(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
mapset "github.com/deckarep/golang-set/v2"
|
mapset "github.com/deckarep/golang-set/v2"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/logs"
|
"github.com/psviderski/uncloud/internal/cli/logs"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
@@ -61,12 +62,20 @@ If no services are specified, streams logs from all services defined in the Comp
|
|||||||
return runLogs(cmd.Context(), uncli, args, options)
|
return runLogs(cmd.Context(), uncli, args, options)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringSliceVar(&options.Files, "file", nil,
|
cmd.Flags().StringSliceVar(&options.Files, "file", nil,
|
||||||
"One or more Compose files to load service names from when no services are specified. (default compose.yaml)")
|
"One or more Compose files to load service names from when no services are specified. (default compose.yaml)")
|
||||||
|
|
||||||
cmd.Flags().AddFlagSet(logs.Flags(&options))
|
cmd.Flags().AddFlagSet(logs.Flags(&options))
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,6 +32,10 @@ directives in image Dockerfiles) are automatically removed with their containers
|
|||||||
return rm(cmd.Context(), uncli, opts)
|
return rm(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/docker/docker/daemon/names"
|
"github.com/docker/docker/daemon/names"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/secret"
|
"github.com/psviderski/uncloud/internal/secret"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client/deploy"
|
"github.com/psviderski/uncloud/pkg/client/deploy"
|
||||||
@@ -124,6 +125,8 @@ func NewRunCommand(groupID string) *cobra.Command {
|
|||||||
" -v /data/uploads:/app/uploads Bind mount /data/uploads host directory to /app/uploads in container\n"+
|
" -v /data/uploads:/app/uploads Bind mount /data/uploads host directory to /app/uploads in container\n"+
|
||||||
" -v /host/path:/container/path:ro Bind mount a host directory or file as read-only")
|
" -v /host/path:/container/path:ro Bind mount a host directory or file as read-only")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -44,6 +45,13 @@ func NewScaleCommand(groupID string) *cobra.Command {
|
|||||||
return scale(cmd.Context(), uncli, opts)
|
return scale(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
||||||
@@ -147,8 +155,7 @@ func scale(ctx context.Context, uncli *cli.CLI, opts scaleOptions) error {
|
|||||||
return fmt.Errorf("confirm scaling: %w", err)
|
return fmt.Errorf("confirm scaling: %w", err)
|
||||||
}
|
}
|
||||||
if !confirmed {
|
if !confirmed {
|
||||||
fmt.Println("Cancelled. No changes were made.")
|
return cli.Cancelled("Scaling cancelled. No changes were made.")
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,6 +31,10 @@ Services can be specified by name or ID.`,
|
|||||||
return start(cmd.Context(), uncli, opts)
|
return start(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,6 +34,10 @@ Services can be specified by name or ID. Stopped services can be restarted with
|
|||||||
return stop(cmd.Context(), uncli, opts)
|
return stop(cmd.Context(), uncli, opts)
|
||||||
},
|
},
|
||||||
GroupID: groupID,
|
GroupID: groupID,
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Services(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringVarP(&opts.signal, "signal", "s", "",
|
cmd.Flags().StringVarP(&opts.signal, "signal", "s", "",
|
||||||
"Signal to send to each container's main process.\n"+
|
"Signal to send to each container's main process.\n"+
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -50,6 +51,8 @@ func NewCreateCommand() *cobra.Command {
|
|||||||
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
||||||
"Name or ID of the machine to create the volume on.")
|
"Name or ID of the machine to create the volume on.")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -26,12 +27,21 @@ func NewInspectCommand() *cobra.Command {
|
|||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
return inspect(cmd.Context(), uncli, args[0], opts)
|
return inspect(cmd.Context(), uncli, args[0], opts)
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Volumes(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
||||||
"Name or ID of the machine where the volume is located. "+
|
"Name or ID of the machine where the volume is located. "+
|
||||||
"If not specified, the volume will be searched across all machines.")
|
"If not specified, the volume will be searched across all machines.")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -36,6 +37,8 @@ func NewListCommand() *cobra.Command {
|
|||||||
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false,
|
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false,
|
||||||
"Only display volume names.")
|
"Only display volume names.")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -30,6 +31,10 @@ func NewRemoveCommand() *cobra.Command {
|
|||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
return remove(cmd.Context(), uncli, args, opts)
|
return remove(cmd.Context(), uncli, args, opts)
|
||||||
},
|
},
|
||||||
|
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return completion.Volumes(cmd.Context(), uncli, args, toComplete)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVarP(&opts.force, "force", "f", false,
|
cmd.Flags().BoolVarP(&opts.force, "force", "f", false,
|
||||||
@@ -41,6 +46,8 @@ func NewRemoveCommand() *cobra.Command {
|
|||||||
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false,
|
||||||
"Do not prompt for confirmation before removing the volume(s).")
|
"Do not prompt for confirmation before removing the volume(s).")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/completion"
|
||||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -44,6 +45,9 @@ func newShowCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
cmd.Flags().StringVarP(&opts.machine, "machine", "m", "",
|
||||||
"Name or ID of the machine to show the configuration for. (default is connected machine)")
|
"Name or ID of the machine to show the configuration for. (default is connected machine)")
|
||||||
|
|
||||||
|
completion.MachinesFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
module github.com/psviderski/uncloud/experiment/netbird-load
|
||||||
|
|
||||||
|
go 1.26.1
|
||||||
|
|
||||||
|
require github.com/netbirdio/netbird v0.71.0
|
||||||
|
|
||||||
|
require (
|
||||||
|
cunicu.li/go-rosenpass v0.4.0 // indirect
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.38.3 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.31.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.18.10 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.29.1 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.38.2 // indirect
|
||||||
|
github.com/aws/smithy-go v1.23.0 // indirect
|
||||||
|
github.com/caddyserver/certmagic v0.21.3 // indirect
|
||||||
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/cilium/ebpf v0.15.0 // indirect
|
||||||
|
github.com/cloudflare/circl v1.3.3 // indirect
|
||||||
|
github.com/coder/websocket v1.8.14 // indirect
|
||||||
|
github.com/coreos/go-iptables v0.7.0 // indirect
|
||||||
|
github.com/creack/pty v1.1.24 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/gliderlabs/ssh v0.3.8 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
github.com/google/btree v1.1.2 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
|
github.com/google/nftables v0.3.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/gopacket/gopacket v1.1.1 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
|
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||||
|
github.com/huin/goupnp v1.2.0 // indirect
|
||||||
|
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||||
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
|
github.com/libdns/libdns v0.2.2 // indirect
|
||||||
|
github.com/libdns/route53 v1.5.0 // indirect
|
||||||
|
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||||
|
github.com/libp2p/go-netroute v0.4.0 // indirect
|
||||||
|
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||||
|
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
|
||||||
|
github.com/mdlayher/socket v0.5.1 // indirect
|
||||||
|
github.com/mholt/acmez/v2 v2.0.1 // indirect
|
||||||
|
github.com/miekg/dns v1.1.72 // indirect
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
|
github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 // indirect
|
||||||
|
github.com/pion/dtls/v2 v2.2.10 // indirect
|
||||||
|
github.com/pion/dtls/v3 v3.0.9 // indirect
|
||||||
|
github.com/pion/ice/v4 v4.0.0-00010101000000-000000000000 // indirect
|
||||||
|
github.com/pion/logging v0.2.4 // indirect
|
||||||
|
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||||
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
|
github.com/pion/stun/v2 v2.0.0 // indirect
|
||||||
|
github.com/pion/stun/v3 v3.1.0 // indirect
|
||||||
|
github.com/pion/transport/v2 v2.2.4 // indirect
|
||||||
|
github.com/pion/transport/v3 v3.1.1 // indirect
|
||||||
|
github.com/pion/turn/v3 v3.0.1 // indirect
|
||||||
|
github.com/pion/turn/v4 v4.1.1 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pkg/sftp v1.13.9 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
|
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
||||||
|
github.com/shoenig/go-m1cpu v0.2.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||||
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||||
|
github.com/things-go/go-socks5 v0.0.4 // indirect
|
||||||
|
github.com/ti-mo/conntrack v0.5.1 // indirect
|
||||||
|
github.com/ti-mo/netfilter v0.5.2 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||||
|
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||||
|
github.com/vishvananda/netns v0.0.5 // indirect
|
||||||
|
github.com/wlynxg/anet v0.0.5 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
github.com/zcalusic/sysinfo v1.1.3 // indirect
|
||||||
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
|
golang.org/x/crypto v0.50.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||||
|
golang.org/x/mod v0.34.0 // indirect
|
||||||
|
golang.org/x/net v0.53.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.36.0 // indirect
|
||||||
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
|
golang.org/x/sys v0.43.0 // indirect
|
||||||
|
golang.org/x/text v0.36.0 // indirect
|
||||||
|
golang.org/x/time v0.15.0 // indirect
|
||||||
|
golang.org/x/tools v0.43.0 // indirect
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 // indirect
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||||
|
google.golang.org/grpc v1.80.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260219192049-0f2374377e89 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mirror the replace directives from netbird's own go.mod.
|
||||||
|
// See https://github.com/netbirdio/netbird/blob/v0.71.0/go.mod.
|
||||||
|
replace (
|
||||||
|
github.com/cloudflare/circl => codeberg.org/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
||||||
|
github.com/dexidp/dex => github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1
|
||||||
|
github.com/dexidp/dex/api/v2 => github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1
|
||||||
|
github.com/getlantern/systray => github.com/netbirdio/systray v0.0.0-20231030152038-ef1ed2a27949
|
||||||
|
github.com/kardianos/service => github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502
|
||||||
|
github.com/mailru/easyjson => github.com/netbirdio/easyjson v0.9.0
|
||||||
|
github.com/pion/ice/v4 => github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51
|
||||||
|
golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0
|
||||||
|
)
|
||||||
@@ -0,0 +1,675 @@
|
|||||||
|
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
|
||||||
|
cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q=
|
||||||
|
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||||
|
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||||
|
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||||
|
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||||
|
codeberg.org/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6 h1:b8xUw3004wk+3ipBhu0VU4RtUJsegMIiqjxSK4++lzA=
|
||||||
|
codeberg.org/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
|
||||||
|
cunicu.li/go-rosenpass v0.4.0 h1:LtPtBgFWY/9emfgC4glKLEqS0MJTylzV6+ChRhiZERw=
|
||||||
|
cunicu.li/go-rosenpass v0.4.0/go.mod h1:MPbjH9nxV4l3vEagKVdFNwHOketqgS5/To1VYJplf/M=
|
||||||
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
|
filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=
|
||||||
|
filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/AppsFlyer/go-sundheit v0.6.0 h1:d2hBvCjBSb2lUsEWGfPigr4MCOt04sxB+Rppl0yUMSk=
|
||||||
|
github.com/AppsFlyer/go-sundheit v0.6.0/go.mod h1:LDdBHD6tQBtmHsdW+i1GwdTt6Wqc0qazf5ZEJVTbTME=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A=
|
||||||
|
github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
|
||||||
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||||
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.38.3 h1:B6cV4oxnMs45fql4yRH+/Po/YU+597zgWqvDpYMturk=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.38.3/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 h1:i8p8P4diljCr60PpJp6qZXNlgX4m2yQFpYk+9ZT+J4E=
|
||||||
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1/go.mod h1:ddqbooRZYNoJ2dsTwOty16rM+/Aqmk/GOXrK8cg7V00=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.31.6 h1:a1t8fXY4GT4xjyJExz4knbuoxSCacB5hT/WgtfPyLjo=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.31.6/go.mod h1:5ByscNi7R+ztvOGzeUaIu49vkMk2soq5NaH5PYe33MQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.18.10 h1:xdJnXCouCx8Y0NncgoptztUocIYLKeQxrCgN6x9sdhg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.18.10/go.mod h1:7tQk08ntj914F/5i9jC4+2HQTAuJirq7m1vZVIhEkWs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.6 h1:wbjnrrMnKew78/juW7I2BtKQwa1qlf6EjQgS69uYY14=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.6/go.mod h1:AtiqqNrDioJXuUgz3+3T0mBWN7Hro2n9wll2zRUc0ww=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 h1:uF68eJA6+S9iVr9WgX1NaRGyQ/6MdIyc4JNUo6TN1FA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6/go.mod h1:qlPeVZCGPiobx8wb1ft0GHT5l+dc6ldnwInDFaMvC7Y=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 h1:pa1DEC6JoI0zduhZePp3zmhWvk/xxm4NB8Hy/Tlsgos=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6/go.mod h1:gxEjPebnhWGJoaDdtDkA0JX46VRg1wcTHYe63OfX5pE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.6 h1:R0tNFJqfjHL3900cqhXuwQ+1K4G0xc9Yf8EDbFXCKEw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.6/go.mod h1:y/7sDdu+aJvPtGXr4xYosdpq9a6T9Z0jkXfugmti0rI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.6 h1:hncKj/4gR+TPauZgTAsxOxNcvBayhUlYZ6LO/BYiQ30=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.8.6/go.mod h1:OiIh45tp6HdJDDJGnja0mw8ihQGz3VGrUflLqSL0SmM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6 h1:LHS1YAIJXJ4K9zS+1d/xa9JAA9sL2QyXIQCQFQW/X08=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6/go.mod h1:c9PCiTEuh0wQID5/KqA32J+HAgZxN9tOGXKCiYJjTZI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.6 h1:nEXUSAwyUfLTgnc9cxlDWy637qsq4UWwp3sNAfl0Z3Y=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.6/go.mod h1:HGzIULx4Ge3Do2V0FaiYKcyKzOqwrhUZgCI77NisswQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 h1:MmLCRqP4U4Cw9gJ4bNrCG0mWqEtBlmAVleyelcHARMU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3/go.mod h1:AMPjK2YnRh0YgOID3PqhJA1BRNfXDfGOnSsKHtAe8yA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.87.3 h1:ETkfWcXP2KNPLecaDa++5bsQhCRa5M5sLUJa5DWYIIg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.87.3/go.mod h1:+/3ZTqoYb3Ur7DObD00tarKMLMuKg8iqz5CHEanqTnw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.29.1 h1:8OLZnVJPvjnrxEwHFg9hVUof/P4sibH+Ea4KKuqAGSg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.29.1/go.mod h1:27M3BpVi0C02UiQh1w9nsBEit6pLhlaH3NHna6WUbDE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.2 h1:gKWSTnqudpo8dAxqBqZnDoDWCiEh/40FziUjr/mo6uA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.2/go.mod h1:x7+rkNmRoEN1U13A6JE2fXne9EWyJy54o3n6d4mGaXQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.38.2 h1:YZPjhyaGzhDQEvsffDEcpycq49nl7fiGcfJTIo8BszI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.38.2/go.mod h1:2dIN8qhQfv37BdUYGgEC8Q3tteM3zFxTI1MLO2O3J3c=
|
||||||
|
github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE=
|
||||||
|
github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||||
|
github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE=
|
||||||
|
github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||||
|
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||||
|
github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
|
||||||
|
github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
|
||||||
|
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||||
|
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
|
||||||
|
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
||||||
|
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||||
|
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||||
|
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||||
|
github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8=
|
||||||
|
github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.18.0 h1:V9orjXynvu5wiC9SemFTWnG4F45v403aIcjWo0d41+A=
|
||||||
|
github.com/coreos/go-oidc/v3 v3.18.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||||
|
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||||
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0=
|
||||||
|
github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||||
|
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
|
github.com/eko/gocache/lib/v4 v4.2.0 h1:MNykyi5Xw+5Wu3+PUrvtOCaKSZM1nUSVftbzmeC7Yuw=
|
||||||
|
github.com/eko/gocache/lib/v4 v4.2.0/go.mod h1:7ViVmbU+CzDHzRpmB4SXKyyzyuJ8A3UW3/cszpcqB4M=
|
||||||
|
github.com/eko/gocache/store/go_cache/v4 v4.2.2 h1:tAI9nl6TLoJyKG1ujF0CS0n/IgTEMl+NivxtR5R3/hw=
|
||||||
|
github.com/eko/gocache/store/go_cache/v4 v4.2.2/go.mod h1:T9zkHokzr8K9EiC7RfMbDg6HSwaV6rv3UdcNu13SGcA=
|
||||||
|
github.com/eko/gocache/store/redis/v4 v4.2.2 h1:Thw31fzGuH3WzJywsdbMivOmP550D6JS7GDHhvCJPA0=
|
||||||
|
github.com/eko/gocache/store/redis/v4 v4.2.2/go.mod h1:LaTxLKx9TG/YUEybQvPMij++D7PBTIJ4+pzvk0ykz0w=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ=
|
||||||
|
github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/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=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
|
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||||
|
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/go-webauthn/webauthn v0.16.4 h1:R9jqR/cYZa7hRquFF7Za/8qoH/K/TIs1/Q/4CyGN+1Q=
|
||||||
|
github.com/go-webauthn/webauthn v0.16.4/go.mod h1:SU2ljAgToTV/YLPI0C05QS4qn+e04WpB5g1RMfcZfS4=
|
||||||
|
github.com/go-webauthn/x v0.2.3 h1:8oArS+Rc1SWFLXhE17KZNx258Z4kUSyaDgsSncCO5RA=
|
||||||
|
github.com/go-webauthn/x v0.2.3/go.mod h1:tM04GF3V6VYq79AZMl7vbj4q6pz9r7L2criWRzbWhPk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||||
|
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||||
|
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||||
|
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||||
|
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||||
|
github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg=
|
||||||
|
github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM=
|
||||||
|
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||||
|
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.21.0 h1:h45NjjzEO3faG9Lg/cFrBh2PgegVVgzqKzuZl/wMbiI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.21.0/go.mod h1:But/NJU6TnZsrLai/xBAQLLz+Hc7fHZJt/hsCz3Fih4=
|
||||||
|
github.com/gopacket/gopacket v1.1.1 h1:zbx9F9d6A7sWNkFKrvMBZTfGgxFoY4NgUudFVVHMfcw=
|
||||||
|
github.com/gopacket/gopacket v1.1.1/go.mod h1:HavMeONEl7W9036of9LbSWoonqhH7HA1+ZRO+rMIvFs=
|
||||||
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240212192251-757544f21357 h1:Fkzd8ktnpOR9h47SXHe2AYPwelXLH2GjGsjlAloiWfo=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.2-0.20240212192251-757544f21357/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
|
||||||
|
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||||
|
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
|
||||||
|
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
|
||||||
|
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||||
|
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
|
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
|
||||||
|
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||||
|
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||||
|
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||||
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
|
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||||
|
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||||
|
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
|
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||||
|
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
|
github.com/libdns/route53 v1.5.0 h1:2SKdpPFl/qgWsXQvsLNJJAoX7rSxlk7zgoL4jnWdXVA=
|
||||||
|
github.com/libdns/route53 v1.5.0/go.mod h1:joT4hKmaTNKHEwb7GmZ65eoDz1whTu7KKYPS8ZqIh6Q=
|
||||||
|
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
|
||||||
|
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
|
||||||
|
github.com/libp2p/go-netroute v0.4.0 h1:sZZx9hyANYUx9PZyqcgE/E1GUG3iEtTZHUEvdtXT7/Q=
|
||||||
|
github.com/libp2p/go-netroute v0.4.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
|
||||||
|
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81 h1:J56rFEfUTFT9j9CiRXhi1r8lUJ4W5idG3CiaBZGojNU=
|
||||||
|
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81/go.mod h1:RD8ML/YdXctQ7qbcizZkw5mZ6l8Ogrl1dodBzVJduwI=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||||
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
|
||||||
|
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
|
||||||
|
github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI=
|
||||||
|
github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o=
|
||||||
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
|
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
|
||||||
|
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||||
|
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||||
|
github.com/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k=
|
||||||
|
github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U=
|
||||||
|
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||||
|
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||||
|
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
|
||||||
|
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||||
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||||
|
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/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||||
|
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||||
|
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||||
|
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||||
|
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||||
|
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
|
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||||
|
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||||
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1 h1:4TaYr9O4xX0D2kszeOLclTiCbA3eHq3xWV+9ILJbIYs=
|
||||||
|
github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1/go.mod h1:IHH+H8vK2GfqtIt5u/5OdPh18yk0oDHuj2vz5+Goetg=
|
||||||
|
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1 h1:neE7z+FPUkldl3faK/Jt+hJK2L+1XfQ1W33TQhU9m88=
|
||||||
|
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1/go.mod h1:awuTyT29CYALpEyET0S307EgNlPWrc7fFKRAyhsO45M=
|
||||||
|
github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51 h1:Ov4qdafATOgGMB1wbSuh+0aAHcwz9hdvB6VZjh1mVMI=
|
||||||
|
github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51/go.mod h1:ZSIbPdBn5hePO8CpF1PekH2SfpTxg1PDhEwtbqZS7R8=
|
||||||
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42 h1:F3zS5fT9xzD1OFLfcdAE+3FfyiwjGukF1hvj0jErgs8=
|
||||||
|
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42/go.mod h1:n47r67ZSPgwSmT/Z1o48JjZQW9YJ6m/6Bd/uAXkL3Pg=
|
||||||
|
github.com/netbirdio/netbird v0.71.0 h1:Igfaxx2Wr2YldY8Skr7+ff8Icy7G88Z224JCx6LAJ8I=
|
||||||
|
github.com/netbirdio/netbird v0.71.0/go.mod h1:tCvJgm3e4Ej1TM191rirzwGs+Yarao1bwgtudtwWBXg=
|
||||||
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
|
||||||
|
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45/go.mod h1:5/sjFmLb8O96B5737VCqhHyGRzNFIaN/Bu7ZodXc3qQ=
|
||||||
|
github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0 h1:h/QnNzm7xzHPm+gajcblYUOclrW2FeNeDlUNj6tTWKQ=
|
||||||
|
github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
||||||
|
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
||||||
|
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI=
|
||||||
|
github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||||
|
github.com/okta/okta-sdk-golang/v2 v2.18.0 h1:cfDasMb7CShbZvOrF6n+DnLevWwiHgedWMGJ8M8xKDc=
|
||||||
|
github.com/okta/okta-sdk-golang/v2 v2.18.0/go.mod h1:dz30v3ctAiMb7jpsCngGfQUAEGm1/NsWT92uTbNDQIs=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||||
|
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||||
|
github.com/openbao/openbao/api/v2 v2.5.1 h1:Br79D6L20SbAa5P7xqENxmvv8LyI4HoKosPy7klhn4o=
|
||||||
|
github.com/openbao/openbao/api/v2 v2.5.1/go.mod h1:Dh5un77tqGgMbmlVEqjqN+8/dMyUohnkaQVg/wXW0Ig=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||||
|
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
|
github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 h1:E7Kmf11E4K7B5hDti2K2NqPb1nlYlGYsu02S1JNd/Bs=
|
||||||
|
github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||||
|
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||||
|
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||||
|
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||||
|
github.com/pion/dtls/v2 v2.2.10 h1:u2Axk+FyIR1VFTPurktB+1zoEPGIW3bmyj3LEFrXjAA=
|
||||||
|
github.com/pion/dtls/v2 v2.2.10/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
|
||||||
|
github.com/pion/dtls/v3 v3.0.9 h1:4AijfFRm8mAjd1gfdlB1wzJF3fjjR/VPIpJgkEtvYmM=
|
||||||
|
github.com/pion/dtls/v3 v3.0.9/go.mod h1:abApPjgadS/ra1wvUzHLc3o2HvoxppAh+NZkyApL4Os=
|
||||||
|
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
|
github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=
|
||||||
|
github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so=
|
||||||
|
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
|
||||||
|
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
|
||||||
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
|
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
|
||||||
|
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
|
||||||
|
github.com/pion/stun/v3 v3.1.0 h1:bS1jjT3tGWZ4UPmIUeyalOylamTMTFg1OvXtY/r6seM=
|
||||||
|
github.com/pion/stun/v3 v3.1.0/go.mod h1:egmx1CUcfSSGJxQCOjtVlomfPqmQ58BibPyuOWNGQEU=
|
||||||
|
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||||
|
github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo=
|
||||||
|
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||||
|
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||||
|
github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM=
|
||||||
|
github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ=
|
||||||
|
github.com/pion/turn/v3 v3.0.1 h1:wLi7BTQr6/Q20R0vt/lHbjv6y4GChFtC33nkYbasoT8=
|
||||||
|
github.com/pion/turn/v3 v3.0.1/go.mod h1:MrJDKgqryDyWy1/4NT9TWfXWGMC7UHT6pJIv1+gMeNE=
|
||||||
|
github.com/pion/turn/v4 v4.1.1 h1:9UnY2HB99tpDyz3cVVZguSxcqkJ1DsTSZ+8TGruh4fc=
|
||||||
|
github.com/pion/turn/v4 v4.1.1/go.mod h1:2123tHk1O++vmjI5VSD0awT50NywDAq5A2NNNU4Jjs8=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||||
|
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
|
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||||
|
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
|
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||||
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
|
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||||
|
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
|
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||||
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/russellhaering/goxmldsig v1.6.0 h1:8fdWXEPh2k/NZNQBPFNoVfS3JmzS4ZprY/sAOpKQLks=
|
||||||
|
github.com/russellhaering/goxmldsig v1.6.0/go.mod h1:TrnaquDcYxWXfJrOjeMBTX4mLBeYAqaHEyUeWPxZlBM=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
||||||
|
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
||||||
|
github.com/shirou/gopsutil/v4 v4.25.8 h1:NnAsw9lN7587WHxjJA9ryDnqhJpFH6A+wagYWTOH970=
|
||||||
|
github.com/shirou/gopsutil/v4 v4.25.8/go.mod h1:q9QdMmfAOVIw7a+eF86P7ISEU6ka+NLgkUxlopV4RwI=
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||||
|
github.com/shoenig/go-m1cpu v0.2.1 h1:yqRB4fvOge2+FyRXFkXqsyMoqPazv14Yyy+iyccT2E4=
|
||||||
|
github.com/shoenig/go-m1cpu v0.2.1/go.mod h1:KkDOw6m3ZJQAPHbrzkZki4hnx+pDRR1Lo+ldA56wD5w=
|
||||||
|
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||||
|
github.com/shoenig/test v1.7.0 h1:eWcHtTXa6QLnBvm0jgEabMRN/uJ4DMV3M8xUGgRkZmk=
|
||||||
|
github.com/shoenig/test v1.7.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
|
||||||
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||||
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
|
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg=
|
||||||
|
github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/mysql v0.37.0 h1:LqUos1oR5iuuzorFnSvxsHNdYdCHB/DfI82CuT58wbI=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/mysql v0.37.0/go.mod h1:vHEEHx5Kf+uq5hveaVAMrTzPY8eeRZcKcl23MRw5Tkc=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.37.0 h1:hsVwFkS6s+79MbKEO+W7A1wNIw1fmkMtF4fg83m6kbc=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.37.0/go.mod h1:Qj/eGbRbO/rEYdcRLmN+bEojzatP/+NS1y8ojl2PQsc=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/redis v0.37.0 h1:9HIY28I9ME/Zmb+zey1p/I1mto5+5ch0wLX+nJdOsQ4=
|
||||||
|
github.com/testcontainers/testcontainers-go/modules/redis v0.37.0/go.mod h1:Abu9g/25Qv+FkYVx3U4Voaynou1c+7D0HIhaQJXvk6E=
|
||||||
|
github.com/things-go/go-socks5 v0.0.4 h1:jMQjIc+qhD4z9cITOMnBiwo9dDmpGuXmBlkRFrl/qD0=
|
||||||
|
github.com/things-go/go-socks5 v0.0.4/go.mod h1:sh4K6WHrmHZpjxLTCHyYtXYH8OUuD+yZun41NomR1IQ=
|
||||||
|
github.com/ti-mo/conntrack v0.5.1 h1:opEwkFICnDbQc0BUXl73PHBK0h23jEIFVjXsqvF4GY0=
|
||||||
|
github.com/ti-mo/conntrack v0.5.1/go.mod h1:T6NCbkMdVU4qEIgwL0njA6lw/iCAbzchlnwm1Sa314o=
|
||||||
|
github.com/ti-mo/netfilter v0.5.2 h1:CTjOwFuNNeZ9QPdRXt1MZFLFUf84cKtiQutNauHWd40=
|
||||||
|
github.com/ti-mo/netfilter v0.5.2/go.mod h1:Btx3AtFiOVdHReTDmP9AE+hlkOcvIy403u7BXXbWZKo=
|
||||||
|
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
|
||||||
|
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||||
|
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||||
|
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||||
|
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||||
|
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||||
|
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||||
|
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||||
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
|
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||||
|
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
github.com/zcalusic/sysinfo v1.1.3 h1:u/AVENkuoikKuIZ4sUEJ6iibpmQP6YpGD8SSMCrqAF0=
|
||||||
|
github.com/zcalusic/sysinfo v1.1.3/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4=
|
||||||
|
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||||
|
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||||
|
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||||
|
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
|
||||||
|
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||||
|
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
|
||||||
|
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
|
||||||
|
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro=
|
||||||
|
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
|
||||||
|
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
|
||||||
|
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||||
|
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||||
|
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
|
goauthentik.io/api/v3 v3.2023051.3 h1:NebAhD/TeTWNo/9X3/Uj+rM5fG1HaiLOlKTNLQv9Qq4=
|
||||||
|
goauthentik.io/api/v3 v3.2023051.3/go.mod h1:nYECml4jGbp/541hj8GcylKQG1gVBsKppHy4+7G8u4U=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
|
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||||
|
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||||
|
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||||
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
|
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
|
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||||
|
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||||
|
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||||
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
|
google.golang.org/api v0.276.0 h1:nVArUtfLEihtW+b0DdcqRGK1xoEm2+ltAihyztq7MKY=
|
||||||
|
google.golang.org/api v0.276.0/go.mod h1:Fnag/EWUPIcJXuIkP1pjoTgS5vdxlk3eeemL7Do6bvw=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||||
|
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
|
||||||
|
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
|
||||||
|
gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
|
||||||
|
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260219192049-0f2374377e89 h1:mGJaeA61P8dEHTqdvAgc70ZIV3QoUoJcXCRyyjO26OA=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260219192049-0f2374377e89/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// netbird-load launches N userspace NetBird nodes and has each one periodically
|
||||||
|
// TCP-dial a peer to measure connect latency through the wireguard overlay.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// NB_SETUP_KEY=nb-... go run . -count 10 -interval 5s -target 100.x.y.z:22
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand/v2"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
setupKey := flag.String("setupkey", os.Getenv("NB_SETUP_KEY"),
|
||||||
|
"NetBird reusable setup key (or set NB_SETUP_KEY).")
|
||||||
|
mgmt := flag.String("mgmt", os.Getenv("NB_MGMT_URL"),
|
||||||
|
"NetBird management URL (empty = embed default, i.e. NetBird Cloud).")
|
||||||
|
count := flag.Int("count", 10, "Number of embedded netbird nodes to launch.")
|
||||||
|
interval := flag.Duration("interval", 5*time.Second, "Interval between actions per node.")
|
||||||
|
hostnamePrefix := flag.String("hostname-prefix", "uncloud", "Hostname prefix for netbird nodes.")
|
||||||
|
stateRoot := flag.String("state-dir", "./state", "Directory to keep netbird state (empty = a fresh temp dir).")
|
||||||
|
target := flag.String("target", "", "TCP host:port to dial each tick (required).")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *setupKey == "" {
|
||||||
|
log.Fatal("missing NetBird setup key: pass -setupkey or set NB_SETUP_KEY.")
|
||||||
|
}
|
||||||
|
if *target == "" {
|
||||||
|
log.Fatal("missing -target: provide a TCP host:port reachable through the netbird network.")
|
||||||
|
}
|
||||||
|
|
||||||
|
root := *stateRoot
|
||||||
|
if root == "" {
|
||||||
|
var err error
|
||||||
|
root, err = os.MkdirTemp("", "netbird-load-*")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("mktemp: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
} else if err := os.MkdirAll(root, 0o700); err != nil {
|
||||||
|
log.Fatalf("mkdir state dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < *count; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(id int) {
|
||||||
|
defer wg.Done()
|
||||||
|
runNode(ctx, id, *setupKey, *mgmt, *hostnamePrefix, root, *target, *interval)
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNode(ctx context.Context, id int, setupKey, mgmt, prefix, stateRoot, target string, interval time.Duration) {
|
||||||
|
logPrefix := fmt.Sprintf("[node-%02d] ", id)
|
||||||
|
logger := log.New(os.Stderr, logPrefix, log.LstdFlags|log.Lmsgprefix)
|
||||||
|
|
||||||
|
nodeDir := filepath.Join(stateRoot, fmt.Sprintf("node-%02d", id))
|
||||||
|
deviceName := fmt.Sprintf("%s-%02d", prefix, id)
|
||||||
|
|
||||||
|
client, err := embed.New(embed.Options{
|
||||||
|
DeviceName: deviceName,
|
||||||
|
SetupKey: setupKey,
|
||||||
|
ManagementURL: mgmt,
|
||||||
|
StatePath: nodeDir,
|
||||||
|
ConfigPath: filepath.Join(nodeDir, "config"),
|
||||||
|
// Silence per-node netbird chatter. Swap to os.Stderr to debug.
|
||||||
|
LogOutput: io.Discard,
|
||||||
|
//NoUserspace: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("netbird new: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
stopCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
_ = client.Stop(stopCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
upCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := client.Start(upCtx); err != nil {
|
||||||
|
logger.Printf("netbird start: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Printf("up as %s", deviceName)
|
||||||
|
|
||||||
|
// Stagger ticks so all nodes don't fire in lockstep.
|
||||||
|
time.Sleep(time.Duration(rand.Int64N(int64(interval))))
|
||||||
|
|
||||||
|
tick := time.NewTicker(interval)
|
||||||
|
defer tick.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-tick.C:
|
||||||
|
doDial(ctx, client, target, logger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doDial(ctx context.Context, c *embed.Client, target string, logger *log.Logger) {
|
||||||
|
dctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
conn, err := c.Dial(dctx, "tcp", target)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("dial %s: %v", target, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
latency := time.Since(start)
|
||||||
|
_ = conn.Close()
|
||||||
|
logger.Printf("dial %s ok in %.1fms", target, float64(latency.Microseconds())/1000)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
module github.com/psviderski/uncloud/experiment/tsnet-load
|
||||||
|
|
||||||
|
go 1.26.1
|
||||||
|
|
||||||
|
require tailscale.com v1.96.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
filippo.io/edwards25519 v1.2.0 // indirect
|
||||||
|
github.com/akutz/memconn v0.1.0 // indirect
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
|
||||||
|
github.com/aws/smithy-go v1.24.0 // indirect
|
||||||
|
github.com/coder/websocket v1.8.12 // indirect
|
||||||
|
github.com/creachadair/msync v0.7.1 // indirect
|
||||||
|
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
|
github.com/gaissmai/bart v0.26.1 // indirect
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||||
|
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
||||||
|
github.com/huin/goupnp v1.3.0 // indirect
|
||||||
|
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.18.2 // indirect
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
|
||||||
|
github.com/mdlayher/socket v0.5.0 // indirect
|
||||||
|
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||||
|
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||||
|
github.com/prometheus-community/pro-bing v0.4.0 // indirect
|
||||||
|
github.com/safchain/ethtool v0.3.0 // indirect
|
||||||
|
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
|
||||||
|
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||||
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
||||||
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||||
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
||||||
|
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
|
||||||
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||||
|
golang.org/x/crypto v0.46.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||||
|
golang.org/x/net v0.48.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.33.0 // indirect
|
||||||
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
|
golang.org/x/term v0.38.0 // indirect
|
||||||
|
golang.org/x/text v0.32.0 // indirect
|
||||||
|
golang.org/x/time v0.12.0 // indirect
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q=
|
||||||
|
9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM=
|
||||||
|
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||||
|
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||||
|
filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc=
|
||||||
|
filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA=
|
||||||
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||||
|
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
|
||||||
|
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||||
|
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||||
|
github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ=
|
||||||
|
github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
|
||||||
|
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
|
||||||
|
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
|
||||||
|
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
||||||
|
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||||
|
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
|
||||||
|
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||||
|
github.com/creachadair/mds v0.25.9 h1:080Hr8laN2h+l3NeVCGMBpXtIPnl9mz8e4HLraGPqtA=
|
||||||
|
github.com/creachadair/mds v0.25.9/go.mod h1:4hatI3hRM+qhzuAmqPRFvaBM8mONkS7nsLxkcuTYUIs=
|
||||||
|
github.com/creachadair/msync v0.7.1 h1:SeZmuEBXQPe5GqV/C94ER7QIZPwtvFbeQiykzt/7uho=
|
||||||
|
github.com/creachadair/msync v0.7.1/go.mod h1:8CcFlLsSujfHE5wWm19uUBLHIPDAUr6LXDwneVMO008=
|
||||||
|
github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc=
|
||||||
|
github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g=
|
||||||
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
|
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk=
|
||||||
|
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8=
|
||||||
|
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
|
||||||
|
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q=
|
||||||
|
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A=
|
||||||
|
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||||
|
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
|
github.com/gaissmai/bart v0.26.1 h1:+w4rnLGNlA2GDVn382Tfe3jOsK5vOr5n4KmigJ9lbTo=
|
||||||
|
github.com/gaissmai/bart v0.26.1/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c=
|
||||||
|
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
|
||||||
|
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
|
||||||
|
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
|
github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo=
|
||||||
|
github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/go-tpm v0.9.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I=
|
||||||
|
github.com/google/go-tpm v0.9.4/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||||
|
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
|
||||||
|
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||||
|
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||||
|
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||||
|
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||||
|
github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk=
|
||||||
|
github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U=
|
||||||
|
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA=
|
||||||
|
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||||
|
github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g=
|
||||||
|
github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
|
||||||
|
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
|
||||||
|
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||||
|
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
|
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ=
|
||||||
|
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
|
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
|
||||||
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
|
||||||
|
github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c=
|
||||||
|
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
|
||||||
|
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
|
||||||
|
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
|
||||||
|
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||||
|
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
|
||||||
|
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||||
|
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
|
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
|
||||||
|
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
|
||||||
|
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
|
||||||
|
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||||
|
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
|
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||||
|
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||||
|
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
|
||||||
|
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
|
||||||
|
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
|
||||||
|
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg=
|
||||||
|
github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 h1:SRL6irQkKGQKKLzvQP/ke/2ZuB7Py5+XuqtOgSj+iMM=
|
||||||
|
github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ=
|
||||||
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw=
|
||||||
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8=
|
||||||
|
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU=
|
||||||
|
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0=
|
||||||
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA=
|
||||||
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
||||||
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14=
|
||||||
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ=
|
||||||
|
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M=
|
||||||
|
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y=
|
||||||
|
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da h1:jVRUZPRs9sqyKlYHHzHjAqKN+6e/Vog6NpHYeNPJqOw=
|
||||||
|
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4=
|
||||||
|
github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek=
|
||||||
|
github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg=
|
||||||
|
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||||
|
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
|
||||||
|
github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg=
|
||||||
|
github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE=
|
||||||
|
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||||
|
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||||
|
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||||
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
|
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek=
|
||||||
|
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
|
||||||
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
|
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||||
|
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
|
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8=
|
||||||
|
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||||
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
|
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||||
|
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||||
|
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||||
|
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||||
|
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||||
|
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
|
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||||
|
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||||
|
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||||
|
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||||
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
|
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||||
|
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||||
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||||
|
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 h1:Zy8IV/+FMLxy6j6p87vk/vQGKcdnbprwjTxc8UiUtsA=
|
||||||
|
gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q=
|
||||||
|
honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 h1:5SXjd4ET5dYijLaf0O3aOenC0Z4ZafIWSpjUzsQaNho=
|
||||||
|
honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0/go.mod h1:EPDDhEZqVHhWuPI5zPAsjU0U7v9xNIWjoOVyZ5ZcniQ=
|
||||||
|
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||||
|
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||||
|
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||||
|
tailscale.com v1.96.5 h1:gNkfA/KSZAl6jCH9cj8urq00HRWItDDTtGsyATI89jA=
|
||||||
|
tailscale.com v1.96.5/go.mod h1:/3lnZBYb2UEwnN0MNu2SDXUtT06AGd5k0s+OWx3WmcY=
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
// tsnet-load launches N userspace Tailscale nodes and has each one periodically
|
||||||
|
// ping a tailnet peer (or HTTP-GET a subnet-routed host).
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// TS_AUTHKEY=tskey-... go run . -count 10 -interval 5s
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand/v2"
|
||||||
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tailscale.com/client/tailscale"
|
||||||
|
"tailscale.com/ipn"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/tsnet"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
httpTarget = "http://10.210.1.2"
|
||||||
|
pingTarget = "100.92.123.72"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
authKey := flag.String("authkey", os.Getenv("TS_AUTHKEY"),
|
||||||
|
"Tailscale reusable ephemeral auth key (or set TS_AUTHKEY).")
|
||||||
|
count := flag.Int("count", 10, "Number of tsnet nodes to launch.")
|
||||||
|
interval := flag.Duration("interval", 5*time.Second, "Interval between actions per node.")
|
||||||
|
hostnamePrefix := flag.String("hostname-prefix", "uncloud", "Hostname prefix for tsnet nodes.")
|
||||||
|
stateRoot := flag.String("state-dir", "./state", "Directory to keep tsnet state (default: a fresh temp dir).")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *authKey == "" {
|
||||||
|
log.Fatal("missing Tailscale auth key: pass -authkey or set TS_AUTHKEY.")
|
||||||
|
}
|
||||||
|
|
||||||
|
root := *stateRoot
|
||||||
|
if root == "" {
|
||||||
|
var err error
|
||||||
|
root, err = os.MkdirTemp("", "tsnet-load-*")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("mktemp: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
} else if err := os.MkdirAll(root, 0o700); err != nil {
|
||||||
|
log.Fatalf("mkdir state dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < *count; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(id int) {
|
||||||
|
defer wg.Done()
|
||||||
|
runNode(ctx, id, *authKey, *hostnamePrefix, root, *interval)
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNode(ctx context.Context, id int, authKey, prefix, stateRoot string, interval time.Duration) {
|
||||||
|
logPrefix := fmt.Sprintf("[node-%02d] ", id)
|
||||||
|
logger := log.New(os.Stderr, logPrefix, log.LstdFlags|log.Lmsgprefix)
|
||||||
|
|
||||||
|
s := &tsnet.Server{
|
||||||
|
Hostname: fmt.Sprintf("%s-%02d", prefix, id),
|
||||||
|
AuthKey: authKey,
|
||||||
|
Ephemeral: true,
|
||||||
|
Dir: filepath.Join(stateRoot, fmt.Sprintf("node-%02d", id)),
|
||||||
|
// Silence per-node tsnet chatter. Comment out to debug.
|
||||||
|
Logf: func(string, ...any) {},
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
upCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
status, err := s.Up(upCtx)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("tsnet up: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Printf("up as %s (%v)", s.Hostname, status.TailscaleIPs)
|
||||||
|
|
||||||
|
// Accept subnet routes advertised by other tailnet peers. tsnet defaults
|
||||||
|
// to RouteAll=false, so without this 10.210.0.0/24 etc. are unreachable.
|
||||||
|
lc, err := s.LocalClient()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("local client: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := lc.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||||
|
RouteAllSet: true,
|
||||||
|
Prefs: ipn.Prefs{RouteAll: true},
|
||||||
|
}); err != nil {
|
||||||
|
logger.Printf("edit prefs (RouteAll): %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Transport: &http.Transport{DialContext: s.Dial},
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
_ = httpClient
|
||||||
|
|
||||||
|
// Stagger ticks so all nodes don't fire in lockstep.
|
||||||
|
time.Sleep(time.Duration(rand.Int64N(int64(interval))))
|
||||||
|
|
||||||
|
tick := time.NewTicker(interval)
|
||||||
|
defer tick.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-tick.C:
|
||||||
|
doPing(ctx, lc, logger)
|
||||||
|
//doHTTP(ctx, httpClient, logger)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doPing(ctx context.Context, lc *tailscale.LocalClient, logger *log.Logger) {
|
||||||
|
pctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
res, err := lc.Ping(pctx, netip.MustParseAddr(pingTarget), tailcfg.PingICMP)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("ping %s: %v", pingTarget, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.Err != "" {
|
||||||
|
logger.Printf("ping %s: %s", pingTarget, res.Err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.Printf("ping %s ok in %.1fms via %s", pingTarget, res.LatencySeconds*1000, res.Endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doHTTP(ctx context.Context, c *http.Client, logger *log.Logger) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, httpTarget, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("http build req: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := c.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("http %s: %v", httpTarget, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
n, _ := io.Copy(io.Discard, resp.Body)
|
||||||
|
logger.Printf("http %s: %s, %d bytes in %v", httpTarget, resp.Status, n, time.Since(start).Round(time.Millisecond))
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
composecli "github.com/compose-spec/compose-go/v2/cli"
|
||||||
|
"github.com/psviderski/uncloud/pkg/client/compose"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ComposeServices(ctx context.Context, args []string, toComplete string, files, profiles []string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
project, err := compose.LoadProject(ctx, files, composecli.WithDefaultProfiles(profiles...))
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
|
||||||
|
services := project.ServiceNames()
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, service := range services {
|
||||||
|
if slices.Contains(args, service) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(service, toComplete) {
|
||||||
|
names = append(names, service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Contexts(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
contexts := slices.Sorted(maps.Keys(uncli.Config.Contexts))
|
||||||
|
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, context := range contexts {
|
||||||
|
if slices.Contains(args, context) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(context, toComplete) {
|
||||||
|
names = append(names, context)
|
||||||
|
}
|
||||||
|
names = append(names, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Machines(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
client, err := uncli.ConnectCluster(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
machines, err := client.ListMachines(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, machine := range machines {
|
||||||
|
if slices.Contains(args, machine.Machine.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(machine.Machine.Name, toComplete) {
|
||||||
|
names = append(names, machine.Machine.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
|
||||||
|
func MachinesFlag(cmd *cobra.Command) {
|
||||||
|
cmd.RegisterFlagCompletionFunc("machine",
|
||||||
|
func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
|
return Machines(cmd.Context(), uncli, args, toComplete)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Package completion implements completion functions for the uc cli.
|
||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Services(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
client, err := uncli.ConnectCluster(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
services, err := client.ListServices(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, service := range services {
|
||||||
|
if slices.Contains(args, service.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(service.Name, toComplete) {
|
||||||
|
names = append(names, service.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Volumes(ctx context.Context, uncli *cli.CLI, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
client, err := uncli.ConnectCluster(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
volumes, err := client.ListVolumes(ctx, &api.VolumeFilter{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, volume := range volumes {
|
||||||
|
if slices.Contains(args, volume.Volume.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(volume.Volume.Name, toComplete) {
|
||||||
|
names = append(names, volume.Volume.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
// CancelledError signals an interactive command was aborted by the user at a confirmation prompt.
|
||||||
|
type CancelledError struct {
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *CancelledError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancelled returns a CancelledError carrying the given user-facing message.
|
||||||
|
func Cancelled(msg string) error {
|
||||||
|
return &CancelledError{Message: msg}
|
||||||
|
}
|
||||||
@@ -242,8 +242,8 @@ func (c *Controller) writeCaddyfileIfChanged(caddyfile string) error {
|
|||||||
// caddyfileBody returns the Caddyfile content without its first line, which carries a generation timestamp that
|
// caddyfileBody returns the Caddyfile content without its first line, which carries a generation timestamp that
|
||||||
// rotates on every regeneration.
|
// rotates on every regeneration.
|
||||||
func caddyfileBody(caddyfile string) string {
|
func caddyfileBody(caddyfile string) string {
|
||||||
if i := strings.IndexByte(caddyfile, '\n'); i >= 0 {
|
if _, after, ok := strings.Cut(caddyfile, "\n"); ok {
|
||||||
return caddyfile[i+1:]
|
return after
|
||||||
}
|
}
|
||||||
return caddyfile
|
return caddyfile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ func TestContainerFingerprint_EqualCoversAllFields(t *testing.T) {
|
|||||||
assert.True(t, base.Equal(base), "base fingerprint must be equal to itself")
|
assert.True(t, base.Equal(base), "base fingerprint must be equal to itself")
|
||||||
|
|
||||||
rt := reflect.TypeOf(base)
|
rt := reflect.TypeOf(base)
|
||||||
for i := 0; i < rt.NumField(); i++ {
|
for field := range rt.Fields() {
|
||||||
field := rt.Field(i)
|
|
||||||
t.Run(field.Name, func(t *testing.T) {
|
t.Run(field.Name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ type MockCaddyfileValidator_Validate_Call struct {
|
|||||||
// Validate is a helper method to define mock.On call
|
// Validate is a helper method to define mock.On call
|
||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - caddyfile string
|
// - caddyfile string
|
||||||
func (_e *MockCaddyfileValidator_Expecter) Validate(ctx interface{}, caddyfile interface{}) *MockCaddyfileValidator_Validate_Call {
|
func (_e *MockCaddyfileValidator_Expecter) Validate(ctx any, caddyfile any) *MockCaddyfileValidator_Validate_Call {
|
||||||
return &MockCaddyfileValidator_Validate_Call{Call: _e.mock.On("Validate", ctx, caddyfile)}
|
return &MockCaddyfileValidator_Validate_Call{Call: _e.mock.On("Validate", ctx, caddyfile)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -683,9 +683,7 @@ func (s *Server) CreateServiceContainer(
|
|||||||
// Apply the pre-deploy hook overrides.
|
// Apply the pre-deploy hook overrides.
|
||||||
config.Cmd = spec.PreDeploy.Command
|
config.Cmd = spec.PreDeploy.Command
|
||||||
|
|
||||||
for k, v := range spec.PreDeploy.Env {
|
maps.Copy(envVars, spec.PreDeploy.Env)
|
||||||
envVars[k] = v
|
|
||||||
}
|
|
||||||
envVars["UNCLOUD_HOOK_PRE_DEPLOY"] = "true"
|
envVars["UNCLOUD_HOOK_PRE_DEPLOY"] = "true"
|
||||||
config.Env = envVars.ToSlice()
|
config.Env = envVars.ToSlice()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Package completion implements completion functions for the ucind cli.
|
||||||
|
package completion
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/psviderski/uncloud/internal/ucind"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Clusters(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
p := cmd.Context().Value("provisioner").(*ucind.Provisioner)
|
||||||
|
clusters, err := p.ListClusters(cmd.Context())
|
||||||
|
if err != nil {
|
||||||
|
return nil, cobra.ShellCompDirectiveError
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []cobra.Completion{}
|
||||||
|
for _, cluster := range clusters {
|
||||||
|
if slices.Contains(args, cluster.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(cluster.Name, toComplete) {
|
||||||
|
names = append(names, cluster.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
+201
-44
@@ -5,7 +5,10 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -32,6 +35,12 @@ import (
|
|||||||
netproxy "golang.org/x/net/proxy"
|
netproxy "golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This is the container image used to run socat proxy containers.
|
||||||
|
// TODO: it's an external dependency that we don't control, so we should consider vendoring it or
|
||||||
|
// automatically building an ad-hoc image with socat-like functionality (e.g. using a lightweight Go
|
||||||
|
// proxy) as part of the push process.
|
||||||
|
const socatImage = "alpine/socat:1.8.0.3"
|
||||||
|
|
||||||
func (cli *Client) InspectImage(ctx context.Context, id string) ([]api.MachineImage, error) {
|
func (cli *Client) InspectImage(ctx context.Context, id string) ([]api.MachineImage, error) {
|
||||||
images, err := cli.Docker.InspectImage(ctx, id)
|
images, err := cli.Docker.InspectImage(ctx, id)
|
||||||
if errdefs.IsNotFound(err) {
|
if errdefs.IsNotFound(err) {
|
||||||
@@ -235,26 +244,55 @@ func (cli *Client) pushImageToMachine(
|
|||||||
return fmt.Errorf("get proxy dialer: %w", err)
|
return fmt.Errorf("get proxy dialer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dockerEnv, err := detectDockerEnvironment(ctx, dockerCli)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
slog.Debug("Detected Docker environment:", "virtualised", dockerEnv.Virtualised, "rootless", dockerEnv.Rootless)
|
||||||
|
|
||||||
proxyEventID := fmt.Sprintf("Proxy to unregistry on %s", boldStyle.Render(machine.Name))
|
proxyEventID := fmt.Sprintf("Proxy to unregistry on %s", boldStyle.Render(machine.Name))
|
||||||
pw.Event(progress.StartingEvent(proxyEventID))
|
pw.Event(progress.StartingEvent(proxyEventID))
|
||||||
|
|
||||||
// The proxy runs in a goroutine. Capture the first error in a channel
|
// The proxy runs in a goroutine. Capture the first error in a channel
|
||||||
// so we can surface it alongside the push error if push fails.
|
// so we can surface it alongside the push error if push fails.
|
||||||
proxyErrCh := make(chan error, 1)
|
proxyErrCh := make(chan error, 1)
|
||||||
// Forward local port 127.0.0.1:PORT to the machine's unregistry over the established client connection.
|
onProxyError := func(err error) {
|
||||||
unregProxy, err := newUnregistryProxy(ctx, unregistryAddr, dialer, func(err error) {
|
|
||||||
select {
|
select {
|
||||||
case proxyErrCh <- fmt.Errorf("proxy to unregistry: %w", err):
|
case proxyErrCh <- fmt.Errorf("proxy to unregistry: %w", err):
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
|
||||||
return fmt.Errorf("create local proxy to unregistry on machine '%s': %w", machine.Name, err)
|
|
||||||
}
|
}
|
||||||
// Get the local port the unregistry proxy is listening on.
|
|
||||||
proxyPort := unregProxy.Listener.Addr().(*net.TCPAddr).Port
|
// socketPath is set for plain rootless Docker (not running inside a VM): the Go proxy listens on a unix
|
||||||
|
// socket that is bind-mounted into the socat container, bypassing slirp4netns network routing entirely.
|
||||||
|
var (
|
||||||
|
socketPath string
|
||||||
|
proxyPort int
|
||||||
|
)
|
||||||
|
var unregProxy *proxy.Proxy
|
||||||
|
if shouldUseUnregistryUnixProxy(dockerEnv) {
|
||||||
|
suffix, err := secret.RandomAlphaNumeric(4)
|
||||||
|
if err != nil {
|
||||||
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
|
return fmt.Errorf("generate socket path suffix: %w", err)
|
||||||
|
}
|
||||||
|
socketPath = filepath.Join(os.TempDir(), fmt.Sprintf("uncloud-push-%s.sock", suffix))
|
||||||
|
unregProxy, err = newUnregistryUnixProxy(ctx, unregistryAddr, dialer, socketPath, onProxyError)
|
||||||
|
if err != nil {
|
||||||
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
|
return fmt.Errorf("create local unix socket proxy to unregistry on machine '%s': %w", machine.Name, err)
|
||||||
|
}
|
||||||
|
slog.Debug("Listening for unregistry proxy connections.", "mode", "unix", "socket", socketPath)
|
||||||
|
} else {
|
||||||
|
unregProxy, err = newUnregistryTcpProxy(ctx, unregistryAddr, dialer, onProxyError)
|
||||||
|
if err != nil {
|
||||||
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
|
return fmt.Errorf("create local tcp proxy to unregistry on machine '%s': %w", machine.Name, err)
|
||||||
|
}
|
||||||
|
proxyPort = unregProxy.Listener.Addr().(*net.TCPAddr).Port
|
||||||
|
slog.Debug("Listening for unregistry proxy connections.", "mode", "tcp", "port", proxyPort)
|
||||||
|
}
|
||||||
|
|
||||||
proxyCtx, cancelProxy := context.WithCancel(ctx)
|
proxyCtx, cancelProxy := context.WithCancel(ctx)
|
||||||
proxyCtrID := ""
|
proxyCtrID := ""
|
||||||
@@ -272,31 +310,47 @@ func (cli *Client) pushImageToMachine(
|
|||||||
dockerCli.ContainerRemove(ctx, proxyCtrID, container.RemoveOptions{Force: true})
|
dockerCli.ContainerRemove(ctx, proxyCtrID, container.RemoveOptions{Force: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the unix socket file used for rootless Docker proxying.
|
||||||
|
if socketPath != "" {
|
||||||
|
os.Remove(socketPath)
|
||||||
|
}
|
||||||
|
|
||||||
cancelProxy()
|
cancelProxy()
|
||||||
}
|
}
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
go unregProxy.Run(proxyCtx)
|
go unregProxy.Run(proxyCtx)
|
||||||
|
|
||||||
dockerVirtualised, err := isDockerVirtualised(ctx, dockerCli)
|
if dockerEnv.Virtualised {
|
||||||
if err != nil {
|
// VM-based Docker (Docker Desktop, Rancher Desktop, etc.): run a socat container inside the VM
|
||||||
return err
|
// to forward a port via host.docker.internal back to the host-side proxy.
|
||||||
}
|
|
||||||
|
|
||||||
if dockerVirtualised {
|
|
||||||
// Run socat proxy container to forward a localhost port from within the Docker VM to the host machine.
|
|
||||||
pw.Event(progress.Event{
|
pw.Event(progress.Event{
|
||||||
ID: proxyEventID,
|
ID: proxyEventID,
|
||||||
Status: progress.Working,
|
Status: progress.Working,
|
||||||
StatusText: "Starting",
|
StatusText: "Starting",
|
||||||
Text: "(detected Docker in VM locally, starting socat proxy container)",
|
Text: "(detected Docker in VM locally, starting socat proxy container)",
|
||||||
})
|
})
|
||||||
|
|
||||||
proxyCtrID, proxyPort, err = runDockerVMProxyContainer(ctx, dockerCli, proxyPort)
|
proxyCtrID, proxyPort, err = runDockerVMProxyContainer(ctx, dockerCli, proxyPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
return fmt.Errorf("run socat container to proxy unregistry to Docker VM: %w", err)
|
return fmt.Errorf("run socat container to proxy unregistry: %w", err)
|
||||||
}
|
}
|
||||||
|
slog.Debug("Started VM socat proxy container.", "id", proxyCtrID, "hostPort", proxyPort)
|
||||||
|
} else if shouldUseUnregistryUnixProxy(dockerEnv) {
|
||||||
|
// Plain rootless Docker: run a socat container that forwards via a bind-mounted unix socket,
|
||||||
|
// bypassing the slirp4netns --disable-host-loopback restriction.
|
||||||
|
pw.Event(progress.Event{
|
||||||
|
ID: proxyEventID,
|
||||||
|
Status: progress.Working,
|
||||||
|
StatusText: "Starting",
|
||||||
|
Text: "(detected rootless Docker, starting socat proxy container)",
|
||||||
|
})
|
||||||
|
proxyCtrID, proxyPort, err = runUnixSocketProxyContainer(ctx, dockerCli, socketPath)
|
||||||
|
if err != nil {
|
||||||
|
pw.Event(progress.NewEvent(proxyEventID, progress.Error, err.Error()))
|
||||||
|
return fmt.Errorf("run socat container with unix socket to proxy unregistry: %w", err)
|
||||||
|
}
|
||||||
|
slog.Debug("Started unix socket socat proxy container.", "id", proxyCtrID, "hostPort", proxyPort, "socket", socketPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.Event(progress.Event{
|
pw.Event(progress.Event{
|
||||||
@@ -350,18 +404,27 @@ func (cli *Client) pushImageToMachine(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnregistryProxy(
|
// checkRemoteConnectivity verifies that remoteAddr is reachable via dialer within a timeout.
|
||||||
ctx context.Context, remoteAddr string, dialer netproxy.ContextDialer, onError func(error),
|
func checkRemoteConnectivity(ctx context.Context, dialer netproxy.ContextDialer, remoteAddr string) error {
|
||||||
) (*proxy.Proxy, error) {
|
|
||||||
// Test remote connectivity before creating a proxy.
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
testConn, err := dialer.DialContext(ctx, "tcp", remoteAddr)
|
conn, err := dialer.DialContext(ctx, "tcp", remoteAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("connect to remote address '%s': %w", remoteAddr, err)
|
return fmt.Errorf("connect to remote address '%s': %w", remoteAddr, err)
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newUnregistryTcpProxy creates a TCP proxy that listens on localhost and forwards to the unregistry
|
||||||
|
// address on the target machine.
|
||||||
|
func newUnregistryTcpProxy(
|
||||||
|
ctx context.Context, remoteAddr string, dialer netproxy.ContextDialer, onError func(error),
|
||||||
|
) (*proxy.Proxy, error) {
|
||||||
|
if err := checkRemoteConnectivity(ctx, dialer, remoteAddr); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
testConn.Close()
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -378,39 +441,109 @@ func newUnregistryProxy(
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDockerVirtualised checks if Docker is running in a virtualised environment like Docker/Rancher Desktop or Colima.
|
// newUnregistryUnixProxy creates a proxy that listens on a unix socket at socketPath and forwards to the
|
||||||
// On macOS, Docker always requires a VM, so it returns true unless OrbStack is detected (which handles host networking
|
// unregistry address on the target machine.
|
||||||
// natively). On other platforms, it checks for known virtualised Docker hostnames.
|
func newUnregistryUnixProxy(
|
||||||
func isDockerVirtualised(ctx context.Context, dockerCli *docker.Client) (bool, error) {
|
ctx context.Context, remoteAddr string, dialer netproxy.ContextDialer, socketPath string, onError func(error),
|
||||||
info, err := dockerCli.Info(ctx)
|
) (*proxy.Proxy, error) {
|
||||||
if err != nil {
|
if err := checkRemoteConnectivity(ctx, dialer, remoteAddr); err != nil {
|
||||||
return false, fmt.Errorf("get Docker info: %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// On macOS, Docker always runs in a VM. OrbStack is the only known exception that doesn't need a proxy.
|
listener, err := net.Listen("unix", socketPath)
|
||||||
if runtime.GOOS == "darwin" {
|
if err != nil {
|
||||||
if info.Name == "orbstack" {
|
return nil, fmt.Errorf("listen on unix socket %s: %w", socketPath, err)
|
||||||
return false, nil
|
}
|
||||||
|
// Restrict socket access to the current user to prevent other local users from connecting
|
||||||
|
// to the proxy and reaching the unregistry for the duration of the push.
|
||||||
|
if err = os.Chmod(socketPath, 0o600); err != nil {
|
||||||
|
listener.Close()
|
||||||
|
return nil, fmt.Errorf("set unix socket permissions on %s: %w", socketPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &proxy.Proxy{
|
||||||
|
Listener: listener,
|
||||||
|
RemoteAddr: remoteAddr,
|
||||||
|
DialContext: dialer.DialContext,
|
||||||
|
OnError: onError,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dockerEnvironment describes the local Docker environment type.
|
||||||
|
type dockerEnvironment struct {
|
||||||
|
// Virtualised indicates Docker runs inside a VM (Docker Desktop, Rancher Desktop, Colima).
|
||||||
|
Virtualised bool
|
||||||
|
// Rootless indicates Docker is running in rootless mode
|
||||||
|
Rootless bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// detectDockerEnvironment inspects the local Docker daemon to determine if it is running in a virtualised
|
||||||
|
// environment (VM) or in rootless mode. Both cases require a socat proxy container to route connections
|
||||||
|
// across the network boundary between the local Docker daemon and the host.
|
||||||
|
func detectDockerEnvironment(ctx context.Context, dockerCli *docker.Client) (dockerEnvironment, error) {
|
||||||
|
info, err := dockerCli.Info(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return dockerEnvironment{}, fmt.Errorf("get Docker info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
env := dockerEnvironment{}
|
||||||
|
|
||||||
|
for _, opt := range info.SecurityOptions {
|
||||||
|
if strings.Contains(opt, "rootless") {
|
||||||
|
env.Rootless = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return true, nil
|
}
|
||||||
|
|
||||||
|
// On macOS, Docker always requires a VM, so set Virtualised to true unless OrbStack is
|
||||||
|
// detected (which handles host networking natively).
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
if info.Name != "orbstack" {
|
||||||
|
env.Virtualised = true
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// On other platforms, check for known virtualised Docker environments.
|
// On other platforms, check for known virtualised Docker environments.
|
||||||
virtualisedHostnames := []string{"docker-desktop", "rancher-desktop", "colima"}
|
virtualisedHostnames := []string{"docker-desktop", "rancher-desktop", "colima"}
|
||||||
for _, name := range virtualisedHostnames {
|
for _, name := range virtualisedHostnames {
|
||||||
if strings.Contains(strings.ToLower(info.Name), name) {
|
if strings.Contains(strings.ToLower(info.Name), name) {
|
||||||
return true, nil
|
env.Virtualised = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return env, nil
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// runDockerVMProxyContainer creates a socat container to proxy an available localhost port within the Docker VM
|
// shouldUseUnregistryUnixProxy reports whether the local Docker environment requires a unix socket proxy
|
||||||
// (e.g. Docker Desktop on macOS) to the specified target port on the host machine.
|
// to reach the unregistry. This is the case for rootless Docker not running inside a VM, where
|
||||||
|
// slirp4netns --disable-host-loopback blocks TCP routing from the container network namespace back to the host.
|
||||||
|
func shouldUseUnregistryUnixProxy(env dockerEnvironment) bool {
|
||||||
|
// TODO: handle Virtualised AND Rootless case when we encounter it.
|
||||||
|
return env.Rootless && !env.Virtualised
|
||||||
|
}
|
||||||
|
|
||||||
|
// runDockerVMProxyContainer creates a socat container inside the Docker VM (e.g. Docker Desktop on macOS)
|
||||||
|
// to forward TCP connections from a localhost port to the specified target port on the host via host.docker.internal.
|
||||||
// Returns the container ID and the localhost port the container port is bound to.
|
// Returns the container ID and the localhost port the container port is bound to.
|
||||||
// TODO: accept custom image name.
|
|
||||||
func runDockerVMProxyContainer(ctx context.Context, dockerCli *docker.Client, targetPort int) (string, int, error) {
|
func runDockerVMProxyContainer(ctx context.Context, dockerCli *docker.Client, targetPort int) (string, int, error) {
|
||||||
|
return runSocatProxyContainer(ctx, dockerCli,
|
||||||
|
fmt.Sprintf("TCP-CONNECT:host.docker.internal:%d", targetPort), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// runUnixSocketProxyContainer creates a socat container that forwards TCP connections to the host-side Go
|
||||||
|
// proxy via a bind-mounted unix socket.
|
||||||
|
// Returns the container ID and the localhost port that 'docker push' should target.
|
||||||
|
func runUnixSocketProxyContainer(ctx context.Context, dockerCli *docker.Client, socketPath string) (string, int, error) {
|
||||||
|
return runSocatProxyContainer(ctx, dockerCli,
|
||||||
|
fmt.Sprintf("UNIX-CONNECT:%s", socketPath),
|
||||||
|
[]string{fmt.Sprintf("%s:%s", socketPath, socketPath)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// runSocatProxyContainer creates a socat container that listens on TCP port 5000 and forwards to socatDst.
|
||||||
|
// binds is an optional list of host:container bind mounts (e.g. for a unix socket).
|
||||||
|
// Returns the container ID and the localhost port that clients should connect to.
|
||||||
|
func runSocatProxyContainer(ctx context.Context, dockerCli *docker.Client, socatDst string, binds []string) (string, int, error) {
|
||||||
suffix, err := secret.RandomAlphaNumeric(4)
|
suffix, err := secret.RandomAlphaNumeric(4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, fmt.Errorf("generate random suffix: %w", err)
|
return "", 0, fmt.Errorf("generate random suffix: %w", err)
|
||||||
@@ -420,14 +553,14 @@ func runDockerVMProxyContainer(ctx context.Context, dockerCli *docker.Client, ta
|
|||||||
containerPort := nat.Port("5000/tcp")
|
containerPort := nat.Port("5000/tcp")
|
||||||
config := &container.Config{
|
config := &container.Config{
|
||||||
// TODO: make image configurable.
|
// TODO: make image configurable.
|
||||||
Image: "alpine/socat:latest",
|
Image: socatImage,
|
||||||
// Reset the default entrypoint "socat".
|
// Reset the default entrypoint "socat".
|
||||||
Entrypoint: []string{},
|
Entrypoint: []string{},
|
||||||
Cmd: []string{
|
Cmd: []string{
|
||||||
"timeout", "1800", // Auto-terminate socat after 30 minutes.
|
"timeout", "1800", // Auto-terminate socat after 30 minutes.
|
||||||
"socat",
|
"socat",
|
||||||
"TCP-LISTEN:5000,fork,reuseaddr",
|
"TCP-LISTEN:5000,fork,reuseaddr",
|
||||||
fmt.Sprintf("TCP-CONNECT:host.docker.internal:%d", targetPort),
|
socatDst,
|
||||||
},
|
},
|
||||||
ExposedPorts: nat.PortSet{
|
ExposedPorts: nat.PortSet{
|
||||||
containerPort: {},
|
containerPort: {},
|
||||||
@@ -449,6 +582,7 @@ func runDockerVMProxyContainer(ctx context.Context, dockerCli *docker.Client, ta
|
|||||||
|
|
||||||
hostConfig := &container.HostConfig{
|
hostConfig := &container.HostConfig{
|
||||||
AutoRemove: true,
|
AutoRemove: true,
|
||||||
|
Binds: binds,
|
||||||
PortBindings: nat.PortMap{
|
PortBindings: nat.PortMap{
|
||||||
containerPort: []nat.PortBinding{
|
containerPort: []nat.PortBinding{
|
||||||
{
|
{
|
||||||
@@ -474,9 +608,32 @@ func runDockerVMProxyContainer(ctx context.Context, dockerCli *docker.Client, ta
|
|||||||
return "", 0, fmt.Errorf("start socat proxy container %s: %w", resp.ID, err)
|
return "", 0, fmt.Errorf("start socat proxy container %s: %w", resp.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for socat to start listening inside the container. ContainerStart returns as soon as the
|
||||||
|
// container process is launched, but socat may not have bound its port yet. Without this check,
|
||||||
|
// the first 'docker push' connection can arrive before socat is ready and get reset.
|
||||||
|
addr := fmt.Sprintf("127.0.0.1:%d", hostPort)
|
||||||
|
if err = waitForTCPPort(addr, 10*time.Second); err != nil {
|
||||||
|
cleanup()
|
||||||
|
return "", 0, fmt.Errorf("socat proxy container %s: %w", resp.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
return resp.ID, hostPort, nil
|
return resp.ID, hostPort, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// waitForTCPPort polls addr until a TCP connection succeeds or timeout is reached.
|
||||||
|
func waitForTCPPort(addr string, timeout time.Duration) error {
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
conn, err := net.DialTimeout("tcp", addr, time.Second)
|
||||||
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("port %s did not become ready within %s", addr, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
// toPushProgressEvent converts a JSON progress message from the Docker API to a progress event.
|
// toPushProgressEvent converts a JSON progress message from the Docker API to a progress event.
|
||||||
// It's based on toPushProgressEvent from Docker Compose.
|
// It's based on toPushProgressEvent from Docker Compose.
|
||||||
func toPushProgressEvent(jm jsonmessage.JSONMessage) *progress.Event {
|
func toPushProgressEvent(jm jsonmessage.JSONMessage) *progress.Event {
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ func TestLogMerger_ZeroTimestampForwarding(t *testing.T) {
|
|||||||
merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch}, LogMergerOptions{})
|
merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch}, LogMergerOptions{})
|
||||||
output := merger.Stream()
|
output := merger.Stream()
|
||||||
|
|
||||||
for i := 0; i < zeroCount; i++ {
|
for range zeroCount {
|
||||||
ch <- testEntry(api.LogStreamStdout, time.Time{}, "zero")
|
ch <- testEntry(api.LogStreamStdout, time.Time{}, "zero")
|
||||||
}
|
}
|
||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
@@ -237,7 +237,7 @@ func TestLogMerger_ZeroTimestampForwarding(t *testing.T) {
|
|||||||
results := collectEntries(t, output, 0)
|
results := collectEntries(t, output, 0)
|
||||||
require.Len(t, results, zeroCount+1)
|
require.Len(t, results, zeroCount+1)
|
||||||
|
|
||||||
for i := 0; i < zeroCount; i++ {
|
for i := range zeroCount {
|
||||||
assert.True(t, results[i].Timestamp.IsZero(), "entry %d should have zero timestamp", i)
|
assert.True(t, results[i].Timestamp.IsZero(), "entry %d should have zero timestamp", i)
|
||||||
assert.Equal(t, "zero", string(results[i].Message))
|
assert.Equal(t, "zero", string(results[i].Message))
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -27,4 +27,4 @@ COPY ./Caddyfile /etc/caddy/Caddyfile
|
|||||||
COPY --from=prod /opt/docusaurus/build /usr/share/caddy
|
COPY --from=prod /opt/docusaurus/build /usr/share/caddy
|
||||||
# Copy the landing page assets.
|
# Copy the landing page assets.
|
||||||
COPY landing/images /usr/share/caddy/images
|
COPY landing/images /usr/share/caddy/images
|
||||||
COPY landing/index.html landing/style.css /usr/share/caddy/
|
COPY landing/index.html landing/hub.html landing/style.css /usr/share/caddy/
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ services:
|
|||||||
|
|
||||||
reverse_proxy {{upstreams 8000}} {
|
reverse_proxy {{upstreams 8000}} {
|
||||||
import common_proxy
|
import common_proxy
|
||||||
|
lb_policy first
|
||||||
}
|
}
|
||||||
log
|
log
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ uc machine add [USER@]HOST[:PORT] [flags]
|
|||||||
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
||||||
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
||||||
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
||||||
--wg-endpoint strings WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port 51820 is used if omitted.
|
--wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections
|
||||||
Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.
|
to this machine. This doesn't change the address/port WireGuard listens on the machine.
|
||||||
|
Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is 51820 if omitted.
|
||||||
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
||||||
If not specified, the machine's routable IPs and public IP are auto-detected and used as endpoints.
|
Defaults to the auto-detected public and routable machine IPs.
|
||||||
-y, --yes Auto-confirm prompts (e.g., resetting an already initialised machine).
|
-y, --yes Auto-confirm prompts (e.g., resetting an already initialised machine).
|
||||||
Should be explicitly set when running non-interactively, e.g., in CI/CD pipelines. [$UNCLOUD_AUTO_CONFIRM]
|
Should be explicitly set when running non-interactively, e.g., in CI/CD pipelines. [$UNCLOUD_AUTO_CONFIRM]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -46,10 +46,11 @@ uc machine init [schema://]USER@HOST[:PORT] [flags]
|
|||||||
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
||||||
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
||||||
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
||||||
--wg-endpoint strings WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port 51820 is used if omitted.
|
--wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections
|
||||||
Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.
|
to this machine. This doesn't change the address/port WireGuard listens on the machine.
|
||||||
|
Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is 51820 if omitted.
|
||||||
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
||||||
If not specified, the machine's routable IPs and public IP are auto-detected and used as endpoints.
|
Defaults to the auto-detected public and routable machine IPs.
|
||||||
-y, --yes Auto-confirm prompts (e.g., resetting an already initialised machine).
|
-y, --yes Auto-confirm prompts (e.g., resetting an already initialised machine).
|
||||||
Should be explicitly set when running non-interactively, e.g., in CI/CD pipelines. [$UNCLOUD_AUTO_CONFIRM]
|
Should be explicitly set when running non-interactively, e.g., in CI/CD pipelines. [$UNCLOUD_AUTO_CONFIRM]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ uc machine update MACHINE [flags]
|
|||||||
-h, --help help for update
|
-h, --help help for update
|
||||||
--name string New name for the machine
|
--name string New name for the machine
|
||||||
--public-ip string Public IP address of the machine for ingress configuration. Use 'none' or '' to remove the public IP.
|
--public-ip string Public IP address of the machine for ingress configuration. Use 'none' or '' to remove the public IP.
|
||||||
--wg-endpoint strings WireGuard endpoint address in format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port 51820 is used if omitted.
|
--wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections
|
||||||
Other machines in the cluster will use this endpoint to establish a WireGuard connection to this machine.
|
to this machine. This doesn't change the address/port WireGuard listens on the machine.
|
||||||
|
Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is 51820 if omitted.
|
||||||
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
Multiple endpoints can be specified by repeating the flag or using a comma-separated list.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,896 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Uncloud Hub | Hosted dashboard and observability for Uncloud</title>
|
||||||
|
<meta name="description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster.">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<link href="./style.css" rel="stylesheet">
|
||||||
|
<link rel="apple-touch-icon" href="./images/apple-touch-icon.png" sizes="180x180"/>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="./images/logo.svg"/>
|
||||||
|
<link rel="alternate icon" type="image/png" href="./images/favicon.png" sizes="96x96"/>
|
||||||
|
|
||||||
|
<!-- OpenGraph tags for social media -->
|
||||||
|
<meta property="og:title"
|
||||||
|
content="Uncloud Hub | Hosted dashboard and observability for Uncloud"/>
|
||||||
|
<meta property="og:description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster."/>
|
||||||
|
<meta property="og:image" content="https://uncloud.run/images/logo-wide.png"/>
|
||||||
|
<meta property="og:image:alt" content="Uncloud Hub - Observability for self-hosted apps"/>
|
||||||
|
<meta property="og:url" content="https://uncloud.run/hub"/>
|
||||||
|
<meta property="og:type" content="website"/>
|
||||||
|
<meta property="og:site_name" content="Uncloud"/>
|
||||||
|
<!-- Twitter card tags -->
|
||||||
|
<meta property="twitter:domain" content="uncloud.run">
|
||||||
|
<meta property="twitter:url" content="https://uncloud.run/hub">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title"
|
||||||
|
content="Uncloud Hub | Hosted dashboard and observability for Uncloud">
|
||||||
|
<meta name="twitter:description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster.">
|
||||||
|
<meta name="twitter:image" content="https://uncloud.run/images/logo-wide.png">
|
||||||
|
<meta name="twitter:image:alt" content="Uncloud Hub - Observability for self-hosted apps">
|
||||||
|
<style>
|
||||||
|
/* Prevent all inline SVGs from appearing full screen. */
|
||||||
|
svg {
|
||||||
|
max-width: 24px;
|
||||||
|
max-height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="font-inter antialiased bg-white text-zinc-900 tracking-tight">
|
||||||
|
|
||||||
|
<!-- Page wrapper -->
|
||||||
|
<div class="flex flex-col min-h-screen overflow-hidden supports-[overflow:clip]:overflow-clip">
|
||||||
|
|
||||||
|
<!-- Site header -->
|
||||||
|
<header class="absolute top-2 md:top-6 w-full z-30">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="flex items-center justify-between h-14">
|
||||||
|
<!-- Site branding -->
|
||||||
|
<div class="shrink-0 mr-4">
|
||||||
|
<a class="flex items-center" href="/">
|
||||||
|
<img class="w-8 h-8 rounded-lg shadow-sm shadow-zinc-950/20" src="./images/logo.svg" alt="Logo"
|
||||||
|
width="32" height="32">
|
||||||
|
<span class="ml-2 font-semibold text-lg text-zinc-900">uncloud</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<nav class="flex grow">
|
||||||
|
<!-- Left side navigation -->
|
||||||
|
<ul class="flex items-center">
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition inline-flex items-center"
|
||||||
|
href="/hub">
|
||||||
|
Hub
|
||||||
|
<span class="ml-1.5 text-[10px] font-semibold uppercase tracking-wide text-emerald-700 bg-emerald-100 px-1.5 py-0.5 rounded">
|
||||||
|
New
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="/docs">Docs</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="/blog">Blog</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="https://psviderski.substack.com/" target="_blank">Newsletter</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- Right side navigation -->
|
||||||
|
<ul class="flex grow justify-end items-center shrink-0">
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 flex items-center transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu">
|
||||||
|
<svg class="w-4 h-4 sm:mr-1 fill-current" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-1 hidden sm:inline">Discord</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-1 sm:px-5 py-2 flex items-center transition"
|
||||||
|
href="https://github.com/psviderski/uncloud">
|
||||||
|
<svg class="w-4 h-4 sm:mr-1 fill-current" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-1 hidden sm:inline">GitHub</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Page content -->
|
||||||
|
<main class="grow">
|
||||||
|
|
||||||
|
<!-- Hero -->
|
||||||
|
<section
|
||||||
|
class="relative before:absolute before:inset-0 before:h-80 before:pointer-events-none before:bg-gradient-to-b before:from-zinc-100 before:-z-10">
|
||||||
|
<div class="pt-32 pb-12 md:pt-40 md:pb-20">
|
||||||
|
<!-- Section content -->
|
||||||
|
<div class="px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto">
|
||||||
|
<div class="text-center pb-12 md:pb-16">
|
||||||
|
<!-- Eyebrow -->
|
||||||
|
<div class="inline-flex items-center text-sm font-medium text-zinc-500 px-4 py-0.5 mb-6 border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.white))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-full">
|
||||||
|
<span class="relative flex w-1.5 h-1.5 mr-2">
|
||||||
|
<span class="absolute inline-flex w-full h-full rounded-full bg-violet-500 opacity-75 animate-ping"></span>
|
||||||
|
<span class="relative inline-flex w-1.5 h-1.5 rounded-full bg-violet-500"></span>
|
||||||
|
</span>
|
||||||
|
Coming soon
|
||||||
|
</div>
|
||||||
|
<h1 class="font-inter-tight text-4xl md:text-5xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-zinc-500 via-zinc-900 to-zinc-900 pb-4">
|
||||||
|
See what's happening<br>
|
||||||
|
<!-- TODO: highlight anything? e.g. "in production" -->
|
||||||
|
in production
|
||||||
|
</h1>
|
||||||
|
<p class="text-lg text-zinc-500 mb-8">
|
||||||
|
<b>Uncloud Hub</b> is the UI and Grafana stack for your Uncloud clusters.<br>
|
||||||
|
Get real-time metrics, logs, and alerts out of the box to catch issues early and fix
|
||||||
|
faster.
|
||||||
|
</p>
|
||||||
|
<div class="max-w-xs mx-auto sm:max-w-none sm:inline-flex sm:justify-center space-y-4 sm:space-y-0 sm:space-x-4">
|
||||||
|
<div>
|
||||||
|
<a class="btn text-zinc-100 bg-zinc-900 hover:bg-zinc-800 w-full shadow"
|
||||||
|
href="#feedback">
|
||||||
|
Help shape Hub
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a class="btn text-zinc-600 bg-white hover:text-zinc-900 w-full shadow flex items-center justify-center"
|
||||||
|
href="#how-it-works">
|
||||||
|
How it works
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hero image -->
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 flex justify-center pb-12 md:pb-20 relative before:absolute before:-top-12 before:w-96 before:h-96 before:bg-zinc-900 before:opacity-[.15] before:rounded-full before:blur-3xl before:-z-10">
|
||||||
|
<img class="rounded-lg shadow-2xl" src="./images/hub-hero.webp" width="2560" height="1520"
|
||||||
|
alt="Uncloud Hub services dashboard, design preview">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trust / stats -->
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<p class="text-center text-base text-zinc-500 mb-8">
|
||||||
|
Hub is built for Uncloud, the open-source orchestrator that runs your apps across machines.
|
||||||
|
</p>
|
||||||
|
<div class="max-w-sm mx-auto grid gap-12 sm:grid-cols-2 md:grid-cols-4 md:-mx-5 md:gap-0 items-start md:max-w-none">
|
||||||
|
|
||||||
|
<!-- GitHub stars -->
|
||||||
|
<a href="https://github.com/psviderski/uncloud" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(5.2)" x-text="counterValue">0</span>K+</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">GitHub stars</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Downloads -->
|
||||||
|
<a href="https://github.com/psviderski/uncloud/releases" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(19)" x-text="counterValue">0</span>K+</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Downloads</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Hacker News front-page -->
|
||||||
|
<a href="https://news.ycombinator.com/item?id=46144275" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(2)" x-text="counterValue">0</span>x</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Hacker News front page</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Discord members. -->
|
||||||
|
<a href="https://uncloud.run/discord" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(366)" x-text="counterValue">0</span></h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Fans on Discord</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Animate counter functionality: https://github.com/alpinejs/alpine -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener('alpine:init', () => {
|
||||||
|
Alpine.data('counter', (target = 0, duration = 3000) => ({
|
||||||
|
startTimestamp: null,
|
||||||
|
step: null,
|
||||||
|
rawValue: 0,
|
||||||
|
counterValue: 0,
|
||||||
|
target: target,
|
||||||
|
precision: (target % 1 === 0) ? 0 : (target.toString().split('.')[1] || []).length,
|
||||||
|
animationRequestId: null,
|
||||||
|
animationCompleted: false,
|
||||||
|
observer: null,
|
||||||
|
init() {
|
||||||
|
// Intersection observer to watch visibility.
|
||||||
|
this.observer = new IntersectionObserver(entries => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
// Check if element is in view.
|
||||||
|
if (entry.isIntersecting && !this.animationCompleted) {
|
||||||
|
this.startAnimation()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.observer.observe(this.$el)
|
||||||
|
},
|
||||||
|
startAnimation() {
|
||||||
|
this.step = (timestamp) => {
|
||||||
|
if (!this.startTimestamp) this.startTimestamp = timestamp
|
||||||
|
const progress = Math.min((timestamp - this.startTimestamp) / duration, 1)
|
||||||
|
const easedProgress = this.easeOut(progress)
|
||||||
|
this.rawValue = parseFloat((easedProgress * this.target).toFixed(this.precision))
|
||||||
|
this.counterValue = this.rawValue.toFixed(this.precision)
|
||||||
|
if (progress < 1) {
|
||||||
|
this.animationRequestId = window.requestAnimationFrame(this.step)
|
||||||
|
} else {
|
||||||
|
this.animationCompleted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.animationRequestId = window.requestAnimationFrame(this.step);
|
||||||
|
},
|
||||||
|
easeOut(t) {
|
||||||
|
return 1 - Math.pow(1 - t, 5)
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
// Detach the handler to avoid memory and side-effect leakage.
|
||||||
|
this.animationRequestId && window.cancelAnimationFrame(this.step)
|
||||||
|
this.observer && this.observer.disconnect()
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Feature blocks -->
|
||||||
|
<section class="relative bg-zinc-50">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto text-center pb-12 md:pb-16">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-4">
|
||||||
|
What you actually see
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-zinc-500">
|
||||||
|
Pre-built dashboards and alerts for the failure modes you care about.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid sm:grid-cols-2 gap-6 lg:gap-8">
|
||||||
|
<!-- HTTP edge metrics -->
|
||||||
|
<article
|
||||||
|
class="flex flex-col border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.zinc.50))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<svg class="stroke-zinc-400 shrink-0" xmlns="http://www.w3.org/2000/svg" width="20"
|
||||||
|
height="20" fill="none" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
||||||
|
</svg>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-900">
|
||||||
|
HTTP edge metrics from Caddy
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||||
|
Per-service latency, error rate, status codes. From the proxy your apps already pass
|
||||||
|
through. No agent in your app. No code changes.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Logs in context -->
|
||||||
|
<article
|
||||||
|
class="flex flex-col border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.zinc.50))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<svg class="stroke-zinc-400 shrink-0" xmlns="http://www.w3.org/2000/svg" width="20"
|
||||||
|
height="20" fill="none" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||||
|
<path d="M14 2v6h6M9 13h6M9 17h6"/>
|
||||||
|
</svg>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-900">
|
||||||
|
Logs next to the spike
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||||
|
When something goes red, the relevant application logs are right there. No hunting for
|
||||||
|
log files across machines. No new query language to learn.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Slow Postgres queries -->
|
||||||
|
<article
|
||||||
|
class="flex flex-col border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.zinc.50))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<svg class="stroke-zinc-400 shrink-0" xmlns="http://www.w3.org/2000/svg" width="20"
|
||||||
|
height="20" fill="none" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<ellipse cx="12" cy="5" rx="9" ry="3"/>
|
||||||
|
<path d="M3 5v14a9 3 0 0 0 18 0V5M3 12a9 3 0 0 0 18 0"/>
|
||||||
|
</svg>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-900">
|
||||||
|
Slow Postgres queries
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||||
|
Hub watches every Uncloud-managed Postgres for queries eating your latency budget.
|
||||||
|
Find them before your users do.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<!-- Alerts that mean something -->
|
||||||
|
<article
|
||||||
|
class="flex flex-col border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.zinc.50))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<svg class="stroke-zinc-400 shrink-0" xmlns="http://www.w3.org/2000/svg" width="20"
|
||||||
|
height="20" fill="none" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10 21a2 2 0 0 0 4 0"/>
|
||||||
|
</svg>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-900">
|
||||||
|
Alerts that mean something
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||||
|
Pre-built rules for the failures you actually care about. Service unavailable. Edge
|
||||||
|
errors climbing. Disk filling. Postgres replication lag.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- How it works -->
|
||||||
|
<section id="how-it-works"
|
||||||
|
class="relative bg-zinc-800 text-zinc-400">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto text-center pb-12 md:pb-16">
|
||||||
|
<div class="inline-flex text-sm font-medium text-zinc-400 px-4 py-0.5 border border-transparent [background:linear-gradient(theme(colors.zinc.800),theme(colors.zinc.800))_padding-box,linear-gradient(120deg,theme(colors.zinc.700),theme(colors.zinc.700/0),theme(colors.zinc.700))_border-box] rounded-full mb-4">
|
||||||
|
How it works
|
||||||
|
</div>
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-100 mb-4">
|
||||||
|
Connect, collect, see
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg">
|
||||||
|
Three steps. The same stack you'd build by hand, set up for you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid md:grid-cols-3 gap-6 lg:gap-8">
|
||||||
|
<!-- Step 1 -->
|
||||||
|
<div class="border border-transparent [background:linear-gradient(theme(colors.zinc.800),theme(colors.zinc.800))_padding-box,linear-gradient(120deg,theme(colors.zinc.700),theme(colors.zinc.700/0),theme(colors.zinc.700))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<div class="w-7 h-7 rounded-full bg-zinc-700 text-zinc-200 flex items-center justify-center font-semibold text-sm">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-100">Connect</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm leading-relaxed mb-4">
|
||||||
|
Got an Uncloud cluster running? Connect it in one command. New to Uncloud? Hub walks
|
||||||
|
you through setting one up from your own machines.
|
||||||
|
</p>
|
||||||
|
<pre class="text-xs bg-zinc-900/60 border border-zinc-700/50 rounded p-3 text-zinc-300 overflow-x-auto"><span
|
||||||
|
class="text-emerald-500 select-none">$ </span>uc hub connect</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 2 -->
|
||||||
|
<div class="border border-transparent [background:linear-gradient(theme(colors.zinc.800),theme(colors.zinc.800))_padding-box,linear-gradient(120deg,theme(colors.zinc.700),theme(colors.zinc.700/0),theme(colors.zinc.700))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<div class="w-7 h-7 rounded-full bg-zinc-700 text-zinc-200 flex items-center justify-center font-semibold text-sm">
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-100">Install the agent</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm leading-relaxed mb-4">
|
||||||
|
Hub detects what's running. Caddy as your ingress, Postgres on machine 2, your worker,
|
||||||
|
your web app. It configures the right collectors for each. No exporters to install by
|
||||||
|
hand.
|
||||||
|
</p>
|
||||||
|
<div class="text-xs bg-zinc-900/60 border border-zinc-700/50 rounded p-3 text-zinc-400 space-y-1">
|
||||||
|
<div><span class="text-emerald-500">✓</span> Detected Caddy ingress</div>
|
||||||
|
<div><span class="text-emerald-500">✓</span> Detected Postgres 16</div>
|
||||||
|
<div><span class="text-emerald-500">✓</span> Configuring exporters</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 3 -->
|
||||||
|
<div class="border border-transparent [background:linear-gradient(theme(colors.zinc.800),theme(colors.zinc.800))_padding-box,linear-gradient(120deg,theme(colors.zinc.700),theme(colors.zinc.700/0),theme(colors.zinc.700))_border-box] rounded-lg p-6">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<div class="w-7 h-7 rounded-full bg-zinc-700 text-zinc-200 flex items-center justify-center font-semibold text-sm">
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<h3 class="font-inter-tight text-lg font-semibold text-zinc-100">See</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm leading-relaxed mb-4">
|
||||||
|
Within minutes, dashboards are live. Failed HTTP requests, slow queries, application
|
||||||
|
logs, system health. Plus alerts that page when users are affected.
|
||||||
|
</p>
|
||||||
|
<div class="text-xs bg-zinc-900/60 border border-zinc-700/50 rounded p-3 text-zinc-400 space-y-1">
|
||||||
|
<div>4 dashboards live</div>
|
||||||
|
<div>12 alert rules active</div>
|
||||||
|
<div>logs streaming</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- See inside the box -->
|
||||||
|
<section class="relative bg-zinc-50">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="lg:flex lg:items-start lg:gap-12">
|
||||||
|
<div class="lg:flex-1 mb-8 lg:mb-0">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-4">
|
||||||
|
Same Grafana stack you'd have built. Full access.
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-zinc-500 leading-relaxed">
|
||||||
|
Hub does the setup and the ongoing maintenance for you. It ships with opinions about
|
||||||
|
what's worth watching. Underneath, it's still your data and your tools.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="lg:flex-1">
|
||||||
|
<ul class="space-y-4">
|
||||||
|
<li class="flex gap-3 items-start">
|
||||||
|
<svg class="w-5 h-5 text-emerald-500 shrink-0 mt-1" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"/>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium text-zinc-900">Click any chart, see the query</div>
|
||||||
|
<div class="text-sm text-zinc-500">No black boxes. The PromQL is right there,
|
||||||
|
ready to copy or edit.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3 items-start">
|
||||||
|
<svg class="w-5 h-5 text-emerald-500 shrink-0 mt-1" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"/>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium text-zinc-900">Customise our dashboards or add
|
||||||
|
your own
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-zinc-500">Full Grafana editor. Your panels live
|
||||||
|
alongside the pre-built ones.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3 items-start">
|
||||||
|
<svg class="w-5 h-5 text-emerald-500 shrink-0 mt-1" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"/>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium text-zinc-900">Hand the data to an AI agent</div>
|
||||||
|
<div class="text-sm text-zinc-500">Read-only data API. Ask plain-English
|
||||||
|
questions about your fleet. It's your data.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3 items-start">
|
||||||
|
<svg class="w-5 h-5 text-emerald-500 shrink-0 mt-1" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"/>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<div class="font-medium text-zinc-900">Out of the critical path</div>
|
||||||
|
<div class="text-sm text-zinc-500">If Hub goes down, your apps keep running.
|
||||||
|
Hub watches. It does not run things.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Trust block -->
|
||||||
|
<section class="relative bg-white">
|
||||||
|
<div class="py-12 md:py-16">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto text-center pb-10">
|
||||||
|
<p class="text-sm font-medium text-zinc-500 uppercase tracking-wide">
|
||||||
|
Built on the back of Uncloud
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 max-w-4xl mx-auto">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900">5K+</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1">GitHub stars</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900">19K+</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1">Downloads</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900">2x</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1">Hacker News front page</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900">In use</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1">Radboud University</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Note from us -->
|
||||||
|
<section class="relative bg-zinc-50">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h2 class="font-inter-tight text-2xl md:text-3xl font-bold text-zinc-900 mb-2">
|
||||||
|
A note from us
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-4 text-lg text-zinc-600 leading-relaxed">
|
||||||
|
<p>
|
||||||
|
I'm Pasha. I've spent a decade building commercial software and keeping production
|
||||||
|
infrastructure healthy. Uncloud started because I wanted a simpler way to run my own apps
|
||||||
|
across cloud VMs and machines at home, without a Kubernetes degree.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Hub is the dashboard we needed for that, productised. If the problem above sounds like your
|
||||||
|
weekend, We'd like to hear about your setup. The design partner round is small. The
|
||||||
|
feedback we get now is what shapes what ships.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-8">
|
||||||
|
<a class="text-sm font-medium text-zinc-900 hover:underline" href="#feedback">
|
||||||
|
Tell us about your setup →
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Where Hub is going -->
|
||||||
|
<section class="relative bg-white">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 sm:px-6">
|
||||||
|
<h2 class="font-inter-tight text-2xl md:text-3xl font-bold text-zinc-900 mb-6 text-center">
|
||||||
|
Where Hub is going
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4 text-lg text-zinc-600 leading-relaxed">
|
||||||
|
<p>
|
||||||
|
Hub starts with observability because that's what we keep hearing from people running things
|
||||||
|
on their own servers. After that, the direction is broader. Shared cluster access without
|
||||||
|
juggling SSH keys. Connectivity for machines behind NAT. A clean way to reach your cluster
|
||||||
|
from your laptop as if you were already inside it.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
None of this is on the page yet because none of it is shipping yet. Observability lands
|
||||||
|
first. The rest follows once the wedge is real.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- FAQ -->
|
||||||
|
<section class="relative bg-zinc-50">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="text-center pb-10">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-2">
|
||||||
|
Frequently asked questions
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
What's open source and what's paid?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
Uncloud itself stays open source under Apache-2.0. The on-cluster agent that connects
|
||||||
|
to Hub will be open source too, with a configurable endpoint. The Hub backend is closed
|
||||||
|
source and paid.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
Does it work without Uncloud?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
No, by design. Hub knows what's running because Uncloud manages it. That auto-discovery
|
||||||
|
is the difference between Hub and a generic Grafana you set up yourself.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
Can my team log in too?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
Single user for now. Multi-user and team access are planned. If single user is a
|
||||||
|
blocker for you, please tell us on the form below. That's a strong signal for
|
||||||
|
prioritising it sooner.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
Can I self-host Hub itself?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
Planned for orgs that need to keep everything on their own infrastructure. Not in the
|
||||||
|
first release.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
I already run Grafana. What now?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
Keep it if it's working. Hub can sit alongside as a separate dashboard for the
|
||||||
|
Uncloud-aware views. If you'd rather stop maintaining your own Grafana, Hub replaces it
|
||||||
|
entirely. Same Grafana underneath either way.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
When does it ship and how much does it cost?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
First version is in design now. Pricing is per cluster, designed to land below the cost
|
||||||
|
of the machines you're watching. The form below is the way into the design partner
|
||||||
|
round.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details
|
||||||
|
class="group bg-white border border-zinc-200 rounded-lg p-5 [&[open]>summary>svg]:rotate-180">
|
||||||
|
<summary
|
||||||
|
class="flex items-center justify-between cursor-pointer font-medium text-zinc-900 list-none">
|
||||||
|
What if Hub is down?
|
||||||
|
<svg class="w-4 h-4 text-zinc-400 transition-transform" fill="none"
|
||||||
|
stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"/>
|
||||||
|
</svg>
|
||||||
|
</summary>
|
||||||
|
<p class="text-sm text-zinc-600 leading-relaxed mt-3">
|
||||||
|
Your apps keep running. Hub watches your cluster from outside it and is not in the
|
||||||
|
critical path of your traffic, your data, or your deploys. If hub.uncloud.run becomes
|
||||||
|
unavailable, you lose dashboards and alerts for that period. You do not lose your
|
||||||
|
applications.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Final CTA -->
|
||||||
|
<section id="feedback">
|
||||||
|
<div class="py-12 md:py-20 border-t border-zinc-200">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="relative max-w-3xl mx-auto text-center">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-4">
|
||||||
|
Help shape
|
||||||
|
<em class="relative not-italic inline-flex justify-center items-end">
|
||||||
|
Hub
|
||||||
|
<svg class="absolute fill-zinc-300 w-[calc(100%+1rem)] -z-10"
|
||||||
|
style="max-width: none;"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" width="120" height="10" viewBox="0 0 120 10"
|
||||||
|
aria-hidden="true" preserveAspectRatio="none">
|
||||||
|
<path d="M118.273 6.09C79.243 4.558 40.297 5.459 1.305 9.034c-1.507.13-1.742-1.521-.199-1.81C39.81-.228 79.647-1.568 118.443 4.2c1.63.233 1.377 1.943-.17 1.89Z"/>
|
||||||
|
</svg>
|
||||||
|
</em>
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-zinc-500 mb-8">
|
||||||
|
We're picking 5 to 10 design partners for the first version. If you run things on a few
|
||||||
|
servers and the Day 2 part is what's grinding you down, We'd like to hear about your setup.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Feedback form. Replace href with the real form URL when ready. -->
|
||||||
|
<div class="flex justify-center mb-6">
|
||||||
|
<a class="btn text-zinc-100 bg-zinc-900 hover:bg-zinc-800 shadow"
|
||||||
|
href="#"
|
||||||
|
data-todo="link-to-real-feedback-form">
|
||||||
|
Tell us about your setup
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-sm text-zinc-500">
|
||||||
|
<p>
|
||||||
|
Or drop your email below and we'll send updates as Hub takes shape.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email capture fallback. Reuses the Substack embed from the main site. -->
|
||||||
|
<div class="flex justify-center mt-4">
|
||||||
|
<iframe src="https://psviderski.substack.com/embed" width="480" height="150"
|
||||||
|
style="border:1px solid #EEE; background:white;" frameborder="0"
|
||||||
|
scrolling="no"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Site footer -->
|
||||||
|
<footer>
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<!-- Top area: Blocks -->
|
||||||
|
<div class="grid sm:grid-cols-12 gap-8 py-8 md:py-12 border-t border-zinc-200">
|
||||||
|
<!-- 1st block - Brand -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-6 lg:col-span-8 max-md:order-1 flex flex-col">
|
||||||
|
<div class="mb-4">
|
||||||
|
<!-- Logo -->
|
||||||
|
<a class="flex items-center" href="index.html">
|
||||||
|
<img class="w-8 h-8 rounded shadow-sm shadow-zinc-950/20" src="./images/logo.svg"
|
||||||
|
alt="Logo">
|
||||||
|
<span class="ml-2 font-semibold text-lg text-zinc-900">uncloud</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="grow text-sm text-zinc-500">
|
||||||
|
Made with ❤️ by
|
||||||
|
<a class="underline hover:text-zinc-900" href="https://github.com/unlabs-dev">unLabs</a>
|
||||||
|
in Australia
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Social links -->
|
||||||
|
<ul class="flex space-x-4 mt-4 mb-1">
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu" aria-label="Discord">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
height="20">
|
||||||
|
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://x.com/psviderski" aria-label="X/Twitter">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
|
||||||
|
<path d="m7.063 3 3.495 4.475L14.601 3h2.454l-5.359 5.931L18 17h-4.938l-3.866-4.893L4.771 17H2.316l5.735-6.342L2 3h5.063Zm-.74 1.347H4.866l8.875 11.232h1.36L6.323 4.347Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://t.me/spyyy" aria-label="Telegram">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
|
||||||
|
<path d="M17.968 3.276a.338.338 0 0 0-.232-.253 1.192 1.192 0 0 0-.63.045S3.087 8.106 2.286 8.664c-.172.121-.23.19-.259.272-.138.4.293.573.293.573l3.613 1.177a.388.388 0 0 0 .183-.011c.822-.519 8.27-5.222 8.7-5.38.068-.02.118 0 .1.049-.172.6-6.606 6.319-6.64 6.354a.138.138 0 0 0-.05.118l-.337 3.528s-.142 1.1.956 0a30.66 30.66 0 0 1 1.9-1.738c1.242.858 2.58 1.806 3.156 2.3a1 1 0 0 0 .732.283.825.825 0 0 0 .7-.622S17.894 5.292 17.98 3.909c.008-.135.021-.217.021-.317a1.177 1.177 0 0 0-.032-.316Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud" aria-label="GitHub">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
height="20">
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2nd block - Documentation -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
|
|
||||||
|
<h6 class="text-sm text-zinc-800 font-medium mb-2">Documentation</h6>
|
||||||
|
<ul class="text-sm space-y-2">
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/docs/#use-cases">Use cases</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/docs/getting-started/deploy-demo-app">Quick start</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/blog">Blog</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3rd block - Resources -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
|
<h6 class="text-sm text-zinc-800 font-medium mb-2">Resources</h6>
|
||||||
|
<ul class="text-sm space-y-2">
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud">GitHub project</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud/releases">Releases</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud/blob/main/LICENSE">License</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu">Community</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./js/vendors/alpinejs.min.js" defer></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,512 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Uncloud Hub | Hosted dashboard and observability for Uncloud</title>
|
||||||
|
<meta name="description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster.">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<link href="./style.css" rel="stylesheet">
|
||||||
|
<link rel="apple-touch-icon" href="./images/apple-touch-icon.png" sizes="180x180"/>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="./images/logo.svg"/>
|
||||||
|
<link rel="alternate icon" type="image/png" href="./images/favicon.png" sizes="96x96"/>
|
||||||
|
|
||||||
|
<!-- OpenGraph tags for social media -->
|
||||||
|
<meta property="og:title"
|
||||||
|
content="Uncloud Hub | Hosted dashboard and observability for Uncloud"/>
|
||||||
|
<meta property="og:description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster."/>
|
||||||
|
<meta property="og:image" content="https://uncloud.run/images/logo-wide.png"/>
|
||||||
|
<meta property="og:image:alt" content="Uncloud Hub - Observability for self-hosted apps"/>
|
||||||
|
<meta property="og:url" content="https://uncloud.run/hub"/>
|
||||||
|
<meta property="og:type" content="website"/>
|
||||||
|
<meta property="og:site_name" content="Uncloud"/>
|
||||||
|
<!-- Twitter card tags -->
|
||||||
|
<meta property="twitter:domain" content="uncloud.run">
|
||||||
|
<meta property="twitter:url" content="https://uncloud.run/hub">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title"
|
||||||
|
content="Uncloud Hub | Hosted dashboard and observability for Uncloud">
|
||||||
|
<meta name="twitter:description"
|
||||||
|
content="Uncloud Hub is the UI and hosted Grafana stack for your Uncloud clusters. Get metrics, logs, and alerts out of the box to catch issues early and fix faster.">
|
||||||
|
<meta name="twitter:image" content="https://uncloud.run/images/logo-wide.png">
|
||||||
|
<meta name="twitter:image:alt" content="Uncloud Hub - Observability for self-hosted apps">
|
||||||
|
<style>
|
||||||
|
/* Prevent all inline SVGs from appearing full screen. */
|
||||||
|
svg {
|
||||||
|
max-width: 24px;
|
||||||
|
max-height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="font-inter antialiased bg-white text-zinc-900 tracking-tight">
|
||||||
|
|
||||||
|
<!-- Page wrapper -->
|
||||||
|
<div class="flex flex-col min-h-screen overflow-hidden supports-[overflow:clip]:overflow-clip">
|
||||||
|
|
||||||
|
<!-- Site header -->
|
||||||
|
<header class="absolute top-2 md:top-6 w-full z-30">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="flex items-center justify-between h-14">
|
||||||
|
<!-- Site branding -->
|
||||||
|
<div class="shrink-0 mr-4">
|
||||||
|
<a class="flex items-center" href="/">
|
||||||
|
<img class="w-8 h-8 rounded-lg shadow-sm shadow-zinc-950/20" src="./images/logo.svg" alt="Logo"
|
||||||
|
width="32" height="32">
|
||||||
|
<span class="ml-2 font-semibold text-lg text-zinc-900">uncloud</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<nav class="flex grow">
|
||||||
|
<!-- Left side navigation -->
|
||||||
|
<ul class="flex items-center">
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition inline-flex items-center"
|
||||||
|
href="/hub">
|
||||||
|
Hub
|
||||||
|
<span class="ml-1.5 text-[10px] font-semibold uppercase tracking-wide text-emerald-700 bg-emerald-100 px-1.5 py-0.5 rounded">
|
||||||
|
New
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="/docs">Docs</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="/blog">Blog</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 transition"
|
||||||
|
href="https://psviderski.substack.com/" target="_blank">Newsletter</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- Right side navigation -->
|
||||||
|
<ul class="flex grow justify-end items-center shrink-0">
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-2 sm:px-5 py-2 flex items-center transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu">
|
||||||
|
<svg class="w-4 h-4 sm:mr-1 fill-current" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-1 hidden sm:inline">Discord</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-sm font-medium text-zinc-500 hover:text-zinc-900 px-1 sm:px-5 py-2 flex items-center transition"
|
||||||
|
href="https://github.com/psviderski/uncloud">
|
||||||
|
<svg class="w-4 h-4 sm:mr-1 fill-current" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-1 hidden sm:inline">GitHub</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Page content -->
|
||||||
|
<main class="grow">
|
||||||
|
|
||||||
|
<!-- Hero -->
|
||||||
|
<section
|
||||||
|
class="relative before:absolute before:inset-0 before:h-80 before:pointer-events-none before:bg-gradient-to-b before:from-zinc-100 before:-z-10">
|
||||||
|
<div class="pt-32 pb-12 md:pt-40 md:pb-20">
|
||||||
|
<!-- Section content -->
|
||||||
|
<div class="px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto">
|
||||||
|
<div class="text-center pb-12 md:pb-16">
|
||||||
|
<!-- Eyebrow -->
|
||||||
|
<div class="inline-flex items-center text-sm font-medium text-zinc-500 px-4 py-0.5 mb-6 border border-transparent [background:linear-gradient(theme(colors.white),theme(colors.white))_padding-box,linear-gradient(120deg,theme(colors.zinc.300),theme(colors.zinc.100),theme(colors.zinc.300))_border-box] rounded-full">
|
||||||
|
<span class="relative flex w-1.5 h-1.5 mr-2">
|
||||||
|
<span class="absolute inline-flex w-full h-full rounded-full bg-violet-500 opacity-75 animate-ping"></span>
|
||||||
|
<span class="relative inline-flex w-1.5 h-1.5 rounded-full bg-violet-500"></span>
|
||||||
|
</span>
|
||||||
|
Coming soon
|
||||||
|
</div>
|
||||||
|
<h1 class="font-inter-tight text-4xl md:text-5xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-zinc-500 via-zinc-900 to-zinc-900 pb-4">
|
||||||
|
See what's happening<br>
|
||||||
|
<!-- TODO: highlight anything? e.g. "in production" -->
|
||||||
|
in production
|
||||||
|
</h1>
|
||||||
|
<p class="text-lg text-zinc-500 mb-8">
|
||||||
|
<b>Uncloud Hub</b> is the UI and Grafana stack for your Uncloud clusters.<br>
|
||||||
|
Get real-time metrics, logs, and alerts out of the box to catch issues early and fix
|
||||||
|
faster.
|
||||||
|
</p>
|
||||||
|
<div class="max-w-xs mx-auto sm:max-w-none sm:inline-flex sm:justify-center space-y-4 sm:space-y-0 sm:space-x-4">
|
||||||
|
<div>
|
||||||
|
<a class="btn text-zinc-100 bg-zinc-900 hover:bg-zinc-800 w-full shadow"
|
||||||
|
href="#feedback">
|
||||||
|
Help shape Hub
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a class="btn text-zinc-600 bg-white hover:text-zinc-900 w-full shadow flex items-center justify-center"
|
||||||
|
href="#how-it-works">
|
||||||
|
How it works
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hero image -->
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 flex justify-center pb-12 md:pb-20 relative before:absolute before:-top-12 before:w-96 before:h-96 before:bg-zinc-900 before:opacity-[.15] before:rounded-full before:blur-3xl before:-z-10">
|
||||||
|
<img class="rounded-lg shadow-2xl" src="./images/hub-hero.webp" width="2560" height="1520"
|
||||||
|
alt="Uncloud Hub services dashboard, design preview">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trust / stats -->
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<p class="text-center text-base text-zinc-500 mb-8">
|
||||||
|
Hub is built for Uncloud, the open-source orchestrator that runs your apps across machines.
|
||||||
|
</p>
|
||||||
|
<div class="max-w-sm mx-auto grid gap-12 sm:grid-cols-2 md:grid-cols-4 md:-mx-5 md:gap-0 items-start md:max-w-none">
|
||||||
|
|
||||||
|
<!-- GitHub stars -->
|
||||||
|
<a href="https://github.com/psviderski/uncloud" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(5.2)" x-text="counterValue">0</span>K+</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">GitHub stars</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Downloads -->
|
||||||
|
<a href="https://github.com/psviderski/uncloud/releases" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(19)" x-text="counterValue">0</span>K+</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Downloads</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Hacker News front-page -->
|
||||||
|
<a href="https://news.ycombinator.com/item?id=46144275" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(2)" x-text="counterValue">0</span>x</h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Hacker News front page</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Discord members. -->
|
||||||
|
<a href="https://uncloud.run/discord" target="_blank" rel="noopener"
|
||||||
|
class="group block relative text-center md:px-5 after:hidden md:after:block after:absolute after:right-0 after:top-1/2 after:-translate-y-1/2 after:w-px after:h-8 after:border-l after:border-zinc-300 after:border-dashed last:after:hidden">
|
||||||
|
<h4 class="font-inter-tight text-2xl md:text-3xl font-bold tabular-nums mb-2"><span x-data="counter(368)" x-text="counterValue">0</span></h4>
|
||||||
|
<p class="text-sm text-zinc-500 transition-colors group-hover:text-zinc-800">Fans on Discord</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Animate counter functionality: https://github.com/alpinejs/alpine -->
|
||||||
|
<script>
|
||||||
|
document.addEventListener('alpine:init', () => {
|
||||||
|
Alpine.data('counter', (target = 0, duration = 3000) => ({
|
||||||
|
startTimestamp: null,
|
||||||
|
step: null,
|
||||||
|
rawValue: 0,
|
||||||
|
counterValue: 0,
|
||||||
|
target: target,
|
||||||
|
precision: (target % 1 === 0) ? 0 : (target.toString().split('.')[1] || []).length,
|
||||||
|
animationRequestId: null,
|
||||||
|
animationCompleted: false,
|
||||||
|
observer: null,
|
||||||
|
init() {
|
||||||
|
// Intersection observer to watch visibility.
|
||||||
|
this.observer = new IntersectionObserver(entries => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
// Check if element is in view.
|
||||||
|
if (entry.isIntersecting && !this.animationCompleted) {
|
||||||
|
this.startAnimation()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.observer.observe(this.$el)
|
||||||
|
},
|
||||||
|
startAnimation() {
|
||||||
|
this.step = (timestamp) => {
|
||||||
|
if (!this.startTimestamp) this.startTimestamp = timestamp
|
||||||
|
const progress = Math.min((timestamp - this.startTimestamp) / duration, 1)
|
||||||
|
const easedProgress = this.easeOut(progress)
|
||||||
|
this.rawValue = parseFloat((easedProgress * this.target).toFixed(this.precision))
|
||||||
|
this.counterValue = this.rawValue.toFixed(this.precision)
|
||||||
|
if (progress < 1) {
|
||||||
|
this.animationRequestId = window.requestAnimationFrame(this.step)
|
||||||
|
} else {
|
||||||
|
this.animationCompleted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.animationRequestId = window.requestAnimationFrame(this.step);
|
||||||
|
},
|
||||||
|
easeOut(t) {
|
||||||
|
return 1 - Math.pow(1 - t, 5)
|
||||||
|
},
|
||||||
|
destroy() {
|
||||||
|
// Detach the handler to avoid memory and side-effect leakage.
|
||||||
|
this.animationRequestId && window.cancelAnimationFrame(this.step)
|
||||||
|
this.observer && this.observer.disconnect()
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Day 2 problem: the long part of running an app. -->
|
||||||
|
<section class="relative bg-zinc-50">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
|
||||||
|
<!-- Section heading -->
|
||||||
|
<div class="max-w-3xl mx-auto text-center pb-12 md:pb-16">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-4">
|
||||||
|
Frustrated by the complexity of setting up observability?
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-zinc-500">
|
||||||
|
Observability is what killing the joy of shipping.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vertical timeline: a single line carries Build, Ship, Run, the questions, and the stack. -->
|
||||||
|
<div class="max-w-xl mx-auto">
|
||||||
|
<div class="relative pl-10 sm:pl-12 pb-10">
|
||||||
|
<!-- The continuous line, spanning from the first marker to just above the arrow. -->
|
||||||
|
<span class="absolute left-3 sm:left-4 top-1.5 bottom-0 w-px bg-zinc-200" aria-hidden="true"></span>
|
||||||
|
|
||||||
|
<!-- Build. -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<span class="absolute -left-[33px] sm:-left-[37px] top-1 w-3 h-3 rounded-full bg-emerald-500 ring-4 ring-zinc-50" aria-hidden="true"></span>
|
||||||
|
<div class="text-xs font-semibold uppercase tracking-wider text-zinc-500">Build</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1">The fun part.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Ship. -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<span class="absolute -left-[33px] sm:-left-[37px] top-1 w-3 h-3 rounded-full bg-emerald-500 ring-4 ring-zinc-50" aria-hidden="true"></span>
|
||||||
|
<div class="text-xs font-semibold uppercase tracking-wider text-zinc-500">Ship</div>
|
||||||
|
<div class="text-sm text-zinc-500 mt-1"><code class="font-mono text-zinc-700">uc deploy</code> and you're done.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Run, emphasized: filled dark marker, bolder copy. -->
|
||||||
|
<div class="relative mb-10">
|
||||||
|
<span class="absolute -left-[35px] sm:-left-[39px] top-0.5 w-3.5 h-3.5 rounded-full bg-zinc-900 ring-4 ring-zinc-50 shadow-sm" aria-hidden="true"></span>
|
||||||
|
<div class="text-xs font-semibold uppercase tracking-wider text-zinc-900">Run / Monitor and observe</div>
|
||||||
|
<p class="text-base text-zinc-900 mt-1 font-medium">This is what matters.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bridge into the observability beat. New H2 + subhead carry the emotional load. -->
|
||||||
|
<div class="mt-2 mb-6">
|
||||||
|
<h3 class="font-inter-tight text-xl sm:text-2xl font-bold text-zinc-900 mb-2">
|
||||||
|
Observability for developers who'd rather be shipping.
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-zinc-600">
|
||||||
|
It's not optional.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- The questions: standalone list, ? as bullets. Mix of why and how to catch both ICPs. -->
|
||||||
|
<ul class="space-y-3 mb-6 text-sm text-zinc-700">
|
||||||
|
<li class="flex gap-3">
|
||||||
|
<span class="font-inter-tight font-semibold text-base leading-snug text-zinc-400 shrink-0 select-none" aria-hidden="true">?</span>
|
||||||
|
<span>Are you finding out about outages from your users?</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3">
|
||||||
|
<span class="font-inter-tight font-semibold text-base leading-snug text-zinc-400 shrink-0 select-none" aria-hidden="true">?</span>
|
||||||
|
<span>When something breaks, where do you start looking?</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3">
|
||||||
|
<span class="font-inter-tight font-semibold text-base leading-snug text-zinc-400 shrink-0 select-none" aria-hidden="true">?</span>
|
||||||
|
<span>Prometheus or VictoriaMetrics? Loki or VictoriaLogs?</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3">
|
||||||
|
<span class="font-inter-tight font-semibold text-base leading-snug text-zinc-400 shrink-0 select-none" aria-hidden="true">?</span>
|
||||||
|
<span>Vector, Grafana Alloy, or Fluent Bit?</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-3">
|
||||||
|
<span class="font-inter-tight font-semibold text-base leading-snug text-zinc-400 shrink-0 select-none" aria-hidden="true">?</span>
|
||||||
|
<span>Which alerts wake you for real problems, not 3 AM noise?</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Connector line into the tangle. -->
|
||||||
|
<p class="text-sm text-zinc-600 mb-6">
|
||||||
|
And that's before you've drawn a single graph.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Tangle: first-pass SVG. Overlapping bezier curves with tool name labels around a big "?". To be iterated separately. -->
|
||||||
|
<div class="my-6">
|
||||||
|
<svg viewBox="0 0 480 300" class="block w-full h-auto" style="max-width:100%;max-height:none;" preserveAspectRatio="xMidYMid meet" aria-hidden="true">
|
||||||
|
<g fill="none" stroke="rgb(212 212 216)" stroke-width="1.5" stroke-linecap="round">
|
||||||
|
<path d="M 60 30 C 180 80, 100 180, 240 150 S 360 200, 420 110"/>
|
||||||
|
<path d="M 100 260 C 200 220, 180 100, 320 130 S 420 220, 380 270"/>
|
||||||
|
<path d="M 80 120 C 200 60, 320 200, 440 140"/>
|
||||||
|
<path d="M 240 30 C 280 100, 160 200, 240 280"/>
|
||||||
|
<path d="M 40 200 C 160 240, 240 80, 360 200"/>
|
||||||
|
</g>
|
||||||
|
<text x="240" y="195" text-anchor="middle" font-family="Inter Tight, Inter, sans-serif" font-size="140" font-weight="700" fill="rgb(228 228 231)">?</text>
|
||||||
|
<g font-family="ui-monospace, Menlo, Monaco, monospace" font-size="11" fill="rgb(82 82 91)">
|
||||||
|
<text x="60" y="44">prometheus</text>
|
||||||
|
<text x="360" y="92">VictoriaMetrics</text>
|
||||||
|
<text x="30" y="170">loki</text>
|
||||||
|
<text x="380" y="170">grafana</text>
|
||||||
|
<text x="90" y="250">vector</text>
|
||||||
|
<text x="300" y="270">alertmanager</text>
|
||||||
|
<text x="230" y="60">cadvisor</text>
|
||||||
|
<text x="380" y="40">alloy</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Arrow capping the line, pointing into the next section. -->
|
||||||
|
<span class="absolute left-3 sm:left-4 -bottom-1 -translate-x-1/2 translate-y-full" aria-hidden="true">
|
||||||
|
<svg width="10" height="10" viewBox="0 0 10 10" class="block fill-zinc-300">
|
||||||
|
<path d="M5 10 0 0 H10 Z"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="relative bg-white text-zinc-800">
|
||||||
|
<div class="py-12 md:py-20">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<div class="max-w-3xl mx-auto text-center pb-12 md:pb-16">
|
||||||
|
<h2 class="font-inter-tight text-3xl md:text-4xl font-bold text-zinc-900 mb-4">
|
||||||
|
Untangle the observability mess and start monitoring instantly
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-zinc-500">
|
||||||
|
A hosted Grafana stack that knows about your Uncloud apps.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Site footer -->
|
||||||
|
<footer>
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
|
<!-- Top area: Blocks -->
|
||||||
|
<div class="grid sm:grid-cols-12 gap-8 py-8 md:py-12 border-t border-zinc-200">
|
||||||
|
<!-- 1st block - Brand -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-6 lg:col-span-8 max-md:order-1 flex flex-col">
|
||||||
|
<div class="mb-4">
|
||||||
|
<!-- Logo -->
|
||||||
|
<a class="flex items-center" href="index.html">
|
||||||
|
<img class="w-8 h-8 rounded shadow-sm shadow-zinc-950/20" src="./images/logo.svg"
|
||||||
|
alt="Logo">
|
||||||
|
<span class="ml-2 font-semibold text-lg text-zinc-900">uncloud</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="grow text-sm text-zinc-500">
|
||||||
|
Made with ❤️ by
|
||||||
|
<a class="underline hover:text-zinc-900" href="https://github.com/unlabs-dev">unLabs</a>
|
||||||
|
in Australia
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Social links -->
|
||||||
|
<ul class="flex space-x-4 mt-4 mb-1">
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu" aria-label="Discord">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
height="20">
|
||||||
|
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://x.com/psviderski" aria-label="X/Twitter">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
|
||||||
|
<path d="m7.063 3 3.495 4.475L14.601 3h2.454l-5.359 5.931L18 17h-4.938l-3.866-4.893L4.771 17H2.316l5.735-6.342L2 3h5.063Zm-.74 1.347H4.866l8.875 11.232h1.36L6.323 4.347Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://t.me/spyyy" aria-label="Telegram">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
|
||||||
|
<path d="M17.968 3.276a.338.338 0 0 0-.232-.253 1.192 1.192 0 0 0-.63.045S3.087 8.106 2.286 8.664c-.172.121-.23.19-.259.272-.138.4.293.573.293.573l3.613 1.177a.388.388 0 0 0 .183-.011c.822-.519 8.27-5.222 8.7-5.38.068-.02.118 0 .1.049-.172.6-6.606 6.319-6.64 6.354a.138.138 0 0 0-.05.118l-.337 3.528s-.142 1.1.956 0a30.66 30.66 0 0 1 1.9-1.738c1.242.858 2.58 1.806 3.156 2.3a1 1 0 0 0 .732.283.825.825 0 0 0 .7-.622S17.894 5.292 17.98 3.909c.008-.135.021-.217.021-.317a1.177 1.177 0 0 0-.032-.316Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="flex justify-center items-center text-zinc-700 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud" aria-label="GitHub">
|
||||||
|
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
width="20"
|
||||||
|
height="20">
|
||||||
|
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2nd block - Documentation -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
|
|
||||||
|
<h6 class="text-sm text-zinc-800 font-medium mb-2">Documentation</h6>
|
||||||
|
<ul class="text-sm space-y-2">
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/docs/#use-cases">Use cases</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/docs/getting-started/deploy-demo-app">Quick start</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="/blog">Blog</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3rd block - Resources -->
|
||||||
|
<div class="sm:col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
|
<h6 class="text-sm text-zinc-800 font-medium mb-2">Resources</h6>
|
||||||
|
<ul class="text-sm space-y-2">
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud">GitHub project</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud/releases">Releases</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://github.com/psviderski/uncloud/blob/main/LICENSE">License</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="text-zinc-500 hover:text-zinc-900 transition"
|
||||||
|
href="https://discord.gg/eR35KQJhPu">Community</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./js/vendors/alpinejs.min.js" defer></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
+5
File diff suppressed because one or more lines are too long
@@ -1139,6 +1139,14 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
transition: y 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), width 0.1s ease-out;
|
transition: y 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), width 0.1s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.visible{
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse{
|
||||||
|
visibility: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
.absolute{
|
.absolute{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
@@ -1147,6 +1155,42 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.-bottom-1{
|
||||||
|
bottom: -0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-left-\[33px\]{
|
||||||
|
left: -33px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.-left-\[35px\]{
|
||||||
|
left: -35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-0{
|
||||||
|
bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-3{
|
||||||
|
left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-0{
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-0\.5{
|
||||||
|
top: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-1{
|
||||||
|
top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-1\.5{
|
||||||
|
top: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.top-2{
|
.top-2{
|
||||||
top: 0.5rem;
|
top: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1164,18 +1208,35 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.my-6{
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mb-1{
|
.mb-1{
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb-10{
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mb-2{
|
.mb-2{
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb-3{
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mb-4{
|
.mb-4{
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb-6{
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mb-8{
|
.mb-8{
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
@@ -1184,6 +1245,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ml-1\.5{
|
||||||
|
margin-left: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.ml-2{
|
.ml-2{
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1220,6 +1285,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mt-3{
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mt-4{
|
.mt-4{
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
@@ -1256,6 +1325,14 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-1{
|
||||||
|
height: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-1\.5{
|
||||||
|
height: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.h-14{
|
.h-14{
|
||||||
height: 3.5rem;
|
height: 3.5rem;
|
||||||
}
|
}
|
||||||
@@ -1272,6 +1349,14 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
height: 6rem;
|
height: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-3{
|
||||||
|
height: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-3\.5{
|
||||||
|
height: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
.h-4{
|
.h-4{
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
@@ -1280,14 +1365,38 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-7{
|
||||||
|
height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.h-8{
|
.h-8{
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-auto{
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-full{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-px{
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.min-h-screen{
|
.min-h-screen{
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-1{
|
||||||
|
width: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-1\.5{
|
||||||
|
width: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-2{
|
.w-2{
|
||||||
width: 0.5rem;
|
width: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1296,6 +1405,14 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
width: 0.625rem;
|
width: 0.625rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-3{
|
||||||
|
width: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-3\.5{
|
||||||
|
width: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-4{
|
.w-4{
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
}
|
}
|
||||||
@@ -1304,6 +1421,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-7{
|
||||||
|
width: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-8{
|
.w-8{
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
}
|
}
|
||||||
@@ -1316,6 +1437,14 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-px{
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-w-2xl{
|
||||||
|
max-width: 42rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-3xl{
|
.max-w-3xl{
|
||||||
max-width: 48rem;
|
max-width: 48rem;
|
||||||
}
|
}
|
||||||
@@ -1324,6 +1453,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
max-width: 56rem;
|
max-width: 56rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-5xl{
|
||||||
|
max-width: 64rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-6xl{
|
.max-w-6xl{
|
||||||
max-width: 72rem;
|
max-width: 72rem;
|
||||||
}
|
}
|
||||||
@@ -1332,6 +1465,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
max-width: 28rem;
|
max-width: 28rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-sm{
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-xl{
|
.max-w-xl{
|
||||||
max-width: 36rem;
|
max-width: 36rem;
|
||||||
}
|
}
|
||||||
@@ -1348,11 +1485,44 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.-translate-x-1\/2{
|
||||||
|
--tw-translate-x: -50%;
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|
||||||
|
.translate-y-full{
|
||||||
|
--tw-translate-y: 100%;
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|
||||||
|
.transform{
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ping{
|
||||||
|
75%, 100%{
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-ping{
|
||||||
|
animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.select-none{
|
.select-none{
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-none{
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
.grid-cols-1{
|
.grid-cols-1{
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
@@ -1361,10 +1531,18 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-cols-\[20\%_20\%_1fr\]{
|
||||||
|
grid-template-columns: 20% 20% 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-col{
|
.flex-col{
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-wrap{
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.items-start{
|
.items-start{
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
@@ -1389,6 +1567,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-12{
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.gap-2{
|
.gap-2{
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
@@ -1417,6 +1599,12 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
|
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-y-1 > :not([hidden]) ~ :not([hidden]){
|
||||||
|
--tw-space-y-reverse: 0;
|
||||||
|
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
|
||||||
|
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
|
||||||
|
}
|
||||||
|
|
||||||
.space-y-12 > :not([hidden]) ~ :not([hidden]){
|
.space-y-12 > :not([hidden]) ~ :not([hidden]){
|
||||||
--tw-space-y-reverse: 0;
|
--tw-space-y-reverse: 0;
|
||||||
margin-top: calc(3rem * calc(1 - var(--tw-space-y-reverse)));
|
margin-top: calc(3rem * calc(1 - var(--tw-space-y-reverse)));
|
||||||
@@ -1518,6 +1706,16 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
border-color: rgb(63 63 70 / 0.5);
|
border-color: rgb(63 63 70 / 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-emerald-100{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(209 250 229 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-emerald-500{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(16 185 129 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-gray-100{
|
.bg-gray-100{
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
||||||
@@ -1538,6 +1736,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-violet-500{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(139 92 246 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-white{
|
.bg-white{
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||||
@@ -1548,11 +1751,26 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
background-color: rgb(234 179 8 / var(--tw-bg-opacity));
|
background-color: rgb(234 179 8 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-zinc-200{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(228 228 231 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-zinc-300{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(212 212 216 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-zinc-50{
|
.bg-zinc-50{
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(250 250 250 / var(--tw-bg-opacity));
|
background-color: rgb(250 250 250 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-zinc-700{
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(63 63 70 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-zinc-800{
|
.bg-zinc-800{
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(39 39 42 / var(--tw-bg-opacity));
|
background-color: rgb(39 39 42 / var(--tw-bg-opacity));
|
||||||
@@ -1563,21 +1781,39 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
background-color: rgb(24 24 27 / var(--tw-bg-opacity));
|
background-color: rgb(24 24 27 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-zinc-900\/60{
|
||||||
|
background-color: rgb(24 24 27 / 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
.bg-gradient-to-r{
|
.bg-gradient-to-r{
|
||||||
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.from-zinc-300{
|
||||||
|
--tw-gradient-from: #d4d4d8 var(--tw-gradient-from-position);
|
||||||
|
--tw-gradient-to: rgb(212 212 216 / 0) var(--tw-gradient-to-position);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||||
|
}
|
||||||
|
|
||||||
.from-zinc-500{
|
.from-zinc-500{
|
||||||
--tw-gradient-from: #71717a var(--tw-gradient-from-position);
|
--tw-gradient-from: #71717a var(--tw-gradient-from-position);
|
||||||
--tw-gradient-to: rgb(113 113 122 / 0) var(--tw-gradient-to-position);
|
--tw-gradient-to: rgb(113 113 122 / 0) var(--tw-gradient-to-position);
|
||||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.from-\[40\%\]{
|
||||||
|
--tw-gradient-from-position: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
.via-zinc-900{
|
.via-zinc-900{
|
||||||
--tw-gradient-to: rgb(24 24 27 / 0) var(--tw-gradient-to-position);
|
--tw-gradient-to: rgb(24 24 27 / 0) var(--tw-gradient-to-position);
|
||||||
--tw-gradient-stops: var(--tw-gradient-from), #18181b var(--tw-gradient-via-position), var(--tw-gradient-to);
|
--tw-gradient-stops: var(--tw-gradient-from), #18181b var(--tw-gradient-via-position), var(--tw-gradient-to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.to-transparent{
|
||||||
|
--tw-gradient-to: transparent var(--tw-gradient-to-position);
|
||||||
|
}
|
||||||
|
|
||||||
.to-zinc-900{
|
.to-zinc-900{
|
||||||
--tw-gradient-to: #18181b var(--tw-gradient-to-position);
|
--tw-gradient-to: #18181b var(--tw-gradient-to-position);
|
||||||
}
|
}
|
||||||
@@ -1603,6 +1839,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
stroke: #a1a1aa;
|
stroke: #a1a1aa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-3{
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.p-4{
|
.p-4{
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
@@ -1611,6 +1851,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-6{
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.px-0{
|
.px-0{
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
@@ -1626,11 +1870,21 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-right: 0.25rem;
|
padding-right: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.px-1\.5{
|
||||||
|
padding-left: 0.375rem;
|
||||||
|
padding-right: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
.px-2{
|
.px-2{
|
||||||
padding-left: 0.5rem;
|
padding-left: 0.5rem;
|
||||||
padding-right: 0.5rem;
|
padding-right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.px-3{
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
padding-right: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.px-4{
|
.px-4{
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
padding-right: 1rem;
|
padding-right: 1rem;
|
||||||
@@ -1651,6 +1905,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-bottom: 0.125rem;
|
padding-bottom: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-1{
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.py-12{
|
.py-12{
|
||||||
padding-top: 3rem;
|
padding-top: 3rem;
|
||||||
padding-bottom: 3rem;
|
padding-bottom: 3rem;
|
||||||
@@ -1661,6 +1920,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-3{
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.py-4{
|
.py-4{
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
@@ -1671,6 +1935,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pb-10{
|
||||||
|
padding-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pb-12{
|
.pb-12{
|
||||||
padding-bottom: 3rem;
|
padding-bottom: 3rem;
|
||||||
}
|
}
|
||||||
@@ -1679,10 +1947,22 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pb-8{
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-10{
|
||||||
|
padding-left: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pl-4{
|
.pl-4{
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pr-2{
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pt-32{
|
.pt-32{
|
||||||
padding-top: 8rem;
|
padding-top: 8rem;
|
||||||
}
|
}
|
||||||
@@ -1711,6 +1991,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
font-family: Inter Tight, sans-serif;
|
font-family: Inter Tight, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-mono{
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.text-2xl{
|
.text-2xl{
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
line-height: 1.415;
|
line-height: 1.415;
|
||||||
@@ -1729,6 +2013,16 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
letter-spacing: -0.017em;
|
letter-spacing: -0.017em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-\[10px\]{
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-base{
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
letter-spacing: -0.017em;
|
||||||
|
}
|
||||||
|
|
||||||
.text-lg{
|
.text-lg{
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
@@ -1740,6 +2034,17 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
line-height: 1.5715;
|
line-height: 1.5715;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-xl{
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
letter-spacing: -0.017em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-xs{
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
.font-bold{
|
.font-bold{
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
@@ -1752,14 +2057,39 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uppercase{
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.not-italic{
|
.not-italic{
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabular-nums{
|
||||||
|
--tw-numeric-spacing: tabular-nums;
|
||||||
|
font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leading-relaxed{
|
||||||
|
line-height: 1.625;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leading-snug{
|
||||||
|
line-height: 1.375;
|
||||||
|
}
|
||||||
|
|
||||||
.tracking-tight{
|
.tracking-tight{
|
||||||
letter-spacing: -0.025em;
|
letter-spacing: -0.025em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tracking-wide{
|
||||||
|
letter-spacing: 0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tracking-wider{
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
.text-black{
|
.text-black{
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||||
@@ -1770,6 +2100,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
color: rgb(16 185 129 / var(--tw-text-opacity));
|
color: rgb(16 185 129 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-emerald-700{
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(4 120 87 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.text-gray-500{
|
.text-gray-500{
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||||
@@ -1814,6 +2149,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
color: rgb(228 228 231 / var(--tw-text-opacity));
|
color: rgb(228 228 231 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-zinc-300{
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(212 212 216 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.text-zinc-400{
|
.text-zinc-400{
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(161 161 170 / var(--tw-text-opacity));
|
color: rgb(161 161 170 / var(--tw-text-opacity));
|
||||||
@@ -1853,6 +2193,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opacity-75{
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
.shadow{
|
.shadow{
|
||||||
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||||
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
||||||
@@ -1882,6 +2226,17 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
--tw-shadow: var(--tw-shadow-colored);
|
--tw-shadow: var(--tw-shadow-colored);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ring-4{
|
||||||
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ring-zinc-50{
|
||||||
|
--tw-ring-opacity: 1;
|
||||||
|
--tw-ring-color: rgb(250 250 250 / var(--tw-ring-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.blur{
|
.blur{
|
||||||
--tw-blur: blur(8px);
|
--tw-blur: blur(8px);
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
@@ -1899,6 +2254,22 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
transition-duration: 150ms;
|
transition-duration: 150ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transition-colors{
|
||||||
|
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
||||||
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
transition-duration: 150ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-transform{
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
transition-duration: 150ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.\[background\:linear-gradient\(theme\(colors\.white\)\2c theme\(colors\.white\)\)_padding-box\2c linear-gradient\(120deg\2c theme\(colors\.zinc\.300\)\2c theme\(colors\.zinc\.100\)\2c theme\(colors\.zinc\.300\)\)_border-box\]{
|
||||||
|
background: linear-gradient(#fff,#fff) padding-box,linear-gradient(120deg,#d4d4d8,#f4f4f5,#d4d4d8) border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.\[background\:linear-gradient\(theme\(colors\.white\)\2c theme\(colors\.zinc\.50\)\)_padding-box\2c linear-gradient\(120deg\2c theme\(colors\.zinc\.300\)\2c theme\(colors\.zinc\.100\)\2c theme\(colors\.zinc\.300\)\)_border-box\]{
|
.\[background\:linear-gradient\(theme\(colors\.white\)\2c theme\(colors\.zinc\.50\)\)_padding-box\2c linear-gradient\(120deg\2c theme\(colors\.zinc\.300\)\2c theme\(colors\.zinc\.100\)\2c theme\(colors\.zinc\.300\)\)_border-box\]{
|
||||||
background: linear-gradient(#fff,#fafafa) padding-box,linear-gradient(120deg,#d4d4d8,#f4f4f5,#d4d4d8) border-box;
|
background: linear-gradient(#fff,#fafafa) padding-box,linear-gradient(120deg,#d4d4d8,#f4f4f5,#d4d4d8) border-box;
|
||||||
}
|
}
|
||||||
@@ -2007,6 +2378,21 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
top: 0px;
|
top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.after\:top-1\/2::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:hidden::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:h-8::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.after\:h-full::after{
|
.after\:h-full::after{
|
||||||
content: var(--tw-content);
|
content: var(--tw-content);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -2017,6 +2403,33 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
width: 24rem;
|
width: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.after\:w-px::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:-translate-y-1\/2::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
--tw-translate-y: -50%;
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:border-l::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:border-dashed::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.after\:border-zinc-300::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(212 212 216 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.after\:bg-gradient-to-l::after{
|
.after\:bg-gradient-to-l::after{
|
||||||
content: var(--tw-content);
|
content: var(--tw-content);
|
||||||
background-image: linear-gradient(to left, var(--tw-gradient-stops));
|
background-image: linear-gradient(to left, var(--tw-gradient-stops));
|
||||||
@@ -2029,6 +2442,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.last\:after\:hidden:last-child::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.hover\:bg-zinc-800:hover{
|
.hover\:bg-zinc-800:hover{
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(39 39 42 / var(--tw-bg-opacity));
|
background-color: rgb(39 39 42 / var(--tw-bg-opacity));
|
||||||
@@ -2122,6 +2540,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
--tw-ring-offset-width: 2px;
|
--tw-ring-offset-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group:hover .group-hover\:text-zinc-800{
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(39 39 42 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
@supports (overflow:clip){
|
@supports (overflow:clip){
|
||||||
.supports-\[overflow\:clip\]\:overflow-clip{
|
.supports-\[overflow\:clip\]\:overflow-clip{
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
@@ -2142,6 +2565,18 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 640px){
|
@media (min-width: 640px){
|
||||||
|
.sm\:-left-\[37px\]{
|
||||||
|
left: -37px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm\:-left-\[39px\]{
|
||||||
|
left: -39px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm\:left-4{
|
||||||
|
left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:col-span-6{
|
.sm\:col-span-6{
|
||||||
grid-column: span 6 / span 6;
|
grid-column: span 6 / span 6;
|
||||||
}
|
}
|
||||||
@@ -2204,6 +2639,16 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-right: 1.5rem;
|
padding-right: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:pl-12{
|
||||||
|
padding-left: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm\:text-2xl{
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 1.415;
|
||||||
|
letter-spacing: -0.017em;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:text-\[0\.9375rem\]{
|
.sm\:text-\[0\.9375rem\]{
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
}
|
}
|
||||||
@@ -2222,6 +2667,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
grid-column: span 6 / span 6;
|
grid-column: span 6 / span 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:-mx-5{
|
||||||
|
margin-left: -1.25rem;
|
||||||
|
margin-right: -1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:mb-0{
|
.md\:mb-0{
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
@@ -2230,6 +2680,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
max-width: 56rem;
|
max-width: 56rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:max-w-none{
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:grid-cols-2{
|
.md\:grid-cols-2{
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
@@ -2238,11 +2692,33 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:grid-cols-4{
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.md\:grid-cols-\[15\%_15\%_1fr\]{
|
||||||
|
grid-template-columns: 15% 15% 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md\:gap-0{
|
||||||
|
gap: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md\:px-5{
|
||||||
|
padding-left: 1.25rem;
|
||||||
|
padding-right: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:py-12{
|
.md\:py-12{
|
||||||
padding-top: 3rem;
|
padding-top: 3rem;
|
||||||
padding-bottom: 3rem;
|
padding-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:py-16{
|
||||||
|
padding-top: 4rem;
|
||||||
|
padding-bottom: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:py-20{
|
.md\:py-20{
|
||||||
padding-top: 5rem;
|
padding-top: 5rem;
|
||||||
padding-bottom: 5rem;
|
padding-bottom: 5rem;
|
||||||
@@ -2260,6 +2736,12 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
padding-top: 10rem;
|
padding-top: 10rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:text-3xl{
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 1.3125;
|
||||||
|
letter-spacing: -0.017em;
|
||||||
|
}
|
||||||
|
|
||||||
.md\:text-4xl{
|
.md\:text-4xl{
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
@@ -2271,6 +2753,11 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
letter-spacing: -0.017em;
|
letter-spacing: -0.017em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:after\:block::after{
|
||||||
|
content: var(--tw-content);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px){
|
@media (min-width: 1024px){
|
||||||
@@ -2282,6 +2769,10 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
grid-column: span 8 / span 8;
|
grid-column: span 8 / span 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:mb-0{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:mt-24{
|
.lg\:mt-24{
|
||||||
margin-top: 6rem;
|
margin-top: 6rem;
|
||||||
}
|
}
|
||||||
@@ -2306,10 +2797,22 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
max-width: none;
|
max-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:flex-1{
|
||||||
|
flex: 1 1 0%;
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:grid-cols-3{
|
.lg\:grid-cols-3{
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:items-start{
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg\:gap-12{
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:gap-16{
|
.lg\:gap-16{
|
||||||
gap: 4rem;
|
gap: 4rem;
|
||||||
}
|
}
|
||||||
@@ -2338,3 +2841,8 @@ input[type="search"]::-webkit-search-results-decoration {
|
|||||||
margin-left: calc(6rem * calc(1 - var(--tw-space-x-reverse)));
|
margin-left: calc(6rem * calc(1 - var(--tw-space-x-reverse)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.\[\&\[open\]\>summary\>svg\]\:rotate-180[open]>summary>svg{
|
||||||
|
--tw-rotate: 180deg;
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user