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

[WIP] PoC ResourceClass #3

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/kube-apiserver/app/server.go
Expand Up @@ -689,6 +689,10 @@ func postProcessOpenAPISpecForBackwardCompatibility(s *spec.Swagger) (*spec.Swag
"v1beta1.ClusterRoleList": "k8s.io/kubernetes/pkg/apis/rbac/v1beta1.ClusterRoleList",
"v1beta1.ResourceAttributes": "k8s.io/kubernetes/pkg/apis/authorization/v1beta1.ResourceAttributes",
"v1.Pod": "k8s.io/kubernetes/pkg/api/v1.Pod",
"v1.ResourceClass": "k8s.io/kubernetes/pkg/api/v1.ResourceClass",
"v1.ResourceClassList": "k8s.io/kubernetes/pkg/api/v1.ResourceClassList",
"v1.ResourceClassSpec": "k8s.io/kubernetes/pkg/api/v1.ResourceClassSpec",
"v1.ResourceClassStatus": "k8s.io/kubernetes/pkg/api/v1.ResourceClassStatus",
"v1.FCVolumeSource": "k8s.io/kubernetes/pkg/api/v1.FCVolumeSource",
"v1beta1.SubresourceReference": "k8s.io/kubernetes/pkg/apis/extensions/v1beta1.SubresourceReference",
"v1.ResourceQuotaStatus": "k8s.io/kubernetes/pkg/api/v1.ResourceQuotaStatus",
Expand Down
1 change: 1 addition & 0 deletions cmd/kubelet/app/options/options.go
Expand Up @@ -150,6 +150,7 @@ func (c *kubeletConfiguration) addFlags(fs *pflag.FlagSet) {
fs.BoolVar(&c.ExperimentalFailSwapOn, "experimental-fail-swap-on", c.ExperimentalFailSwapOn, "Makes the Kubelet fail to start if swap is enabled on the node. This is a temporary opton to maintain legacy behavior, failing due to swap enabled will happen by default in v1.6.")

fs.StringVar(&c.PodManifestPath, "pod-manifest-path", c.PodManifestPath, "Path to to the directory containing pod manifest files to run, or the path to a single pod manifest file. Files starting with dots will be ignored.")
fs.StringVar(&c.DeviceFilePath, "experimental-device-file-path", c.DeviceFilePath, "Path to the directory containing device yaml files to run, or the path to a single device file. Files starting with dots will be ignored.")
fs.DurationVar(&c.SyncFrequency.Duration, "sync-frequency", c.SyncFrequency.Duration, "Max period between synchronizing running containers and config")
fs.DurationVar(&c.FileCheckFrequency.Duration, "file-check-frequency", c.FileCheckFrequency.Duration, "Duration between checking config files for new data")
fs.DurationVar(&c.HTTPCheckFrequency.Duration, "http-check-frequency", c.HTTPCheckFrequency.Duration, "Duration between checking http for new data")
Expand Down
14 changes: 14 additions & 0 deletions examples/resource-class/nvidia.tesla.gpu.yaml
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Device
metadata:
name: nvidia-tesla-gpu
labels:
type: nvidia-gpu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[root@dell-r620-01 kubernetes]# kubectl get node mynode -o yaml

apiVersion: v1
kind: Node
metadata:
annotations:
node.alpha.kubernetes.io/ttl: "0"
volumes.kubernetes.io/controller-managed-attach-detach: "true"
creationTimestamp: 2017-05-24T16:32:26Z
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
uid: 927af813-409e-11e7-80f5-bc305bf4e400
spec:
externalID: dell-r620-01.perf.lab.eng.rdu.redhat.com
status:
addresses:

  • address: 10.12.20.41
    type: InternalIP
  • address: dell-r620-01.perf.lab.eng.rdu.redhat.com
    type: Hostname
  • address: 10.12.20.41
    type: LegacyHostIP
    allocatable:
    cpu: "16"
    memory: 131714184Ki
    pods: "110"
    capacity:
    cpu: "16"
    memory: 131816584Ki
    pods: "110"
    conditions:

daemonEndpoints:
kubeletEndpoint:
Port: 10250

deviceAllocatable:
- metadata:
    creationTimestamp: null
    labels:
      compute-ability: "3.7"
      ecc: "true"
      family: tesla
      memory: 10Gi
      model: k80
      nvlink: "true"
      quantity: "8"
      type: nvidia-gpu
    name: nvidia-tesla-gpu
deviceCapacity:
- metadata:
    creationTimestamp: null
    labels:
      compute-ability: "3.7"
      ecc: "true"
      family: tesla
      memory: 10Gi
      model: k80
      nvlink: "true"
      quantity: "8"
      type: nvidia-gpu
    name: nvidia-tesla-gpu

images:

  • names:
    • kube-build:build-748641720b-5-v1.8.1-2
      sizeBytes: 3158843585
  • names:
    • @
    • :
      sizeBytes: 3158843585
  • names:
    • gcr.io/google_containers/kube-cross@sha256:ac1327a97b1b3e01d2ded9a781bb5675cd657af3c9d1ff56b97fcc3f2f2cd59c
    • gcr.io/google_containers/kube-cross:v1.8.1-2
      sizeBytes: 2357991939
  • names:

quantity: "8"
compute-ability: "3.7"
memory: 10Gi
ecc: "true"
family: tesla
nvlink: "true"
model: k80

14 changes: 14 additions & 0 deletions examples/resource-class/rclass.yml
@@ -0,0 +1,14 @@
---
kind: ResourceClass
metadata:
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[root@dell-r620-01 kubernetes]# kubectl get resourceclass my.rc2 -o yaml
apiVersion: v1
kind: ResourceClass
metadata:
creationTimestamp: 2017-05-30T05:27:48Z
name: my.rc2
resourceVersion: "15222"
selfLink: /api/v1/namespaces/default/resourceclasses/my.rc2
uid: b820fe43-44f8-11e7-94f7-bc305bf4e400
spec:
resourceSelector:

  • matchExpressions:
    • key: Type
      operator: In
      values:
      • nvidia-gpu
        status: {}

name: my.rc2
spec:
resourceSelector:
-
matchExpressions:
-
key: "Type"
operator: "In"
values:
- "nvidia-gpu"

1 change: 1 addition & 0 deletions pkg/api/install/install.go
Expand Up @@ -44,6 +44,7 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
"Namespace",
"PersistentVolume",
"ComponentStatus",
"ResourceClass",
),
IgnoredKinds: sets.NewString(
"ListOptions",
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/register.go
Expand Up @@ -94,6 +94,9 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceClass{},
&ResourceClassList{},
&Device{},
&ResourceQuota{},
&ResourceQuotaList{},
&Namespace{},
Expand Down
81 changes: 81 additions & 0 deletions pkg/api/types.go
Expand Up @@ -1325,6 +1325,43 @@ type EnvVarSource struct {
SecretKeyRef *SecretKeySelector
}

// +nonNamespaced=true
// +genclient=true

// ResourceClass
type ResourceClass struct {
metav1.TypeMeta
// +optional
metav1.ObjectMeta

// Spec defines resources required
// +optional
Spec ResourceClassSpec
// +optional
Status ResourceClassStatus
}

type ResourceClassStatus struct {
Allocatable int32
Request int32
}

// Spec dictates features and properties of devices targeted by Resource Class
type ResourceClassSpec struct {
// ResourceSelector selects resources. ORed from each selector
ResourceSelector []ResourcePropertySelector
// +optional
SubResourcesCount int32
}

// RCList is a list of Rcs
type ResourceClassList struct {
metav1.TypeMeta
// +optional
metav1.ListMeta
Items []ResourceClass
}

// ObjectFieldSelector selects an APIVersioned field of an object.
type ObjectFieldSelector struct {
// Required: Version of the schema the FieldPath is written in terms of.
Expand Down Expand Up @@ -2859,6 +2896,44 @@ type NodeSystemInfo struct {
Architecture string
}

type DeviceSubResources struct {
// Name of the Device
Name string
// Count of devices
Quantity int32
}

// Device is a physical or logical device
type Device struct {
metav1.TypeMeta
// +optional
metav1.ObjectMeta
// Count of devices
Quantity int32
// Device can be a group of several other devices
// +optional
SubResources DeviceSubResources
}

type ResourceSelectorOperator NodeSelectorOperator

// A resource selector requirement is a selector that contains values, a key, and an operator
// that relates the key and values
type ResourceSelectorRequirement struct {
// The label key that the selector applies to
Key string
// Example 0.1, intel etc
Values []string
// operator
Operator ResourceSelectorOperator
}

// A null or empty selector matches no resources
type ResourcePropertySelector struct {
// A list of resource/device selector requirements
MatchExpressions []ResourceSelectorRequirement
}

// NodeStatus is information about the current status of a node.
type NodeStatus struct {
// Capacity represents the total resources of a node.
Expand Down Expand Up @@ -2891,6 +2966,12 @@ type NodeStatus struct {
// List of volumes that are attached to the node.
// +optional
VolumesAttached []AttachedVolume
// Total devices that are attached to the node.
// +optional
CapacityDevices []Device
// Allocatable devices that are attached to the node.
// +optional
AllocatableDevices []Device
}

type UniqueVolumeName string
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/v1/annotation_key_constants.go
Expand Up @@ -34,6 +34,10 @@ const (
// in the Annotations of a Node.
TaintsAnnotationKey string = "scheduler.alpha.kubernetes.io/taints"

// ResClassPodAnnotationKeyPrefix represents the key of a device allocated
// to one container of a pod.
ResClassPodAnnotationKeyPrefix string = "scheduler.alpha.kubernetes.io/resClass"

// SeccompPodAnnotationKey represents the key of a seccomp profile applied
// to all containers of a pod.
SeccompPodAnnotationKey string = "seccomp.security.alpha.kubernetes.io/pod"
Expand Down
34 changes: 34 additions & 0 deletions pkg/api/v1/helper/helpers.go
Expand Up @@ -169,6 +169,40 @@ func containsAccessMode(modes []v1.PersistentVolumeAccessMode, mode v1.Persisten
return false
}

// NodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements
// labels.Selector.
func ResourceSelectorRequirementsAsSelector(nsm []v1.ResourceSelectorRequirement) (labels.Selector, error) {
if len(nsm) == 0 {
return labels.Nothing(), nil
}
selector := labels.NewSelector()
for _, expr := range nsm {
var op selection.Operator
switch expr.Operator {
case v1.ResourceSelectorOpIn:
op = selection.In
case v1.ResourceSelectorOpNotIn:
op = selection.NotIn
case v1.ResourceSelectorOpExists:
op = selection.Exists
case v1.ResourceSelectorOpDoesNotExist:
op = selection.DoesNotExist
case v1.ResourceSelectorOpGt:
op = selection.GreaterThan
case v1.ResourceSelectorOpLt:
op = selection.LessThan
default:
return nil, fmt.Errorf("%q is not a valid node selector operator", expr.Operator)
}
r, err := labels.NewRequirement(expr.Key, op, expr.Values)
if err != nil {
return nil, err
}
selector = selector.Add(*r)
}
return selector, nil
}

// NodeSelectorRequirementsAsSelector converts the []NodeSelectorRequirement api type into a struct that implements
// labels.Selector.
func NodeSelectorRequirementsAsSelector(nsm []v1.NodeSelectorRequirement) (labels.Selector, error) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/v1/register.go
Expand Up @@ -72,6 +72,9 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceClass{},
&ResourceClassList{},
&Device{},
&ResourceQuota{},
&ResourceQuotaList{},
&Namespace{},
Expand Down
104 changes: 104 additions & 0 deletions pkg/api/v1/types.go
Expand Up @@ -1421,6 +1421,50 @@ type EnvVarSource struct {
SecretKeyRef *SecretKeySelector `json:"secretKeyRef,omitempty" protobuf:"bytes,4,opt,name=secretKeyRef"`
}

// +nonNamespaced=true
// +genclient=true

// ResourceClass is a resource class
type ResourceClass struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Spec defines resources required
// +optional
Spec ResourceClassSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Most recently observed status of the resource class.
// Populated by the system.
// Read-only
// +optional
Status ResourceClassStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// Spec defines resources required
type ResourceClassSpec struct {
// Resource Selector selects resources
ResourceSelector []ResourcePropertySelector `json:"resourceSelector" protobuf:"bytes,1,rep,name=resourceSelector"`
// +optional
SubResourcesCount int32 `json:"subResourcesCount" protobuf:"varint,2,opt,name=subResourcesCount"`
}

// ResourceClassStatus is information about the current status of a resource class
type ResourceClassStatus struct {
Allocatable int32 `json:"allocatable" protobuf:"varint,1,name=allocatable"`
Request int32 `json:"request" protobuf:"varint,2,name=request"`
}

// ResourceClassList is list of rcs
type ResourceClassList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// List of nodes
Items []ResourceClass `json:"items" protobuf:"bytes,2,rep,name=items"`
}

// ObjectFieldSelector selects an APIVersioned field of an object.
type ObjectFieldSelector struct {
// Version of the schema the FieldPath is written in terms of, defaults to "v1".
Expand Down Expand Up @@ -3279,6 +3323,60 @@ type NodeSystemInfo struct {
Architecture string `json:"architecture" protobuf:"bytes,10,opt,name=architecture"`
}

type DeviceSubResources struct {
// Name of the Device
Name string `json:"name" protobuf:"varint,1,name=name"`
// Count of devices
Quantity int32 `json:"quantity" protobuf:"varint,2,name=quantity"`
}

// +nonNamespaced=true

// ResourceClass is a resource class
// Device is a physical or logical device
type Device struct {
metav1.TypeMeta `json:",inline"`
// Standard object's metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// count of such devices on node
Quantity int32 `json:"quantity" protobuf:"varint,2,name=quantity"`
// Device can be a group of several other devices
// +optional
SubResources DeviceSubResources `json:"SubResources" protobuf:"bytes,3,opt,name=SubResources,casttype=DeviceSubResources"`
}

type ResourceSelectorOperator string

const (
ResourceSelectorOpIn ResourceSelectorOperator = "In"
ResourceSelectorOpNotIn ResourceSelectorOperator = "NotIn"
ResourceSelectorOpExists ResourceSelectorOperator = "Exists"
ResourceSelectorOpDoesNotExist ResourceSelectorOperator = "DoesNotExist"
ResourceSelectorOpGt ResourceSelectorOperator = "Gt"
ResourceSelectorOpLt ResourceSelectorOperator = "Lt"
)

// A resource selector requirement is a selector that contains values, a key, and an operator
// that relates the key and values
type ResourceSelectorRequirement struct {
// The label key that the selector applies to
// +patchMergeKey=key
// +patchStrategy=merge
Key string `json:"key" patchStrategy:"merge" patchMergeKey:"key" protobuf:"bytes,1,opt,name=key"`
// Example 0.1, intel etc
// +optional
Values []string `json:"values,omitempty" protobuf:"bytes,2,rep,name=values"`
// operator
Operator ResourceSelectorOperator `json:"operator" protobuf:"bytes,3,opt,name=operator,casttype=ResourceSelectorOperator"`
}

// A null or empty selector matches no resources
type ResourcePropertySelector struct {
// A list of resource/device selector requirements. ANDed from each ResourceSelectorRequirement
MatchExpressions []ResourceSelectorRequirement `json:"matchExpressions" protobuf:"bytes,1,rep,name=matchExpressions"`
}

// NodeStatus is information about the current status of a node.
type NodeStatus struct {
// Capacity represents the total resources of a node.
Expand Down Expand Up @@ -3323,6 +3421,12 @@ type NodeStatus struct {
// List of volumes that are attached to the node.
// +optional
VolumesAttached []AttachedVolume `json:"volumesAttached,omitempty" protobuf:"bytes,10,rep,name=volumesAttached"`
// Total devices that are attached to the node.
// +optional
CapacityDevices []Device `json:"deviceCapacity,omitempty" protobuf:"bytes,11,rep,name=deviceCapacity"`
// Allocatable devices that are attached to the node.
// +optional
AllocatableDevices []Device `json:"deviceAllocatable,omitempty" protobuf:"bytes,12,rep,name=deviceAllocatable"`
}

type UniqueVolumeName string
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/v1/validation/validation.go
Expand Up @@ -57,7 +57,8 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
for resourceName, quantity := range requirements.Requests {
fldPath := reqPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
//TODO(vikasc): commenting resource name validation because need to add handling for resource class name validation. One way, though very restrictive, could be to prefix rClass name with special string like "res-class-". For now switching off validation.
//allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
// Validate resource quantity.
allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...)
}
Expand Down