Merge pull request #49342 from RenaudWasTaken/protobufapionly

Automatic merge from submit-queue (batch tested with PRs 49342, 50581, 50777)

Device Plugin Protobuf API

**What this PR does / why we need it:**
This implements the Device Plugin API

- Design document: kubernetes/community#695
- PR tracking: [kubernetes/features#368](https://github.com/kubernetes/features/issues/368#issuecomment-321625420)

Special notes for your reviewer:

First proposal submitted to the community repo, please advise if something's not right with the format or procedure, etc.
@vishh @derekwaynecarr

**Release note:**
```
NONE
```
pull/6/head
Kubernetes Submit Queue 2017-08-16 23:08:08 -07:00 committed by GitHub
commit ccc40f49ee
10 changed files with 2745 additions and 0 deletions

View File

@ -231,6 +231,7 @@ pkg/kubelet
pkg/kubelet/apis
pkg/kubelet/apis/cri/testing
pkg/kubelet/apis/cri/v1alpha1/runtime
pkg/kubelet/apis/deviceplugin/v1alpha1
pkg/kubelet/apis/kubeletconfig
pkg/kubelet/apis/kubeletconfig/v1alpha1
pkg/kubelet/cadvisor

91
hack/lib/protoc.sh Normal file
View File

@ -0,0 +1,91 @@
#!/bin/bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
# The root of the build/dist directory
KUBE_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/../.." && pwd -P)"
source "${KUBE_ROOT}/hack/lib/init.sh"
# Generates $1/api.pb.go from the protobuf file $1/api.proto
# and formats it correctly
# $1: Full path to the directory where the api.proto file is
function kube::protoc::generate_proto() {
kube::golang::setup_env
local bins=(
vendor/k8s.io/kube-gen/cmd/go-to-protobuf/protoc-gen-gogo
)
make -C "${KUBE_ROOT}" WHAT="${bins[*]}"
kube::protoc::check_protoc
local package=${1}
kube::protoc::protoc ${package}
kube::protoc::format ${package}
}
# Checks that the current protoc version is at least version 3.0.0-beta1
# exit 1 if it's not the case
function kube::protoc::check_protoc() {
if [[ -z "$(which protoc)" || "$(protoc --version)" != "libprotoc 3."* ]]; then
echo "Generating protobuf requires protoc 3.0.0-beta1 or newer. Please download and"
echo "install the platform appropriate Protobuf package for your OS: "
echo
echo " https://github.com/google/protobuf/releases"
echo
echo "WARNING: Protobuf changes are not being validated"
exit 1
fi
}
# Generates $1/api.pb.go from the protobuf file $1/api.proto
# $1: Full path to the directory where the api.proto file is
function kube::protoc::protoc() {
local package=${1}
gogopath=$(dirname $(kube::util::find-binary "protoc-gen-gogo"))
PATH="${gogopath}:${PATH}" protoc \
--proto_path="${package}" \
--proto_path="${KUBE_ROOT}/vendor" \
--gogo_out=plugins=grpc:${package} ${package}/api.proto
}
# Formats $1/api.pb.go, adds the boilerplate comments and run gofmt on it
# $1: Full path to the directory where the api.proto file is
function kube::protoc::format() {
local package=${1}
# Update boilerplate for the generated file.
echo "$(cat hack/boilerplate/boilerplate.go.txt ${package}/api.pb.go)" > ${package}/api.pb.go
sed -i".bak" "s/Copyright YEAR/Copyright $(date '+%Y')/g" ${package}/api.pb.go
# Run gofmt to clean up the generated code.
kube::golang::verify_go_version
gofmt -l -s -w ${package}/api.pb.go
}
# Compares the contents of $1 and $2
# Echo's $3 in case of error and exits 1
function kube::protoc::diff() {
local ret=0
diff -I "gzipped FileDescriptorProto" -I "0x" -Naupr ${1} ${2} || ret=$?
if [[ $ret -ne 0 ]]; then
echo ${3}
exit 1
fi
}

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT="$(cd "$(dirname "${BASH_SOURCE}")/../" && pwd -P)"
DEVICE_PLUGIN_ROOT="${KUBE_ROOT}/pkg/kubelet/apis/deviceplugin/v1alpha1/"
source "${KUBE_ROOT}/hack/lib/protoc.sh"
kube::protoc::generate_proto ${DEVICE_PLUGIN_ROOT}

View File

@ -0,0 +1,27 @@
#!/bin/bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
# NOTE: All output from this script needs to be copied back to the calling
# source tree. This is managed in kube::build::copy_output in build/common.sh.
# If the output set is changed update that function.
${KUBE_ROOT}/build/run.sh hack/update-generated-device-plugin-dockerized.sh "$@"

View File

@ -0,0 +1,39 @@
#!/bin/bash
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
DEVICE_PLUGIN_ROOT="${KUBE_ROOT}/pkg/kubelet/apis/deviceplugin/v1alpha1/"
ERROR="Device plugin api is out of date. Please run hack/update-generated-device-plugin.sh"
source "${KUBE_ROOT}/hack/lib/protoc.sh"
kube::golang::setup_env
function cleanup {
rm -rf ${DEVICE_PLUGIN_ROOT}/_tmp/
}
trap cleanup EXIT
mkdir -p ${DEVICE_PLUGIN_ROOT}/_tmp
cp ${DEVICE_PLUGIN_ROOT}/api.pb.go ${DEVICE_PLUGIN_ROOT}/_tmp/
KUBE_VERBOSE=3 "${KUBE_ROOT}/hack/update-generated-device-plugin.sh"
kube::protoc::diff "${DEVICE_PLUGIN_ROOT}/api.pb.go" "${DEVICE_PLUGIN_ROOT}/_tmp/api.pb.go" ${ERROR}
echo "Generated device plugin api is up to date."

View File

@ -25,6 +25,7 @@ filegroup(
srcs = [
":package-srcs",
"//pkg/kubelet/apis/cri:all-srcs",
"//pkg/kubelet/apis/deviceplugin/v1alpha1:all-srcs",
"//pkg/kubelet/apis/kubeletconfig:all-srcs",
"//pkg/kubelet/apis/stats/v1alpha1:all-srcs",
],

View File

@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"api.pb.go",
"constants.go",
],
tags = ["automanaged"],
deps = [
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
"//vendor/golang.org/x/net/context:go_default_library",
"//vendor/google.golang.org/grpc:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
filegroup(
name = "go_default_library_protos",
srcs = ["api.proto"],
visibility = ["//visibility:public"],
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
// To regenerate api.pb.go run hack/update-device-plugin.sh
syntax = 'proto3';
package deviceplugin;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
option (gogoproto.goproto_getters_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_unrecognized_all) = false;
// Registration is the service advertised by the Kubelet
// Only when Kubelet answers with a success code to a Register Request
// may Device Plugins start their service
// Registration may fail when device plugin version is not supported by
// Kubelet or the registered resourceName is already taken by another
// active device plugin. Device plugin is expected to terminate upon registration failure
service Registration {
rpc Register(RegisterRequest) returns (Empty) {}
}
message RegisterRequest {
// Version of the API the Device Plugin was built against
string version = 1;
// Name of the unix socket the device plugin is listening on
// PATH = path.Join(DevicePluginPath, endpoint)
string endpoint = 2;
// Schedulable resource name. As of now it's expected to be a DNS Label
string resource_name = 3;
}
message Empty {
}
// DevicePlugin is the service advertised by Device Plugins
service DevicePlugin {
// ListAndWatch returns a stream of List of Devices
// Whenever a Device state change or a Device disapears, ListAndWatch
// returns the new list
rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}
// Allocate is called during container creation so that the Device
// Plugin can run device specific operations and instruct Kubelet
// of the steps to make the Device available in the container
rpc Allocate(AllocateRequest) returns (AllocateResponse) {}
}
// ListAndWatch returns a stream of List of Devices
// Whenever a Device state change or a Device disapears, ListAndWatch
// returns the new list
message ListAndWatchResponse {
repeated Device devices = 1;
}
/* E.g:
* struct Device {
* ID: "GPU-fef8089b-4820-abfc-e83e-94318197576e",
* State: "Healthy",
*} */
message Device {
// A unique ID assigned by the device plugin used
// to identify devices during the communication
// Max length of this field is 63 characters
string ID = 1;
// Health of the device, can be healthy or unhealthy, see constants.go
string health = 2;
}
// - Allocate is expected to be called during pod creation since allocation
// failures for any container would result in pod startup failure.
// - Allocate allows kubelet to exposes additional artifacts in a pod's
// environment as directed by the plugin.
// - Allocate allows Device Plugin to run device specific operations on
// the Devices requested
message AllocateRequest {
repeated string devicesIDs = 1;
}
// Failure Handling:
// if Kubelet sends an allocation request for dev1 and dev2.
// Allocation on dev1 succeeds but allocation on dev2 fails.
// The Device plugin should send a ListAndWatch update and fail the
// Allocation request
message AllocateResponse {
repeated DeviceRuntimeSpec spec = 1;
}
// The list to be added to the CRI spec
message DeviceRuntimeSpec {
// ID of the Device
string ID = 1;
// List of environment variable to set in the container.
map<string, string> envs = 2;
// Mounts for the container.
repeated Mount mounts = 3;
// Devices for the container
repeated DeviceSpec devices = 4;
}
// Mount specifies a host volume to mount into a container.
// where device library or tools are installed on host and container
message Mount {
// Path of the mount within the container.
string container_path = 1;
// Path of the mount on the host.
string host_path = 2;
// If set, the mount is read-only.
bool read_only = 3;
}
// DeviceSpec specifies a host device to mount into a container.
message DeviceSpec {
// Path of the device within the container.
string container_path = 1;
// Path of the device on the host.
string host_path = 2;
// Cgroups permissions of the device, candidates are one or more of
// * r - allows container to read from the specified device.
// * w - allows container to write to the specified device.
// * m - allows container to create device files that do not yet exist.
string permissions = 3;
}

View File

@ -0,0 +1,33 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package deviceplugin
const (
// Healthy means that the device is healty
Healthy = "Healthy"
// UnHealthy means that the device is unhealty
Unhealthy = "Unhealthy"
// Version is the API version
Version = "0.1"
// DevicePluginPath is the folder the Device Plugin is expecting sockets to be on
// Only privileged pods have access to this path
// Note: Placeholder until we find a "standard path"
DevicePluginPath = "/var/lib/kubelet/device-plugins/"
// KubeletSocket is the path of the Kubelet registry socket
KubeletSocket = DevicePluginPath + "kubelet.sock"
)