mirror of
https://github.com/openziti/zrok.git
synced 2024-12-22 14:50:55 +01:00
Merge branch 'v0.3.0' into alternate-token-method
This commit is contained in:
commit
602c54cc43
@ -1,12 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/privateFrontend"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -43,36 +46,38 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
endpointUrl, err := url.Parse("http://" + cmd.bindAddress)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("invalid endpoint address", err)
|
||||
tui.Error("invalid endpoint address", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
}
|
||||
panic(err)
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := share.NewAccessParams()
|
||||
req.Body = &rest_model_zrok.AccessRequest{
|
||||
ShrToken: shrToken,
|
||||
EnvZID: env.ZId,
|
||||
EnvZID: zrd.Env.ZId,
|
||||
}
|
||||
accessResp, err := zrok.Share.Access(req, auth)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to access", err)
|
||||
tui.Error("unable to access", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -81,30 +86,54 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
cfg := privateFrontend.DefaultConfig("backend")
|
||||
cfg.ShrToken = shrToken
|
||||
cfg.Address = cmd.bindAddress
|
||||
cfg.RequestsChan = make(chan *endpoints.Request, 1024)
|
||||
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
cmd.destroy(accessResp.Payload.FrontendToken, env.ZId, shrToken, zrok, auth)
|
||||
cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth)
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
frontend, err := privateFrontend.NewHTTP(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to create private frontend", err)
|
||||
tui.Error("unable to create private frontend", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logrus.Infof("access your share at: %v", endpointUrl.String())
|
||||
|
||||
if err := frontend.Run(); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to run frontend", err)
|
||||
go func() {
|
||||
if err := frontend.Run(); err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to run frontend", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
mdl := newAccessModel(shrToken, endpointUrl.String())
|
||||
logrus.SetOutput(mdl)
|
||||
prg := tea.NewProgram(mdl, tea.WithAltScreen())
|
||||
mdl.prg = prg
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case req := <-cfg.RequestsChan:
|
||||
if req != nil {
|
||||
prg.Send(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := prg.Run(); err != nil {
|
||||
tui.Error("An error occurred", err)
|
||||
}
|
||||
|
||||
close(cfg.RequestsChan)
|
||||
cmd.destroy(accessResp.Payload.FrontendToken, zrd.Env.ZId, shrToken, zrok, auth)
|
||||
}
|
||||
|
||||
func (cmd *accessPrivateCommand) destroy(frotendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/michaelquigley/cf"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/publicFrontend"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -33,7 +34,7 @@ func (self *accessPublicCommand) run(_ *cobra.Command, args []string) {
|
||||
if len(args) == 1 {
|
||||
if err := cfg.Load(args[0]); err != nil {
|
||||
if !panicInstead {
|
||||
showError(fmt.Sprintf("unable to load configuration '%v'", args[0]), err)
|
||||
tui.Error(fmt.Sprintf("unable to load configuration '%v'", args[0]), err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -42,13 +43,13 @@ func (self *accessPublicCommand) run(_ *cobra.Command, args []string) {
|
||||
frontend, err := publicFrontend.NewHTTP(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to create http frontend", err)
|
||||
tui.Error("unable to create http frontend", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
if err := frontend.Run(); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to run http frontend", err)
|
||||
tui.Error("unable to run http frontend", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
202
cmd/zrok/accessTui.go
Normal file
202
cmd/zrok/accessTui.go
Normal file
@ -0,0 +1,202 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/muesli/reflow/wordwrap"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const accessTuiBacklog = 256
|
||||
|
||||
type accessModel struct {
|
||||
shrToken string
|
||||
localEndpoint string
|
||||
requests []*endpoints.Request
|
||||
log []string
|
||||
showLog bool
|
||||
width int
|
||||
height int
|
||||
prg *tea.Program
|
||||
}
|
||||
|
||||
type accessLogLine string
|
||||
|
||||
func newAccessModel(shrToken, localEndpoint string) *accessModel {
|
||||
return &accessModel{
|
||||
shrToken: shrToken,
|
||||
localEndpoint: localEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *accessModel) Init() tea.Cmd { return nil }
|
||||
|
||||
func (m *accessModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case *endpoints.Request:
|
||||
m.requests = append(m.requests, msg)
|
||||
if len(m.requests) > accessTuiBacklog {
|
||||
m.requests = m.requests[1:]
|
||||
}
|
||||
|
||||
case accessLogLine:
|
||||
m.showLog = true
|
||||
m.adjustPaneHeights()
|
||||
|
||||
m.log = append(m.log, string(msg))
|
||||
if len(m.log) > accessTuiBacklog {
|
||||
m.log = m.log[1:]
|
||||
}
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
accessHeaderStyle.Width(m.width - 2)
|
||||
accessRequestsStyle.Width(m.width - 2)
|
||||
accessLogStyle.Width(m.width - 2)
|
||||
|
||||
m.height = msg.Height
|
||||
m.adjustPaneHeights()
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
return m, tea.Quit
|
||||
case "ctrl+l":
|
||||
return m, tea.ClearScreen
|
||||
case "l":
|
||||
m.showLog = !m.showLog
|
||||
m.adjustPaneHeights()
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *accessModel) View() string {
|
||||
var panes string
|
||||
if m.showLog {
|
||||
panes = lipgloss.JoinVertical(lipgloss.Left,
|
||||
accessRequestsStyle.Render(m.renderRequests()),
|
||||
accessLogStyle.Render(m.renderLog()),
|
||||
)
|
||||
} else {
|
||||
panes = accessRequestsStyle.Render(m.renderRequests())
|
||||
}
|
||||
|
||||
return lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
accessHeaderStyle.Render(fmt.Sprintf("%v -> %v", m.localEndpoint, m.shrToken)),
|
||||
panes,
|
||||
)
|
||||
}
|
||||
|
||||
func (m *accessModel) adjustPaneHeights() {
|
||||
if !m.showLog {
|
||||
accessRequestsStyle.Height(m.height - 5)
|
||||
} else {
|
||||
splitHeight := m.height - 5
|
||||
accessRequestsStyle.Height(splitHeight/2 - 1)
|
||||
accessLogStyle.Height(splitHeight/2 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *accessModel) renderRequests() string {
|
||||
var requestLines []string
|
||||
for _, req := range m.requests {
|
||||
reqLine := fmt.Sprintf("%v %v -> %v %v",
|
||||
timeStyle.Render(req.Stamp.Format(time.RFC850)),
|
||||
addressStyle.Render(req.RemoteAddr),
|
||||
m.renderMethod(req.Method),
|
||||
req.Path,
|
||||
)
|
||||
reqLineWrapped := wordwrap.String(reqLine, m.width-2)
|
||||
splitWrapped := strings.Split(reqLineWrapped, "\n")
|
||||
for _, splitLine := range splitWrapped {
|
||||
splitLine := strings.ReplaceAll(splitLine, "\n", "")
|
||||
if splitLine != "" {
|
||||
requestLines = append(requestLines, splitLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
maxRows := accessRequestsStyle.GetHeight()
|
||||
startRow := 0
|
||||
if len(requestLines) > maxRows {
|
||||
startRow = len(requestLines) - maxRows
|
||||
}
|
||||
out := ""
|
||||
for i := startRow; i < len(requestLines); i++ {
|
||||
outLine := requestLines[i]
|
||||
if i < len(requestLines)-1 {
|
||||
outLine += "\n"
|
||||
}
|
||||
out += outLine
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *accessModel) renderMethod(method string) string {
|
||||
switch strings.ToLower(method) {
|
||||
case "get":
|
||||
return getStyle.Render(method)
|
||||
case "post":
|
||||
return postStyle.Render(method)
|
||||
default:
|
||||
return otherMethodStyle.Render(method)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *accessModel) renderLog() string {
|
||||
var splitLines []string
|
||||
for _, line := range m.log {
|
||||
wrapped := wordwrap.String(line, m.width-2)
|
||||
wrappedLines := strings.Split(wrapped, "\n")
|
||||
for _, wrappedLine := range wrappedLines {
|
||||
splitLine := strings.ReplaceAll(wrappedLine, "\n", "")
|
||||
if splitLine != "" {
|
||||
splitLines = append(splitLines, splitLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
maxRows := accessLogStyle.GetHeight()
|
||||
startRow := 0
|
||||
if len(splitLines) > maxRows {
|
||||
startRow = len(splitLines) - maxRows
|
||||
}
|
||||
out := ""
|
||||
for i := startRow; i < len(splitLines); i++ {
|
||||
outLine := splitLines[i]
|
||||
if i < len(splitLines)-1 {
|
||||
outLine += "\n"
|
||||
}
|
||||
out += outLine
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *accessModel) Write(p []byte) (n int, err error) {
|
||||
in := string(p)
|
||||
lines := strings.Split(in, "\n")
|
||||
for _, line := range lines {
|
||||
cleanLine := strings.ReplaceAll(line, "\n", "")
|
||||
if cleanLine != "" {
|
||||
m.prg.Send(accessLogLine(cleanLine))
|
||||
}
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
var accessHeaderStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63")).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
var accessRequestsStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63"))
|
||||
|
||||
var accessLogStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63"))
|
@ -33,7 +33,12 @@ func (cmd *adminCreateFrontendCommand) run(_ *cobra.Command, args []string) {
|
||||
publicName := args[1]
|
||||
urlTemplate := args[2]
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -41,7 +41,12 @@ func (cmd *adminCreateIdentity) run(_ *cobra.Command, args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -31,7 +31,12 @@ func newAdminDeleteFrontendCommand() *adminDeleteFrontendCommand {
|
||||
func (cmd *adminDeleteFrontendCommand) run(_ *cobra.Command, args []string) {
|
||||
feToken := args[0]
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -30,8 +30,13 @@ func newAdminListFrontendsCommand() *adminListFrontendsCommand {
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, args []string) {
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, _ []string) {
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -38,7 +38,12 @@ func (cmd *adminUpdateFrontendCommand) run(_ *cobra.Command, args []string) {
|
||||
panic("must specify at least one of public name or url template")
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
46
cmd/zrok/configGet.go
Normal file
46
cmd/zrok/configGet.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(newConfigGetCommand().cmd)
|
||||
}
|
||||
|
||||
type configGetCommand struct {
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newConfigGetCommand() *configGetCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "get <configName>",
|
||||
Short: "Get a value from the environment config",
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &configGetCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *configGetCommand) run(_ *cobra.Command, args []string) {
|
||||
configName := args[0]
|
||||
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch configName {
|
||||
case "apiEndpoint":
|
||||
if zrd.Cfg != nil && zrd.Cfg.ApiEndpoint != "" {
|
||||
fmt.Printf("apiEndpoint = %v\n", zrd.Cfg.ApiEndpoint)
|
||||
} else {
|
||||
fmt.Println("apiEndpoint = <unset>")
|
||||
}
|
||||
default:
|
||||
fmt.Printf("unknown config name '%v'\n", configName)
|
||||
}
|
||||
}
|
58
cmd/zrok/configSet.go
Normal file
58
cmd/zrok/configSet.go
Normal file
@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(newConfigSetCommand().cmd)
|
||||
}
|
||||
|
||||
type configSetCommand struct {
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newConfigSetCommand() *configSetCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set <configName> <value>",
|
||||
Short: "Set a value into the environment config",
|
||||
Args: cobra.ExactArgs(2),
|
||||
}
|
||||
command := &configSetCommand{cmd: cmd}
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *configSetCommand) run(_ *cobra.Command, args []string) {
|
||||
configName := args[0]
|
||||
value := args[1]
|
||||
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
modified := false
|
||||
switch configName {
|
||||
case "apiEndpoint":
|
||||
if zrd.Cfg == nil {
|
||||
zrd.Cfg = &zrokdir.Config{}
|
||||
}
|
||||
zrd.Cfg.ApiEndpoint = value
|
||||
modified = true
|
||||
|
||||
default:
|
||||
fmt.Printf("unknown config name '%v'\n", configName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if modified {
|
||||
if err := zrd.Save(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("zrok configuration updated")
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import (
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/environment"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -29,25 +30,30 @@ func newDisableCommand() *disableCommand {
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *disableCommand) run(_ *cobra.Command, args []string) {
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
func (cmd *disableCommand) run(_ *cobra.Command, _ []string) {
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("could not load environment; not active?", err)
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Error("no environment found; nothing to disable!", nil)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("could not create zrok client", err)
|
||||
tui.Error("could not create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := environment.NewDisableParams()
|
||||
req.Body = &rest_model_zrok.DisableRequest{
|
||||
Identity: env.ZId,
|
||||
Identity: zrd.Env.ZId,
|
||||
}
|
||||
_, err = zrok.Environment.Disable(req, auth)
|
||||
if err != nil {
|
||||
@ -55,14 +61,14 @@ func (cmd *disableCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
if err := zrokdir.DeleteEnvironment(); err != nil {
|
||||
if !panicInstead {
|
||||
showError("error removing zrok environment", err)
|
||||
tui.Error("error removing zrok environment", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
if err := zrokdir.DeleteZitiIdentity("backend"); err != nil {
|
||||
if !panicInstead {
|
||||
showError("error removing zrok backend identity", err)
|
||||
tui.Error("error removing zrok backend identity", err)
|
||||
}
|
||||
}
|
||||
fmt.Printf("zrok environment '%v' disabled for '%v'\n", env.ZId, env.Token)
|
||||
fmt.Println("zrok environment disabled...")
|
||||
}
|
||||
|
@ -2,12 +2,16 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/environment"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
user2 "os/user"
|
||||
)
|
||||
|
||||
@ -33,11 +37,10 @@ func newEnableCommand() *enableCommand {
|
||||
}
|
||||
|
||||
func (cmd *enableCommand) run(_ *cobra.Command, args []string) {
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
if err == nil {
|
||||
showError(fmt.Sprintf("you already have an environment '%v' for '%v'", env.ZId, env.Token), nil)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
token := args[0]
|
||||
|
||||
hostName, hostDetail, err := getHost()
|
||||
@ -52,8 +55,7 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) {
|
||||
if cmd.description == "<user>@<hostname>" {
|
||||
cmd.description = fmt.Sprintf("%v@%v", user.Username, hostName)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -63,27 +65,49 @@ func (cmd *enableCommand) run(_ *cobra.Command, args []string) {
|
||||
Description: cmd.description,
|
||||
Host: hostDetail,
|
||||
}
|
||||
|
||||
var prg *tea.Program
|
||||
var mdl enableTuiModel
|
||||
var done = make(chan struct{})
|
||||
go func() {
|
||||
mdl = newEnableTuiModel()
|
||||
mdl.msg = "contacting the zrok service..."
|
||||
prg = tea.NewProgram(mdl)
|
||||
if _, err := prg.Run(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
close(done)
|
||||
if mdl.quitting {
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
resp, err := zrok.Environment.Enable(req, auth)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("the zrok service returned an error", err)
|
||||
}
|
||||
panic(err)
|
||||
prg.Send(fmt.Sprintf("the zrok service returned an error: %v", err))
|
||||
prg.Quit()
|
||||
<-done
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := zrokdir.SaveEnvironment(&zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint}); err != nil {
|
||||
if !panicInstead {
|
||||
showError("there was an error saving the new environment", err)
|
||||
}
|
||||
panic(err)
|
||||
prg.Send("writing the environment details...")
|
||||
apiEndpoint, _ := zrd.ApiEndpoint()
|
||||
zrd.Env = &zrokdir.Environment{Token: token, ZId: resp.Payload.Identity, ApiEndpoint: apiEndpoint}
|
||||
if err := zrd.Save(); err != nil {
|
||||
prg.Send(fmt.Sprintf("there was an error saving the new environment: %v", err))
|
||||
prg.Quit()
|
||||
<-done
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := zrokdir.SaveZitiIdentity("backend", resp.Payload.Cfg); err != nil {
|
||||
if !panicInstead {
|
||||
showError("there was an error writing the environment file", err)
|
||||
}
|
||||
panic(err)
|
||||
prg.Send(fmt.Sprintf("there was an error writing the environment: %v", err))
|
||||
prg.Quit()
|
||||
<-done
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("zrok environment '%v' enabled for '%v'\n", resp.Payload.Identity, token)
|
||||
prg.Send(fmt.Sprintf("the zrok environment was successfully enabled..."))
|
||||
prg.Quit()
|
||||
<-done
|
||||
}
|
||||
|
||||
func getHost() (string, string, error) {
|
||||
@ -95,3 +119,52 @@ func getHost() (string, string, error) {
|
||||
info.Hostname, info.OS, info.Platform, info.PlatformFamily, info.PlatformVersion, info.KernelVersion, info.KernelArch)
|
||||
return info.Hostname, thisHost, nil
|
||||
}
|
||||
|
||||
type enableTuiModel struct {
|
||||
spinner spinner.Model
|
||||
msg string
|
||||
quitting bool
|
||||
}
|
||||
|
||||
func newEnableTuiModel() enableTuiModel {
|
||||
s := spinner.New()
|
||||
s.Spinner = spinner.Dot
|
||||
s.Style = tui.WarningStyle
|
||||
return enableTuiModel{spinner: s}
|
||||
}
|
||||
|
||||
func (m enableTuiModel) Init() tea.Cmd { return m.spinner.Tick }
|
||||
|
||||
func (m enableTuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case string:
|
||||
m.msg = msg
|
||||
return m, nil
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "q", "esc", "ctrl+c":
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
|
||||
default:
|
||||
return m, nil
|
||||
}
|
||||
|
||||
case struct{}:
|
||||
return m, tea.Quit
|
||||
|
||||
default:
|
||||
var cmd tea.Cmd
|
||||
m.spinner, cmd = m.spinner.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
}
|
||||
|
||||
func (m enableTuiModel) View() string {
|
||||
str := fmt.Sprintf("%s %s\n", m.spinner.View(), m.msg)
|
||||
if m.quitting {
|
||||
return str
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
@ -2,12 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/account"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/util"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/openziti/foundation/v2/term"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -18,6 +23,7 @@ func init() {
|
||||
type inviteCommand struct {
|
||||
cmd *cobra.Command
|
||||
token string
|
||||
tui inviteTui
|
||||
}
|
||||
|
||||
func newInviteCommand() *inviteCommand {
|
||||
@ -26,8 +32,10 @@ func newInviteCommand() *inviteCommand {
|
||||
Short: "Invite a new user to zrok",
|
||||
Args: cobra.ExactArgs(0),
|
||||
}
|
||||
|
||||
command := &inviteCommand{cmd: cmd}
|
||||
command := &inviteCommand{
|
||||
cmd: cmd,
|
||||
tui: newInviteTui(),
|
||||
}
|
||||
cmd.Run = command.run
|
||||
|
||||
cmd.Flags().StringVar(&command.token, "token", "", "Invite token required when zrok running in token store mode")
|
||||
@ -36,40 +44,180 @@ func newInviteCommand() *inviteCommand {
|
||||
}
|
||||
|
||||
func (cmd *inviteCommand) run(_ *cobra.Command, _ []string) {
|
||||
email, err := term.Prompt("New Email: ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !util.IsValidEmail(email) {
|
||||
showError(fmt.Sprintf("'%v' is not a valid email address", email), nil)
|
||||
}
|
||||
confirm, err := term.Prompt("Confirm Email: ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if confirm != email {
|
||||
showError("entered emails do not match... aborting!", nil)
|
||||
if _, err := tea.NewProgram(&cmd.tui).Run(); err != nil {
|
||||
tui.Error("unable to run interface", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if cmd.tui.done {
|
||||
email := cmd.tui.inputs[0].Value()
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(apiEndpoint)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("error creating zrok api client", err)
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
tui.Error("error loading zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
req := account.NewInviteParams()
|
||||
req.Body = &rest_model_zrok.InviteRequest{
|
||||
Email: email,
|
||||
Token: cmd.token,
|
||||
}
|
||||
_, err = zrok.Account.Invite(req)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("error creating invitation", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("invitation sent to '%v'!\n", email)
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error creating zrok api client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
req := account.NewInviteParams()
|
||||
req.Body = &rest_model_zrok.InviteRequest{
|
||||
Email: email,
|
||||
Token: cmd.token,
|
||||
}
|
||||
_, err = zrok.Account.Invite(req)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error creating invitation", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("invitation sent to '%v'!\n", email)
|
||||
}
|
||||
}
|
||||
|
||||
type inviteTui struct {
|
||||
focusIndex int
|
||||
msg string
|
||||
inputs []textinput.Model
|
||||
cursorMode textinput.CursorMode
|
||||
done bool
|
||||
|
||||
msgOk string
|
||||
msgMismatch string
|
||||
focusedStyle lipgloss.Style
|
||||
blurredStyle lipgloss.Style
|
||||
errorStyle lipgloss.Style
|
||||
cursorStyle lipgloss.Style
|
||||
noStyle lipgloss.Style
|
||||
helpStyle lipgloss.Style
|
||||
focusedButton string
|
||||
blurredButton string
|
||||
}
|
||||
|
||||
func newInviteTui() inviteTui {
|
||||
m := inviteTui{
|
||||
inputs: make([]textinput.Model, 2),
|
||||
}
|
||||
m.focusedStyle = tui.WarningStyle
|
||||
m.blurredStyle = tui.CodeStyle
|
||||
m.errorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00"))
|
||||
m.cursorStyle = m.focusedStyle.Copy()
|
||||
m.noStyle = lipgloss.NewStyle()
|
||||
m.helpStyle = m.blurredStyle.Copy()
|
||||
m.focusedButton = m.focusedStyle.Copy().Render("[ Submit ]")
|
||||
m.blurredButton = fmt.Sprintf("[ %v ]", m.blurredStyle.Render("Submit"))
|
||||
m.msgOk = m.noStyle.Render("enter and confirm your email address...")
|
||||
m.msg = m.msgOk
|
||||
m.msgMismatch = m.errorStyle.Render("email is invalid or does not match confirmation...")
|
||||
|
||||
var t textinput.Model
|
||||
for i := range m.inputs {
|
||||
t = textinput.New()
|
||||
t.CursorStyle = m.cursorStyle
|
||||
t.CharLimit = 96
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
t.Placeholder = "Email Address"
|
||||
t.Focus()
|
||||
t.PromptStyle = m.focusedStyle
|
||||
t.TextStyle = m.focusedStyle
|
||||
case 1:
|
||||
t.Placeholder = "Confirm Email"
|
||||
}
|
||||
|
||||
m.inputs[i] = t
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m inviteTui) Init() tea.Cmd { return textinput.Blink }
|
||||
|
||||
func (m *inviteTui) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "esc":
|
||||
return m, tea.Quit
|
||||
|
||||
case "tab", "shift+tab", "enter", "up", "down":
|
||||
s := msg.String()
|
||||
|
||||
if s == "enter" && m.focusIndex == len(m.inputs) {
|
||||
if util.IsValidEmail(m.inputs[0].Value()) && m.inputs[0].Value() == m.inputs[1].Value() {
|
||||
m.done = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
m.msg = m.msgMismatch
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if s == "up" || s == "shift+tab" {
|
||||
m.msg = m.msgOk
|
||||
m.focusIndex--
|
||||
} else {
|
||||
m.msg = m.msgOk
|
||||
m.focusIndex++
|
||||
}
|
||||
|
||||
if m.focusIndex > len(m.inputs) {
|
||||
m.focusIndex = 0
|
||||
} else if m.focusIndex < 0 {
|
||||
m.focusIndex = len(m.inputs)
|
||||
}
|
||||
|
||||
cmds := make([]tea.Cmd, len(m.inputs))
|
||||
for i := 0; i <= len(m.inputs)-1; i++ {
|
||||
if i == m.focusIndex {
|
||||
cmds[i] = m.inputs[i].Focus()
|
||||
m.inputs[i].PromptStyle = m.focusedStyle
|
||||
m.inputs[i].TextStyle = m.focusedStyle
|
||||
continue
|
||||
}
|
||||
m.inputs[i].Blur()
|
||||
m.inputs[i].PromptStyle = m.noStyle
|
||||
m.inputs[i].TextStyle = m.noStyle
|
||||
}
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := m.updateInputs(msg)
|
||||
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m *inviteTui) updateInputs(msg tea.Msg) tea.Cmd {
|
||||
cmds := make([]tea.Cmd, len(m.inputs))
|
||||
for i := range m.inputs {
|
||||
m.inputs[i], cmds[i] = m.inputs[i].Update(msg)
|
||||
}
|
||||
return tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
func (m inviteTui) View() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("\n%v\n\n", m.msg))
|
||||
|
||||
for i := range m.inputs {
|
||||
b.WriteString(m.inputs[i].View())
|
||||
if i < len(m.inputs)-1 {
|
||||
b.WriteRune('\n')
|
||||
}
|
||||
}
|
||||
|
||||
button := &m.blurredButton
|
||||
if m.focusIndex == len(m.inputs) {
|
||||
button = &m.focusedButton
|
||||
}
|
||||
_, _ = fmt.Fprintf(&b, "\n\n%s\n\n", *button)
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/util"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/openziti/sdk-golang/ziti"
|
||||
@ -170,16 +171,21 @@ func (l *looper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
func (l *looper) startup() {
|
||||
logrus.Infof("starting #%d", l.id)
|
||||
|
||||
var err error
|
||||
l.env, err = zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
l.env = zrd.Env
|
||||
|
||||
l.zif, err = zrokdir.ZitiIdentityFile("backend")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
l.zrok, err = zrokdir.ZrokClient(l.env.ApiEndpoint)
|
||||
l.zrok, err = zrd.Client()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
@ -14,13 +13,13 @@ func init() {
|
||||
pfxlog.GlobalInit(logrus.InfoLevel, pfxlog.DefaultOptions().SetTrimPrefix("github.com/openziti-test-kitchen/"))
|
||||
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose logging")
|
||||
rootCmd.PersistentFlags().BoolVarP(&panicInstead, "panic", "p", false, "Panic instead of showing pretty errors")
|
||||
zrokdir.AddZrokApiEndpointFlag(&apiEndpoint, rootCmd.PersistentFlags())
|
||||
rootCmd.AddCommand(accessCmd)
|
||||
adminCmd.AddCommand(adminCreateCmd)
|
||||
adminCmd.AddCommand(adminDeleteCmd)
|
||||
adminCmd.AddCommand(adminListCmd)
|
||||
adminCmd.AddCommand(adminUpdateCmd)
|
||||
rootCmd.AddCommand(adminCmd)
|
||||
rootCmd.AddCommand(configCmd)
|
||||
rootCmd.AddCommand(shareCmd)
|
||||
rootCmd.AddCommand(testCmd)
|
||||
}
|
||||
@ -36,7 +35,6 @@ var rootCmd = &cobra.Command{
|
||||
}
|
||||
var verbose bool
|
||||
var panicInstead bool
|
||||
var apiEndpoint string
|
||||
|
||||
var accessCmd = &cobra.Command{
|
||||
Use: "access",
|
||||
@ -68,6 +66,11 @@ var adminUpdateCmd = &cobra.Command{
|
||||
Short: "Update global resources",
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Configure your zrok environment",
|
||||
}
|
||||
|
||||
var shareCmd = &cobra.Command{
|
||||
Use: "share",
|
||||
Short: "Create backend access for shares",
|
||||
|
@ -1,10 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
ui "github.com/gizak/termui/v3"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@ -31,33 +31,36 @@ func newReleaseCommand() *releaseCommand {
|
||||
|
||||
func (cmd *releaseCommand) run(_ *cobra.Command, args []string) {
|
||||
shrToken := args[0]
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := share.NewUnshareParams()
|
||||
req.Body = &rest_model_zrok.UnshareRequest{
|
||||
EnvZID: env.ZId,
|
||||
EnvZID: zrd.Env.ZId,
|
||||
ShrToken: shrToken,
|
||||
Reserved: true,
|
||||
}
|
||||
if _, err := zrok.Share.Unshare(req, auth); err != nil {
|
||||
if !panicInstead {
|
||||
showError("error releasing share", err)
|
||||
tui.Error("error releasing share", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
ui "github.com/gizak/termui/v3"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/model"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -21,18 +21,20 @@ func init() {
|
||||
type reserveCommand struct {
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newReserveCommand() *reserveCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "reserve <public|private> <targetEndpoint>",
|
||||
Use: "reserve <public|private> <target>",
|
||||
Short: "Create a reserved share",
|
||||
Args: cobra.ExactArgs(2),
|
||||
}
|
||||
command := &reserveCommand{cmd: cmd}
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
||||
cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
@ -40,44 +42,54 @@ func newReserveCommand() *reserveCommand {
|
||||
func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
shareMode := args[0]
|
||||
if shareMode != "public" && shareMode != "private" {
|
||||
showError("invalid sharing mode; expecting 'public' or 'private'", nil)
|
||||
tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil)
|
||||
}
|
||||
|
||||
targetEndpoint, err := url.Parse(args[1])
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("invalid target endpoint URL", err)
|
||||
var target string
|
||||
switch cmd.backendMode {
|
||||
case "proxy":
|
||||
targetEndpoint, err := url.Parse(args[1])
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("invalid target endpoint URL", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
if targetEndpoint.Scheme == "" {
|
||||
targetEndpoint.Scheme = "https"
|
||||
if targetEndpoint.Scheme == "" {
|
||||
targetEndpoint.Scheme = "https"
|
||||
}
|
||||
target = targetEndpoint.String()
|
||||
|
||||
case "web":
|
||||
target = args[1]
|
||||
}
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
tui.Error("error loading zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := share.NewShareParams()
|
||||
req.Body = &rest_model_zrok.ShareRequest{
|
||||
EnvZID: env.ZId,
|
||||
EnvZID: zrd.Env.ZId,
|
||||
ShareMode: shareMode,
|
||||
BackendMode: "proxy",
|
||||
BackendProxyEndpoint: targetEndpoint.String(),
|
||||
BackendMode: cmd.backendMode,
|
||||
BackendProxyEndpoint: target,
|
||||
AuthScheme: string(model.None),
|
||||
Reserved: true,
|
||||
}
|
||||
@ -100,7 +112,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
||||
resp, err := zrok.Share.Share(req, auth)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to create tunnel", err)
|
||||
tui.Error("unable to create tunnel", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
@ -2,15 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ui "github.com/gizak/termui/v3"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/webBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/model"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -20,7 +22,6 @@ import (
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -30,18 +31,20 @@ func init() {
|
||||
type sharePrivateCommand struct {
|
||||
basicAuth []string
|
||||
backendMode string
|
||||
headless bool
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
func newSharePrivateCommand() *sharePrivateCommand {
|
||||
cmd := &cobra.Command{
|
||||
Use: "private <targetEndpoint>",
|
||||
Short: "Share a target endpoint privately",
|
||||
Use: "private <target>",
|
||||
Short: "Share a target resource privately",
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &sharePrivateCommand{cmd: cmd}
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
|
||||
cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}")
|
||||
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
@ -54,7 +57,7 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
targetEndpoint, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("invalid target endpoint URL", err)
|
||||
tui.Error("invalid target endpoint URL", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -67,38 +70,43 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
target = args[0]
|
||||
|
||||
default:
|
||||
showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
|
||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
|
||||
}
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zif, err := zrokdir.ZitiIdentityFile("backend")
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to load ziti identity configuration", err)
|
||||
tui.Error("unable to load ziti identity configuration", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := share.NewShareParams()
|
||||
req.Body = &rest_model_zrok.ShareRequest{
|
||||
EnvZID: env.ZId,
|
||||
EnvZID: zrd.Env.ZId,
|
||||
ShareMode: "private",
|
||||
BackendMode: "proxy",
|
||||
BackendMode: cmd.backendMode,
|
||||
BackendProxyEndpoint: target,
|
||||
AuthScheme: string(model.None),
|
||||
}
|
||||
@ -116,9 +124,8 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
resp, err := zrok.Share.Share(req, auth)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create share", err)
|
||||
tui.Error("unable to create share", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -127,22 +134,23 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
requestsChan := make(chan *endpoints.Request, 1024)
|
||||
switch cmd.backendMode {
|
||||
case "proxy":
|
||||
cfg := &proxyBackend.Config{
|
||||
IdentityPath: zif,
|
||||
EndpointAddress: target,
|
||||
ShrToken: resp.Payload.ShrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
_, err = cmd.proxyBackendMode(cfg)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create proxy backend handler", err)
|
||||
tui.Error("unable to create proxy backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -152,29 +160,55 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
|
||||
IdentityPath: zif,
|
||||
WebRoot: target,
|
||||
ShrToken: resp.Payload.ShrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
_, err = cmd.webBackendMode(cfg)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create web backend handler", err)
|
||||
tui.Error("unable to create web backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
default:
|
||||
ui.Close()
|
||||
showError("invalid backend mode", nil)
|
||||
tui.Error("invalid backend mode", nil)
|
||||
}
|
||||
|
||||
logrus.Infof("share with others; they will use this command for access: 'zrok access private %v'", resp.Payload.ShrToken)
|
||||
if cmd.headless {
|
||||
logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", resp.Payload.ShrToken)
|
||||
for {
|
||||
select {
|
||||
case req := <-requestsChan:
|
||||
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
time.Sleep(30 * time.Second)
|
||||
} else {
|
||||
shareDescription := fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", resp.Payload.ShrToken)))
|
||||
mdl := newShareModel(resp.Payload.ShrToken, []string{shareDescription}, "private", cmd.backendMode)
|
||||
logrus.SetOutput(mdl)
|
||||
prg := tea.NewProgram(mdl, tea.WithAltScreen())
|
||||
mdl.prg = prg
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case req := <-requestsChan:
|
||||
prg.Send(req)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := prg.Run(); err != nil {
|
||||
tui.Error("An error occurred", err)
|
||||
}
|
||||
|
||||
close(requestsChan)
|
||||
cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (backendHandler, error) {
|
||||
func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := proxyBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http proxy backend")
|
||||
@ -189,7 +223,7 @@ func (cmd *sharePrivateCommand) proxyBackendMode(cfg *proxyBackend.Config) (back
|
||||
return be, nil
|
||||
}
|
||||
|
||||
func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (backendHandler, error) {
|
||||
func (cmd *sharePrivateCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := webBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http web backend")
|
||||
|
@ -2,17 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"github.com/gizak/termui/v3/widgets"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
tb "github.com/nsf/termbox-go"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/webBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/model"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -22,7 +22,6 @@ import (
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -30,10 +29,10 @@ func init() {
|
||||
}
|
||||
|
||||
type sharePublicCommand struct {
|
||||
quiet bool
|
||||
basicAuth []string
|
||||
frontendSelection []string
|
||||
backendMode string
|
||||
headless bool
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
@ -44,10 +43,10 @@ func newSharePublicCommand() *sharePublicCommand {
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
command := &sharePublicCommand{cmd: cmd}
|
||||
cmd.Flags().BoolVarP(&command.quiet, "quiet", "q", false, "Disable TUI 'chrome' for quiet operation")
|
||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
||||
cmd.Flags().StringVar(&command.backendMode, "backend-mode", "proxy", "The backend mode {proxy, web}")
|
||||
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
@ -60,7 +59,7 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
targetEndpoint, err := url.Parse(args[0])
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("invalid target endpoint URL", err)
|
||||
tui.Error("invalid target endpoint URL", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -73,52 +72,44 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
target = args[0]
|
||||
|
||||
default:
|
||||
showError(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
|
||||
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
|
||||
}
|
||||
|
||||
if !cmd.quiet {
|
||||
if err := ui.Init(); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to initialize user interface", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
defer ui.Close()
|
||||
tb.SetInputMode(tb.InputEsc)
|
||||
}
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zif, err := zrokdir.ZitiIdentityFile("backend")
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load ziti identity configuration", err)
|
||||
tui.Error("unable to load ziti identity configuration", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := share.NewShareParams()
|
||||
req.Body = &rest_model_zrok.ShareRequest{
|
||||
EnvZID: env.ZId,
|
||||
EnvZID: zrd.Env.ZId,
|
||||
ShareMode: "public",
|
||||
FrontendSelection: cmd.frontendSelection,
|
||||
BackendMode: "proxy",
|
||||
BackendMode: cmd.backendMode,
|
||||
BackendProxyEndpoint: target,
|
||||
AuthScheme: string(model.None),
|
||||
}
|
||||
@ -136,9 +127,8 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
}
|
||||
resp, err := zrok.Share.Share(req, auth)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create tunnel", err)
|
||||
tui.Error("unable to create share", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -147,23 +137,23 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-c
|
||||
cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
var bh backendHandler
|
||||
requestsChan := make(chan *endpoints.Request, 1024)
|
||||
switch cmd.backendMode {
|
||||
case "proxy":
|
||||
cfg := &proxyBackend.Config{
|
||||
IdentityPath: zif,
|
||||
EndpointAddress: target,
|
||||
ShrToken: resp.Payload.ShrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
bh, err = cmd.proxyBackendMode(cfg)
|
||||
_, err = cmd.proxyBackendMode(cfg)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create proxy backend handler", err)
|
||||
tui.Error("unable to create proxy backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -173,90 +163,54 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
||||
IdentityPath: zif,
|
||||
WebRoot: target,
|
||||
ShrToken: resp.Payload.ShrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
bh, err = cmd.webBackendMode(cfg)
|
||||
_, err = cmd.webBackendMode(cfg)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create web backend handler", err)
|
||||
tui.Error("unable to create web backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
default:
|
||||
ui.Close()
|
||||
showError("invalid backend mode", nil)
|
||||
tui.Error("invalid backend mode", nil)
|
||||
}
|
||||
|
||||
if !cmd.quiet {
|
||||
ui.Clear()
|
||||
w, h := ui.TerminalDimensions()
|
||||
|
||||
p := widgets.NewParagraph()
|
||||
p.Border = true
|
||||
p.Title = " access your zrok share "
|
||||
p.Text = fmt.Sprintf("%v%v", strings.Repeat(" ", (((w-12)-len(resp.Payload.FrontendProxyEndpoints[0]))/2)-1), resp.Payload.FrontendProxyEndpoints[0])
|
||||
p.TextStyle = ui.Style{Fg: ui.ColorWhite}
|
||||
p.PaddingTop = 1
|
||||
p.SetRect(5, 5, w-10, 10)
|
||||
|
||||
lastRequests := float64(0)
|
||||
var requestData []float64
|
||||
spk := widgets.NewSparkline()
|
||||
spk.Title = " requests "
|
||||
spk.Data = requestData
|
||||
spk.LineColor = ui.ColorCyan
|
||||
|
||||
slg := widgets.NewSparklineGroup(spk)
|
||||
slg.SetRect(5, 11, w-10, h-5)
|
||||
|
||||
ui.Render(p, slg)
|
||||
|
||||
ticker := time.NewTicker(time.Second).C
|
||||
uiEvents := ui.PollEvents()
|
||||
if cmd.headless {
|
||||
logrus.Infof("access your zrok share at the following endpoints:\n %v", strings.Join(resp.Payload.FrontendProxyEndpoints, "\n"))
|
||||
for {
|
||||
select {
|
||||
case e := <-uiEvents:
|
||||
switch e.Type {
|
||||
case ui.ResizeEvent:
|
||||
ui.Clear()
|
||||
w, h = ui.TerminalDimensions()
|
||||
p.SetRect(5, 5, w-10, 10)
|
||||
slg.SetRect(5, 11, w-10, h-5)
|
||||
ui.Render(p, slg)
|
||||
|
||||
case ui.KeyboardEvent:
|
||||
switch e.ID {
|
||||
case "q", "<C-c>":
|
||||
ui.Close()
|
||||
cmd.destroy(env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
case <-ticker:
|
||||
currentRequests := float64(bh.Requests()())
|
||||
deltaRequests := currentRequests - lastRequests
|
||||
requestData = append(requestData, deltaRequests)
|
||||
lastRequests = currentRequests
|
||||
requestData = append(requestData, deltaRequests)
|
||||
for len(requestData) > w-17 {
|
||||
requestData = requestData[1:]
|
||||
}
|
||||
spk.Title = fmt.Sprintf(" requests (%d) ", int(currentRequests))
|
||||
spk.Data = requestData
|
||||
ui.Render(p, slg)
|
||||
case req := <-requestsChan:
|
||||
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
logrus.Infof("access your zrok share: %v", resp.Payload.FrontendProxyEndpoints[0])
|
||||
for {
|
||||
time.Sleep(30 * time.Second)
|
||||
mdl := newShareModel(resp.Payload.ShrToken, resp.Payload.FrontendProxyEndpoints, "public", cmd.backendMode)
|
||||
logrus.SetOutput(mdl)
|
||||
prg := tea.NewProgram(mdl, tea.WithAltScreen())
|
||||
mdl.prg = prg
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case req := <-requestsChan:
|
||||
prg.Send(req)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := prg.Run(); err != nil {
|
||||
tui.Error("An error occurred", err)
|
||||
}
|
||||
|
||||
close(requestsChan)
|
||||
cmd.destroy(zrd.Env.ZId, resp.Payload.ShrToken, zrok, auth)
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (backendHandler, error) {
|
||||
func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := proxyBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http proxy backend")
|
||||
@ -271,7 +225,7 @@ func (cmd *sharePublicCommand) proxyBackendMode(cfg *proxyBackend.Config) (backe
|
||||
return be, nil
|
||||
}
|
||||
|
||||
func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (backendHandler, error) {
|
||||
func (cmd *sharePublicCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := webBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http web backend")
|
||||
|
@ -1,17 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/proxyBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints/webBackend"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/metadata"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/share"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -20,6 +23,7 @@ func init() {
|
||||
|
||||
type shareReservedCommand struct {
|
||||
overrideEndpoint string
|
||||
headless bool
|
||||
cmd *cobra.Command
|
||||
}
|
||||
|
||||
@ -30,116 +34,182 @@ func newShareReservedCommand() *shareReservedCommand {
|
||||
}
|
||||
command := &shareReservedCommand{cmd: cmd}
|
||||
cmd.Flags().StringVar(&command.overrideEndpoint, "override-endpoint", "", "Override the stored target endpoint with a replacement")
|
||||
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
||||
cmd.Run = command.run
|
||||
return command
|
||||
}
|
||||
|
||||
func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
|
||||
shrToken := args[0]
|
||||
targetEndpoint := ""
|
||||
if cmd.overrideEndpoint != "" {
|
||||
e, err := url.Parse(cmd.overrideEndpoint)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("invalid override endpoint URL", err)
|
||||
}
|
||||
panic(err)
|
||||
var target string
|
||||
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("error loading zrokdir", err)
|
||||
}
|
||||
if e.Scheme == "" {
|
||||
e.Scheme = "https"
|
||||
}
|
||||
targetEndpoint = e.String()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
if zrd.Env == nil {
|
||||
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
|
||||
}
|
||||
|
||||
zrok, err := zrd.Client()
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load environment; did you 'zrok enable'?", err)
|
||||
tui.Error("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
zrok, err := zrokdir.ZrokClient(env.ApiEndpoint)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create zrok client", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Token)
|
||||
auth := httptransport.APIKeyAuth("X-TOKEN", "header", zrd.Env.Token)
|
||||
req := metadata.NewGetShareDetailParams()
|
||||
req.ShrToken = shrToken
|
||||
resp, err := zrok.Metadata.GetShareDetail(req, auth)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to retrieve reserved share", err)
|
||||
tui.Error("unable to retrieve reserved share", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
if targetEndpoint == "" {
|
||||
targetEndpoint = resp.Payload.BackendProxyEndpoint
|
||||
if target == "" {
|
||||
target = resp.Payload.BackendProxyEndpoint
|
||||
}
|
||||
|
||||
zif, err := zrokdir.ZitiIdentityFile("backend")
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to load ziti identity configuration", err)
|
||||
tui.Error("unable to load ziti identity configuration", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
cfg := &proxyBackend.Config{
|
||||
IdentityPath: zif,
|
||||
EndpointAddress: targetEndpoint,
|
||||
ShrToken: shrToken,
|
||||
}
|
||||
logrus.Infof("sharing target endpoint: '%v'", cfg.EndpointAddress)
|
||||
|
||||
if resp.Payload.BackendProxyEndpoint != targetEndpoint {
|
||||
logrus.Infof("sharing target: '%v'", target)
|
||||
|
||||
if resp.Payload.BackendProxyEndpoint != target {
|
||||
upReq := share.NewUpdateShareParams()
|
||||
upReq.Body = &rest_model_zrok.UpdateShareRequest{
|
||||
ShrToken: shrToken,
|
||||
BackendProxyEndpoint: targetEndpoint,
|
||||
BackendProxyEndpoint: target,
|
||||
}
|
||||
if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to update backend proxy endpoint", err)
|
||||
tui.Error("unable to update backend proxy endpoint", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
logrus.Infof("updated backend proxy endpoint to: %v", targetEndpoint)
|
||||
logrus.Infof("updated backend proxy endpoint to: %v", target)
|
||||
} else {
|
||||
logrus.Infof("using existing backend proxy endpoint: %v", targetEndpoint)
|
||||
logrus.Infof("using existing backend proxy endpoint: %v", target)
|
||||
}
|
||||
|
||||
httpProxy, err := proxyBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
ui.Close()
|
||||
if !panicInstead {
|
||||
showError("unable to create http backend", err)
|
||||
requestsChan := make(chan *endpoints.Request, 1024)
|
||||
switch resp.Payload.BackendMode {
|
||||
case "proxy":
|
||||
cfg := &proxyBackend.Config{
|
||||
IdentityPath: zif,
|
||||
EndpointAddress: target,
|
||||
ShrToken: shrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
panic(err)
|
||||
_, err := cmd.proxyBackendMode(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to create proxy backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
case "web":
|
||||
cfg := &webBackend.Config{
|
||||
IdentityPath: zif,
|
||||
WebRoot: target,
|
||||
ShrToken: shrToken,
|
||||
RequestsChan: requestsChan,
|
||||
}
|
||||
_, err := cmd.webBackendMode(cfg)
|
||||
if err != nil {
|
||||
if !panicInstead {
|
||||
tui.Error("unable to create web backend handler", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
||||
default:
|
||||
tui.Error("invalid backend mode", nil)
|
||||
}
|
||||
|
||||
if cmd.headless {
|
||||
switch resp.Payload.ShareMode {
|
||||
case "public":
|
||||
logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint)
|
||||
|
||||
case "private":
|
||||
logrus.Infof("use this command to access your zrok share: 'zrok access private %v'", shrToken)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case req := <-requestsChan:
|
||||
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var shareDescription string
|
||||
switch resp.Payload.ShareMode {
|
||||
case "public":
|
||||
shareDescription = resp.Payload.FrontendEndpoint
|
||||
case "private":
|
||||
shareDescription = fmt.Sprintf("access your share with: %v", tui.CodeStyle.Render(fmt.Sprintf("zrok access private %v", shrToken)))
|
||||
}
|
||||
|
||||
mdl := newShareModel(shrToken, []string{shareDescription}, resp.Payload.ShareMode, resp.Payload.BackendMode)
|
||||
logrus.SetOutput(mdl)
|
||||
prg := tea.NewProgram(mdl, tea.WithAltScreen())
|
||||
mdl.prg = prg
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case req := <-requestsChan:
|
||||
prg.Send(req)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := prg.Run(); err != nil {
|
||||
tui.Error("An error occurred", err)
|
||||
}
|
||||
|
||||
close(requestsChan)
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *shareReservedCommand) proxyBackendMode(cfg *proxyBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := proxyBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http proxy backend")
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := httpProxy.Run(); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to run http proxy", err)
|
||||
}
|
||||
panic(err)
|
||||
if err := be.Run(); err != nil {
|
||||
logrus.Errorf("error running http proxy backend: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
switch resp.Payload.ShareMode {
|
||||
case "public":
|
||||
logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint)
|
||||
|
||||
case "private":
|
||||
logrus.Infof("use this command to access your zrok share: 'zrok access private %v'", shrToken)
|
||||
}
|
||||
|
||||
for {
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
return be, nil
|
||||
}
|
||||
|
||||
func (cmd *shareReservedCommand) webBackendMode(cfg *webBackend.Config) (endpoints.RequestHandler, error) {
|
||||
be, err := webBackend.NewBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating http web backend")
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := be.Run(); err != nil {
|
||||
logrus.Errorf("error running http web backend: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return be, nil
|
||||
}
|
||||
|
240
cmd/zrok/shareTui.go
Normal file
240
cmd/zrok/shareTui.go
Normal file
@ -0,0 +1,240 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/muesli/reflow/wordwrap"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const shareTuiBacklog = 256
|
||||
|
||||
type shareModel struct {
|
||||
shrToken string
|
||||
frontendDescriptions []string
|
||||
shareMode string
|
||||
backendMode string
|
||||
requests []*endpoints.Request
|
||||
log []string
|
||||
showLog bool
|
||||
width int
|
||||
height int
|
||||
headerHeight int
|
||||
prg *tea.Program
|
||||
}
|
||||
|
||||
type shareLogLine string
|
||||
|
||||
func newShareModel(shrToken string, frontendEndpoints []string, shareMode, backendMode string) *shareModel {
|
||||
return &shareModel{
|
||||
shrToken: shrToken,
|
||||
frontendDescriptions: frontendEndpoints,
|
||||
shareMode: shareMode,
|
||||
backendMode: backendMode,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *shareModel) Init() tea.Cmd { return nil }
|
||||
|
||||
func (m *shareModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case *endpoints.Request:
|
||||
m.requests = append(m.requests, msg)
|
||||
if len(m.requests) > shareTuiBacklog {
|
||||
m.requests = m.requests[1:]
|
||||
}
|
||||
|
||||
case shareLogLine:
|
||||
m.showLog = true
|
||||
m.adjustPaneHeights()
|
||||
|
||||
m.log = append(m.log, string(msg))
|
||||
if len(m.log) > shareTuiBacklog {
|
||||
m.log = m.log[1:]
|
||||
}
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
shareHeaderStyle.Width(m.width - 30)
|
||||
shareConfigStyle.Width(26)
|
||||
shareRequestsStyle.Width(m.width - 2)
|
||||
shareLogStyle.Width(m.width - 2)
|
||||
|
||||
m.height = msg.Height
|
||||
m.headerHeight = len(m.frontendDescriptions) + 4
|
||||
m.adjustPaneHeights()
|
||||
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
return m, tea.Quit
|
||||
case "ctrl+l":
|
||||
return m, tea.ClearScreen
|
||||
case "l":
|
||||
m.showLog = !m.showLog
|
||||
m.adjustPaneHeights()
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *shareModel) View() string {
|
||||
topRow := lipgloss.JoinHorizontal(lipgloss.Top,
|
||||
shareHeaderStyle.Render(strings.Join(m.frontendDescriptions, "\n")),
|
||||
shareConfigStyle.Render(m.renderConfig()),
|
||||
)
|
||||
var panes string
|
||||
if m.showLog {
|
||||
panes = lipgloss.JoinVertical(lipgloss.Left,
|
||||
shareRequestsStyle.Render(m.renderRequests()),
|
||||
shareLogStyle.Render(m.renderLog()),
|
||||
)
|
||||
} else {
|
||||
panes = shareRequestsStyle.Render(m.renderRequests())
|
||||
}
|
||||
return lipgloss.JoinVertical(lipgloss.Left, topRow, panes)
|
||||
}
|
||||
|
||||
func (m *shareModel) adjustPaneHeights() {
|
||||
if !m.showLog {
|
||||
shareRequestsStyle.Height(m.height - m.headerHeight)
|
||||
} else {
|
||||
splitHeight := m.height - m.headerHeight
|
||||
shareRequestsStyle.Height(splitHeight/2 - 1)
|
||||
shareLogStyle.Height(splitHeight/2 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *shareModel) renderConfig() string {
|
||||
out := "["
|
||||
if m.shareMode == "public" {
|
||||
out += shareModePublicStyle.Render(strings.ToUpper(m.shareMode))
|
||||
} else {
|
||||
out += shareModePrivateStyle.Render(strings.ToUpper(m.shareMode))
|
||||
}
|
||||
out += "] ["
|
||||
if m.backendMode == "proxy" {
|
||||
out += backendModeProxyStyle.Render(strings.ToUpper(m.backendMode))
|
||||
} else {
|
||||
out += backendModeWebStyle.Render(strings.ToUpper(m.backendMode))
|
||||
}
|
||||
out += "]"
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *shareModel) renderRequests() string {
|
||||
var requestLines []string
|
||||
for _, req := range m.requests {
|
||||
reqLine := fmt.Sprintf("%v %v -> %v %v",
|
||||
timeStyle.Render(req.Stamp.Format(time.RFC850)),
|
||||
addressStyle.Render(req.RemoteAddr),
|
||||
m.renderMethod(req.Method),
|
||||
req.Path,
|
||||
)
|
||||
reqLineWrapped := wordwrap.String(reqLine, m.width-2)
|
||||
splitWrapped := strings.Split(reqLineWrapped, "\n")
|
||||
for _, splitLine := range splitWrapped {
|
||||
splitLine := strings.ReplaceAll(splitLine, "\n", "")
|
||||
if splitLine != "" {
|
||||
requestLines = append(requestLines, splitLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
maxRows := shareRequestsStyle.GetHeight()
|
||||
startRow := 0
|
||||
if len(requestLines) > maxRows {
|
||||
startRow = len(requestLines) - maxRows
|
||||
}
|
||||
out := ""
|
||||
for i := startRow; i < len(requestLines); i++ {
|
||||
outLine := requestLines[i]
|
||||
if i < len(requestLines)-1 {
|
||||
outLine += "\n"
|
||||
}
|
||||
out += outLine
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *shareModel) renderMethod(method string) string {
|
||||
switch strings.ToLower(method) {
|
||||
case "get":
|
||||
return getStyle.Render(method)
|
||||
case "post":
|
||||
return postStyle.Render(method)
|
||||
default:
|
||||
return otherMethodStyle.Render(method)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *shareModel) renderLog() string {
|
||||
var splitLines []string
|
||||
for _, line := range m.log {
|
||||
wrapped := wordwrap.String(line, m.width-2)
|
||||
wrappedLines := strings.Split(wrapped, "\n")
|
||||
for _, wrappedLine := range wrappedLines {
|
||||
splitLine := strings.ReplaceAll(wrappedLine, "\n", "")
|
||||
if splitLine != "" {
|
||||
splitLines = append(splitLines, splitLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
maxRows := shareLogStyle.GetHeight()
|
||||
startRow := 0
|
||||
if len(splitLines) > maxRows {
|
||||
startRow = len(splitLines) - maxRows
|
||||
}
|
||||
out := ""
|
||||
for i := startRow; i < len(splitLines); i++ {
|
||||
outLine := splitLines[i]
|
||||
if i < len(splitLines)-1 {
|
||||
outLine += "\n"
|
||||
}
|
||||
out += outLine
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *shareModel) Write(p []byte) (n int, err error) {
|
||||
in := string(p)
|
||||
lines := strings.Split(in, "\n")
|
||||
for _, line := range lines {
|
||||
cleanLine := strings.ReplaceAll(line, "\n", "")
|
||||
if cleanLine != "" {
|
||||
m.prg.Send(shareLogLine(cleanLine))
|
||||
}
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
var shareHeaderStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63")).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
var shareConfigStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63")).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
var shareRequestsStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63"))
|
||||
|
||||
var shareLogStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("63"))
|
||||
|
||||
var shareModePublicStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0F0"))
|
||||
var shareModePrivateStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#F00"))
|
||||
var backendModeProxyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
|
||||
var backendModeWebStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#0CC"))
|
||||
var timeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#444"))
|
||||
var addressStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
|
||||
var getStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("98"))
|
||||
var postStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("101"))
|
||||
var otherMethodStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("166"))
|
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/openziti-test-kitchen/zrok/zrokdir"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
@ -31,23 +32,34 @@ func newStatusCommand() *statusCommand {
|
||||
func (cmd *statusCommand) run(_ *cobra.Command, _ []string) {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "\n")
|
||||
|
||||
env, err := zrokdir.LoadEnvironment()
|
||||
zrd, err := zrokdir.Load()
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%v: Unable to load your local environment! (%v)\n\n", warningLabel, err)
|
||||
_, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", codeStyle.Render("zrok enable"))
|
||||
tui.Error("unable to load zrokdir", err)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stdout, tui.CodeStyle.Render("Config")+":\n\n")
|
||||
t := table.NewWriter()
|
||||
t.SetOutputMirror(os.Stdout)
|
||||
t.SetStyle(table.StyleColoredDark)
|
||||
t.AppendHeader(table.Row{"Config", "Value", "Source"})
|
||||
apiEndpoint, from := zrd.ApiEndpoint()
|
||||
t.AppendRow(table.Row{"apiEndpoint", apiEndpoint, from})
|
||||
t.Render()
|
||||
_, _ = fmt.Fprintf(os.Stderr, "\n")
|
||||
|
||||
if zrd.Env == nil {
|
||||
tui.Warning("Unable to load your local environment!\n")
|
||||
_, _ = fmt.Fprintf(os.Stderr, "To create a local environment use the %v command.\n", tui.CodeStyle.Render("zrok enable"))
|
||||
} else {
|
||||
_, _ = fmt.Fprintf(os.Stdout, codeStyle.Render("Environment"+":\n"))
|
||||
_, _ = fmt.Fprintf(os.Stdout, "\n")
|
||||
_, _ = fmt.Fprintf(os.Stdout, tui.CodeStyle.Render("Environment")+":\n\n")
|
||||
|
||||
t := table.NewWriter()
|
||||
t.SetOutputMirror(os.Stdout)
|
||||
t.SetStyle(table.StyleColoredDark)
|
||||
t.AppendHeader(table.Row{"Property", "Value"})
|
||||
t.AppendRow(table.Row{"API Endpoint", env.ApiEndpoint})
|
||||
t.AppendRow(table.Row{"Secret Token", env.Token})
|
||||
t.AppendRow(table.Row{"Ziti Identity", env.ZId})
|
||||
t.AppendRow(table.Row{"Secret Token", zrd.Env.Token})
|
||||
t.AppendRow(table.Row{"Ziti Identity", zrd.Env.ZId})
|
||||
t.Render()
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "\n")
|
||||
_, _ = fmt.Fprintf(os.Stdout, "\n")
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/opentracing/opentracing-go/log"
|
||||
"github.com/openziti-test-kitchen/zrok/cmd/zrok/endpointUi"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"html/template"
|
||||
@ -33,7 +34,7 @@ func newTestEndpointCommand() *testEndpointCommand {
|
||||
var err error
|
||||
if command.t, err = template.ParseFS(endpointUi.FS, "index.gohtml"); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to parse index template", err)
|
||||
tui.Error("unable to parse index template", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
@ -47,7 +48,7 @@ func (cmd *testEndpointCommand) run(_ *cobra.Command, _ []string) {
|
||||
http.HandleFunc("/", cmd.serveIndex)
|
||||
if err := http.ListenAndServe(fmt.Sprintf("%v:%d", cmd.address, cmd.port), nil); err != nil {
|
||||
if !panicInstead {
|
||||
showError("unable to start http listener", err)
|
||||
tui.Error("unable to start http listener", err)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1,18 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type backendHandler interface {
|
||||
Requests() func() int32
|
||||
}
|
||||
|
||||
func mustGetAdminAuth() runtime.ClientAuthInfoWriter {
|
||||
adminToken := os.Getenv("ZROK_ADMIN_TOKEN")
|
||||
if adminToken == "" {
|
||||
@ -20,18 +13,3 @@ func mustGetAdminAuth() runtime.ClientAuthInfoWriter {
|
||||
}
|
||||
return httptransport.APIKeyAuth("X-TOKEN", "header", adminToken)
|
||||
}
|
||||
|
||||
var errorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#D90166"))
|
||||
var errorLabel = errorStyle.Render("ERROR")
|
||||
var warningStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
|
||||
var warningLabel = warningStyle.Render("WARNING")
|
||||
var codeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF"))
|
||||
|
||||
func showError(msg string, err error) {
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%v: %v (%v)\n", errorLabel, msg, strings.TrimSpace(err.Error()))
|
||||
} else {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%v %v\n", errorLabel, msg)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/openziti-test-kitchen/zrok/build"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -27,5 +28,5 @@ func newVersionCommand() *versionCommand {
|
||||
|
||||
func (cmd *versionCommand) run(_ *cobra.Command, _ []string) {
|
||||
zrokStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FF00EE"))
|
||||
fmt.Println(zrokStyle.Render(" _ \n _____ __ ___ | | __\n|_ / '__/ _ \\| |/ /\n / /| | | (_) | < \n/___|_| \\___/|_|\\_\\") + "\n\n" + codeStyle.Render(build.String()) + "\n")
|
||||
fmt.Println(zrokStyle.Render(" _ \n _____ __ ___ | | __\n|_ / '__/ _ \\| |/ /\n / /| | | (_) | < \n/___|_| \\___/|_|\\_\\") + "\n\n" + tui.CodeStyle.Render(build.String()) + "\n")
|
||||
}
|
||||
|
@ -31,7 +31,12 @@ func (h *enableHandler) Handle(params environment.EnableParams, principal *rest_
|
||||
logrus.Errorf("error getting edge client: %v", err)
|
||||
return environment.NewEnableInternalServerError()
|
||||
}
|
||||
ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(principal.Email, params.Body.Description, client)
|
||||
uniqueToken, err := createShareToken()
|
||||
if err != nil {
|
||||
logrus.Errorf("error creating unique identity token: %v", err)
|
||||
return environment.NewEnableInternalServerError()
|
||||
}
|
||||
ident, err := zrokEdgeSdk.CreateEnvironmentIdentity(uniqueToken, principal.Email, params.Body.Description, client)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return environment.NewEnableInternalServerError()
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreateEnvironmentIdentity(accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) {
|
||||
func CreateEnvironmentIdentity(uniqueToken, accountEmail, envDescription string, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) {
|
||||
identityType := rest_model_edge.IdentityTypeUser
|
||||
moreTags := map[string]interface{}{"zrokEmail": accountEmail}
|
||||
return CreateIdentity(accountEmail+"-"+envDescription, identityType, moreTags, edge)
|
||||
return CreateIdentity(accountEmail+"-"+uniqueToken+"-"+envDescription, identityType, moreTags, edge)
|
||||
}
|
||||
|
||||
func CreateIdentity(name string, identityType rest_model_edge.IdentityType, addlTags map[string]interface{}, edge *rest_management_api_client.ZitiEdgeManagement) (*identity.CreateIdentityCreated, error) {
|
||||
|
@ -1,9 +1,12 @@
|
||||
package privateFrontend
|
||||
|
||||
import "github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
|
||||
type Config struct {
|
||||
IdentityName string
|
||||
ShrToken string
|
||||
Address string
|
||||
RequestsChan chan *endpoints.Request
|
||||
}
|
||||
|
||||
func DefaultConfig(identityName string) *Config {
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type httpFrontend struct {
|
||||
@ -75,6 +76,14 @@ func newServiceProxy(cfg *Config, ctx ziti.Context) (*httputil.ReverseProxy, err
|
||||
proxy := serviceTargetProxy(cfg, ctx)
|
||||
director := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
if cfg.RequestsChan != nil {
|
||||
cfg.RequestsChan <- &endpoints.Request{
|
||||
Stamp: time.Now(),
|
||||
RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]),
|
||||
Method: req.Method,
|
||||
Path: req.URL.String(),
|
||||
}
|
||||
}
|
||||
director(req)
|
||||
req.Header.Set("X-Proxy", "zrok")
|
||||
}
|
||||
@ -98,7 +107,7 @@ func serviceTargetProxy(cfg *Config, ctx ziti.Context) *httputil.ReverseProxy {
|
||||
logrus.Warn("no config!")
|
||||
}
|
||||
if target, err := url.Parse(fmt.Sprintf("http://%v", targetShrToken)); err == nil {
|
||||
logrus.Infof("[%v] -> %v", targetShrToken, req.URL)
|
||||
logrus.Debugf("[%v] -> %v", targetShrToken, req.URL)
|
||||
|
||||
targetQuery := target.RawQuery
|
||||
req.URL.Scheme = target.Scheme
|
||||
|
@ -2,6 +2,8 @@ package proxyBackend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti-test-kitchen/zrok/util"
|
||||
"github.com/openziti/sdk-golang/ziti"
|
||||
"github.com/openziti/sdk-golang/ziti/config"
|
||||
@ -19,6 +21,7 @@ type Config struct {
|
||||
IdentityPath string
|
||||
EndpointAddress string
|
||||
ShrToken string
|
||||
RequestsChan chan *endpoints.Request
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
@ -42,7 +45,7 @@ func NewBackend(cfg *Config) (*backend, error) {
|
||||
return nil, errors.Wrap(err, "error listening")
|
||||
}
|
||||
|
||||
proxy, err := newReverseProxy(cfg.EndpointAddress)
|
||||
proxy, err := newReverseProxy(cfg.EndpointAddress, cfg.RequestsChan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -67,7 +70,7 @@ func (self *backend) Requests() func() int32 {
|
||||
return self.requests
|
||||
}
|
||||
|
||||
func newReverseProxy(target string) (*httputil.ReverseProxy, error) {
|
||||
func newReverseProxy(target string, requests chan *endpoints.Request) (*httputil.ReverseProxy, error) {
|
||||
targetURL, err := url.Parse(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -80,8 +83,15 @@ func newReverseProxy(target string) (*httputil.ReverseProxy, error) {
|
||||
proxy.Transport = tpt
|
||||
director := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
if requests != nil {
|
||||
requests <- &endpoints.Request{
|
||||
Stamp: time.Now(),
|
||||
RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]),
|
||||
Method: req.Method,
|
||||
Path: req.URL.String(),
|
||||
}
|
||||
}
|
||||
director(req)
|
||||
logrus.Debugf("-> %v", req.URL.String())
|
||||
req.Header.Set("X-Proxy", "zrok")
|
||||
}
|
||||
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
|
14
endpoints/requests.go
Normal file
14
endpoints/requests.go
Normal file
@ -0,0 +1,14 @@
|
||||
package endpoints
|
||||
|
||||
import "time"
|
||||
|
||||
type RequestHandler interface {
|
||||
Requests() func() int32
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
Stamp time.Time
|
||||
RemoteAddr string
|
||||
Method string
|
||||
Path string
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package webBackend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openziti-test-kitchen/zrok/endpoints"
|
||||
"github.com/openziti/sdk-golang/ziti"
|
||||
"github.com/openziti/sdk-golang/ziti/config"
|
||||
"github.com/openziti/sdk-golang/ziti/edge"
|
||||
@ -13,6 +15,7 @@ type Config struct {
|
||||
IdentityPath string
|
||||
WebRoot string
|
||||
ShrToken string
|
||||
RequestsChan chan *endpoints.Request
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
@ -35,11 +38,16 @@ func NewBackend(cfg *Config) (*backend, error) {
|
||||
return nil, errors.Wrap(err, "error listening")
|
||||
}
|
||||
|
||||
return &backend{
|
||||
be := &backend{
|
||||
cfg: cfg,
|
||||
listener: listener,
|
||||
handler: http.FileServer(http.Dir(cfg.WebRoot)),
|
||||
}, nil
|
||||
}
|
||||
if cfg.RequestsChan != nil {
|
||||
be.handler = &requestGrabber{requests: cfg.RequestsChan, handler: http.FileServer(http.Dir(cfg.WebRoot))}
|
||||
} else {
|
||||
be.handler = http.FileServer(http.Dir(cfg.WebRoot))
|
||||
}
|
||||
return be, nil
|
||||
}
|
||||
|
||||
func (self *backend) Run() error {
|
||||
@ -52,3 +60,20 @@ func (self *backend) Run() error {
|
||||
func (self *backend) Requests() func() int32 {
|
||||
return func() int32 { return 0 }
|
||||
}
|
||||
|
||||
type requestGrabber struct {
|
||||
requests chan *endpoints.Request
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func (rl *requestGrabber) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
|
||||
if rl.requests != nil {
|
||||
rl.requests <- &endpoints.Request{
|
||||
Stamp: time.Now(),
|
||||
RemoteAddr: fmt.Sprintf("%v", req.Header["X-Real-Ip"]),
|
||||
Method: req.Method,
|
||||
Path: req.URL.String(),
|
||||
}
|
||||
}
|
||||
rl.handler.ServeHTTP(resp, req)
|
||||
}
|
||||
|
20
go.mod
20
go.mod
@ -3,8 +3,8 @@ module github.com/openziti-test-kitchen/zrok
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/charmbracelet/bubbletea v0.23.1
|
||||
github.com/charmbracelet/lipgloss v0.6.0
|
||||
github.com/gizak/termui/v3 v3.1.0
|
||||
github.com/go-openapi/errors v0.20.2
|
||||
github.com/go-openapi/loads v0.21.1
|
||||
github.com/go-openapi/runtime v0.24.1
|
||||
@ -22,7 +22,6 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.14
|
||||
github.com/michaelquigley/cf v0.0.13
|
||||
github.com/michaelquigley/pfxlog v0.6.9
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/openziti/edge v0.22.39
|
||||
github.com/openziti/foundation/v2 v2.0.4
|
||||
@ -32,7 +31,6 @@ require (
|
||||
github.com/shirou/gopsutil/v3 v3.22.8
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.5.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/wneessen/go-mail v0.2.7
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||
@ -42,7 +40,11 @@ require (
|
||||
require (
|
||||
github.com/Jeffail/gabs v1.4.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/charmbracelet/bubbles v0.14.0 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
@ -64,14 +66,16 @@ require (
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 // indirect
|
||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.13.0 // indirect
|
||||
github.com/netfoundry/secretstream v0.1.2 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/openziti/channel/v2 v2.0.1 // indirect
|
||||
@ -85,6 +89,7 @@ require (
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/speps/go-hashids v2.0.0+incompatible // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
@ -93,6 +98,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
|
||||
golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect
|
||||
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
42
go.sum
42
go.sum
@ -53,11 +53,22 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og=
|
||||
github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc=
|
||||
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
|
||||
github.com/charmbracelet/bubbletea v0.23.1 h1:CYdteX1wCiCzKNUlwm25ZHBIc1GXlYFyUIte8WPvhck=
|
||||
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
|
||||
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
|
||||
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@ -67,6 +78,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@ -100,8 +113,6 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvD
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc=
|
||||
github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -322,6 +333,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@ -361,12 +373,15 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
||||
@ -388,8 +403,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
||||
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/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
@ -404,15 +417,21 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 h1:y1p/ycavWjGT9FnmSjdbWUlLGvcxrY0Rw3ATltrxOhk=
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 h1:STjmj0uFfRryL9fzRA/OupNppeAID6QJYPMavTL7jtY=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0=
|
||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||
github.com/netfoundry/secretstream v0.1.2 h1:NgqrYytDnjKbOfWI29TT0SJM+RwB3yf9MIkJVJaU+J0=
|
||||
github.com/netfoundry/secretstream v0.1.2/go.mod h1:uasYkYSp0MmNSlKOWJ2sVzxPms8e58TS4ENq4yro86k=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
|
||||
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||
@ -479,6 +498,7 @@ github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMH
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
|
||||
@ -755,6 +775,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
27
tui/messages.go
Normal file
27
tui/messages.go
Normal file
@ -0,0 +1,27 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ErrorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#D90166"))
|
||||
var ErrorLabel = ErrorStyle.Render("ERROR")
|
||||
var WarningStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFA500"))
|
||||
var WarningLabel = WarningStyle.Render("WARNING")
|
||||
var CodeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF"))
|
||||
|
||||
func Error(msg string, err error) {
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "[%v]: %v (%v)\n", ErrorLabel, msg, strings.TrimSpace(err.Error()))
|
||||
} else {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "[%v] %v\n", ErrorLabel, msg)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func Warning(msg string, v ...interface{}) {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%v: "+msg+"\n", append([]interface{}{WarningLabel}, v...))
|
||||
}
|
@ -7,24 +7,16 @@ import (
|
||||
"github.com/openziti-test-kitchen/zrok/build"
|
||||
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func AddZrokApiEndpointFlag(v *string, flags *pflag.FlagSet) {
|
||||
defaultEndpoint := os.Getenv("ZROK_API_ENDPOINT")
|
||||
if defaultEndpoint == "" {
|
||||
defaultEndpoint = "https://api.zrok.io"
|
||||
}
|
||||
flags.StringVarP(v, "endpoint", "e", defaultEndpoint, "zrok API endpoint address")
|
||||
}
|
||||
|
||||
func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) {
|
||||
apiUrl, err := url.Parse(endpoint)
|
||||
func (zrd *ZrokDir) Client() (*rest_client_zrok.Zrok, error) {
|
||||
apiEndpoint, _ := zrd.ApiEndpoint()
|
||||
apiUrl, err := url.Parse(apiEndpoint)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error parsing api endpoint '%v'", endpoint)
|
||||
return nil, errors.Wrapf(err, "error parsing api endpoint '%v'", zrd)
|
||||
}
|
||||
transport := httptransport.New(apiUrl.Host, "/api/v1", []string{apiUrl.Scheme})
|
||||
transport.Producers["application/zrok.v1+json"] = runtime.JSONProducer()
|
||||
@ -33,7 +25,7 @@ func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) {
|
||||
zrok := rest_client_zrok.New(transport, strfmt.Default)
|
||||
v, err := zrok.Metadata.Version(nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error getting version from api endpoint '%v': %v", endpoint, err)
|
||||
return nil, errors.Wrapf(err, "error getting version from api endpoint '%v': %v", apiEndpoint, err)
|
||||
}
|
||||
if !strings.HasPrefix(string(v.Payload), build.Series) {
|
||||
return nil, errors.Errorf("expected a '%v' version, received: '%v'", build.Series, v.Payload)
|
||||
@ -41,3 +33,26 @@ func ZrokClient(endpoint string) (*rest_client_zrok.Zrok, error) {
|
||||
|
||||
return zrok, nil
|
||||
}
|
||||
|
||||
func (zrd *ZrokDir) ApiEndpoint() (apiEndpoint string, from string) {
|
||||
apiEndpoint = "https://api.zrok.io"
|
||||
from = "binary"
|
||||
|
||||
if zrd.Cfg != nil && zrd.Cfg.ApiEndpoint != "" {
|
||||
apiEndpoint = zrd.Cfg.ApiEndpoint
|
||||
from = "config"
|
||||
}
|
||||
|
||||
env := os.Getenv("ZROK_API_ENDPOINT")
|
||||
if env != "" {
|
||||
apiEndpoint = env
|
||||
from = "ZROK_API_ENDPOINT"
|
||||
}
|
||||
|
||||
if zrd.Env != nil && zrd.Env.ApiEndpoint != "" {
|
||||
apiEndpoint = zrd.Env.ApiEndpoint
|
||||
from = "env"
|
||||
}
|
||||
|
||||
return apiEndpoint, from
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ type Config struct {
|
||||
ApiEndpoint string `json:"api_endpoint"`
|
||||
}
|
||||
|
||||
func HasConfig() (bool, error) {
|
||||
func hasConfig() (bool, error) {
|
||||
cf, err := configFile()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error getting config file path")
|
||||
@ -26,7 +26,7 @@ func HasConfig() (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func LoadConfig() (*Config, error) {
|
||||
func loadConfig() (*Config, error) {
|
||||
cf, err := configFile()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting config file path")
|
||||
@ -42,7 +42,7 @@ func LoadConfig() (*Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func SaveConfig(cfg *Config) error {
|
||||
func saveConfig(cfg *Config) error {
|
||||
data, err := json.MarshalIndent(cfg, "", " ")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error marshaling config")
|
||||
|
@ -13,7 +13,22 @@ type Environment struct {
|
||||
ApiEndpoint string `json:"api_endpoint"`
|
||||
}
|
||||
|
||||
func LoadEnvironment() (*Environment, error) {
|
||||
func hasEnvironment() (bool, error) {
|
||||
ef, err := environmentFile()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "error getting environment file path")
|
||||
}
|
||||
_, err = os.Stat(ef)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "error stat-ing environment file '%v'", ef)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func loadEnvironment() (*Environment, error) {
|
||||
ef, err := environmentFile()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting environment file")
|
||||
@ -29,7 +44,7 @@ func LoadEnvironment() (*Environment, error) {
|
||||
return env, nil
|
||||
}
|
||||
|
||||
func SaveEnvironment(env *Environment) error {
|
||||
func saveEnvironment(env *Environment) error {
|
||||
data, err := json.MarshalIndent(env, "", " ")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error marshaling environment")
|
||||
|
@ -1,18 +1,13 @@
|
||||
package zrokdir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func ZitiIdentityFile(name string) (string, error) {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(zrd, "identities", fmt.Sprintf("%v.json", name)), nil
|
||||
return identityFile(name)
|
||||
}
|
||||
|
||||
func SaveZitiIdentity(name, data string) error {
|
||||
|
53
zrokdir/version.go
Normal file
53
zrokdir/version.go
Normal file
@ -0,0 +1,53 @@
|
||||
package zrokdir
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/openziti-test-kitchen/zrok/tui"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const V = "v0.3"
|
||||
|
||||
type Metadata struct {
|
||||
V string `json:"v"`
|
||||
}
|
||||
|
||||
func checkMetadata() error {
|
||||
mf, err := metadataFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.ReadFile(mf)
|
||||
if err != nil {
|
||||
tui.Warning("unable to open zrokdir metadata; ignoring\n")
|
||||
return nil
|
||||
}
|
||||
m := &Metadata{}
|
||||
if err := json.Unmarshal(data, m); err != nil {
|
||||
return errors.Wrapf(err, "error unmarshaling metadata file '%v'", mf)
|
||||
}
|
||||
if m.V != V {
|
||||
return errors.Errorf("invalid zrokdir metadata version '%v'", m.V)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeMetadata() error {
|
||||
mf, err := metadataFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(&Metadata{V: V})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(mf), os.FileMode(0700)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(mf, data, os.FileMode(0600)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,10 +1,135 @@
|
||||
package zrokdir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ZrokDir struct {
|
||||
Env *Environment
|
||||
Cfg *Config
|
||||
identities map[string]struct{}
|
||||
}
|
||||
|
||||
func Initialize() (*ZrokDir, error) {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting zrokdir path")
|
||||
}
|
||||
if err := os.MkdirAll(zrd, os.FileMode(0700)); err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating zrokdir root path '%v'", zrd)
|
||||
}
|
||||
if err := DeleteEnvironment(); err != nil {
|
||||
return nil, errors.Wrap(err, "error deleting environment")
|
||||
}
|
||||
idd, err := identitiesDir()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting zrokdir identities path")
|
||||
}
|
||||
if err := os.MkdirAll(idd, os.FileMode(0700)); err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating zrokdir identities root path '%v'", idd)
|
||||
}
|
||||
return Load()
|
||||
}
|
||||
|
||||
func Load() (*ZrokDir, error) {
|
||||
if err := checkMetadata(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zrd := &ZrokDir{}
|
||||
|
||||
ids, err := listIdentities()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zrd.identities = ids
|
||||
|
||||
hasCfg, err := hasConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasCfg {
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zrd.Cfg = cfg
|
||||
}
|
||||
|
||||
hasEnv, err := hasEnvironment()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hasEnv {
|
||||
env, err := loadEnvironment()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zrd.Env = env
|
||||
}
|
||||
|
||||
return zrd, nil
|
||||
}
|
||||
|
||||
func (zrd *ZrokDir) Save() error {
|
||||
if err := writeMetadata(); err != nil {
|
||||
return errors.Wrap(err, "error saving metadata")
|
||||
}
|
||||
if zrd.Env != nil {
|
||||
if err := saveEnvironment(zrd.Env); err != nil {
|
||||
return errors.Wrap(err, "error saving environment")
|
||||
}
|
||||
}
|
||||
if zrd.Cfg != nil {
|
||||
if err := saveConfig(zrd.Cfg); err != nil {
|
||||
return errors.Wrap(err, "error saving config")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Obliterate() error {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(zrd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listIdentities() (map[string]struct{}, error) {
|
||||
ids := make(map[string]struct{})
|
||||
|
||||
idd, err := identitiesDir()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting zrokdir identities path")
|
||||
}
|
||||
_, err = os.Stat(idd)
|
||||
if os.IsNotExist(err) {
|
||||
return ids, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error stat-ing zrokdir identities root '%v'", idd)
|
||||
}
|
||||
des, err := os.ReadDir(idd)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error listing zrokdir identities from '%v'", idd)
|
||||
}
|
||||
for _, de := range des {
|
||||
if strings.HasSuffix(de.Name(), ".json") && !de.IsDir() {
|
||||
name := strings.TrimSuffix(de.Name(), ".json")
|
||||
ids[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func configFile() (string, error) {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
@ -21,6 +146,30 @@ func environmentFile() (string, error) {
|
||||
return filepath.Join(zrd, "environment.json"), nil
|
||||
}
|
||||
|
||||
func identityFile(name string) (string, error) {
|
||||
idd, err := identitiesDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(idd, fmt.Sprintf("%v.json", name)), nil
|
||||
}
|
||||
|
||||
func identitiesDir() (string, error) {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(zrd, "identities"), nil
|
||||
}
|
||||
|
||||
func metadataFile() (string, error) {
|
||||
zrd, err := zrokDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(zrd, "metadata.json"), nil
|
||||
}
|
||||
|
||||
func zrokDir() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user