1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 18:57:10 +00:00

Refactored feature sources.

- Added interface FeatureSource, moved cpuid, rdt and pstate
  discovery logic into implementations.
- Updated logging output to make it more machine-readable
  (one feature, in label-format, per line).
- Normalized label names (derived from the underlying feature source).
- Added makefile.
- Added command-line argument parsing and proper CLI documentation.
- Added ability to filter the enabled feature sources: cpuid,rdt,pstate.
- Added ability to print the software version and exit.
- Added ability to print the CLI help.
- Updated README.
- Updated dep versions.
- Added -s -w to ldflags.
- Output version label along with discovered feature labels.
- Added sources section to README.
- Normalized README link for pstate
This commit is contained in:
Connor Doyle 2016-07-19 15:35:42 -07:00
parent 7788f2ebea
commit e79ffd2c2a
8 changed files with 664 additions and 117 deletions

5
.gitignore vendored
View file

@ -1,2 +1,7 @@
dbi-iafeature-discovery
dbi-iafeature-discovery-job.json
vendor/
intel-cmt-cat/
rdt-discovery/l2-alloc-discovery
rdt-discovery/l3-alloc-discovery
rdt-discovery/mon-discovery

View file

@ -22,7 +22,7 @@ RUN cd rdt-discovery; make
RUN go get github.com/Masterminds/glide
RUN glide install
RUN go install \
-ldflags "-X main.version=`git describe --tags --dirty --always`" \
-ldflags "-s -w -X main.version=`git describe --tags --dirty --always`" \
github.com/intelsdi-x/dbi-iafeature-discovery
ENTRYPOINT /go/bin/dbi-iafeature-discovery
ENTRYPOINT ["/go/bin/dbi-iafeature-discovery"]

13
Makefile Normal file
View file

@ -0,0 +1,13 @@
.PHONY: all
DOCKER_REGISTRY_USER := intelsdi
DOCKER_IMAGE_NAME := nodelabels
VERSION := $(shell git describe --tags --dirty --always)
all: docker
# To override DOCKER_REGISTRY_USER use the -e option as follows:
# DOCKER_REGISTRY_USER=<my-username> make docker -e
docker:
docker build -t $(DOCKER_REGISTRY_USER)/$(DOCKER_IMAGE_NAME):$(VERSION) ./

View file

