mirror of
https://github.com/openziti/zrok.git
synced 2024-11-22 08:03:49 +01:00
231 lines
6.0 KiB
Go
231 lines
6.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/charmbracelet/bubbles/spinner"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
httptransport "github.com/go-openapi/runtime/client"
|
|
"github.com/openziti/zrok/environment"
|
|
"github.com/openziti/zrok/environment/env_core"
|
|
restEnvironment "github.com/openziti/zrok/rest_client_zrok/environment"
|
|
"github.com/openziti/zrok/rest_model_zrok"
|
|
"github.com/openziti/zrok/tui"
|
|
"github.com/shirou/gopsutil/v3/host"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
"os"
|
|
user2 "os/user"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(newEnableCommand().cmd)
|
|
}
|
|
|
|
type enableCommand struct {
|
|
description string
|
|
headless bool
|
|
cmd *cobra.Command
|
|
}
|
|
|
|
func newEnableCommand() *enableCommand {
|
|
cmd := &cobra.Command{
|
|
Use: "enable <token>",
|
|
Short: "Enable an environment for zrok",
|
|
Args: cobra.ExactArgs(1),
|
|
}
|
|
command := &enableCommand{cmd: cmd}
|
|
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
|
|
cmd.Flags().StringVarP(&command.description, "description", "d", "<user>@<hostname>", "Description of this environment")
|
|
cmd.Run = command.run
|
|
return command
|
|
}
|
|
|
|
func (cmd *enableCommand) run(_ *cobra.Command, args []string) {
|
|
env, err := environment.LoadRoot()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
token := args[0]
|
|
|
|
if env.IsEnabled() {
|
|
tui.Error(fmt.Sprintf("you already have an enabled environment, %v first before you %v", tui.Code.Render("zrok disable"), tui.Code.Render("zrok enable")), nil)
|
|
}
|
|
|
|
hostName, hostDetail, err := getHost()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
var username string
|
|
user, err := user2.Current()
|
|
if err != nil {
|
|
username := os.Getenv("USER")
|
|
if username == "" {
|
|
logrus.Panicf("unable to determine the current user: %v", err)
|
|
}
|
|
} else {
|
|
username = user.Username
|
|
}
|
|
hostDetail = fmt.Sprintf("%v; %v", username, hostDetail)
|
|
if cmd.description == "<user>@<hostname>" {
|
|
cmd.description = fmt.Sprintf("%v@%v", username, hostName)
|
|
}
|
|
zrok, err := env.Client()
|
|
if err != nil {
|
|
cmd.endpointError(env.ApiEndpoint())
|
|
tui.Error("error creating service client", err)
|
|
}
|
|
auth := httptransport.APIKeyAuth("X-TOKEN", "header", token)
|
|
req := restEnvironment.NewEnableParams()
|
|
req.Body = &rest_model_zrok.EnableRequest{
|
|
Description: cmd.description,
|
|
Host: hostDetail,
|
|
}
|
|
|
|
var prg *tea.Program
|
|
var done = make(chan struct{})
|
|
if !cmd.headless {
|
|
var mdl enableTuiModel
|
|
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)
|
|
}
|
|
}()
|
|
} else {
|
|
logrus.Infof("contacting the zrok service...")
|
|
}
|
|
|
|
resp, err := zrok.Environment.Enable(req, auth)
|
|
//Switch on err type (401, 400, 500, etc...)
|
|
if err != nil {
|
|
time.Sleep(250 * time.Millisecond)
|
|
if !cmd.headless && prg != nil {
|
|
prg.Send(fmt.Sprintf("the zrok service returned an error: %v\n", err))
|
|
prg.Quit()
|
|
} else {
|
|
logrus.Errorf("the zrok service returned an error: %v", err)
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(1 * time.Second):
|
|
}
|
|
cmd.endpointError(env.ApiEndpoint())
|
|
os.Exit(1)
|
|
}
|
|
if err != nil {
|
|
prg.Send("writing the environment details...")
|
|
}
|
|
apiEndpoint, _ := env.ApiEndpoint()
|
|
if err := env.SetEnvironment(&env_core.Environment{Token: token, ZitiIdentity: resp.Payload.Identity, ApiEndpoint: apiEndpoint}); err != nil {
|
|
if !cmd.headless && prg != nil {
|
|
prg.Send(fmt.Sprintf("there was an error saving the new environment: %v", err))
|
|
prg.Quit()
|
|
} else {
|
|
logrus.Errorf("there was an error saving the new environment: %v", err)
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(1 * time.Second):
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
if err := env.SaveZitiIdentityNamed(env.EnvironmentIdentityName(), resp.Payload.Cfg); err != nil {
|
|
if !cmd.headless && prg != nil {
|
|
prg.Send(fmt.Sprintf("there was an error writing the environment: %v", err))
|
|
prg.Quit()
|
|
} else {
|
|
logrus.Errorf("there was an error writing the environment: %v", err)
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(1 * time.Second):
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !cmd.headless && prg != nil {
|
|
prg.Send(fmt.Sprintf("the zrok environment was successfully enabled..."))
|
|
prg.Quit()
|
|
} else {
|
|
logrus.Infof("the zrok environment was successfully enabled...")
|
|
}
|
|
select {
|
|
case <-done:
|
|
case <-time.After(1 * time.Second):
|
|
}
|
|
}
|
|
|
|
func (cmd *enableCommand) endpointError(apiEndpoint, _ string) {
|
|
fmt.Printf("%v\n\n", tui.SeriousBusiness.Render("there was a problem enabling your environment!"))
|
|
fmt.Printf("you are trying to use the zrok service at: %v\n\n", tui.Code.Render(apiEndpoint))
|
|
fmt.Printf("you can change your zrok service endpoint using this command:\n\n")
|
|
fmt.Printf("%v\n\n", tui.Code.Render("$ zrok config set apiEndpoint <newEndpoint>"))
|
|
fmt.Printf("(where newEndpoint is something like: %v)\n\n", tui.Code.Render("https://some.zrok.io"))
|
|
}
|
|
|
|
func getHost() (string, string, error) {
|
|
info, err := host.Info()
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
thisHost := fmt.Sprintf("%v; %v; %v; %v; %v; %v; %v",
|
|
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.Attention
|
|
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
|
|
}
|