Files
zrok/agent/commandBuilder.go

185 lines
5.3 KiB
Go

package agent
import (
"fmt"
"os"
)
// CommandBuilder provides a fluent interface for building zrok commands
// eliminating repetitive command construction patterns across the agent
type CommandBuilder struct {
executable string
args []string
}
// newCommandBuilder creates a new command builder with the base executable
func newCommandBuilder(subcommands ...string) *CommandBuilder {
args := []string{os.Args[0]}
args = append(args, subcommands...)
return &CommandBuilder{
executable: os.Args[0],
args: args,
}
}
// NewSharePublicCommand creates a command builder for public share commands
func NewSharePublicCommand() *CommandBuilder {
return newCommandBuilder("share", "public", "--subordinate")
}
// NewSharePrivateCommand creates a command builder for private share commands
func NewSharePrivateCommand() *CommandBuilder {
return newCommandBuilder("share", "private", "--subordinate")
}
// NewAccessPrivateCommand creates a command builder for private access commands
func NewAccessPrivateCommand() *CommandBuilder {
return newCommandBuilder("access", "private", "--subordinate")
}
// BackendMode adds the backend mode option (-b)
func (cb *CommandBuilder) BackendMode(mode string) *CommandBuilder {
if mode != "" {
cb.args = append(cb.args, "-b", mode)
}
return cb
}
// Target adds the target as the final argument
func (cb *CommandBuilder) Target(target string) *CommandBuilder {
if target != "" {
cb.args = append(cb.args, target)
}
return cb
}
// ShareToken adds the --share-token option for private shares
func (cb *CommandBuilder) ShareToken(token string) *CommandBuilder {
if token != "" {
cb.args = append(cb.args, "--share-token", token)
}
return cb
}
// BindAddress adds the bind address as a positional argument for access commands
func (cb *CommandBuilder) BindAddress(address string) *CommandBuilder {
if address != "" {
cb.args = append(cb.args, "-b", address)
}
return cb
}
// AddFlag adds a simple flag (e.g., --insecure, --open)
func (cb *CommandBuilder) AddFlag(flag string) *CommandBuilder {
cb.args = append(cb.args, flag)
return cb
}
// AddOption adds an option with a value (e.g., --option value)
func (cb *CommandBuilder) AddOption(option, value string) *CommandBuilder {
if value != "" {
cb.args = append(cb.args, option, value)
}
return cb
}
// AddConditionalFlag adds a flag only if the condition is true
func (cb *CommandBuilder) AddConditionalFlag(condition bool, flag string) *CommandBuilder {
if condition {
cb.args = append(cb.args, flag)
}
return cb
}
// AddMultipleOptions adds multiple instances of the same option
func (cb *CommandBuilder) AddMultipleOptions(option string, values []string) *CommandBuilder {
for _, value := range values {
if value != "" {
cb.args = append(cb.args, option, value)
}
}
return cb
}
// BasicAuth adds multiple --basic-auth options
func (cb *CommandBuilder) BasicAuth(auths []string) *CommandBuilder {
return cb.AddMultipleOptions("--basic-auth", auths)
}
// NameSelections adds multiple --name-selection options with namespace:name format
func (cb *CommandBuilder) NameSelections(selections []NameSelection) *CommandBuilder {
for _, nss := range selections {
nssStr := nss.NamespaceToken
if nss.Name != "" {
nssStr += ":" + nss.Name
}
if nssStr != "" {
cb.args = append(cb.args, "--name-selection", nssStr)
}
}
return cb
}
// OauthProvider adds the --oauth-provider option
func (cb *CommandBuilder) OauthProvider(provider string) *CommandBuilder {
return cb.AddOption("--oauth-provider", provider)
}
// OauthEmailDomains adds multiple --oauth-email-domain options
func (cb *CommandBuilder) OauthEmailDomains(domains []string) *CommandBuilder {
return cb.AddMultipleOptions("--oauth-email-domain", domains)
}
// OauthRefreshInterval adds the --oauth-refresh-interval option
func (cb *CommandBuilder) OauthRefreshInterval(interval string) *CommandBuilder {
if interval != "3h0m0s" {
return cb.AddOption("--oauth-refresh-interval", interval)
}
return cb
}
// AccessGrants adds multiple --access-grant options
func (cb *CommandBuilder) AccessGrants(grants []string) *CommandBuilder {
return cb.AddMultipleOptions("--access-grant", grants)
}
// Insecure adds the --insecure flag if true
func (cb *CommandBuilder) Insecure(insecure bool) *CommandBuilder {
return cb.AddConditionalFlag(insecure, "--insecure")
}
// Open adds the --open flag if true (note: inverted logic from Closed)
func (cb *CommandBuilder) Open(open bool) *CommandBuilder {
return cb.AddConditionalFlag(open, "--open")
}
// AutoMode adds auto mode options for access commands
func (cb *CommandBuilder) AutoMode(auto bool, address string, startPort, endPort int) *CommandBuilder {
if auto {
cb.args = append(cb.args, "--auto")
if address != "" {
cb.args = append(cb.args, "--auto-address", address)
}
if startPort > 0 {
cb.args = append(cb.args, "--auto-start-port", fmt.Sprintf("%d", startPort))
}
if endPort > 0 {
cb.args = append(cb.args, "--auto-end-port", fmt.Sprintf("%d", endPort))
}
}
return cb
}
// Build returns the final command as a string slice
func (cb *CommandBuilder) Build() []string {
// return a copy to prevent external modification
result := make([]string, len(cb.args))
copy(result, cb.args)
return result
}
// String returns a string representation of the command for debugging
func (cb *CommandBuilder) String() string {
return fmt.Sprintf("%v", cb.args)
}