| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- //
- // Use and distribution licensed under the Apache license version 2.
- //
- // See the COPYING file in the root project directory for full text.
- //
- package option
- import (
- "io"
- "io/ioutil"
- "log"
- "os"
- )
- const (
- DefaultChroot = "/"
- )
- const (
- envKeyChroot = "GHW_CHROOT"
- envKeyDisableWarnings = "GHW_DISABLE_WARNINGS"
- envKeyDisableTools = "GHW_DISABLE_TOOLS"
- envKeySnapshotPath = "GHW_SNAPSHOT_PATH"
- envKeySnapshotRoot = "GHW_SNAPSHOT_ROOT"
- envKeySnapshotExclusive = "GHW_SNAPSHOT_EXCLUSIVE"
- envKeySnapshotPreserve = "GHW_SNAPSHOT_PRESERVE"
- )
- // Alerter emits warnings about undesirable but recoverable errors.
- // We use a subset of a logger interface only to emit warnings, and
- // `Warninger` sounded ugly.
- type Alerter interface {
- Printf(format string, v ...interface{})
- }
- var (
- NullAlerter = log.New(ioutil.Discard, "", 0)
- )
- // EnvOrDefaultAlerter returns the default instance ghw will use to emit
- // its warnings. ghw will emit warnings to stderr by default unless the
- // environs variable GHW_DISABLE_WARNINGS is specified; in the latter case
- // all warning will be suppressed.
- func EnvOrDefaultAlerter() Alerter {
- var dest io.Writer
- if _, exists := os.LookupEnv(envKeyDisableWarnings); exists {
- dest = ioutil.Discard
- } else {
- // default
- dest = os.Stderr
- }
- return log.New(dest, "", 0)
- }
- // EnvOrDefaultChroot returns the value of the GHW_CHROOT environs variable or
- // the default value of "/" if not set
- func EnvOrDefaultChroot() string {
- // Grab options from the environs by default
- if val, exists := os.LookupEnv(envKeyChroot); exists {
- return val
- }
- return DefaultChroot
- }
- // EnvOrDefaultSnapshotPath returns the value of the GHW_SNAPSHOT_PATH environs variable
- // or the default value of "" (disable snapshot consumption) if not set
- func EnvOrDefaultSnapshotPath() string {
- if val, exists := os.LookupEnv(envKeySnapshotPath); exists {
- return val
- }
- return "" // default is no snapshot
- }
- // EnvOrDefaultSnapshotRoot returns the value of the the GHW_SNAPSHOT_ROOT environs variable
- // or the default value of "" (self-manage the snapshot unpack directory, if relevant) if not set
- func EnvOrDefaultSnapshotRoot() string {
- if val, exists := os.LookupEnv(envKeySnapshotRoot); exists {
- return val
- }
- return "" // default is to self-manage the snapshot directory
- }
- // EnvOrDefaultSnapshotExclusive returns the value of the GHW_SNAPSHOT_EXCLUSIVE environs variable
- // or the default value of false if not set
- func EnvOrDefaultSnapshotExclusive() bool {
- if _, exists := os.LookupEnv(envKeySnapshotExclusive); exists {
- return true
- }
- return false
- }
- // EnvOrDefaultSnapshotPreserve returns the value of the GHW_SNAPSHOT_PRESERVE environs variable
- // or the default value of false if not set
- func EnvOrDefaultSnapshotPreserve() bool {
- if _, exists := os.LookupEnv(envKeySnapshotPreserve); exists {
- return true
- }
- return false
- }
- // EnvOrDefaultTools return true if ghw should use external tools to augment the data collected
- // from sysfs. Most users want to do this most of time, so this is enabled by default.
- // Users consuming snapshots may want to opt out, thus they can set the GHW_DISABLE_TOOLS
- // environs variable to any value to make ghw skip calling external tools even if they are available.
- func EnvOrDefaultTools() bool {
- if _, exists := os.LookupEnv(envKeyDisableTools); exists {
- return false
- }
- return true
- }
- // Option is used to represent optionally-configured settings. Each field is a
- // pointer to some concrete value so that we can tell when something has been
- // set or left unset.
- type Option struct {
- // To facilitate querying of sysfs filesystems that are bind-mounted to a
- // non-default root mountpoint, we allow users to set the GHW_CHROOT environ
- // variable to an alternate mountpoint. For instance, assume that the user of
- // ghw is a Golang binary being executed from an application container that has
- // certain host filesystems bind-mounted into the container at /host. The user
- // would ensure the GHW_CHROOT environ variable is set to "/host" and ghw will
- // build its paths from that location instead of /
- Chroot *string
- // Snapshot contains options for handling ghw snapshots
- Snapshot *SnapshotOptions
- // Alerter contains the target for ghw warnings
- Alerter Alerter
- // EnableTools optionally request ghw to not call any external program to learn
- // about the hardware. The default is to use such tools if available.
- EnableTools *bool
- // PathOverrides optionally allows to override the default paths ghw uses internally
- // to learn about the system resources.
- PathOverrides PathOverrides
- // Context may contain a pointer to a `Context` struct that is constructed
- // during a call to the `context.WithContext` function. Only used internally.
- // This is an interface to get around recursive package import issues.
- Context interface{}
- }
- // SnapshotOptions contains options for handling of ghw snapshots
- type SnapshotOptions struct {
- // Path allows users to specify a snapshot (captured using ghw-snapshot) to be
- // automatically consumed. Users need to supply the path of the snapshot, and
- // ghw will take care of unpacking it on a temporary directory.
- // Set the environment variable "GHW_SNAPSHOT_PRESERVE" to make ghw skip the cleanup
- // stage and keep the unpacked snapshot in the temporary directory.
- Path string
- // Root is the directory on which the snapshot must be unpacked. This allows
- // the users to manage their snapshot directory instead of ghw doing that on
- // their behalf. Relevant only if SnapshotPath is given.
- Root *string
- // Exclusive tells ghw if the given directory should be considered of exclusive
- // usage of ghw or not If the user provides a Root. If the flag is set, ghw will
- // unpack the snapshot in the given SnapshotRoot iff the directory is empty; otherwise
- // any existing content will be left untouched and the unpack stage will exit silently.
- // As additional side effect, give both this option and SnapshotRoot to make each
- // context try to unpack the snapshot only once.
- Exclusive bool
- }
- // WithChroot allows to override the root directory ghw uses.
- func WithChroot(dir string) *Option {
- return &Option{Chroot: &dir}
- }
- // WithSnapshot sets snapshot-processing options for a ghw run
- func WithSnapshot(opts SnapshotOptions) *Option {
- return &Option{
- Snapshot: &opts,
- }
- }
- // WithAlerter sets alerting options for ghw
- func WithAlerter(alerter Alerter) *Option {
- return &Option{
- Alerter: alerter,
- }
- }
- // WithNullAlerter sets No-op alerting options for ghw
- func WithNullAlerter() *Option {
- return &Option{
- Alerter: NullAlerter,
- }
- }
- // WithDisableTools sets enables or prohibts ghw to call external tools to discover hardware capabilities.
- func WithDisableTools() *Option {
- false_ := false
- return &Option{EnableTools: &false_}
- }
- // PathOverrides is a map, keyed by the string name of a mount path, of override paths
- type PathOverrides map[string]string
- // WithPathOverrides supplies path-specific overrides for the context
- func WithPathOverrides(overrides PathOverrides) *Option {
- return &Option{
- PathOverrides: overrides,
- }
- }
- // There is intentionally no Option related to GHW_SNAPSHOT_PRESERVE because we see that as
- // a debug/troubleshoot aid more something users wants to do regularly.
- // Hence we allow that only via the environment variable for the time being.
- // Merge accepts one or more Options and merges them together, returning the
- // merged Option
- func Merge(opts ...*Option) *Option {
- merged := &Option{}
- for _, opt := range opts {
- if opt.Chroot != nil {
- merged.Chroot = opt.Chroot
- }
- if opt.Snapshot != nil {
- merged.Snapshot = opt.Snapshot
- }
- if opt.Alerter != nil {
- merged.Alerter = opt.Alerter
- }
- if opt.EnableTools != nil {
- merged.EnableTools = opt.EnableTools
- }
- // intentionally only programmatically
- if opt.PathOverrides != nil {
- merged.PathOverrides = opt.PathOverrides
- }
- if opt.Context != nil {
- merged.Context = opt.Context
- }
- }
- // Set the default value if missing from mergeOpts
- if merged.Chroot == nil {
- chroot := EnvOrDefaultChroot()
- merged.Chroot = &chroot
- }
- if merged.Alerter == nil {
- merged.Alerter = EnvOrDefaultAlerter()
- }
- if merged.Snapshot == nil {
- snapRoot := EnvOrDefaultSnapshotRoot()
- merged.Snapshot = &SnapshotOptions{
- Path: EnvOrDefaultSnapshotPath(),
- Root: &snapRoot,
- Exclusive: EnvOrDefaultSnapshotExclusive(),
- }
- }
- if merged.EnableTools == nil {
- enabled := EnvOrDefaultTools()
- merged.EnableTools = &enabled
- }
- return merged
- }
|