Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurability via a config file and command line flags #169

Merged
merged 2 commits into from
Oct 10, 2018
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
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ RUN glide install --strip-vendor
RUN go install \
-ldflags "-s -w -X main.version=$NFD_VERSION" \
github.com/kubernetes-incubator/node-feature-discovery
RUN install -D -m644 node-feature-discovery.conf.example /etc/kubernetes/node-feature-discovery/node-feature-discovery.conf

RUN go test .

Expand All @@ -35,6 +36,7 @@ FROM debian:stretch-slim

COPY --from=builder /usr/local/bin /usr/local/bin
COPY --from=builder /usr/local/lib /usr/local/lib
COPY --from=builder /etc/kubernetes/node-feature-discovery /etc/kubernetes/node-feature-discovery
RUN ldconfig
COPY --from=builder /go/bin/node-feature-discovery /usr/bin/node-feature-discovery

Expand Down
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,21 @@ node-feature-discovery.

Usage:
node-feature-discovery [--no-publish] [--sources=<sources>] [--label-whitelist=<pattern>]
[--oneshot | --sleep-interval=<seconds>]
[--oneshot | --sleep-interval=<seconds>] [--config=<path>]
[--options=<config>]
node-feature-discovery -h | --help
node-feature-discovery --version

Options:
-h --help Show this screen.
--version Output version and exit.
--config=<path> Config file to use.
[Default: /etc/kubernetes/node-feature-discovery/node-feature-discovery.conf]
--options=<config> Specify config options from command line. Config
options are specified in the same format as in the
config file (i.e. json or yaml). These options
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,memory,network,pstate,rdt,selinux,storage]
--no-publish Do not publish discovered features to the
Expand Down Expand Up @@ -231,6 +239,50 @@ For example, if some node is tainted NoSchedule or fails to start a job for some

