Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions pkg/config/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ allowed_annotations = [

const templateStringCrioRuntimeWorkloads = `# The workloads table defines ways to customize containers with different resources
# that work based on annotations, rather than the CRI.
# Note, the behavior of this table is EXPERIMENTAL and may change at any time.
# Each workload, has a name, activation_annotation, annotation_prefix and set of resources it supports mutating.
# The currently supported resources are "cpu" (to configure the cpu shares) and "cpuset" to configure the cpuset.
# Each resource can have a default value specified, or be empty.
Expand All @@ -971,21 +972,23 @@ const templateStringCrioRuntimeWorkloads = `# The workloads table defines ways t
# [crio.runtime.workloads.workload-type]
# activation_annotation = "io.crio/workload"
# annotation_prefix = "io.crio.workload-type"
# resources = { "cpu" = "", "cpuset" = "0-1", }
# [crio.runtime.workloads.workload-type.resources]
# cpuset = 0
# cpushares = "0-1"
# Where:
# The workload name is workload-type.
# To specify, the pod must have the "io.crio.workload" annotation (this is a precise string match).
# This workload supports setting cpuset and cpu resources.
# annotation_prefix is used to customize the different resources.
# To configure the cpu shares a container gets in the example above, the pod would have to have the following annotation:
# "io.crio.workload-type.cpu/{container_name} = {shares}"
# "io.crio.workload-type/$container_name = {"cpushares": "value"}"
{{ range $workload_type, $workload_config := .Workloads }}
[crio.runtime.workloads.{{ $workload_type }}]
activation_annotation = "{{ $workload_config.ActivationAnnotation }}"
annotation_prefix = "{{ $workload_config.AnnotationPrefix }}"
{{ if $workload_config.Resources }}
resources = { {{ range $resource, $default := $workload_config.Resources }}{{ printf "%q = %q, " $resource $default }}{{ end }}}
{{ end }}
[crio.runtime.workloads.{{ $workload_type }}.resources]
cpuset = "{{ $workload_config.Resources.CPUSet }}"
cpushares = {{ $workload_config.Resources.CPUShares }}
{{ end }}

`
Expand Down
106 changes: 35 additions & 71 deletions pkg/config/workloads.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package config

import (
"strconv"
"encoding/json"

"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
libresource "k8s.io/apimachinery/pkg/api/resource"
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
)

const (
CPUShareResource = "cpushares"
CPUSetResource = "cpuset"
)
type Resources struct {
CPUShares uint64 `json:"cpushares,omitempty"`
CPUSet string `json:"cpuset,omitempty"`
}

type Workloads map[string]*WorkloadConfig

Expand All @@ -30,7 +29,7 @@ type WorkloadConfig struct {
// If a container is configured to use this workload, and does not specify
// the annotation with the resource and value, the default value will apply.
// Default values do not need to be specified.
Resources map[string]string `toml:"resources"`
Resources *Resources `toml:"resources"`
}

func (w Workloads) Validate() error {
Expand All @@ -46,39 +45,20 @@ func (w *WorkloadConfig) Validate(workloadName string) error {
if w.ActivationAnnotation == "" {
return errors.Errorf("annotation shouldn't be empty for workload %q", workloadName)
}
for resource, defaultValue := range w.Resources {
m, ok := mutators[resource]
if !ok {
return errors.Errorf("process resource %s for workload %s: resource not supported", resource, workloadName)
}
if err := m.ValidateDefault(defaultValue); err != nil {
return errors.Wrapf(err, "process resource %s for workload %s: default value %s invalid", resource, workloadName, defaultValue)
}
}
return nil
return w.Resources.ValidateDefaults()
}

func (w Workloads) MutateSpecGivenAnnotations(ctrName string, specgen *generate.Generator, sboxAnnotations map[string]string) error {
workload := w.workloadGivenActivationAnnotation(sboxAnnotations)
if workload == nil {
return nil
}
for resource, defaultValue := range workload.Resources {
value := valueFromAnnotation(resource, defaultValue, workload.AnnotationPrefix, ctrName, sboxAnnotations)
if value == "" {
continue
}

m, ok := mutators[resource]
if !ok {
// CRI-O bug
panic(errors.Errorf("resource %s is not defined", resource))
}

if err := m.MutateSpec(specgen, value); err != nil {
return errors.Wrapf(err, "mutating spec given workload %s", workload.ActivationAnnotation)
}
resources, err := resourcesFromAnnotation(workload.AnnotationPrefix, ctrName, sboxAnnotations, workload.Resources)
if err != nil {
return err
}
resources.MutateSpec(specgen)

return nil
}

Expand All @@ -93,57 +73,41 @@ func (w Workloads) workloadGivenActivationAnnotation(sboxAnnotations map[string]
return nil
}

func valueFromAnnotation(resource, defaultValue, prefix, ctrName string, annotations map[string]string) string {
annotationKey := prefix + "." + resource + "/" + ctrName
func resourcesFromAnnotation(prefix, ctrName string, annotations map[string]string, defaultResources *Resources) (*Resources, error) {
annotationKey := prefix + "/" + ctrName
value, ok := annotations[annotationKey]
if !ok {
return defaultValue
return defaultResources, nil
}
return value
}

var mutators = map[string]Mutator{
CPUShareResource: new(cpuShareMutator),
CPUSetResource: new(cpusetMutator),
}

type Mutator interface {
ValidateDefault(string) error
MutateSpec(*generate.Generator, string) error
}

type cpusetMutator struct{}
var resources *Resources
if err := json.Unmarshal([]byte(value), &resources); err != nil {
return nil, err
}

func (m *cpusetMutator) ValidateDefault(set string) error {
if set == "" {
return nil
if resources.CPUSet == "" {
resources.CPUSet = defaultResources.CPUSet
}
if resources.CPUShares == 0 {
resources.CPUShares = defaultResources.CPUShares
}
_, err := cpuset.Parse(set)
return err
}

func (*cpusetMutator) MutateSpec(specgen *generate.Generator, configuredValue string) error {
specgen.SetLinuxResourcesCPUCpus(configuredValue)
return nil
return resources, nil
}

type cpuShareMutator struct{}

func (*cpuShareMutator) ValidateDefault(cpuShare string) error {
if cpuShare == "" {
func (r *Resources) ValidateDefaults() error {
if r.CPUSet == "" {
return nil
}
if _, err := libresource.ParseQuantity(cpuShare); err != nil {
return err
}
return nil
_, err := cpuset.Parse(r.CPUSet)
return err
}

func (*cpuShareMutator) MutateSpec(specgen *generate.Generator, configuredValue string) error {
u, err := strconv.ParseUint(configuredValue, 0, 64)
if err != nil {
return err
func (r *Resources) MutateSpec(specgen *generate.Generator) {
if r.CPUSet != "" {
specgen.SetLinuxResourcesCPUCpus(r.CPUSet)
}
if r.CPUShares != 0 {
specgen.SetLinuxResourcesCPUShares(r.CPUShares)
}
specgen.SetLinuxResourcesCPUShares(u)
return nil
}
16 changes: 9 additions & 7 deletions test/workloads.bats
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ function create_workload() {
[crio.runtime.workloads.management]
activation_annotation = "$activation"
annotation_prefix = "$prefix"
resources = { "cpushares" = "$cpushares", "cpuset" = "$cpuset" }
[crio.runtime.workloads.management.resources]
cpushares = $cpushares
cpuset = "$cpuset"
EOF
}

Expand Down Expand Up @@ -71,12 +73,12 @@ function check_cpu_fields() {

start_crio

jq --arg act "$activation" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$act] = "true"
| .annotations[$setkey] = $set' \
"$TESTDATA"/sandbox_config.json > "$sboxconfig"

jq --arg act "$activation" --arg name "$name" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg name "$name" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$act] = "true"
| .annotations[$setkey] = $set
| .metadata.name = $name' \
Expand All @@ -94,12 +96,12 @@ function check_cpu_fields() {

start_crio

jq --arg act "$activation" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$act] = "true"
| .annotations[$setkey] = $set' \
"$TESTDATA"/sandbox_config.json > "$sboxconfig"

jq --arg act "$activation" --arg name "$name" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg name "$name" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$act] = "true"
| .annotations[$setkey] = $set
| .metadata.name = $name' \
Expand All @@ -117,11 +119,11 @@ function check_cpu_fields() {

start_crio

jq --arg act "$activation" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$setkey] = $set' \
"$TESTDATA"/sandbox_config.json > "$sboxconfig"

jq --arg act "$activation" --arg name "$name" --arg set "$set" --arg setkey "$prefix.cpuset/$name" \
jq --arg act "$activation" --arg name "$name" --arg set "{\"cpuset\": \"$set\"}" --arg setkey "$prefix/$name" \
' .annotations[$setkey] = $set
| .metadata.name = $name
| del(.linux.resources.cpu_shares)' \
Expand Down