diff --git a/.golangci.yml b/.golangci.yml index 4ff6418..1598c1d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -24,7 +24,6 @@ linters: - gocyclo - godot - godox - - goerr113 - gofmt - goheader - gomodguard @@ -116,6 +115,9 @@ linters: # Needs package whitelists - depguard + # This is mostly a CLI tool, not a package, so it's OK to have dynamic errors + - goerr113 + issues: # Don't hide multiple issues that belong to one class since GitHub annotations can handle them all nicely. max-issues-per-linter: 0 diff --git a/internal/command/create/vm.go b/internal/command/create/vm.go index d9ef9dd..8042b76 100644 --- a/internal/command/create/vm.go +++ b/internal/command/create/vm.go @@ -18,6 +18,8 @@ var memory uint64 var netSoftnet bool var netBridged string var headless bool +var username string +var password string var resources map[string]string var restartPolicy string var startupScript string @@ -38,6 +40,10 @@ func newCreateVMCommand() *cobra.Command { command.PersistentFlags().BoolVar(&netSoftnet, "net-softnet", false, "whether to use Softnet network isolation") command.PersistentFlags().StringVar(&netBridged, "net-bridged", "", "whether to use Bridged network mode") command.PersistentFlags().BoolVar(&headless, "headless", true, "whether to run without graphics") + command.PersistentFlags().StringVar(&username, "username", "admin", + "SSH username to use when executing a startup script on the VM") + command.PersistentFlags().StringVar(&password, "password", "admin", + "SSH password to use when executing a startup script on the VM") command.PersistentFlags().StringToStringVar(&resources, "resources", map[string]string{}, "resources to request for this VM") command.PersistentFlags().StringVar(&restartPolicy, "restart-policy", string(v1.RestartPolicyNever), @@ -82,6 +88,8 @@ func runCreateVM(cmd *cobra.Command, args []string) error { NetSoftnet: netSoftnet, NetBridged: netBridged, Headless: headless, + Username: username, + Password: password, HostDirs: hostDirs, } diff --git a/internal/command/worker/run.go b/internal/command/worker/run.go index 8a91663..2ecf54d 100644 --- a/internal/command/worker/run.go +++ b/internal/command/worker/run.go @@ -12,13 +12,19 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" + "io" + "os" + "strings" ) -var ErrRunFailed = errors.New("failed to run worker") - -var ErrBootstrapTokenNotProvided = errors.New("no bootstrap token provided") +var ( + ErrRunFailed = errors.New("failed to run worker") + ErrNoBootstrapTokenProvided = errors.New("no bootstrap token was provided") + ErrEmptyBootstrapTokenProvided = errors.New("empty bootstrap token was provided") +) var bootstrapTokenRaw string +var bootstrapTokenStdin bool var logFilePath string var stringToStringResources map[string]string var noPKI bool @@ -33,7 +39,9 @@ func newRunCommand() *cobra.Command { } cmd.PersistentFlags().StringVar(&bootstrapTokenRaw, "bootstrap-token", "", - "a bootstrap token retrieved via `orchard get bootstrap-token `") + "a bootstrap token retrieved via \"orchard get bootstrap-token \"") + cmd.PersistentFlags().BoolVar(&bootstrapTokenStdin, "bootstrap-token-stdin", false, + "use this flag to provide a bootstrap token via the standard input") cmd.PersistentFlags().StringVar(&logFilePath, "log-file", "", "optional path to a file where logs (up to 100 Mb) will be written.") cmd.PersistentFlags().StringToStringVar(&stringToStringResources, "resources", map[string]string{}, @@ -55,8 +63,12 @@ func runWorker(cmd *cobra.Command, args []string) (err error) { } // Parse bootstrap token + bootstrapTokenRaw, err := readBootstrapToken() + if err != nil { + return err + } if bootstrapTokenRaw == "" { - return ErrBootstrapTokenNotProvided + return ErrEmptyBootstrapTokenProvided } bootstrapToken, err := bootstraptoken.NewFromString(bootstrapTokenRaw) if err != nil { @@ -110,6 +122,27 @@ func runWorker(cmd *cobra.Command, args []string) (err error) { return workerInstance.Run(cmd.Context()) } +func readBootstrapToken() (string, error) { + if bootstrapTokenRaw != "" && bootstrapTokenStdin { + return "", fmt.Errorf("--bootstrap-token and --bootstrap-token-stdin are mutually exclusive") + } + + if bootstrapTokenRaw != "" { + return bootstrapTokenRaw, nil + } + + if bootstrapTokenStdin { + stdinBytes, err := io.ReadAll(os.Stdin) + if err != nil { + return "", fmt.Errorf("failed to read the bootstrap token from the standard input: %w", err) + } + + return strings.TrimSuffix(string(stdinBytes), "\n"), nil + } + + return "", ErrNoBootstrapTokenProvided +} + func createLogger() (*zap.Logger, error) { level := zap.InfoLevel if debug {