[![asciicast](https://asciinema.org/a/11wir751y89617oemwnsgli4a.png)](https://asciinema.org/a/11wir751y89617oemwnsgli4a)

### Configuration options

NFD supports a configuration file. The default location is
`/etc/kubernetes/node-feature-discovery/node-feature-discovery.conf`, but,
this can be changed by specifying the`--config` command line flag. The file is
read inside the Docker image, and thus, Volumes and VolumeMounts are needed to
make your configuration available for NFD. The preferred method is to use a
ConfigMap.
For example, create a config map using the example config as a template:
```
cp node-feature-discovery.conf.example node-feature-discovery.conf
vim node-feature-discovery.conf # edit the configuration
kubectl create configmap node-feature-discovery-config --from-file=node-feature-discovery.conf
```
Then, configure Volumes and VolumeMounts in the Pod spec (just the relevant
snippets shown below):
```
...
containers:
volumeMounts:
- name: node-feature-discovery-config
mountPath: "/etc/kubernetes/node-feature-discovery/"
...
volumes:
- name: node-feature-discovery-config
configMap:
name: node-feature-discovery-config
...
```
You could also use other types of volumes, of course. That is, hostPath if
different config for different nodes would be required, for example.

The (empty-by-default)
[example config](https://github.com/kubernetes-incubator/node-feature-discovery/blob/master/node-feature-discovery.conf.example)
is used as a config in the NFD Docker image. Thus, this can be used as a default
configuration in custom-built images.

Configuration options can also be specified via the `--options` command line
flag, in which case no mounts need to be used. The same format as in the config
file must be used, i.e. JSON (or YAML).

Configuration options specified from the command line will override those read
from the config file.

## Building from source

Download the source code.
Expand Down
52 changes: 51 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package main

import (
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
"time"

"github.com/docopt/docopt-go"
"github.com/ghodss/yaml"
"github.com/kubernetes-incubator/node-feature-discovery/source"
"github.com/kubernetes-incubator/node-feature-discovery/source/cpuid"
"github.com/kubernetes-incubator/node-feature-discovery/source/fake"
Expand Down Expand Up @@ -48,6 +50,14 @@ var (
stderrLogger = log.New(os.Stderr, "", log.LstdFlags)
)

// Global config
type NFDConfig struct {
Sources struct {
} `json:"sources,omitempty"`
}

var config = NFDConfig{}

// Labels are a Kubernetes representation of discovered features.
type Labels map[string]string

Expand Down Expand Up @@ -76,7 +86,9 @@ type APIHelpers interface {
// Command line arguments
type Args struct {
labelWhiteList string
configFile string
noPublish bool
options string
oneshot bool
sleepInterval time.Duration
sources []string
Expand All @@ -91,6 +103,12 @@ func main() {
// Parse command-line arguments.
args := argsParse(nil)

// Parse config
err := configParse(args.configFile, args.options)
if err != nil {
stderrLogger.Print(err)
}

// Configure the parameters for feature discovery.
enabledSources, labelWhiteList, err := configureParameters(args.sources, args.labelWhiteList)
if err != nil {
Expand Down Expand Up @@ -129,13 +147,21 @@ func argsParse(argv []string) (args Args) {

Usage:
%s [--no-publish] [--sources=<sources>] [--label-whitelist=<pattern>]
[--oneshot | --sleep-interval=<seconds>]
[--oneshot | --sleep-interval=<seconds>] [--config=<path>]
[--options=<config>]
%s -h | --help
%s --version

Options:
-h --help Show this screen.
--version Output version and exit.
--config=<path> Config file to use.
[Default: /etc/kubernetes/node-feature-discovery/node-feature-discovery.conf]
--options=<config> Specify config options from command line. Config
options are specified in the same format as in the
config file (i.e. json or yaml). These options
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,memory,network,pstate,rdt,selinux,storage]
--no-publish Do not publish discovered features to the
Expand All @@ -157,7 +183,9 @@ func argsParse(argv []string) (args Args) {

// Parse argument values as usable types.
var err error
args.configFile = arguments["--config"].(string)
args.noPublish = arguments["--no-publish"].(bool)
args.options = arguments["--options"].(string)
args.sources = strings.Split(arguments["--sources"].(string), ",")
args.labelWhiteList = arguments["--label-whitelist"].(string)
args.oneshot = arguments["--oneshot"].(bool)
Expand All @@ -175,6 +203,28 @@ func argsParse(argv []string) (args Args) {
return args
}

// Parse configuration options
func configParse(filepath string, overrides string) error {
data, err := ioutil.ReadFile(filepath)
if err != nil {
return fmt.Errorf("Failed to read config file: %s", err)
}

// Read config file
err = yaml.Unmarshal(data, &config)
if err != nil {
return fmt.Errorf("Failed to parse config file: %s", err)
}

// Parse config overrides
err = yaml.Unmarshal([]byte(overrides), &config)
if err != nil {
return fmt.Errorf("Failed to parse --options: %s", err)
}

return nil
}

// configureParameters returns all the variables required to perform feature
// discovery based on command line arguments.
func configureParameters(sourcesWhiteList []string, labelWhiteListStr string) (enabledSources []source.FeatureSource, labelWhiteList *regexp.Regexp, err error) {
Expand Down
28 changes: 28 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"fmt"
"io/ioutil"
"os"
"regexp"
"testing"
"time"
Expand Down Expand Up @@ -174,6 +176,32 @@ func TestArgsParse(t *testing.T) {
})
}

func TestConfigParse(t *testing.T) {
Convey("When parsing configuration file", t, func() {
Convey("When non-accessible file is given", func() {
err := configParse("non-existing-file", "")

Convey("Should return error", func() {
So(err, ShouldNotBeNil)
})
})
// Create a temporary config file
f, err := ioutil.TempFile("", "nfd-test-")
defer os.Remove(f.Name())
So(err, ShouldBeNil)
f.WriteString(`sources:`)
f.Close()

Convey("When proper config file is given", func() {
err := configParse(f.Name(), "")

Convey("Should return error", func() {
So(err, ShouldBeNil)
})
})
})
}

func TestConfigureParameters(t *testing.T) {
Convey("When configuring parameters for node feature discovery", t, func() {

Expand Down
1 change: 1 addition & 0 deletions node-feature-discovery.conf.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#sources: