Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions cmd/humioctl/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import (
)

type login struct {
address string
token string
username string
caCertificate string
insecure bool
address string
token string
username string
caCertificate string
insecure bool
unixSocketProxy string
}

// usersCmd represents the users command
Expand Down
22 changes: 12 additions & 10 deletions cmd/humioctl/profiles_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,25 @@ func addAccount(newName string, profile *login) {
}

profiles[newName] = map[string]interface{}{
viperkey.Address: profile.address,
viperkey.Token: profile.token,
viperkey.Username: profile.username,
viperkey.CACertificate: profile.caCertificate,
viperkey.Insecure: profile.insecure,
viperkey.Address: profile.address,
viperkey.Token: profile.token,
viperkey.Username: profile.username,
viperkey.CACertificate: profile.caCertificate,
viperkey.Insecure: profile.insecure,
viperkey.UnixSocketProxy: profile.unixSocketProxy,
}

viper.Set(viperkey.Profiles, profiles)
}

func mapToLogin(data interface{}) *login {
return &login{
address: getMapKeyString(data, viperkey.Address),
username: getMapKeyString(data, viperkey.Username),
token: getMapKeyString(data, viperkey.Token),
caCertificate: getMapKeyString(data, viperkey.CACertificate),
insecure: getMapKeyBool(data, viperkey.Insecure),
address: getMapKeyString(data, viperkey.Address),
username: getMapKeyString(data, viperkey.Username),
token: getMapKeyString(data, viperkey.Token),
caCertificate: getMapKeyString(data, viperkey.CACertificate),
insecure: getMapKeyBool(data, viperkey.Insecure),
unixSocketProxy: getMapKeyString(data, viperkey.UnixSocketProxy),
}
}

Expand Down
10 changes: 6 additions & 4 deletions cmd/humioctl/profiles_set_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func newProfilesSetDefaultCmd() *cobra.Command {
viper.Set(viperkey.Token, profile.token)
viper.Set(viperkey.CACertificateFile, profile.caCertificate)
viper.Set(viperkey.Insecure, profile.insecure)
viper.Set(viperkey.UnixSocketProxy, profile.unixSocketProxy)

err = saveConfig()
exitOnError(cmd, err, "Error saving config")
Expand All @@ -44,10 +45,11 @@ func loadProfile(profileName string) (*login, error) {
insecureFromProfileData, _ := profileData[viperkey.Insecure].(bool) // false if not found in map, or type isn't bool

profile := login{
address: getMapKeyString(profileData, viperkey.Address),
token: getMapKeyString(profileData, viperkey.Token),
caCertificate: getMapKeyString(profileData, viperkey.CACertificate),
insecure: insecureFromProfileData,
address: getMapKeyString(profileData, viperkey.Address),
token: getMapKeyString(profileData, viperkey.Token),
caCertificate: getMapKeyString(profileData, viperkey.CACertificate),
insecure: insecureFromProfileData,
unixSocketProxy: getMapKeyString(profileData, viperkey.UnixSocketProxy),
}

return &profile, nil
Expand Down
8 changes: 7 additions & 1 deletion cmd/humioctl/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"github.com/spf13/viper"
)

var cfgFile, tokenFile, token, address, caCertificateFile, profileFlag, proxyOrganization string
var cfgFile, tokenFile, token, address, caCertificateFile, profileFlag, proxyOrganization, unixSocketProxy string
var insecure bool

var printVersion bool
Expand Down Expand Up @@ -96,6 +96,7 @@ Common Management Commands:
rootCmd.PersistentFlags().StringVar(&caCertificateFile, "ca-certificate-file", "", "File path to a file containing the CA certificate in PEM format. Overrides the value in your config file.")
rootCmd.PersistentFlags().BoolVar(&insecure, "insecure", false, "By default, all encrypted connections will verify that the hostname in the TLS certificate matches the name from the URL. Set this to true to ignore hostname validation.")
rootCmd.PersistentFlags().StringVar(&proxyOrganization, "proxy-organization", "", "Commands are executed in the specified organization.")
rootCmd.PersistentFlags().StringVar(&unixSocketProxy, "unix-socket-proxy", "", "Path to a unix socket to use as an HTTP proxy.")
rootCmd.PersistentFlags().String("format", "", "Change output format of commands, if supported. Valid formats: json")

_ = viper.BindPFlag(viperkey.Address, rootCmd.PersistentFlags().Lookup("address"))
Expand All @@ -104,6 +105,7 @@ Common Management Commands:
_ = viper.BindPFlag(viperkey.CACertificateFile, rootCmd.PersistentFlags().Lookup("ca-certificate-file"))
_ = viper.BindPFlag(viperkey.Insecure, rootCmd.PersistentFlags().Lookup("insecure"))
_ = viper.BindPFlag(viperkey.ProxyOrganization, rootCmd.PersistentFlags().Lookup("proxy-organization"))
_ = viper.BindPFlag(viperkey.UnixSocketProxy, rootCmd.PersistentFlags().Lookup("unix-socket-proxy"))

rootCmd.Flags().BoolVarP(&printVersion, "version", "v", false, "Print the client version")

Expand Down Expand Up @@ -182,6 +184,9 @@ func initConfig() {
if !insecure {
viper.Set(viperkey.Insecure, profile.insecure)
}
if unixSocketProxy == "" {
viper.Set(viperkey.UnixSocketProxy, profile.unixSocketProxy)
}
}

if tokenFile != "" {
Expand Down Expand Up @@ -223,6 +228,7 @@ func newApiClientE(opts ...func(config *api.Config)) (*api.Client, error) {
config.CACertificatePEM = viper.GetString(viperkey.CACertificate)
config.Insecure = viper.GetBool(viperkey.Insecure)
config.ProxyOrganization = viper.GetString(viperkey.ProxyOrganization)
config.UnixSocketProxy = viper.GetString(viperkey.UnixSocketProxy)
config.UserAgent = fmt.Sprintf("humioctl/%s (%s on %s)", version, commit, date)

for _, opt := range opts {
Expand Down
1 change: 1 addition & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ type Config struct {
CACertificatePEM string
Insecure bool
ProxyOrganization string
UnixSocketProxy string
DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
}

Expand Down
21 changes: 21 additions & 0 deletions internal/api/httpclient.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package api

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"net/http"
"time"
Expand All @@ -16,6 +18,20 @@ type headerTransport struct {
headers map[string]string
}

// newUnixSocketProxyDialer creates a dialer that connects through a unix socket proxy
func newUnixSocketProxyDialer(socketPath string, fallbackDialer func(ctx context.Context, network, addr string) (net.Conn, error)) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
// Connect directly to the unix socket
// The proxy is expected to handle the connection transparently
conn, err := net.Dial("unix", socketPath)
if err != nil {
return nil, fmt.Errorf("failed to connect to unix socket proxy: %w", err)
}

return conn, nil
}
}

func NewHttpTransport(config Config) *http.Transport {
dialContext := config.DialContext
if dialContext == nil {
Expand All @@ -26,6 +42,11 @@ func NewHttpTransport(config Config) *http.Transport {
}).DialContext
}

// If a unix socket proxy is specified, wrap the dialer to use it
if config.UnixSocketProxy != "" {
dialContext = newUnixSocketProxyDialer(config.UnixSocketProxy, dialContext)
}

if config.Insecure {
// Return HTTP transport where we skip certificate verification
return &http.Transport{
Expand Down
1 change: 1 addition & 0 deletions internal/viperkey/viperkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ const (
Username = "username"
Profiles = "profiles"
ProxyOrganization = "proxy-organization"
UnixSocketProxy = "unix-socket-proxy"
)