mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-30 19:54:46 +00:00
Merge pull request #3 from ConnorDoyle/replay-history
Replayed history.
This commit is contained in:
commit
28a2ec2052
18 changed files with 1303 additions and 2 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
node-feature-discovery
|
||||||
|
node-feature-discovery-job.json
|
||||||
|
vendor/
|
||||||
|
intel-cmt-cat/
|
||||||
|
rdt-discovery/l2-alloc-discovery
|
||||||
|
rdt-discovery/l3-alloc-discovery
|
||||||
|
rdt-discovery/mon-discovery
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
sudo: required
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
script:
|
||||||
|
- docker build -t intelsdi/dbi-iafeature-discovery .
|
16
Dockerfile
Normal file
16
Dockerfile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
FROM golang:1.6
|
||||||
|
|
||||||
|
ADD . /go/src/github.com/kubernetes-incubator/node-feature-discovery
|
||||||
|
|
||||||
|
WORKDIR /go/src/github.com/kubernetes-incubator/node-feature-discovery
|
||||||
|
|
||||||
|
RUN git clone --depth 1 https://github.com/01org/intel-cmt-cat.git
|
||||||
|
RUN cd intel-cmt-cat/lib; make install
|
||||||
|
RUN cd rdt-discovery; make
|
||||||
|
RUN go get github.com/Masterminds/glide
|
||||||
|
RUN glide install
|
||||||
|
RUN go install \
|
||||||
|
-ldflags "-s -w -X main.version=`git describe --tags --dirty --always`" \
|
||||||
|
github.com/kubernetes-incubator/node-feature-discovery
|
||||||
|
|
||||||
|
ENTRYPOINT ["/go/bin/node-feature-discovery"]
|
13
Makefile
Normal file
13
Makefile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.PHONY: all
|
||||||
|
|
||||||
|
DOCKER_REGISTRY_USER := kubernetesincubator
|
||||||
|
DOCKER_IMAGE_NAME := node-feature-discovery
|
||||||
|
|
||||||
|
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) ./
|
147
README.md
147
README.md
|
@ -1,6 +1,16 @@
|
||||||
# Node feature discovery for [Kubernetes](https://kubernetes.io)
|
# Node feature discovery for [Kubernetes](https://kubernetes.io)
|
||||||
|
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
|
- [Command line interface](#command-line-interface)
|
||||||
|
- [Feature discovery](#feature-discovery)
|
||||||
|
- [Feature sources](#feature-sources)
|
||||||
|
- [Feature labels](#feature-labels)
|
||||||
|
- [Getting started](#getting-started)
|
||||||
|
- [System requirements](#system-requirements)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Building from source](#building-from-source)
|
||||||
|
- [Targeting nodes with specific features](#targeting-nodes-with-specific-features)
|
||||||
|
- [References](#references)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
@ -9,8 +19,29 @@ This software enables node feature discovery for Kubernetes. It detects
|
||||||
hardware features available on each node in a Kubernetes cluster, and advertises
|
hardware features available on each node in a Kubernetes cluster, and advertises
|
||||||
those features using node labels.
|
those features using node labels.
|
||||||
|
|
||||||
|
## Command line interface
|
||||||
|
|
||||||
|
```
|
||||||
|
node-feature-discovery.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
node-feature-discovery [--no-publish --sources=<sources>]
|
||||||
|
node-feature-discovery -h | --help
|
||||||
|
node-feature-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.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature discovery
|
||||||
|
|
||||||
### Feature sources
|
### Feature sources
|
||||||
|
|
||||||
|
The current set of feature sources are the following:
|
||||||
|
|
||||||
- [CPUID][cpuid] for x86 CPU details
|
- [CPUID][cpuid] for x86 CPU details
|
||||||
- [Intel Resource Director Technology][intel-rdt]
|
- [Intel Resource Director Technology][intel-rdt]
|
||||||
- [Intel P-State driver][intel-pstate]
|
- [Intel P-State driver][intel-pstate]
|
||||||
|
@ -31,14 +62,120 @@ the only label value published for features is the string `"true"`._
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"node.alpha.intel.com/dbi-iafeature-discovery.version": "v0.1.0",
|
"node.alpha.intel.com/node-feature-discovery.version": "v0.1.0",
|
||||||
"node.alpha.intel.com/v0.1.0-cpuid-<feature-name>": "true",
|
"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-rdt-<feature-name>": "true",
|
||||||
"node.alpha.intel.com/v0.1.0-pstate-<feature-name>": "true"
|
"node.alpha.intel.com/v0.1.0-pstate-<feature-name>": "true"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### References
|
The `--sources` flag controls which sources to use for discovery.
|
||||||
|
|
||||||
|
### Intel Resource Director Technology (RDT) Features
|
||||||
|
|
||||||
|
| Feature name | Description |
|
||||||
|
| :------------: | :---------------------------------------------------------------------------------: |
|
||||||
|
| RDTMON | Intel Cache Monitoring Technology (CMT) and Intel Memory Bandwidth Monitoring (MBM)
|
||||||
|
| RDTL3CA | Intel L3 Cache Allocation Technology
|
||||||
|
| RDTL2CA | Intel L2 Cache Allocation Technology
|
||||||
|
|
||||||
|
### CPUID Features (Partial List)
|
||||||
|
|
||||||
|
| Feature name | Description |
|
||||||
|
| :------------: | :----------------------------------------------------------: |
|
||||||
|
| ADX | Multi-Precision Add-Carry Instruction Extensions (ADX)
|
||||||
|
| AESNI | Advanced Encryption Standard (AES) New Instructions (AES-NI)
|
||||||
|
| AVX | Advanced Vector Extensions (AVX)
|
||||||
|
| AVX2 | Advanced Vector Extensions 2 (AVX2)
|
||||||
|
| BMI1 | Bit Manipulation Instruction Set 1 (BMI)
|
||||||
|
| BMI2 | Bit Manipulation Instruction Set 2 (BMI2)
|
||||||
|
| SSE4.1 | Streaming SIMD Extensions 4.1 (SSE4.1)
|
||||||
|
| SSE4.2 | Streaming SIMD Extensions 4.2 (SSE4.2)
|
||||||
|
| SGX | Software Guard Extensions (SGX)
|
||||||
|
|
||||||
|
### System Requirements
|
||||||
|
|
||||||
|
1. Linux (x86_64)
|
||||||
|
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
|
||||||
|
|
||||||
|
Feature discovery is done as a one-shot job. There is an example script in this
|
||||||
|
repo that demonstrates how to deploy the job to unlabeled nodes.
|
||||||
|
|
||||||
|
```
|
||||||
|
./label-nodes.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Building from source
|
||||||
|
|
||||||
|
Download the source code.
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/kubernetes-incubator/node-feature-discovery
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build the Docker image:**
|
||||||
|
|
||||||
|
```
|
||||||
|
cd <project-root>
|
||||||
|
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 <registry-user>/<image-name>:<version>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Change the job spec to use your custom image (optional):**
|
||||||
|
|
||||||
|
To use your published image from the step above instead of the
|
||||||
|
`kubernetesincubator/node-feature-discovery` image, edit line 40 in the file
|
||||||
|
[node-feature-discovery-job.json.template](node-feature-discovery-job.json.template)
|
||||||
|
to the new location (`<registry-user>/<image-name>[:<version>]`).
|
||||||
|
|
||||||
|
## Targeting Nodes with Specific Features
|
||||||
|
|
||||||
|
Nodes with specific features can be targeted using the `nodeSelector` field. The
|
||||||
|
following example shows how to target nodes with Intel TurboBoost enabled.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Pod",
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"env": "test"
|
||||||
|
},
|
||||||
|
"name": "golang-test"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"image": "golang",
|
||||||
|
"name": "go1",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodeSelector": {
|
||||||
|
"node.alpha.intel.com/v0.1.0-pstate-turbo": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more details on targeting nodes, see [node selection][node-sel].
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
Github issues
|
Github issues
|
||||||
|
|
||||||
|
@ -48,6 +185,7 @@ Github issues
|
||||||
|
|
||||||
[Design proposal](https://docs.google.com/document/d/1uulT2AjqXjc_pLtDu0Kw9WyvvXm-WAZZaSiUziKsr68/edit)
|
[Design proposal](https://docs.google.com/document/d/1uulT2AjqXjc_pLtDu0Kw9WyvvXm-WAZZaSiUziKsr68/edit)
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This is open source software released under the [Apache 2.0 License](LICENSE).
|
This is open source software released under the [Apache 2.0 License](LICENSE).
|
||||||
|
@ -56,3 +194,8 @@ This is open source software released under the [Apache 2.0 License](LICENSE).
|
||||||
[cpuid]: http://man7.org/linux/man-pages/man4/cpuid.4.html
|
[cpuid]: http://man7.org/linux/man-pages/man4/cpuid.4.html
|
||||||
[intel-rdt]: http://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html
|
[intel-rdt]: http://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html
|
||||||
[intel-pstate]: https://www.kernel.org/doc/Documentation/cpu-freq/intel-pstate.txt
|
[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
|
||||||
|
[node-sel]: http://kubernetes.io/docs/user-guide/node-selection
|
||||||
|
|
366
glide.lock
generated
Normal file
366
glide.lock
generated
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
hash: 9943a35009296355c6a66485228855db99eefab65890c8fa89a4776cba9c9b71
|
||||||
|
updated: 2016-07-28T17:22:20.295749043-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/pmezard/go-difflib
|
||||||
|
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||||
|
subpackages:
|
||||||
|
- difflib
|
||||||
|
- 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/smartystreets/goconvey
|
||||||
|
version: d4c757aa9afd1e2fc1832aaab209b5794eb336e1
|
||||||
|
subpackages:
|
||||||
|
- convey
|
||||||
|
- convey/reporting
|
||||||
|
- convey/gotest
|
||||||
|
- name: github.com/spf13/pflag
|
||||||
|
version: 08b1a584251b5b62f458943640fc8ebd4d50aaa5
|
||||||
|
- name: github.com/stretchr/objx
|
||||||
|
version: 1a9d0bb9f541897e62256577b352fdbc1fb4fd94
|
||||||
|
- name: github.com/stretchr/testify
|
||||||
|
version: f390dcf405f7b83c997eac1b06768bb9f44dec18
|
||||||
|
subpackages:
|
||||||
|
- mock
|
||||||
|
- assert
|
||||||
|
- name: github.com/ugorji/go
|
||||||
|
version: f4485b318aadd133842532f841dc205a8e339d74
|
||||||
|
subpackages:
|
||||||
|
- codec
|
||||||
|
- codec/codecgen
|
||||||
|
- name: github.com/vektra/errors
|
||||||
|
version: c64d83aba85aa4392895aadeefabbd24e89f3580
|
||||||
|
- 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:
|
||||||
|
- name: github.com/gopherjs/gopherjs
|
||||||
|
version: 72e303cb5f235b23471872477b57e573dc1c71d0
|
||||||
|
subpackages:
|
||||||
|
- js
|
||||||
|
- name: github.com/jtolds/gls
|
||||||
|
version: 8ddce2a84170772b95dd5d576c48d517b22cac63
|
||||||
|
- name: github.com/smartystreets/assertions
|
||||||
|
version: 2063fd1cc7c975db70502811a34b06ad034ccdf2
|
||||||
|
subpackages:
|
||||||
|
- internal/go-render/render
|
||||||
|
- internal/oglematchers
|
20
glide.yaml
Normal file
20
glide.yaml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package: github.com/kubernetes-incubator/node-feature-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
|
||||||
|
- package: github.com/smartystreets/goconvey
|
||||||
|
version: 1.6.2
|
||||||
|
subpackages:
|
||||||
|
- convey
|
||||||
|
- package: github.com/stretchr/testify
|
||||||
|
version: v1.1.3
|
||||||
|
subpackages:
|
||||||
|
- mock
|
||||||
|
- package: github.com/vektra/errors
|
12
label-nodes.sh
Executable file
12
label-nodes.sh
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Get the node count in the Kubernetes cluster
|
||||||
|
NumNodes=$(kubectl get nodes | grep -i ready | wc -l)
|
||||||
|
|
||||||
|
# We set the .spec.completions and .spec.parallelism to the node count
|
||||||
|
# We request a specific hostPort in the job spec to limit the number of pods
|
||||||
|
# that run on a node to one. As a result, one pod runs on each node in parallel
|
||||||
|
# We set the POD_NAME and POD_NAMESPACE environemnt variables to the pod name
|
||||||
|
# and pod namespace. These enivornment variables are used by the feature
|
||||||
|
# discovery software to get the Kubernetes pod and node object.
|
||||||
|
sed -e "s/COMPLETION_COUNT/$NumNodes/" -e "s/PARALLELISM_COUNT/$NumNodes/" node-feature-discovery-job.json.template > node-feature-discovery-job.json
|
||||||
|
kubectl create -f node-feature-discovery-job.json
|
233
main.go
Normal file
233
main.go
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docopt/docopt-go"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ProgramName is the canonical name of this discovery program.
|
||||||
|
ProgramName = "node-feature-discovery"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// APIHelpers represents a set of API helpers for Kubernetes
|
||||||
|
type APIHelpers interface {
|
||||||
|
// GetClient returns a client
|
||||||
|
GetClient() (*client.Client, error)
|
||||||
|
|
||||||
|
// GetNode returns the Kubernetes node on which this container is running.
|
||||||
|
GetNode(*client.Client) (*api.Node, error)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
AddLabels(*api.Node, Labels)
|
||||||
|
|
||||||
|
// UpdateNode updates the node via the API server using a client.
|
||||||
|
UpdateNode(*client.Client, *api.Node) error
|
||||||
|
}
|
||||||
|
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
|
||||||
|
usage := fmt.Sprintf(`%s.
|
||||||
|
|
||||||
|
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{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
versionLabel := fmt.Sprintf("%s/%s.version", Namespace, ProgramName)
|
||||||
|
labels[versionLabel] = version
|
||||||
|
// Log version label.
|
||||||
|
log.Printf("%s = %s", versionLabel, version)
|
||||||
|
|
||||||
|
// Do feature discovery from all configured sources.
|
||||||
|
for _, source := range sources {
|
||||||
|
labelsFromSource, err := getFeatureLabels(source)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("discovery failed for source [%s]: %s", source.Name(), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, value := range labelsFromSource {
|
||||||
|
labels[name] = value
|
||||||
|
// Log discovered feature.
|
||||||
|
log.Printf("%s = %s", name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the node with the node labels, unless disabled via flags.
|
||||||
|
if !noPublish {
|
||||||
|
helper := APIHelpers(k8sHelpers{})
|
||||||
|
err := advertiseFeatureLabels(helper, labels)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to advertise labels: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFeatureLabels returns node labels for features discovered by the
|
||||||
|
// supplied source.
|
||||||
|
func getFeatureLabels(source FeatureSource) (Labels, error) {
|
||||||
|
labels := Labels{}
|
||||||
|
features, err := source.Discover()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, f := range features {
|
||||||
|
labels[fmt.Sprintf("%s-%s-%s", prefix, source.Name(), f)] = "true"
|
||||||
|
}
|
||||||
|
return labels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// advertiseFeatureLabels advertises the feature labels to a Kubernetes node
|
||||||
|
// via the API server.
|
||||||
|
func advertiseFeatureLabels(helper APIHelpers, labels Labels) error {
|
||||||
|
// Set up K8S client.
|
||||||
|
cli, err := helper.GetClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't get kubernetes client: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current node.
|
||||||
|
node, err := helper.GetNode(cli)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to get node: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add labels to the node object.
|
||||||
|
helper.AddLabels(node, labels)
|
||||||
|
|
||||||
|
// Send the updated node to the apiserver.
|
||||||
|
err = helper.UpdateNode(cli, node)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't update node: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements main.APIHelpers
|
||||||
|
type k8sHelpers struct{}
|
||||||
|
|
||||||
|
func (h k8sHelpers) GetClient() (*client.Client, error) {
|
||||||
|
// Set up K8S client.
|
||||||
|
cli, err := client.NewInCluster()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cli, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h k8sHelpers) GetNode(cli *client.Client) (*api.Node, error) {
|
||||||
|
// 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.Printf("can't get pods: %s", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the node object using the pod name and pod namespace
|
||||||
|
node, err := cli.Nodes().Get(pod.Spec.NodeName)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't get node: %s", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h k8sHelpers) AddLabels(n *api.Node, labels Labels) {
|
||||||
|
for k, v := range labels {
|
||||||
|
n.Labels[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h k8sHelpers) UpdateNode(c *client.Client, n *api.Node) error {
|
||||||
|
// Send the updated node to the apiserver.
|
||||||
|
_, err := c.Nodes().Update(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
102
main_test.go
Normal file
102
main_test.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"github.com/vektra/errors"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDiscoveryWithMockSources(t *testing.T) {
|
||||||
|
Convey("When I discover features from fake source and update the node using fake client", t, func() {
|
||||||
|
mockFeatureSource := new(MockFeatureSource)
|
||||||
|
fakeFeatureSourceName := string("testSource")
|
||||||
|
fakeFeatures := []string{"testfeature1", "testfeature2", "testfeature3"}
|
||||||
|
fakeFeatureLabels := Labels{}
|
||||||
|
for _, f := range fakeFeatures {
|
||||||
|
fakeFeatureLabels[fmt.Sprintf("%s-testSource-%s", prefix, f)] = "true"
|
||||||
|
}
|
||||||
|
fakeFeatureSource := FeatureSource(mockFeatureSource)
|
||||||
|
|
||||||
|
Convey("When I successfully get the labels from the mock source", func() {
|
||||||
|
mockFeatureSource.On("Name").Return(fakeFeatureSourceName)
|
||||||
|
mockFeatureSource.On("Discover").Return(fakeFeatures, nil)
|
||||||
|
|
||||||
|
returnedLabels, err := getFeatureLabels(fakeFeatureSource)
|
||||||
|
Convey("Proper label is returned", func() {
|
||||||
|
So(returnedLabels, ShouldResemble, fakeFeatureLabels)
|
||||||
|
})
|
||||||
|
Convey("Error is nil", func() {
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When I fail to get the labels from the mock source", func() {
|
||||||
|
expectedError := errors.New("fake error")
|
||||||
|
mockFeatureSource.On("Discover").Return(nil, expectedError)
|
||||||
|
|
||||||
|
returnedLabels, err := getFeatureLabels(fakeFeatureSource)
|
||||||
|
Convey("No label is returned", func() {
|
||||||
|
So(returnedLabels, ShouldBeNil)
|
||||||
|
})
|
||||||
|
Convey("Error is produced", func() {
|
||||||
|
So(err, ShouldEqual, expectedError)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
mockAPIHelper := new(MockAPIHelpers)
|
||||||
|
testHelper := APIHelpers(mockAPIHelper)
|
||||||
|
var mockClient *client.Client
|
||||||
|
var mockNode *api.Node
|
||||||
|
|
||||||
|
Convey("When I successfully advertise feature labels to a node", func() {
|
||||||
|
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
||||||
|
mockAPIHelper.On("GetNode", mockClient).Return(mockNode, nil).Once()
|
||||||
|
mockAPIHelper.On("AddLabels", mockNode, fakeFeatureLabels).Return().Once()
|
||||||
|
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(nil).Once()
|
||||||
|
err := advertiseFeatureLabels(testHelper, fakeFeatureLabels)
|
||||||
|
|
||||||
|
Convey("Error is nil", func() {
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When I fail to get a mock client while advertising feature labels", func() {
|
||||||
|
expectedError := errors.New("fake error")
|
||||||
|
mockAPIHelper.On("GetClient").Return(nil, expectedError)
|
||||||
|
err := advertiseFeatureLabels(testHelper, fakeFeatureLabels)
|
||||||
|
|
||||||
|
Convey("Error is produced", func() {
|
||||||
|
So(err, ShouldEqual, expectedError)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When I fail to get a mock node while advertising feature labels", func() {
|
||||||
|
expectedError := errors.New("fake error")
|
||||||
|
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
||||||
|
mockAPIHelper.On("GetNode", mockClient).Return(nil, expectedError).Once()
|
||||||
|
err := advertiseFeatureLabels(testHelper, fakeFeatureLabels)
|
||||||
|
|
||||||
|
Convey("Error is produced", func() {
|
||||||
|
So(err, ShouldEqual, expectedError)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("When I fail to update a mock node while advertising feature labels", func() {
|
||||||
|
expectedError := errors.New("fake error")
|
||||||
|
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
||||||
|
mockAPIHelper.On("GetNode", mockClient).Return(mockNode, nil).Once()
|
||||||
|
mockAPIHelper.On("AddLabels", mockNode, fakeFeatureLabels).Return().Once()
|
||||||
|
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(expectedError).Once()
|
||||||
|
err := advertiseFeatureLabels(testHelper, fakeFeatureLabels)
|
||||||
|
|
||||||
|
Convey("Error is produced", func() {
|
||||||
|
So(err, ShouldEqual, expectedError)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
80
mockapihelpers.go
Normal file
80
mockapihelpers.go
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockAPIHelpers struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClient provides a mock function with no input arguments and
|
||||||
|
// *client.Client and error as return value
|
||||||
|
func (_m *MockAPIHelpers) GetClient() (*client.Client, error) {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 *client.Client
|
||||||
|
if rf, ok := ret.Get(0).(func() *client.Client); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*client.Client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func() error); ok {
|
||||||
|
r1 = rf()
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNode provides a mock function with *client.Client as input argument and
|
||||||
|
// *api.Node and error as return values
|
||||||
|
func (_m *MockAPIHelpers) GetNode(_a0 *client.Client) (*api.Node, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
var r0 *api.Node
|
||||||
|
if rf, ok := ret.Get(0).(func(*client.Client) *api.Node); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*api.Node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(*client.Client) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLabels provides a mock function with *api.Node and main.Labels as the input arguments and
|
||||||
|
// no return value
|
||||||
|
func (_m *MockAPIHelpers) AddLabels(_a0 *api.Node, _a1 Labels) {
|
||||||
|
_m.Called(_a0, _a1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNode provides a mock function with *client.Client and *api.Node as the input arguments and
|
||||||
|
// error as the return value
|
||||||
|
func (_m *MockAPIHelpers) UpdateNode(_a0 *client.Client, _a1 *api.Node) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*client.Client, *api.Node) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
46
mockfeaturesource.go
Normal file
46
mockfeaturesource.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
type MockFeatureSource struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name provides a mock function with no input arguments
|
||||||
|
// and string as return value
|
||||||
|
func (_m *MockFeatureSource) Name() string {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 string
|
||||||
|
if rf, ok := ret.Get(0).(func() string); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discover provides a mock function with no input arguments
|
||||||
|
// and []string and error as the return values
|
||||||
|
func (_m *MockFeatureSource) Discover() ([]string, error) {
|
||||||
|
ret := _m.Called()
|
||||||
|
|
||||||
|
var r0 []string
|
||||||
|
if rf, ok := ret.Get(0).(func() []string); ok {
|
||||||
|
r0 = rf()
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func() error); ok {
|
||||||
|
r1 = rf()
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
54
node-feature-discovery-job.json.template
Normal file
54
node-feature-discovery-job.json.template
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"apiVersion": "extensions/v1beta1",
|
||||||
|
"kind": "Job",
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "node-feature-discovery"
|
||||||
|
},
|
||||||
|
"name": "node-feature-discovery"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"completions": COMPLETION_COUNT,
|
||||||
|
"parallelism": PARALLELISM_COUNT,
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "node-feature-discovery"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"env": [
|
||||||
|
{
|
||||||
|
"name": "POD_NAME",
|
||||||
|
"valueFrom": {
|
||||||
|
"fieldRef": {
|
||||||
|
"fieldPath": "metadata.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "POD_NAMESPACE",
|
||||||
|
"valueFrom": {
|
||||||
|
"fieldRef": {
|
||||||
|
"fieldPath": "metadata.namespace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"image": "kubernetesincubator/node-feature-discovery",
|
||||||
|
"name": "node-feature-discovery",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"containerPort": 2233,
|
||||||
|
"hostPort": 7156
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"restartPolicy": "Never"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
rdt-discovery/Makefile
Normal file
14
rdt-discovery/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
CC=gcc
|
||||||
|
LIBDIR=/usr/local/lib
|
||||||
|
INCDIR=/go/src/github.com/kubernetes-incubator/node-feature-discovery/intel-cmt-cat/lib/
|
||||||
|
|
||||||
|
LDFLAGS=-L$(LIBDIR)
|
||||||
|
LDLIBS=-lpqos
|
||||||
|
CFLAGS=-I$(INCDIR)
|
||||||
|
|
||||||
|
default:
|
||||||
|
$(MAKE) all
|
||||||
|
all:
|
||||||
|
$(CC) $(CFLAGS) -o mon-discovery monitoring-discovery.c $(LDFLAGS) $(LDLIBS)
|
||||||
|
$(CC) $(CFLAGS) -o l3-alloc-discovery l3-allocation-discovery.c $(LDFLAGS) $(LDLIBS)
|
||||||
|
$(CC) $(CFLAGS) -o l2-alloc-discovery l2-allocation-discovery.c $(LDFLAGS) $(LDLIBS)
|
27
rdt-discovery/l2-allocation-discovery.c
Normal file
27
rdt-discovery/l2-allocation-discovery.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int ret, det=1;
|
||||||
|
struct cpuid_out res;
|
||||||
|
|
||||||
|
// Logic below from https://github.com/01org/intel-cmt-cat/blob/master/lib/host_cap.c
|
||||||
|
lcpuid(0x7, 0x0, &res);
|
||||||
|
if (!(res.ebx & (1 << 15))) {
|
||||||
|
det = 0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lcpuid(0x10, 0x0, &res);
|
||||||
|
if (!(res.ebx & (1 << 2))) {
|
||||||
|
det = 0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (det)
|
||||||
|
printf("DETECTED");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
30
rdt-discovery/l3-allocation-discovery.c
Normal file
30
rdt-discovery/l3-allocation-discovery.c
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int ret, det=1;
|
||||||
|
struct cpuid_out res;
|
||||||
|
|
||||||
|
// Logic below from https://github.com/01org/intel-cmt-cat/blob/master/lib/host_cap.c
|
||||||
|
// TODO(balajismaniam): Implement L3 CAT detection using brand string and MSR probing if
|
||||||
|
// not detected using cpuid
|
||||||
|
|
||||||
|
lcpuid(0x7, 0x0, &res);
|
||||||
|
if (!(res.ebx & (1 << 15))) {
|
||||||
|
det = 0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lcpuid(0x10, 0x0, &res);
|
||||||
|
if (!(res.ebx & (1 << 1))) {
|
||||||
|
det = 0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (det)
|
||||||
|
printf("DETECTED");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
27
rdt-discovery/monitoring-discovery.c
Normal file
27
rdt-discovery/monitoring-discovery.c
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "machine.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int ret, det=1;
|
||||||
|
struct cpuid_out res;
|
||||||
|
|
||||||
|
// Logic below from https://github.com/01org/intel-cmt-cat/blob/master/lib/host_cap.c
|
||||||
|
lcpuid(0x7, 0x0, &res);
|
||||||
|
if (!(res.ebx & (1 << 12))) {
|
||||||
|
det = 0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lcpuid(0xf, 0x0, &res);
|
||||||
|
if (!(res.edx & (1 << 1))) {
|
||||||
|
det=0;
|
||||||
|
printf("NOT DETECTED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (det)
|
||||||
|
printf("DETECTED");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
104
sources.go
Normal file
104
sources.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
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/kubernetes-incubator/node-feature-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
|
||||||
|
|
||||||
|
// Implements main.FeatureSource.
|
||||||
|
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: %s", err.Error())
|
||||||
|
}
|
||||||
|
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: %s", err.Error())
|
||||||
|
}
|
||||||
|
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: %s", err.Error())
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue