Skip to content

Commit

Permalink
support per-device auth config
Browse files Browse the repository at this point in the history
  • Loading branch information
jcodybaker committed Feb 19, 2024
1 parent 69d4322 commit 5ee74b6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 21 deletions.
50 changes: 31 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Use "shellyctl [command] --help" for more information about a command.

### Prometheus Server
```
host a prometheus metrics exporter for shelly devices
Host a prometheus metrics exporter for shelly devices
Usage:
shellyctl prometheus [flags]
Expand All @@ -57,26 +57,38 @@ Aliases:
prometheus, prom
Flags:
--bind-addr ip local ip address to bind the metrics server to (default ::)
--bind-port uint16 port to bind the metrics server (default 8080)
--device-timeout duration set the maximum time allowed for a device to respond to it probe. (default 5s)
--device-ttl duration time-to-live for discovered devices in long-lived commands like the prometheus server. (default 5m0s)
--discovery-concurrency int number of concurrent (default 5)
-h, --help help for prometheus
--host http host address of a single device. IP, DNS, or mDNS/BonJour addresses are accepted. If a URL scheme is provided, only http and `https` are supported. mDNS names must be within the zone specified by the `--mdns-zone` flag (default `local`).
--mdns-interface string if specified, search only the specified network interface for devices.
--mdns-search if true, devices will be discovered via mDNS
--mdns-service string mDNS service to search (default "_shelly._tcp")
--mdns-zone string mDNS zone to search (default "local")
--prefer-ip-version 4 prefer ip version (4 or `6`)
--probe-concurrency int set the number of concurrent probes which will be made to service a metrics request. (default 10)
--prometheus-namespace string set the namespace string to use for prometheus metric names. (default "shelly")
--prometheus-subsystem string set the subsystem section of the prometheus metric names. (default "status")
--search-timeout duration timeout for devices to respond to the mDNS discovery query. (default 1s)
--skip-failed-hosts continue with other hosts in the face errors.
--auth string password to use for authenticating with devices.
--bind-addr ip local ip address to bind the metrics server to (default ::)
--bind-port uint16 port to bind the metrics server (default 8080)
--ble-device stringArray MAC address of a single bluetooth low-energy device. May be specified multiple times to work with multiple devices.
--ble-search if true, devices will be discovered via Bluetooth Low-Energy
--device-timeout duration set the maximum time allowed for a device to respond to it probe. (default 5s)
--device-ttl duration time-to-live for discovered devices in long-lived commands like the prometheus server. (default 5m0s)
--discovery-concurrency int number of concurrent (default 5)
-h, --help help for prometheus
--host http host address of a single device. IP, DNS, or mDNS/BonJour addresses are accepted.
If a URL scheme is provided, only http and `https` schemes are supported.
mDNS names must be within the zone specified by the `--mdns-zone` flag (default `local`).
URL formatted auth is supported (ex. `http://admin:[email protected]/`)
--interactive if true prompt for confirmation or passwords.
--mdns-interface string if specified, search only the specified network interface for devices.
--mdns-search if true, devices will be discovered via mDNS
--mdns-service string mDNS service to search (default "_shelly._tcp")
--mdns-zone string mDNS zone to search (default "local")
--prefer-ip-version 4 prefer ip version (4 or `6`)
--probe-concurrency int set the number of concurrent probes which will be made to service a metrics request. (default 10)
--prometheus-namespace string set the namespace string to use for prometheus metric names. (default "shelly")
--prometheus-subsystem string set the subsystem section of the prometheus metric names. (default "status")
--scrape-duration-warning duration sets the value for scrape duration warning. Scrapes which exceed this duration will log a warning generate. Default value 8s is 80% of the 10s default prometheus scrape_timeout. (default 8s)
--search-interactive if true confirm devices discovered in search before proceeding with commands. Defers to --interactive if not explicitly set.
--search-strict-timeout ignore devices which have been found but completed their initial query within the search-timeout (default true)
--search-timeout duration timeout for devices to respond to the mDNS discovery query. (default 1s)
--skip-failed-hosts continue with other hosts in the face errors.
Global Flags:
--log-level string threshold for outputing logs: trace, debug, info, warn, error, fatal, panic (default "warn")
--config string path to config file. format will be determined by extension (.yaml, .json, .toml, .ini valid)
--log-level string threshold for outputing logs: trace, debug, info, warn, error, fatal, panic (default "warn")
-o, --output-format string desired output format: json, min-json, yaml, text, log (default "text")
```

### RPC Command-line
Expand Down
5 changes: 4 additions & 1 deletion cmd/helper_discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ func discoveryFlags(f *pflag.FlagSet, opts discoveryFlagsOptions) {
f.StringArray(
"host",
[]string{},
"host address of a single device. IP, DNS, or mDNS/BonJour addresses are accepted. If a URL scheme is provided, only `http` and `https` are supported. mDNS names must be within the zone specified by the `--mdns-zone` flag (default `local`).")
"host address of a single device. IP, DNS, or mDNS/BonJour addresses are accepted.\n"+
"If a URL scheme is provided, only `http` and `https` schemes are supported.\n"+
"mDNS names must be within the zone specified by the `--mdns-zone` flag (default `local`).\n"+
"URL formatted auth is supported (ex. `http://admin:[email protected]/`)")

f.Bool(
"mdns-search",
Expand Down
27 changes: 26 additions & 1 deletion pkg/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/hashicorp/mdns"
"github.com/jcodybaker/go-shelly"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -88,6 +89,29 @@ func (d *Discoverer) AddDeviceByAddress(ctx context.Context, addr string, opts .
if u.RawQuery != "" {
return nil, errors.New("URI query parameters are not supported")
}
ll := d.logCtx(ctx, "").With().Str("host", u.Host).Logger()
// Default to the global auth callback, but if there's a un/pw on the URL we'll use that.
authCallback := d.authCallback
if u.User != nil {
if pw, ok := u.User.Password(); ok {
if u.User.Username() != "" && u.User.Username() != shelly.DefaultAuthenticationUsername {
ll.Warn().
Str("username", u.User.Username()).
Msg("host URI includes username/password with unsupported username; `" + shelly.DefaultAuthenticationUsername + "` expected")
}
authCallback = func(ctx context.Context, desc string) (string, error) {
return pw, nil
}
} else if u.User.Username() != "" {
// Since only one username is allowed, as a special case we'll treat a URL with only
// a username section (no password) as the password. Ex: `http://[email protected]/`.
pw := u.User.Username()
authCallback = func(ctx context.Context, desc string) (string, error) {
return pw, nil
}
}
u.User = nil
}

if strings.HasSuffix(strings.ToLower(u.Hostname()), "."+d.mdnsZone) {
// TODO(cbaker) - URI is mDNS, we want to resolve it to an IP.
Expand All @@ -97,8 +121,9 @@ func (d *Discoverer) AddDeviceByAddress(ctx context.Context, addr string, opts .
dev := &Device{
uri: u.String(),
source: sourceManual,
authCallback: d.authCallback,
authCallback: authCallback,
}

if err = dev.resolveSpecs(ctx); err != nil {
return nil, err
}
Expand Down

0 comments on commit 5ee74b6

Please sign in to comment.