@ -12,10 +12,36 @@
## Overview
This software enables Intel Architecture (IA) feature discovery for Kubernetes.
It detects CPU features available on each node in a Kubernetes cluster, such as
Intel [Resource Director Technology][intel-rdt] and advertises those
features using node labels.
This software enables node feature discovery for Kubernetes. It detects
hardware features available on each node in a Kubernetes cluster, and advertises
those features using node labels.
### Feature sources
The current set of feature sources are the following:
- [CPUID](http://man7.org/linux/man-pages/man4/cpuid.4.html) for x86 CPU details
- [Intel Resource Director Technology][intel-rdt]
- [Intel P-State driver][intel-pstate]
The `--sources` flag controls which sources to use for discovery.
### Command line interface
```
dbi-iafeature-discovery.
Usage:
dbi-iafeature-discovery [--no-publish --sources=<sources>]
dbi-iafeature-discovery -h | --help
dbi-iafeature-discovery --version
Options:
-h --help Show this screen.
--version Output version and exit.
--sources=<sources> Comma separated list of feature sources. [Default: cpuid,rdt,pstate]
--no-publish Do not publish discovered features to the cluster-local Kubernetes API server.
```
### Intel Resource Director Technology (RDT) Features
@ -41,23 +67,26 @@ features using node labels.
The published node labels encode a few pieces of information:
- A "namespace" to denote vendor-specific information
(`node.alpha.intel.com`).
- A "namespace" to denote vendor-specific information (`node.alpha.intel.com`).
- The version of this discovery code that wrote the label, for example
`"node.alpha.intel.com/dbi-iafeature-discovery.version": "v0.1.0"`.
The value of this label corresponds to the output from
`git describe --tags --dirty --always`.
- The relevant hardware component each label describes (e.g. `cpu`).
- The relevant information source for each label (e.g. `cpuid`).
- The name of the discovered feature as it appears in the underlying
source, mostly `cpuid` (e.g. `AESNI`).
_Note: only features that are available on a given node are labeled, so the
only label value published is the string `"true"`. This feature discovery code
will not add a label with the value `"false"` for features that are not
present._
_Note: only features that are available on a given node are labeled, so
the only label value published for features is the string `"true"`. This
feature discovery code will not add a label with the value `"false"` for
features that are not present._
```
"node.alpha.intel.com/v0.1.0-cpu-<feature-name>": "true"
```json
{
"node.alpha.intel.com/v0.1.0-cpuid-<feature-name>": "true",
"node.alpha.intel.com/v0.1.0-rdt-<feature-name>": "true",
"node.alpha.intel.com/v0.1.0-pstate-<feature-name>": "true"
}
```
### System Requirements
@ -65,7 +94,8 @@ present._
At a minimum, you will need:
1. Linux (x86_64)
1. [kubectl] [kubectl-setup] (properly set up and configured to work with your Kubernetes cluster)
1. [kubectl] [kubectl-setup] (properly set up and configured to work with your
Kubernetes cluster)
1. [Docker] [docker-down] (only required to build and push docker images)
### Usage
@ -78,9 +108,8 @@ repo that demonstrates how to deploy the job to unlabeled nodes.
```
The discovery script will launch a job on each each unlabeled node in the
cluster. When the job runs, it contacts the Kubernetes API server to add
labels to the node to advertise hardware features (initially, from `cpuid` and
RDT).
cluster. When the job runs, it contacts the Kubernetes API server to add labels
to the node to advertise hardware features (initially, from `cpuid` and RDT).
## Building from source
@ -94,13 +123,16 @@ git clone https://github.com/intelsdi-x/dbi-iafeature-discovery
```
cd <project-root>
docker build -t <user-name>/<image-name> .
make
```
**NOTE: To override the `DOCKER_REGISTRY_USER` use the `-e` option as follows:
`DOCKER_REGISTRY_USER=<my-username> make docker -e`**
Push the Docker Image (optional)
```
docker push
docker push <registry-user>/<image-name>:<version>
```
**Change the job spec to use your custom image (optional):**
@ -108,13 +140,12 @@ docker push
To use your published image from the step above instead of the
`intelsdi/nodelabels` image, edit line 40 in the file
[dbi-iafeature-discovery-job.json.template](dbi-iafeature-discovery-job.json.template)
to the new location (`<user>/<image-name>`).
to the new location (`<registry-user>/<image-name>`).
## Targeting Nodes with Specific Features
Nodes with specific features can be targeted using the `nodeSelector` field.
The following example shows how to target the Intel RDT L3 cache allocation
(RDTL3CA) feature.
Nodes with specific features can be targeted using the `nodeSelector` field. The
following example shows how to target nodes with Intel TurboBoost enabled.
```json
{
@ -134,7 +165,7 @@ The following example shows how to target the Intel RDT L3 cache allocation
}
],
"nodeSelector": {
"node.alpha.intel.com/v0.1.0-cpu-RDTL3CA": "true"
"node.alpha.intel.com/v0.1.0-pstate-turbo": "true"
}
}
}
@ -149,9 +180,10 @@ This is open source software released under the [Apache 2.0 License](LICENSE).
<!-- Links -->
[intel-rdt]: http://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html
[docker-down]: https://docs.docker.com/engine/installation/
[golang-down]: https://golang.org/dl/
[gcc-down]: https://gcc.gnu.org/
[intel-pstate]: https://www.kernel.org/doc/Documentation/cpu-freq/intel-pstate.txt
[docker-down]: https://docs.docker.com/engine/installation
[golang-down]: https://golang.org/dl
[gcc-down]: https://gcc.gnu.org
[kubectl-setup]: https://coreos.com/kubernetes/docs/latest/configure-kubectl.html
[balaji-github]: https://github.com/balajismaniam
[node-sel]: http://kubernetes.io/docs/user-guide/node-selection/
[node-sel]: http://kubernetes.io/docs/user-guide/node-selection

336
glide.lock generated Normal file
View file

@ -0,0 +1,336 @@
hash: b3a6656f552e85def420fa859d14f27dc2897209ce315ed25ce9cadeff6fae21
updated: 2016-07-20T00:33:41.257155246-07:00
imports:
- name: github.com/beorn7/perks
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
subpackages:
- quantile
- name: github.com/blang/semver
version: 31b736133b98f26d5e078ec9eb591666edfd091f
- name: github.com/coreos/go-oidc
version: 5cf2aa52da8c574d3aa4458f471ad6ae2240fe6b
subpackages:
- http
- jose
- key
- oauth2
- oidc
- name: github.com/coreos/go-systemd
version: 4484981625c1a6a2ecb40a390fcb6a9bcfee76e3
subpackages:
- activation
- daemon
- dbus
- journal
- unit
- util
- name: github.com/coreos/pkg
version: 7f080b6c11ac2d2347c3cd7521e810207ea1a041
subpackages:
- capnslog
- dlopen
- health
- httputil
- timeutil
- name: github.com/davecgh/go-spew
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
subpackages:
- spew
- name: github.com/docker/distribution
version: cd27f179f2c10c5d300e6d09025b538c475b0d51
subpackages:
- digest
- reference
- name: github.com/docker/docker
version: 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
subpackages:
- pkg/jsonmessage
- pkg/mount
- pkg/stdcopy
- pkg/symlink
- pkg/term
- pkg/term/winconsole
- pkg/timeutils
- pkg/units
- name: github.com/docker/go-units
version: 0bbddae09c5a5419a8c6dcdd7ff90da3d450393b
- name: github.com/docopt/docopt-go
version: 784ddc588536785e7299f7272f39101f7faccc3f
- name: github.com/docopt/docopt.go
version: 784ddc588536785e7299f7272f39101f7faccc3f
- name: github.com/emicklei/go-restful
version: 7c47e2558a0bbbaba9ecab06bc6681e73028a28a
subpackages:
- log
- swagger
- name: github.com/ghodss/yaml
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
- name: github.com/gogo/protobuf
version: 82d16f734d6d871204a3feb1a73cb220cc92574c
subpackages:
- gogoproto
- plugin/defaultcheck
- plugin/description
- plugin/embedcheck
- plugin/enumstringer
- plugin/equal
- plugin/face
- plugin/gostring
- plugin/grpc
- plugin/marshalto
- plugin/oneofcheck
- plugin/populate
- plugin/size
- plugin/stringer
- plugin/testgen
- plugin/union
- plugin/unmarshal
- proto
- protoc-gen-gogo/descriptor
- protoc-gen-gogo/generator
- protoc-gen-gogo/plugin
- sortkeys
- vanity
- vanity/command
- name: github.com/golang/glog
version: 44145f04b68cf362d9c4df2182967c2275eaefed
- name: github.com/golang/protobuf
version: b982704f8bb716bb608144408cff30e15fbde841
subpackages:
- proto
- name: github.com/google/cadvisor
version: 4dbefc9b671b81257973a33211fb12370c1a526e
subpackages:
- api
- cache/memory
- collector
- container
- container/common
- container/docker
- container/libcontainer
- container/raw
- container/rkt
- container/systemd
- devicemapper
- events
- fs
- healthz
- http
- http/mux
- info/v1
- info/v1/test
- info/v2
- machine
- manager
- manager/watcher
- manager/watcher/raw
- manager/watcher/rkt
- metrics
- pages
- pages/static
- storage
- summary
- utils
- utils/cloudinfo
- utils/cpuload
- utils/cpuload/netlink
- utils/docker
- utils/oomparser
- utils/sysfs
- utils/sysinfo
- utils/tail
- validate
- version
- name: github.com/google/gofuzz
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5
- name: github.com/jonboulle/clockwork
version: 3f831b65b61282ba6bece21b91beea2edc4c887a
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/klauspost/cpuid
version: 09cded8978dc9e80714c4d85b0322337b0a1e5e0
- name: github.com/matttproud/golang_protobuf_extensions
version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
subpackages:
- pbutil
- name: github.com/opencontainers/runc
version: 7ca2aa4873aea7cb4265b1726acb24b90d8726c6
subpackages:
- libcontainer
- libcontainer/apparmor
- libcontainer/cgroups
- libcontainer/cgroups/fs
- libcontainer/cgroups/systemd
- libcontainer/configs
- libcontainer/configs/validate
- libcontainer/criurpc
- libcontainer/label
- libcontainer/seccomp
- libcontainer/selinux
- libcontainer/stacktrace
- libcontainer/system
- libcontainer/user
- libcontainer/utils
- name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/prometheus/client_golang
version: 3b78d7a77f51ccbc364d4bc170920153022cfd08
subpackages:
- prometheus
- name: github.com/prometheus/client_model
version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6
subpackages:
- go
- name: github.com/prometheus/common
version: a6ab08426bb262e2d190097751f5cfd1cfdfd17d
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: 490cc6eb5fa45bf8a8b7b73c8bc82a8160e8531d
- name: github.com/spf13/pflag
version: 08b1a584251b5b62f458943640fc8ebd4d50aaa5
- name: github.com/ugorji/go
version: f4485b318aadd133842532f841dc205a8e339d74
subpackages:
- codec
- codec/codecgen
- name: golang.org/x/net
version: 62685c2d7ca23c807425dca88b11a3e2323dab41
subpackages:
- context
- context/ctxhttp
- html
- html/atom
- http2
- http2/hpack
- internal/timeseries
- proxy
- trace
- websocket
- name: golang.org/x/oauth2
version: b5adcc2dcdf009d0391547edc6ecbaff889f5bb9
subpackages:
- google
- internal
- jws
- jwt
- name: google.golang.org/appengine
version: 12d5545dc1cfa6047a286d5e853841b6471f4c19
subpackages:
- urlfetch
- internal
- internal/urlfetch
- internal/app_identity
- internal/modules
- internal/base
- internal/datastore
- internal/log
- internal/remote_api
- name: google.golang.org/cloud
version: eb47ba841d53d93506cfbfbc03927daf9cc48f88
subpackages:
- compute/metadata
- internal
- name: gopkg.in/inf.v0
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
- name: k8s.io/kubernetes
version: 283137936a498aed572ee22af6774b6fb6e9fd94
subpackages:
- pkg/api
- pkg/client/unversioned
- pkg/api/meta
- pkg/api/meta/metatypes
- pkg/api/resource
- pkg/api/unversioned
- pkg/auth/user
- pkg/conversion
- pkg/fields
- pkg/labels
- pkg/runtime
- pkg/runtime/serializer
- pkg/types
- pkg/util
- pkg/util/intstr
- pkg/util/rand
- pkg/util/sets
- pkg/api/errors
- pkg/api/install
- pkg/apimachinery/registered
- pkg/apis/apps
- pkg/apis/apps/install
- pkg/apis/authentication.k8s.io/install
- pkg/apis/authorization/install
- pkg/apis/autoscaling
- pkg/apis/autoscaling/install
- pkg/apis/batch
- pkg/apis/batch/install
- pkg/apis/batch/v2alpha1
- pkg/apis/componentconfig/install
- pkg/apis/extensions
- pkg/apis/extensions/install
- pkg/apis/policy
- pkg/apis/policy/install
- pkg/apis/rbac
- pkg/apis/rbac/install
- pkg/client/restclient
- pkg/client/typed/discovery
- pkg/util/net
- pkg/util/wait
- pkg/version
- pkg/watch
- plugin/pkg/client/auth
- pkg/util/errors
- third_party/forked/reflect
- pkg/util/validation
- pkg/conversion/queryparams
- pkg/util/json
- pkg/runtime/serializer/json
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/versioning
- pkg/util/validation/field
- pkg/api/v1
- pkg/apimachinery
- pkg/watch/versioned
- pkg/apis/apps/v1alpha1
- pkg/apis/authentication.k8s.io
- pkg/apis/authentication.k8s.io/v1beta1
- pkg/apis/authorization
- pkg/apis/authorization/v1beta1
- pkg/apis/autoscaling/v1
- pkg/apis/batch/v1
- pkg/apis/componentconfig
- pkg/apis/componentconfig/v1alpha1
- pkg/apis/extensions/v1beta1
- pkg/apis/policy/v1alpha1
- pkg/apis/rbac/v1alpha1
- pkg/api/validation
- pkg/client/metrics
- pkg/client/transport
- pkg/client/unversioned/clientcmd/api
- pkg/runtime/serializer/streaming
- pkg/util/crypto
- pkg/util/flowcontrol
- pkg/util/runtime
- plugin/pkg/client/auth/gcp
- plugin/pkg/client/auth/oidc
- pkg/util/framer
- pkg/util/yaml
- pkg/util/parsers
- pkg/kubelet/qos
- pkg/master/ports
- pkg/api/endpoints
- pkg/api/pod
- pkg/api/service
- pkg/api/unversioned/validation
- pkg/api/util
- pkg/capabilities
- pkg/util/integer
- pkg/kubelet/qos/util
- pkg/util/hash
- pkg/util/net/sets
testImports: []

View file

@ -2,7 +2,10 @@ package: github.com/intelsdi-x/dbi-iafeature-discovery
import:
- package: github.com/klauspost/cpuid
version: v1.0
- package: github.com/docopt/docopt.go
version: ^0.6.2
- package: k8s.io/kubernetes
version: v1.3.0
subpackages:
- pkg/api
- pkg/client/unversioned

229
main.go
View file

@ -17,113 +17,168 @@ import (
"fmt"
"log"
"os"
"os/exec"
"strings"
"github.com/klauspost/cpuid"
"github.com/docopt/docopt-go"
"k8s.io/kubernetes/pkg/api"
client "k8s.io/kubernetes/pkg/client/unversioned"
)
const namespace = "node.alpha.intel.com"
const (
// ProgramName is the canonical name of this discovery program.
ProgramName = "dbi-ia-feature-discovery"
var version = "" // Must not be const, set using ldflags at build time
var prefix = fmt.Sprintf("%s/%s", namespace, version)
// Namespace is the prefix for all published labels.
Namespace = "node.alpha.intel.com"
// PodNameEnv is the environment variable that contains this pod's name.
PodNameEnv = "POD_NAME"
// PodNamespaceEnv is the environment variable that contains this pod's
// namespace.
PodNamespaceEnv = "POD_NAMESPACE"
)
var (
version = "" // Must not be const, set using ldflags at build time
prefix = fmt.Sprintf("%s/%s", Namespace, version)
)
// Labels are a Kubernetes representation of discovered features.
type Labels map[string]string
func main() {
// Assert that the version is known
if version == "" {
log.Fatalf("`main.version` not set! Set -ldflags '-X main.version `git describe --tags --dirty --always`' during build or run.")
}
log.Printf("Version: [%s]", version)
log.Printf("Label prefix: [%s]", prefix)
// Setting-up K8S client
cli, err := client.NewInCluster()
if err != nil {
log.Fatalf("Can't Get K8s Client: %v", err)
log.Fatalf("main.version not set! Set -ldflags \"-X main.version `git describe --tags --dirty --always`\" during build or run.")
}
// Get the pod name and namespace from the env variables
podName := os.Getenv("POD_NAME")
podns := os.Getenv("POD_NAMESPACE")
log.Printf("Pod Name ENV Variable: %s\n", podName)
log.Printf("Pod Namespace ENV Variable: %s\n", podns)
usage := fmt.Sprintf(`%s.
// Get the pod object using the pod name and namespace
pod, err := cli.Pods(podns).Get(podName)
if err != nil {
log.Fatalf("Can't Get Pod: %v", err)
Usage:
%s [--no-publish --sources=<sources>]
%s -h | --help
%s --version
Options:
-h --help Show this screen.
--version Output version and exit.
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,rdt,pstate]
--no-publish Do not publish discovered features to the cluster-local
Kubernetes API server.`,
ProgramName,
ProgramName,
ProgramName,
ProgramName,
)
arguments, _ := docopt.Parse(usage, nil, true,
fmt.Sprintf("%s %s", ProgramName, version), false)
// Parse argument values as usable types.
noPublish := arguments["--no-publish"].(bool)
sourcesArg := strings.Split(arguments["--sources"].(string), ",")
enabledSources := map[string]struct{}{}
for _, s := range sourcesArg {
enabledSources[strings.TrimSpace(s)] = struct{}{}
}
// Get the node object using the pod name and namespace
node, err := cli.Nodes().Get(pod.Spec.NodeName)
if err != nil {
log.Fatalf("Can't Get Node: %v", err)
// Configure feature sources.
allSources := []FeatureSource{
cpuidSource{},
rdtSource{},
pstateSource{},
}
sources := []FeatureSource{}
for _, s := range allSources {
if _, enabled := enabledSources[s.Name()]; enabled {
sources = append(sources, s)
}
}
labels := Labels{}
// Add the version of this discovery code as a node label
node.Labels[fmt.Sprintf("%s/dbi-ia-feature-discovery.version", prefix)] = version
versionLabel := fmt.Sprintf("%s/%s.version", Namespace, ProgramName)
labels[versionLabel] = version
// Log version label.
log.Printf("%s = %s", versionLabel, version)
// Get the cpu features as strings
features := cpuid.CPU.Features.Strings()
log.Printf("CPU Features Detected from cpuid: %s\n", features)
// Add each of the cpu feature as the node label
for _, feature := range features {
node.Labels[fmt.Sprintf("%s-cpu-%s", prefix, feature)] = "true"
// Do feature discovery from all configured sources.
for _, source := range sources {
for name, value := range featureLabels(source) {
labels[name] = value
// Log discovered feature.
log.Printf("%s = %s", name, value)
}
}
// If supported, add CMT, MBM and CAT features as a node label
cmd := "/go/src/github.com/intelsdi-x/dbi-iafeature-discovery/rdt-discovery/mon-discovery"
out, err := exec.Command("bash", "-c", cmd).Output()
if err != nil {
log.Fatalf("Can't Dectect Support for RDT Monitoring: %v", err)
}
// Update the node with the node labels, unless disabled via flags.
if !noPublish {
// Set up K8S client.
cli, err := client.NewInCluster()
if err != nil {
log.Fatalf("can't get kubernetes client: %s", err.Error())
}
outString := string(out[:])
if outString == "DETECTED" {
node.Labels[fmt.Sprintf("%s-cpu-RDTMON", prefix)] = "true"
log.Printf("RDT Monitoring Detected\n")
}
cmd = "/go/src/github.com/intelsdi-x/dbi-iafeature-discovery/rdt-discovery/l3-alloc-discovery"
out, err = exec.Command("bash", "-c", cmd).Output()
if err != nil {
log.Fatalf("Can't Dectect Support for RDT L3 Allocation: %v", err)
}
outString = string(out[:])
if outString == "DETECTED" {
node.Labels[fmt.Sprintf("%s-cpu-RDTL3CA", prefix)] = "true"
log.Printf("RDT L3 Cache Allocation Detected\n")
}
cmd = "/go/src/github.com/intelsdi-x/dbi-iafeature-discovery/rdt-discovery/l2-alloc-discovery"
out, err = exec.Command("bash", "-c", cmd).Output()
if err != nil {
log.Fatalf("Can't Dectect Support for RDT L2 Allocation: %v", err)
}
outString = string(out[:])
if outString == "DETECTED" {
node.Labels[fmt.Sprintf("%s-cpu-RDTL2CA", prefix)] = "true"
log.Printf("RDT L2 Cache Allocation Detected\n")
}
// If turbo boost is enabled, add it as a node label
cmd = "cat /sys/devices/system/cpu/intel_pstate/no_turbo"
out, err = exec.Command("bash", "-c", cmd).Output()
if err != nil {
log.Fatalf("Can't Dectect if Turbo Boost is Enabled: %v", err)
}
outString = string(out[:])
if outString == "0\n" {
node.Labels[fmt.Sprintf("%s-cpu-turbo", prefix)] = "true"
log.Printf("Turbo Boost is Enabled\n")
}
// Update the node with the node labels
_, err = cli.Nodes().Update(node)
if err != nil {
log.Fatalf("Can't Update Node: %v", err)
// Get the current node.
node := getNode(cli)
// Add labels to the node object.
addLabels(node, labels)
// Send the updated node to the apiserver.
_, err = cli.Nodes().Update(node)
if err != nil {
log.Fatalf("can't update node: %s", err.Error())
}
}
}
// featureLabels returns node labels for features discovered by the
// supplied source.
func featureLabels(source FeatureSource) Labels {
labels := Labels{}
features, err := source.Discover()
if err != nil {
log.Fatalf("discovery failed for source [%s]: %s", source.Name(), err.Error())
}
for _, f := range features {
labels[fmt.Sprintf("%s-%s-%s", prefix, source.Name(), f)] = "true"
}
return labels
}
// addLabels modifies the supplied node's labels collection.
//
// In order to publish the labels, the node must be subsequently updated via the
// API server using the client library.
func addLabels(n *api.Node, labels Labels) {
for k, v := range labels {
n.Labels[k] = v
}
}
// getNode returns the Kubernetes node on which this container is running.
func getNode(cli *client.Client) *api.Node {
// Get the pod name and pod namespace from the env variables
podName := os.Getenv(PodNameEnv)
podns := os.Getenv(PodNamespaceEnv)
log.Printf("%s: %s", PodNameEnv, podName)
log.Printf("%s: %s", PodNamespaceEnv, podns)
// Get the pod object using the pod name and pod namespace
pod, err := cli.Pods(podns).Get(podName)
if err != nil {
log.Fatalf("can't get pod: %s", err.Error())
}
// Get the node object using the pod name and pod namespace
node, err := cli.Nodes().Get(pod.Spec.NodeName)
if err != nil {
log.Fatalf("can't get node: %s", err.Error())
}
return node
}

103
sources.go Normal file
View file

@ -0,0 +1,103 @@
package main
import (
"fmt"
"io/ioutil"
"os/exec"
"path"
"github.com/klauspost/cpuid"
)
// FeatureSource represents a source of discovered node features.
type FeatureSource interface {
// Returns a friendly name for this source of node features.
Name() string
// Returns discovered features for this node.
Discover() ([]string, error)
}
const (
// DETECTED is compared with stdout for RDT detection helper programs.
DETECTED = "DETECTED"
// RDTBin is the path to RDT detection helpers.
RDTBin = "/go/src/github.com/intelsdi-x/dbi-iafeature-discovery/rdt-discovery"
)
////////////////////////////////////////////////////////////////////////////////
// CPUID Source
// Implements main.FeatureSource.
type cpuidSource struct{}
func (s cpuidSource) Name() string { return "cpuid" }
func (s cpuidSource) Discover() ([]string, error) {
// Get the cpu features as strings
return cpuid.CPU.Features.Strings(), nil
}
////////////////////////////////////////////////////////////////////////////////
// RDT (Intel Resource Director Technology) Source
type rdtSource struct{}
func (s rdtSource) Name() string { return "rdt" }
// Returns feature names for CMT, MBM and CAT if suppported.
func (s rdtSource) Discover() ([]string, error) {
features := []string{}
out, err := exec.Command("bash", "-c", path.Join(RDTBin, "mon-discovery")).Output()
if err != nil {
return nil, fmt.Errorf("can't detect support for RDT monitoring: %v", err)
}
if string(out[:]) == DETECTED {
// RDT monitoring detected.
features = append(features, "RDTMON")
}
out, err = exec.Command("bash", "-c", path.Join(RDTBin, "l3-alloc-discovery")).Output()
if err != nil {
return nil, fmt.Errorf("can't detect support for RDT L3 allocation: %v", err)
}
if string(out[:]) == DETECTED {
// RDT L3 cache allocation detected.
features = append(features, "RDTL3CA")
}
out, err = exec.Command("bash", "-c", path.Join(RDTBin, "l2-alloc-discovery")).Output()
if err != nil {
return nil, fmt.Errorf("can't detect support for RDT L2 allocation: %v", err)
}
if string(out[:]) == DETECTED {
// RDT L2 cache allocation detected.
features = append(features, "RDTL2CA")
}
return features, nil
}
////////////////////////////////////////////////////////////////////////////////
// PState Source
// Implements main.FeatureSource.
type pstateSource struct{}
func (s pstateSource) Name() string { return "pstate" }
func (s pstateSource) Discover() ([]string, error) {
features := []string{}
// Only looking for turbo boost for now...
bytes, err := ioutil.ReadFile("/sys/devices/system/cpu/intel_pstate/no_turbo")
if err != nil {
return nil, fmt.Errorf("can't detect whether turbo boost is enabled: %s", err.Error())
}
if bytes[0] == byte('0') {
// Turbo boost is enabled.
features = append(features, "turbo")
}
return features, nil
}