Replace godep with dep
This commit is contained in:
parent
1e7489927c
commit
bf5616c65b
14883 changed files with 3937406 additions and 361781 deletions
293
vendor/k8s.io/kubernetes/pkg/kubelet/BUILD
generated
vendored
Normal file
293
vendor/k8s.io/kubernetes/pkg/kubelet/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"active_deadline.go",
|
||||
"doc.go",
|
||||
"kubelet.go",
|
||||
"kubelet_getters.go",
|
||||
"kubelet_network.go",
|
||||
"kubelet_node_status.go",
|
||||
"kubelet_pods.go",
|
||||
"kubelet_resources.go",
|
||||
"kubelet_volumes.go",
|
||||
"networks.go",
|
||||
"oom_watcher.go",
|
||||
"pod_container_deletor.go",
|
||||
"pod_workers.go",
|
||||
"reason_cache.go",
|
||||
"runonce.go",
|
||||
"runtime.go",
|
||||
"util.go",
|
||||
"volume_host.go",
|
||||
],
|
||||
deps = [
|
||||
"//cmd/kubelet/app/options:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/api/v1/helper/qos:go_default_library",
|
||||
"//pkg/api/v1/pod:go_default_library",
|
||||
"//pkg/api/v1/resource:go_default_library",
|
||||
"//pkg/api/v1/validation:go_default_library",
|
||||
"//pkg/capabilities:go_default_library",
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/fieldpath:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/apis/cri:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
|
||||
"//pkg/kubelet/cadvisor:go_default_library",
|
||||
"//pkg/kubelet/certificate:go_default_library",
|
||||
"//pkg/kubelet/cm:go_default_library",
|
||||
"//pkg/kubelet/config:go_default_library",
|
||||
"//pkg/kubelet/configmap:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/dockershim:go_default_library",
|
||||
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||
"//pkg/kubelet/dockershim/remote:go_default_library",
|
||||
"//pkg/kubelet/envvars:go_default_library",
|
||||
"//pkg/kubelet/events:go_default_library",
|
||||
"//pkg/kubelet/eviction:go_default_library",
|
||||
"//pkg/kubelet/gpu:go_default_library",
|
||||
"//pkg/kubelet/gpu/nvidia:go_default_library",
|
||||
"//pkg/kubelet/images:go_default_library",
|
||||
"//pkg/kubelet/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/kuberuntime:go_default_library",
|
||||
"//pkg/kubelet/lifecycle:go_default_library",
|
||||
"//pkg/kubelet/metrics:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/pleg:go_default_library",
|
||||
"//pkg/kubelet/pod:go_default_library",
|
||||
"//pkg/kubelet/preemption:go_default_library",
|
||||
"//pkg/kubelet/prober:go_default_library",
|
||||
"//pkg/kubelet/prober/results:go_default_library",
|
||||
"//pkg/kubelet/remote:go_default_library",
|
||||
"//pkg/kubelet/rkt:go_default_library",
|
||||
"//pkg/kubelet/secret:go_default_library",
|
||||
"//pkg/kubelet/server:go_default_library",
|
||||
"//pkg/kubelet/server/portforward:go_default_library",
|
||||
"//pkg/kubelet/server/remotecommand:go_default_library",
|
||||
"//pkg/kubelet/server/stats:go_default_library",
|
||||
"//pkg/kubelet/server/streaming:go_default_library",
|
||||
"//pkg/kubelet/stats:go_default_library",
|
||||
"//pkg/kubelet/status:go_default_library",
|
||||
"//pkg/kubelet/sysctl:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//pkg/kubelet/util:go_default_library",
|
||||
"//pkg/kubelet/util/format:go_default_library",
|
||||
"//pkg/kubelet/util/queue:go_default_library",
|
||||
"//pkg/kubelet/util/sliceutils:go_default_library",
|
||||
"//pkg/kubelet/volumemanager:go_default_library",
|
||||
"//pkg/security/apparmor:go_default_library",
|
||||
"//pkg/securitycontext:go_default_library",
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/file:go_default_library",
|
||||
"//pkg/util/io:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/oom:go_default_library",
|
||||
"//pkg/util/removeall:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//pkg/volume:go_default_library",
|
||||
"//pkg/volume/util:go_default_library",
|
||||
"//pkg/volume/util/types:go_default_library",
|
||||
"//pkg/volume/util/volumehelper:go_default_library",
|
||||
"//pkg/volume/validation:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm/predicates:go_default_library",
|
||||
"//third_party/forked/golang/expansion:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/golang/groupcache/lru:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/events:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/remotecommand:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/integer:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"active_deadline_test.go",
|
||||
"kubelet_getters_test.go",
|
||||
"kubelet_network_test.go",
|
||||
"kubelet_node_status_test.go",
|
||||
"kubelet_pods_test.go",
|
||||
"kubelet_resources_test.go",
|
||||
"kubelet_test.go",
|
||||
"kubelet_volumes_test.go",
|
||||
"networks_test.go",
|
||||
"oom_watcher_test.go",
|
||||
"pod_container_deletor_test.go",
|
||||
"pod_workers_test.go",
|
||||
"reason_cache_test.go",
|
||||
"runonce_test.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"kubelet_pods_windows_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/capabilities:go_default_library",
|
||||
"//pkg/cloudprovider/providers/fake:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
||||
"//pkg/kubelet/cm:go_default_library",
|
||||
"//pkg/kubelet/config:go_default_library",
|
||||
"//pkg/kubelet/configmap:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/container/testing:go_default_library",
|
||||
"//pkg/kubelet/eviction:go_default_library",
|
||||
"//pkg/kubelet/gpu:go_default_library",
|
||||
"//pkg/kubelet/images:go_default_library",
|
||||
"//pkg/kubelet/lifecycle:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/network/testing:go_default_library",
|
||||
"//pkg/kubelet/pleg:go_default_library",
|
||||
"//pkg/kubelet/pod:go_default_library",
|
||||
"//pkg/kubelet/pod/testing:go_default_library",
|
||||
"//pkg/kubelet/prober/results:go_default_library",
|
||||
"//pkg/kubelet/prober/testing:go_default_library",
|
||||
"//pkg/kubelet/secret:go_default_library",
|
||||
"//pkg/kubelet/server/portforward:go_default_library",
|
||||
"//pkg/kubelet/server/remotecommand:go_default_library",
|
||||
"//pkg/kubelet/server/stats:go_default_library",
|
||||
"//pkg/kubelet/stats:go_default_library",
|
||||
"//pkg/kubelet/status:go_default_library",
|
||||
"//pkg/kubelet/status/testing:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//pkg/kubelet/util/queue:go_default_library",
|
||||
"//pkg/kubelet/util/sliceutils:go_default_library",
|
||||
"//pkg/kubelet/volumemanager:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//pkg/volume:go_default_library",
|
||||
"//pkg/volume/host_path:go_default_library",
|
||||
"//pkg/volume/testing:go_default_library",
|
||||
"//pkg/volume/util/volumehelper:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/rand:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/apis:all-srcs",
|
||||
"//pkg/kubelet/cadvisor:all-srcs",
|
||||
"//pkg/kubelet/certificate:all-srcs",
|
||||
"//pkg/kubelet/client:all-srcs",
|
||||
"//pkg/kubelet/cm:all-srcs",
|
||||
"//pkg/kubelet/config:all-srcs",
|
||||
"//pkg/kubelet/configmap:all-srcs",
|
||||
"//pkg/kubelet/container:all-srcs",
|
||||
"//pkg/kubelet/custommetrics:all-srcs",
|
||||
"//pkg/kubelet/deviceplugin:all-srcs",
|
||||
"//pkg/kubelet/dockershim:all-srcs",
|
||||
"//pkg/kubelet/envvars:all-srcs",
|
||||
"//pkg/kubelet/events:all-srcs",
|
||||
"//pkg/kubelet/eviction:all-srcs",
|
||||
"//pkg/kubelet/gpu:all-srcs",
|
||||
"//pkg/kubelet/images:all-srcs",
|
||||
"//pkg/kubelet/kubeletconfig:all-srcs",
|
||||
"//pkg/kubelet/kuberuntime:all-srcs",
|
||||
"//pkg/kubelet/leaky:all-srcs",
|
||||
"//pkg/kubelet/lifecycle:all-srcs",
|
||||
"//pkg/kubelet/metrics:all-srcs",
|
||||
"//pkg/kubelet/network:all-srcs",
|
||||
"//pkg/kubelet/pleg:all-srcs",
|
||||
"//pkg/kubelet/pod:all-srcs",
|
||||
"//pkg/kubelet/preemption:all-srcs",
|
||||
"//pkg/kubelet/prober:all-srcs",
|
||||
"//pkg/kubelet/qos:all-srcs",
|
||||
"//pkg/kubelet/remote:all-srcs",
|
||||
"//pkg/kubelet/rkt:all-srcs",
|
||||
"//pkg/kubelet/rktshim:all-srcs",
|
||||
"//pkg/kubelet/secret:all-srcs",
|
||||
"//pkg/kubelet/server:all-srcs",
|
||||
"//pkg/kubelet/stats:all-srcs",
|
||||
"//pkg/kubelet/status:all-srcs",
|
||||
"//pkg/kubelet/sysctl:all-srcs",
|
||||
"//pkg/kubelet/types:all-srcs",
|
||||
"//pkg/kubelet/util:all-srcs",
|
||||
"//pkg/kubelet/volumemanager:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
9
vendor/k8s.io/kubernetes/pkg/kubelet/OWNERS
generated
vendored
Normal file
9
vendor/k8s.io/kubernetes/pkg/kubelet/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
approvers:
|
||||
- Random-Liu
|
||||
- dchen1107
|
||||
- derekwaynecarr
|
||||
- tallclair
|
||||
- vishh
|
||||
- yujuhong
|
||||
reviewers:
|
||||
- sig-node-reviewers
|
||||
98
vendor/k8s.io/kubernetes/pkg/kubelet/active_deadline.go
generated
vendored
Normal file
98
vendor/k8s.io/kubernetes/pkg/kubelet/active_deadline.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright 2016 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 kubelet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
)
|
||||
|
||||
const (
|
||||
reason = "DeadlineExceeded"
|
||||
message = "Pod was active on the node longer than the specified deadline"
|
||||
)
|
||||
|
||||
// activeDeadlineHandler knows how to enforce active deadlines on pods.
|
||||
type activeDeadlineHandler struct {
|
||||
// the clock to use for deadline enforcement
|
||||
clock clock.Clock
|
||||
// the provider of pod status
|
||||
podStatusProvider status.PodStatusProvider
|
||||
// the recorder to dispatch events when we identify a pod has exceeded active deadline
|
||||
recorder record.EventRecorder
|
||||
}
|
||||
|
||||
// newActiveDeadlineHandler returns an active deadline handler that can enforce pod active deadline
|
||||
func newActiveDeadlineHandler(
|
||||
podStatusProvider status.PodStatusProvider,
|
||||
recorder record.EventRecorder,
|
||||
clock clock.Clock,
|
||||
) (*activeDeadlineHandler, error) {
|
||||
|
||||
// check for all required fields
|
||||
if clock == nil || podStatusProvider == nil || recorder == nil {
|
||||
return nil, fmt.Errorf("Required arguments must not be nil: %v, %v, %v", clock, podStatusProvider, recorder)
|
||||
}
|
||||
return &activeDeadlineHandler{
|
||||
clock: clock,
|
||||
podStatusProvider: podStatusProvider,
|
||||
recorder: recorder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ShouldSync returns true if the pod is past its active deadline.
|
||||
func (m *activeDeadlineHandler) ShouldSync(pod *v1.Pod) bool {
|
||||
return m.pastActiveDeadline(pod)
|
||||
}
|
||||
|
||||
// ShouldEvict returns true if the pod is past its active deadline.
|
||||
// It dispatches an event that the pod should be evicted if it is past its deadline.
|
||||
func (m *activeDeadlineHandler) ShouldEvict(pod *v1.Pod) lifecycle.ShouldEvictResponse {
|
||||
if !m.pastActiveDeadline(pod) {
|
||||
return lifecycle.ShouldEvictResponse{Evict: false}
|
||||
}
|
||||
m.recorder.Eventf(pod, v1.EventTypeNormal, reason, message)
|
||||
return lifecycle.ShouldEvictResponse{Evict: true, Reason: reason, Message: message}
|
||||
}
|
||||
|
||||
// pastActiveDeadline returns true if the pod has been active for more than its ActiveDeadlineSeconds
|
||||
func (m *activeDeadlineHandler) pastActiveDeadline(pod *v1.Pod) bool {
|
||||
// no active deadline was specified
|
||||
if pod.Spec.ActiveDeadlineSeconds == nil {
|
||||
return false
|
||||
}
|
||||
// get the latest status to determine if it was started
|
||||
podStatus, ok := m.podStatusProvider.GetPodStatus(pod.UID)
|
||||
if !ok {
|
||||
podStatus = pod.Status
|
||||
}
|
||||
// we have no start time so just return
|
||||
if podStatus.StartTime.IsZero() {
|
||||
return false
|
||||
}
|
||||
// determine if the deadline was exceeded
|
||||
start := podStatus.StartTime.Time
|
||||
duration := m.clock.Since(start)
|
||||
allowedDuration := time.Duration(*pod.Spec.ActiveDeadlineSeconds) * time.Second
|
||||
return duration >= allowedDuration
|
||||
}
|
||||
95
vendor/k8s.io/kubernetes/pkg/kubelet/active_deadline_test.go
generated
vendored
Normal file
95
vendor/k8s.io/kubernetes/pkg/kubelet/active_deadline_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2016 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 kubelet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
// mockPodStatusProvider returns the status on the specified pod
|
||||
type mockPodStatusProvider struct {
|
||||
pods []*v1.Pod
|
||||
}
|
||||
|
||||
// GetPodStatus returns the status on the associated pod with matching uid (if found)
|
||||
func (m *mockPodStatusProvider) GetPodStatus(uid types.UID) (v1.PodStatus, bool) {
|
||||
for _, pod := range m.pods {
|
||||
if pod.UID == uid {
|
||||
return pod.Status, true
|
||||
}
|
||||
}
|
||||
return v1.PodStatus{}, false
|
||||
}
|
||||
|
||||
// TestActiveDeadlineHandler verifies the active deadline handler functions as expected.
|
||||
func TestActiveDeadlineHandler(t *testing.T) {
|
||||
pods := newTestPods(4)
|
||||
fakeClock := clock.NewFakeClock(time.Now())
|
||||
podStatusProvider := &mockPodStatusProvider{pods: pods}
|
||||
fakeRecorder := &record.FakeRecorder{}
|
||||
handler, err := newActiveDeadlineHandler(podStatusProvider, fakeRecorder, fakeClock)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
now := metav1.Now()
|
||||
startTime := metav1.NewTime(now.Time.Add(-1 * time.Minute))
|
||||
|
||||
// this pod has exceeded its active deadline
|
||||
exceededActiveDeadlineSeconds := int64(30)
|
||||
pods[0].Status.StartTime = &startTime
|
||||
pods[0].Spec.ActiveDeadlineSeconds = &exceededActiveDeadlineSeconds
|
||||
|
||||
// this pod has not exceeded its active deadline
|
||||
notYetActiveDeadlineSeconds := int64(120)
|
||||
pods[1].Status.StartTime = &startTime
|
||||
pods[1].Spec.ActiveDeadlineSeconds = ¬YetActiveDeadlineSeconds
|
||||
|
||||
// this pod has no deadline
|
||||
pods[2].Status.StartTime = &startTime
|
||||
pods[2].Spec.ActiveDeadlineSeconds = nil
|
||||
|
||||
testCases := []struct {
|
||||
pod *v1.Pod
|
||||
expected bool
|
||||
}{{pods[0], true}, {pods[1], false}, {pods[2], false}, {pods[3], false}}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
if actual := handler.ShouldSync(testCase.pod); actual != testCase.expected {
|
||||
t.Errorf("[%d] ShouldSync expected %#v, got %#v", i, testCase.expected, actual)
|
||||
}
|
||||
actual := handler.ShouldEvict(testCase.pod)
|
||||
if actual.Evict != testCase.expected {
|
||||
t.Errorf("[%d] ShouldEvict.Evict expected %#v, got %#v", i, testCase.expected, actual.Evict)
|
||||
}
|
||||
if testCase.expected {
|
||||
if actual.Reason != reason {
|
||||
t.Errorf("[%d] ShouldEvict.Reason expected %#v, got %#v", i, message, actual.Reason)
|
||||
}
|
||||
if actual.Message != message {
|
||||
t.Errorf("[%d] ShouldEvict.Message expected %#v, got %#v", i, message, actual.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/BUILD
generated
vendored
Normal file
29
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["services.go"],
|
||||
deps = ["//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/apis/cri/testing:all-srcs",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
115
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/services.go
generated
vendored
Normal file
115
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/services.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2016 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 cri
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
// RuntimeVersioner contains methods for runtime name, version and API version.
|
||||
type RuntimeVersioner interface {
|
||||
// Version returns the runtime name, runtime version and runtime API version
|
||||
Version(apiVersion string) (*runtimeapi.VersionResponse, error)
|
||||
}
|
||||
|
||||
// ContainerManager contains methods to manipulate containers managed by a
|
||||
// container runtime. The methods are thread-safe.
|
||||
type ContainerManager interface {
|
||||
// CreateContainer creates a new container in specified PodSandbox.
|
||||
CreateContainer(podSandboxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error)
|
||||
// StartContainer starts the container.
|
||||
StartContainer(containerID string) error
|
||||
// StopContainer stops a running container with a grace period (i.e., timeout).
|
||||
StopContainer(containerID string, timeout int64) error
|
||||
// RemoveContainer removes the container.
|
||||
RemoveContainer(containerID string) error
|
||||
// ListContainers lists all containers by filters.
|
||||
ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error)
|
||||
// ContainerStatus returns the status of the container.
|
||||
ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error)
|
||||
// UpdateContainerResources updates the cgroup resources for the container.
|
||||
UpdateContainerResources(containerID string, resources *runtimeapi.LinuxContainerResources) error
|
||||
// ExecSync executes a command in the container, and returns the stdout output.
|
||||
// If command exits with a non-zero exit code, an error is returned.
|
||||
ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error)
|
||||
// Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
|
||||
Exec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error)
|
||||
// Attach prepares a streaming endpoint to attach to a running container, and returns the address.
|
||||
Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error)
|
||||
}
|
||||
|
||||
// PodSandboxManager contains methods for operating on PodSandboxes. The methods
|
||||
// are thread-safe.
|
||||
type PodSandboxManager interface {
|
||||
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure
|
||||
// the sandbox is in ready state.
|
||||
RunPodSandbox(config *runtimeapi.PodSandboxConfig) (string, error)
|
||||
// StopPodSandbox stops the sandbox. If there are any running containers in the
|
||||
// sandbox, they should be force terminated.
|
||||
StopPodSandbox(podSandboxID string) error
|
||||
// RemovePodSandbox removes the sandbox. If there are running containers in the
|
||||
// sandbox, they should be forcibly removed.
|
||||
RemovePodSandbox(podSandboxID string) error
|
||||
// PodSandboxStatus returns the Status of the PodSandbox.
|
||||
PodSandboxStatus(podSandboxID string) (*runtimeapi.PodSandboxStatus, error)
|
||||
// ListPodSandbox returns a list of Sandbox.
|
||||
ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error)
|
||||
// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
|
||||
PortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error)
|
||||
}
|
||||
|
||||
// ContainerStatsManager contains methods for retriving the container
|
||||
// statistics.
|
||||
type ContainerStatsManager interface {
|
||||
// ContainerStats returns stats of the container. If the container does not
|
||||
// exist, the call returns an error.
|
||||
ContainerStats(containerID string) (*runtimeapi.ContainerStats, error)
|
||||
// ListContainerStats returns stats of all running containers.
|
||||
ListContainerStats(filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error)
|
||||
}
|
||||
|
||||
// RuntimeService interface should be implemented by a container runtime.
|
||||
// The methods should be thread-safe.
|
||||
type RuntimeService interface {
|
||||
RuntimeVersioner
|
||||
ContainerManager
|
||||
PodSandboxManager
|
||||
ContainerStatsManager
|
||||
|
||||
// UpdateRuntimeConfig updates runtime configuration if specified
|
||||
UpdateRuntimeConfig(runtimeConfig *runtimeapi.RuntimeConfig) error
|
||||
// Status returns the status of the runtime.
|
||||
Status() (*runtimeapi.RuntimeStatus, error)
|
||||
}
|
||||
|
||||
// ImageManagerService interface should be implemented by a container image
|
||||
// manager.
|
||||
// The methods should be thread-safe.
|
||||
type ImageManagerService interface {
|
||||
// ListImages lists the existing images.
|
||||
ListImages(filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error)
|
||||
// ImageStatus returns the status of the image.
|
||||
ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error)
|
||||
// PullImage pulls an image with the authentication config.
|
||||
PullImage(image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig) (string, error)
|
||||
// RemoveImage removes the image.
|
||||
RemoveImage(image *runtimeapi.ImageSpec) error
|
||||
// ImageFsInfo returns information of the filesystem that is used to store images.
|
||||
ImageFsInfo() ([]*runtimeapi.FilesystemUsage, error)
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/BUILD
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"fake_image_service.go",
|
||||
"fake_runtime_service.go",
|
||||
"utils.go",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/util/sliceutils:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
157
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/fake_image_service.go
generated
vendored
Normal file
157
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/fake_image_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
Copyright 2016 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 testing
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
|
||||
)
|
||||
|
||||
type FakeImageService struct {
|
||||
sync.Mutex
|
||||
|
||||
FakeImageSize uint64
|
||||
Called []string
|
||||
Images map[string]*runtimeapi.Image
|
||||
|
||||
pulledImages []*pulledImage
|
||||
|
||||
FakeFilesystemUsage []*runtimeapi.FilesystemUsage
|
||||
}
|
||||
|
||||
func (r *FakeImageService) SetFakeImages(images []string) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Images = make(map[string]*runtimeapi.Image)
|
||||
for _, image := range images {
|
||||
r.Images[image] = r.makeFakeImage(image)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeImageService) SetFakeImageSize(size uint64) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.FakeImageSize = size
|
||||
}
|
||||
|
||||
func (r *FakeImageService) SetFakeFilesystemUsage(usage []*runtimeapi.FilesystemUsage) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.FakeFilesystemUsage = usage
|
||||
}
|
||||
|
||||
func NewFakeImageService() *FakeImageService {
|
||||
return &FakeImageService{
|
||||
Called: make([]string, 0),
|
||||
Images: make(map[string]*runtimeapi.Image),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeImageService) makeFakeImage(image string) *runtimeapi.Image {
|
||||
return &runtimeapi.Image{
|
||||
Id: image,
|
||||
Size_: r.FakeImageSize,
|
||||
RepoTags: []string{image},
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeImageService) ListImages(filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ListImages")
|
||||
|
||||
images := make([]*runtimeapi.Image, 0)
|
||||
for _, img := range r.Images {
|
||||
if filter != nil && filter.Image != nil {
|
||||
if !sliceutils.StringInSlice(filter.Image.Image, img.RepoTags) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
images = append(images, img)
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
func (r *FakeImageService) ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ImageStatus")
|
||||
|
||||
return r.Images[image.Image], nil
|
||||
}
|
||||
|
||||
func (r *FakeImageService) PullImage(image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig) (string, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "PullImage")
|
||||
|
||||
r.pulledImages = append(r.pulledImages, &pulledImage{imageSpec: image, authConfig: auth})
|
||||
// ImageID should be randomized for real container runtime, but here just use
|
||||
// image's name for easily making fake images.
|
||||
imageID := image.Image
|
||||
if _, ok := r.Images[imageID]; !ok {
|
||||
r.Images[imageID] = r.makeFakeImage(image.Image)
|
||||
}
|
||||
|
||||
return imageID, nil
|
||||
}
|
||||
|
||||
func (r *FakeImageService) RemoveImage(image *runtimeapi.ImageSpec) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "RemoveImage")
|
||||
|
||||
// Remove the image
|
||||
delete(r.Images, image.Image)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImageFsInfo returns information of the filesystem that is used to store images.
|
||||
func (r *FakeImageService) ImageFsInfo() ([]*runtimeapi.FilesystemUsage, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ImageFsInfo")
|
||||
|
||||
return r.FakeFilesystemUsage, nil
|
||||
}
|
||||
|
||||
func (r *FakeImageService) AssertImagePulledWithAuth(t *testing.T, image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig, failMsg string) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
expected := &pulledImage{imageSpec: image, authConfig: auth}
|
||||
assert.Contains(t, r.pulledImages, expected, failMsg)
|
||||
}
|
||||
|
||||
type pulledImage struct {
|
||||
imageSpec *runtimeapi.ImageSpec
|
||||
authConfig *runtimeapi.AuthConfig
|
||||
}
|
||||
461
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/fake_runtime_service.go
generated
vendored
Normal file
461
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/fake_runtime_service.go
generated
vendored
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
Copyright 2016 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "0.1.0"
|
||||
|
||||
FakeRuntimeName = "fakeRuntime"
|
||||
FakePodSandboxIP = "192.168.192.168"
|
||||
)
|
||||
|
||||
type FakePodSandbox struct {
|
||||
// PodSandboxStatus contains the runtime information for a sandbox.
|
||||
runtimeapi.PodSandboxStatus
|
||||
}
|
||||
|
||||
type FakeContainer struct {
|
||||
// ContainerStatus contains the runtime information for a container.
|
||||
runtimeapi.ContainerStatus
|
||||
|
||||
// the sandbox id of this container
|
||||
SandboxID string
|
||||
}
|
||||
|
||||
type FakeRuntimeService struct {
|
||||
sync.Mutex
|
||||
|
||||
Called []string
|
||||
|
||||
FakeStatus *runtimeapi.RuntimeStatus
|
||||
Containers map[string]*FakeContainer
|
||||
Sandboxes map[string]*FakePodSandbox
|
||||
FakeContainerStats map[string]*runtimeapi.ContainerStats
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) GetContainerID(sandboxID, name string, attempt uint32) (string, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
for id, c := range r.Containers {
|
||||
if c.SandboxID == sandboxID && c.Metadata.Name == name && c.Metadata.Attempt == attempt {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("container (name, attempt, sandboxID)=(%q, %d, %q) not found", name, attempt, sandboxID)
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) SetFakeSandboxes(sandboxes []*FakePodSandbox) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Sandboxes = make(map[string]*FakePodSandbox)
|
||||
for _, sandbox := range sandboxes {
|
||||
sandboxID := sandbox.Id
|
||||
r.Sandboxes[sandboxID] = sandbox
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) SetFakeContainers(containers []*FakeContainer) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Containers = make(map[string]*FakeContainer)
|
||||
for _, c := range containers {
|
||||
containerID := c.Id
|
||||
r.Containers[containerID] = c
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) AssertCalls(calls []string) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if !reflect.DeepEqual(calls, r.Called) {
|
||||
return fmt.Errorf("expected %#v, got %#v", calls, r.Called)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeRuntimeService() *FakeRuntimeService {
|
||||
return &FakeRuntimeService{
|
||||
Called: make([]string, 0),
|
||||
Containers: make(map[string]*FakeContainer),
|
||||
Sandboxes: make(map[string]*FakePodSandbox),
|
||||
FakeContainerStats: make(map[string]*runtimeapi.ContainerStats),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) Version(apiVersion string) (*runtimeapi.VersionResponse, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "Version")
|
||||
|
||||
return &runtimeapi.VersionResponse{
|
||||
Version: version,
|
||||
RuntimeName: FakeRuntimeName,
|
||||
RuntimeVersion: version,
|
||||
RuntimeApiVersion: version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) Status() (*runtimeapi.RuntimeStatus, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "Status")
|
||||
|
||||
return r.FakeStatus, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) RunPodSandbox(config *runtimeapi.PodSandboxConfig) (string, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "RunPodSandbox")
|
||||
|
||||
// PodSandboxID should be randomized for real container runtime, but here just use
|
||||
// fixed name from BuildSandboxName() for easily making fake sandboxes.
|
||||
podSandboxID := BuildSandboxName(config.Metadata)
|
||||
createdAt := time.Now().UnixNano()
|
||||
r.Sandboxes[podSandboxID] = &FakePodSandbox{
|
||||
PodSandboxStatus: runtimeapi.PodSandboxStatus{
|
||||
Id: podSandboxID,
|
||||
Metadata: config.Metadata,
|
||||
State: runtimeapi.PodSandboxState_SANDBOX_READY,
|
||||
CreatedAt: createdAt,
|
||||
Network: &runtimeapi.PodSandboxNetworkStatus{
|
||||
Ip: FakePodSandboxIP,
|
||||
},
|
||||
Labels: config.Labels,
|
||||
Annotations: config.Annotations,
|
||||
},
|
||||
}
|
||||
|
||||
return podSandboxID, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) StopPodSandbox(podSandboxID string) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "StopPodSandbox")
|
||||
|
||||
if s, ok := r.Sandboxes[podSandboxID]; ok {
|
||||
s.State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
} else {
|
||||
return fmt.Errorf("pod sandbox %s not found", podSandboxID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) RemovePodSandbox(podSandboxID string) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "RemovePodSandbox")
|
||||
|
||||
// Remove the pod sandbox
|
||||
delete(r.Sandboxes, podSandboxID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) PodSandboxStatus(podSandboxID string) (*runtimeapi.PodSandboxStatus, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "PodSandboxStatus")
|
||||
|
||||
s, ok := r.Sandboxes[podSandboxID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("pod sandbox %q not found", podSandboxID)
|
||||
}
|
||||
|
||||
status := s.PodSandboxStatus
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ListPodSandbox")
|
||||
|
||||
result := make([]*runtimeapi.PodSandbox, 0)
|
||||
for id, s := range r.Sandboxes {
|
||||
if filter != nil {
|
||||
if filter.Id != "" && filter.Id != id {
|
||||
continue
|
||||
}
|
||||
if filter.State != nil && filter.GetState().State != s.State {
|
||||
continue
|
||||
}
|
||||
if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, s.GetLabels()) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, &runtimeapi.PodSandbox{
|
||||
Id: s.Id,
|
||||
Metadata: s.Metadata,
|
||||
State: s.State,
|
||||
CreatedAt: s.CreatedAt,
|
||||
Labels: s.Labels,
|
||||
Annotations: s.Annotations,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) PortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "PortForward")
|
||||
return &runtimeapi.PortForwardResponse{}, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) CreateContainer(podSandboxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "CreateContainer")
|
||||
|
||||
// ContainerID should be randomized for real container runtime, but here just use
|
||||
// fixed BuildContainerName() for easily making fake containers.
|
||||
containerID := BuildContainerName(config.Metadata, podSandboxID)
|
||||
createdAt := time.Now().UnixNano()
|
||||
createdState := runtimeapi.ContainerState_CONTAINER_CREATED
|
||||
imageRef := config.Image.Image
|
||||
r.Containers[containerID] = &FakeContainer{
|
||||
ContainerStatus: runtimeapi.ContainerStatus{
|
||||
Id: containerID,
|
||||
Metadata: config.Metadata,
|
||||
Image: config.Image,
|
||||
ImageRef: imageRef,
|
||||
CreatedAt: createdAt,
|
||||
State: createdState,
|
||||
Labels: config.Labels,
|
||||
Annotations: config.Annotations,
|
||||
},
|
||||
SandboxID: podSandboxID,
|
||||
}
|
||||
|
||||
return containerID, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) StartContainer(containerID string) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "StartContainer")
|
||||
|
||||
c, ok := r.Containers[containerID]
|
||||
if !ok {
|
||||
return fmt.Errorf("container %s not found", containerID)
|
||||
}
|
||||
|
||||
// Set container to running.
|
||||
c.State = runtimeapi.ContainerState_CONTAINER_RUNNING
|
||||
c.StartedAt = time.Now().UnixNano()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) StopContainer(containerID string, timeout int64) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "StopContainer")
|
||||
|
||||
c, ok := r.Containers[containerID]
|
||||
if !ok {
|
||||
return fmt.Errorf("container %q not found", containerID)
|
||||
}
|
||||
|
||||
// Set container to exited state.
|
||||
finishedAt := time.Now().UnixNano()
|
||||
exitedState := runtimeapi.ContainerState_CONTAINER_EXITED
|
||||
c.State = exitedState
|
||||
c.FinishedAt = finishedAt
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) RemoveContainer(containerID string) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "RemoveContainer")
|
||||
|
||||
// Remove the container
|
||||
delete(r.Containers, containerID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ListContainers")
|
||||
|
||||
result := make([]*runtimeapi.Container, 0)
|
||||
for _, s := range r.Containers {
|
||||
if filter != nil {
|
||||
if filter.Id != "" && filter.Id != s.Id {
|
||||
continue
|
||||
}
|
||||
if filter.PodSandboxId != "" && filter.PodSandboxId != s.SandboxID {
|
||||
continue
|
||||
}
|
||||
if filter.State != nil && filter.GetState().State != s.State {
|
||||
continue
|
||||
}
|
||||
if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, s.GetLabels()) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, &runtimeapi.Container{
|
||||
Id: s.Id,
|
||||
CreatedAt: s.CreatedAt,
|
||||
PodSandboxId: s.SandboxID,
|
||||
Metadata: s.Metadata,
|
||||
State: s.State,
|
||||
Image: s.Image,
|
||||
ImageRef: s.ImageRef,
|
||||
Labels: s.Labels,
|
||||
Annotations: s.Annotations,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ContainerStatus")
|
||||
|
||||
c, ok := r.Containers[containerID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("container %q not found", containerID)
|
||||
}
|
||||
|
||||
status := c.ContainerStatus
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) UpdateContainerResources(string, *runtimeapi.LinuxContainerResources) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ExecSync")
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) Exec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "Exec")
|
||||
return &runtimeapi.ExecResponse{}, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "Attach")
|
||||
return &runtimeapi.AttachResponse{}, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) UpdateRuntimeConfig(runtimeCOnfig *runtimeapi.RuntimeConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) SetFakeContainerStats(containerStats []*runtimeapi.ContainerStats) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.FakeContainerStats = make(map[string]*runtimeapi.ContainerStats)
|
||||
for _, s := range containerStats {
|
||||
r.FakeContainerStats[s.Attributes.Id] = s
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ContainerStats(containerID string) (*runtimeapi.ContainerStats, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ContainerStats")
|
||||
|
||||
s, found := r.FakeContainerStats[containerID]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("no stats for container %q", containerID)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (r *FakeRuntimeService) ListContainerStats(filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
r.Called = append(r.Called, "ListContainerStats")
|
||||
|
||||
var result []*runtimeapi.ContainerStats
|
||||
for _, c := range r.Containers {
|
||||
if filter != nil {
|
||||
if filter.Id != "" && filter.Id != c.Id {
|
||||
continue
|
||||
}
|
||||
if filter.PodSandboxId != "" && filter.PodSandboxId != c.SandboxID {
|
||||
continue
|
||||
}
|
||||
if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, c.GetLabels()) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
s, found := r.FakeContainerStats[c.Id]
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
result = append(result, s)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
46
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/utils.go
generated
vendored
Normal file
46
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/testing/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Copyright 2016 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
func BuildContainerName(metadata *runtimeapi.ContainerMetadata, sandboxID string) string {
|
||||
// include the sandbox ID to make the container ID unique.
|
||||
return fmt.Sprintf("%s_%s_%d", sandboxID, metadata.Name, metadata.Attempt)
|
||||
}
|
||||
|
||||
func BuildSandboxName(metadata *runtimeapi.PodSandboxMetadata) string {
|
||||
return fmt.Sprintf("%s_%s_%s_%d", metadata.Name, metadata.Namespace, metadata.Uid, metadata.Attempt)
|
||||
}
|
||||
|
||||
func filterInLabels(filter, labels map[string]string) bool {
|
||||
for k, v := range filter {
|
||||
if value, ok := labels[k]; ok {
|
||||
if value != v {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
40
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"api.pb.go",
|
||||
"constants.go",
|
||||
],
|
||||
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"],
|
||||
)
|
||||
24840
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/api.pb.go
generated
vendored
Normal file
24840
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/api.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1105
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto
generated
vendored
Normal file
1105
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
27
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/constants.go
generated
vendored
Normal file
27
vendor/k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime/constants.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright 2016 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 runtime
|
||||
|
||||
// This file contains all constants defined in CRI.
|
||||
|
||||
// Required runtime condition type.
|
||||
const (
|
||||
// RuntimeReady means the runtime is up and ready to accept basic containers.
|
||||
RuntimeReady = "RuntimeReady"
|
||||
// NetworkReady means the runtime network is up and ready to accept containers which require network.
|
||||
NetworkReady = "NetworkReady"
|
||||
)
|
||||
43
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/BUILD
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/BUILD
generated
vendored
Normal 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"],
|
||||
)
|
||||
2357
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/api.pb.go
generated
vendored
Normal file
2357
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/api.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
127
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/api.proto
generated
vendored
Normal file
127
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/api.proto
generated
vendored
Normal 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;
|
||||
}
|
||||
33
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/constants.go
generated
vendored
Normal file
33
vendor/k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1alpha1/constants.go
generated
vendored
Normal 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"
|
||||
)
|
||||
44
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/BUILD
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/apis/kubeletconfig/scheme:all-srcs",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:all-srcs",
|
||||
"//pkg/kubelet/apis/kubeletconfig/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
4
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/OWNERS
generated
vendored
Normal file
4
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
approvers:
|
||||
- mtaufen
|
||||
reviewers:
|
||||
- sig-node-reviewers
|
||||
19
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
package kubeletconfig // import "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
51
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/register.go
generated
vendored
Normal file
51
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/register.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
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 kubeletconfig
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "kubeletconfig"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
// TODO this will get cleaned up with the scheme types are fixed
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&KubeletConfiguration{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
27
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme/BUILD
generated
vendored
Normal file
27
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["scheme.go"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
40
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme/scheme.go
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/scheme/scheme.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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 scheme
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
|
||||
)
|
||||
|
||||
// Utility functions for the Kubelet's kubeletconfig API group
|
||||
|
||||
// NewSchemeAndCodecs is a utility funciton that returns a Scheme and CodecFactory
|
||||
// that understand the types in the kubeletconfig API group.
|
||||
func NewSchemeAndCodecs() (*runtime.Scheme, *serializer.CodecFactory, error) {
|
||||
scheme := runtime.NewScheme()
|
||||
if err := kubeletconfig.AddToScheme(scheme); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := v1alpha1.AddToScheme(scheme); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
return scheme, &codecs, nil
|
||||
}
|
||||
458
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/types.go
generated
vendored
Normal file
458
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
Copyright 2015 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 kubeletconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// HairpinMode denotes how the kubelet should configure networking to handle
|
||||
// hairpin packets.
|
||||
type HairpinMode string
|
||||
|
||||
// Enum settings for different ways to handle hairpin packets.
|
||||
const (
|
||||
// Set the hairpin flag on the veth of containers in the respective
|
||||
// container runtime.
|
||||
HairpinVeth = "hairpin-veth"
|
||||
// Make the container bridge promiscuous. This will force it to accept
|
||||
// hairpin packets, even if the flag isn't set on ports of the bridge.
|
||||
PromiscuousBridge = "promiscuous-bridge"
|
||||
// Neither of the above. If the kubelet is started in this hairpin mode
|
||||
// and kube-proxy is running in iptables mode, hairpin packets will be
|
||||
// dropped by the container bridge.
|
||||
HairpinNone = "none"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// A configuration field should go in KubeletFlags instead of KubeletConfiguration if any of these are true:
|
||||
// - its value will never, or cannot safely be changed during the lifetime of a node
|
||||
// - its value cannot be safely shared between nodes at the same time (e.g. a hostname)
|
||||
// KubeletConfiguration is intended to be shared between nodes
|
||||
// In general, please try to avoid adding flags or configuration fields,
|
||||
// we already have a confusingly large amount of them.
|
||||
// TODO: curate the ordering and structure of this config object
|
||||
type KubeletConfiguration struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// Only used for dynamic configuration.
|
||||
// The length of the trial period for this configuration. This configuration will become the last-known-good after this duration.
|
||||
ConfigTrialDuration *metav1.Duration
|
||||
// podManifestPath is the path to the directory containing pod manifests to
|
||||
// run, or the path to a single manifest file
|
||||
PodManifestPath string
|
||||
// syncFrequency is the max period between synchronizing running
|
||||
// containers and config
|
||||
SyncFrequency metav1.Duration
|
||||
// fileCheckFrequency is the duration between checking config files for
|
||||
// new data
|
||||
FileCheckFrequency metav1.Duration
|
||||
// httpCheckFrequency is the duration between checking http for new data
|
||||
HTTPCheckFrequency metav1.Duration
|
||||
// manifestURL is the URL for accessing the container manifest
|
||||
ManifestURL string
|
||||
// manifestURLHeader is the HTTP header to use when accessing the manifest
|
||||
// URL, with the key separated from the value with a ':', as in 'key:value'
|
||||
ManifestURLHeader string
|
||||
// enableServer enables the Kubelet's server
|
||||
EnableServer bool
|
||||
// address is the IP address for the Kubelet to serve on (set to 0.0.0.0
|
||||
// for all interfaces)
|
||||
Address string
|
||||
// port is the port for the Kubelet to serve on.
|
||||
Port int32
|
||||
// readOnlyPort is the read-only port for the Kubelet to serve on with
|
||||
// no authentication/authorization (set to 0 to disable)
|
||||
ReadOnlyPort int32
|
||||
// tlsCertFile is the file containing x509 Certificate for HTTPS. (CA cert,
|
||||
// if any, concatenated after server cert). If tlsCertFile and
|
||||
// tlsPrivateKeyFile are not provided, a self-signed certificate
|
||||
// and key are generated for the public address and saved to the directory
|
||||
// passed to certDir.
|
||||
TLSCertFile string
|
||||
// tlsPrivateKeyFile is the ile containing x509 private key matching
|
||||
// tlsCertFile.
|
||||
TLSPrivateKeyFile string
|
||||
// authentication specifies how requests to the Kubelet's server are authenticated
|
||||
Authentication KubeletAuthentication
|
||||
// authorization specifies how requests to the Kubelet's server are authorized
|
||||
Authorization KubeletAuthorization
|
||||
// seccompProfileRoot is the directory path for seccomp profiles.
|
||||
SeccompProfileRoot string
|
||||
// allowPrivileged enables containers to request privileged mode.
|
||||
// Defaults to false.
|
||||
AllowPrivileged bool
|
||||
// hostNetworkSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use of host network. Defaults to "*". Valid
|
||||
// options are "file", "http", "api", and "*" (all sources).
|
||||
HostNetworkSources []string
|
||||
// hostPIDSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use the host pid namespace. Defaults to "*".
|
||||
HostPIDSources []string
|
||||
// hostIPCSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use the host ipc namespace. Defaults to "*".
|
||||
HostIPCSources []string
|
||||
// registryPullQPS is the limit of registry pulls per second. If 0,
|
||||
// unlimited. Set to 0 for no limit. Defaults to 5.0.
|
||||
RegistryPullQPS int32
|
||||
// registryBurst is the maximum size of a bursty pulls, temporarily allows
|
||||
// pulls to burst to this number, while still not exceeding registryQps.
|
||||
// Only used if registryQPS > 0.
|
||||
RegistryBurst int32
|
||||
// eventRecordQPS is the maximum event creations per second. If 0, there
|
||||
// is no limit enforced.
|
||||
EventRecordQPS int32
|
||||
// eventBurst is the maximum size of a bursty event records, temporarily
|
||||
// allows event records to burst to this number, while still not exceeding
|
||||
// event-qps. Only used if eventQps > 0
|
||||
EventBurst int32
|
||||
// enableDebuggingHandlers enables server endpoints for log collection
|
||||
// and local running of containers and commands
|
||||
EnableDebuggingHandlers bool
|
||||
// enableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
|
||||
EnableContentionProfiling bool
|
||||
// minimumGCAge is the minimum age for a finished container before it is
|
||||
// garbage collected.
|
||||
MinimumGCAge metav1.Duration
|
||||
// maxPerPodContainerCount is the maximum number of old instances to
|
||||
// retain per container. Each container takes up some disk space.
|
||||
MaxPerPodContainerCount int32
|
||||
// maxContainerCount is the maximum number of old instances of containers
|
||||
// to retain globally. Each container takes up some disk space.
|
||||
MaxContainerCount int32
|
||||
// cAdvisorPort is the port of the localhost cAdvisor endpoint (set to 0 to disable)
|
||||
CAdvisorPort int32
|
||||
// healthzPort is the port of the localhost healthz endpoint (set to 0 to disable)
|
||||
HealthzPort int32
|
||||
// healthzBindAddress is the IP address for the healthz server to serve
|
||||
// on.
|
||||
HealthzBindAddress string
|
||||
// oomScoreAdj is The oom-score-adj value for kubelet process. Values
|
||||
// must be within the range [-1000, 1000].
|
||||
OOMScoreAdj int32
|
||||
// registerNode enables automatic registration with the apiserver.
|
||||
RegisterNode bool
|
||||
// clusterDomain is the DNS domain for this cluster. If set, kubelet will
|
||||
// configure all containers to search this domain in addition to the
|
||||
// host's search domains.
|
||||
ClusterDomain string
|
||||
// masterServiceNamespace is The namespace from which the kubernetes
|
||||
// master services should be injected into pods.
|
||||
MasterServiceNamespace string
|
||||
// clusterDNS is a list of IP address for a cluster DNS server. If set,
|
||||
// kubelet will configure all containers to use this for DNS resolution
|
||||
// instead of the host's DNS servers
|
||||
ClusterDNS []string
|
||||
// streamingConnectionIdleTimeout is the maximum time a streaming connection
|
||||
// can be idle before the connection is automatically closed.
|
||||
StreamingConnectionIdleTimeout metav1.Duration
|
||||
// nodeStatusUpdateFrequency is the frequency that kubelet posts node
|
||||
// status to master. Note: be cautious when changing the constant, it
|
||||
// must work with nodeMonitorGracePeriod in nodecontroller.
|
||||
NodeStatusUpdateFrequency metav1.Duration
|
||||
// imageMinimumGCAge is the minimum age for an unused image before it is
|
||||
// garbage collected.
|
||||
ImageMinimumGCAge metav1.Duration
|
||||
// imageGCHighThresholdPercent is the percent of disk usage after which
|
||||
// image garbage collection is always run.
|
||||
ImageGCHighThresholdPercent int32
|
||||
// imageGCLowThresholdPercent is the percent of disk usage before which
|
||||
// image garbage collection is never run. Lowest disk usage to garbage
|
||||
// collect to.
|
||||
ImageGCLowThresholdPercent int32
|
||||
// How frequently to calculate and cache volume disk usage for all pods
|
||||
VolumeStatsAggPeriod metav1.Duration
|
||||
// volumePluginDir is the full path of the directory in which to search
|
||||
// for additional third party volume plugins
|
||||
VolumePluginDir string
|
||||
// KubeletCgroups is the absolute name of cgroups to isolate the kubelet in.
|
||||
// +optional
|
||||
KubeletCgroups string
|
||||
// Enable QoS based Cgroup hierarchy: top level cgroups for QoS Classes
|
||||
// And all Burstable and BestEffort pods are brought up under their
|
||||
// specific top level QoS cgroup.
|
||||
// +optional
|
||||
CgroupsPerQOS bool
|
||||
// driver that the kubelet uses to manipulate cgroups on the host (cgroupfs or systemd)
|
||||
// +optional
|
||||
CgroupDriver string
|
||||
// Cgroups that container runtime is expected to be isolated in.
|
||||
// +optional
|
||||
RuntimeCgroups string
|
||||
// SystemCgroups is absolute name of cgroups in which to place
|
||||
// all non-kernel processes that are not already in a container. Empty
|
||||
// for no container. Rolling back the flag requires a reboot.
|
||||
// +optional
|
||||
SystemCgroups string
|
||||
// CgroupRoot is the root cgroup to use for pods.
|
||||
// If CgroupsPerQOS is enabled, this is the root of the QoS cgroup hierarchy.
|
||||
// +optional
|
||||
CgroupRoot string
|
||||
// containerRuntime is the container runtime to use.
|
||||
ContainerRuntime string
|
||||
// remoteRuntimeEndpoint is the endpoint of remote runtime service
|
||||
RemoteRuntimeEndpoint string
|
||||
// remoteImageEndpoint is the endpoint of remote image service
|
||||
RemoteImageEndpoint string
|
||||
// CPUManagerPolicy is the name of the policy to use.
|
||||
CPUManagerPolicy string
|
||||
// CPU Manager reconciliation period.
|
||||
CPUManagerReconcilePeriod metav1.Duration
|
||||
// runtimeRequestTimeout is the timeout for all runtime requests except long running
|
||||
// requests - pull, logs, exec and attach.
|
||||
// +optional
|
||||
RuntimeRequestTimeout metav1.Duration
|
||||
// experimentalMounterPath is the path of mounter binary. Leave empty to use the default mount path
|
||||
ExperimentalMounterPath string
|
||||
// lockFilePath is the path that kubelet will use to as a lock file.
|
||||
// It uses this file as a lock to synchronize with other kubelet processes
|
||||
// that may be running.
|
||||
LockFilePath string
|
||||
// ExitOnLockContention is a flag that signifies to the kubelet that it is running
|
||||
// in "bootstrap" mode. This requires that 'LockFilePath' has been set.
|
||||
// This will cause the kubelet to listen to inotify events on the lock file,
|
||||
// releasing it and exiting when another process tries to open that file.
|
||||
ExitOnLockContention bool
|
||||
// How should the kubelet configure the container bridge for hairpin packets.
|
||||
// Setting this flag allows endpoints in a Service to loadbalance back to
|
||||
// themselves if they should try to access their own Service. Values:
|
||||
// "promiscuous-bridge": make the container bridge promiscuous.
|
||||
// "hairpin-veth": set the hairpin flag on container veth interfaces.
|
||||
// "none": do nothing.
|
||||
// Generally, one must set --hairpin-mode=veth-flag to achieve hairpin NAT,
|
||||
// because promiscous-bridge assumes the existence of a container bridge named cbr0.
|
||||
HairpinMode string
|
||||
// maxPods is the number of pods that can run on this Kubelet.
|
||||
MaxPods int32
|
||||
// The CIDR to use for pod IP addresses, only used in standalone mode.
|
||||
// In cluster mode, this is obtained from the master.
|
||||
PodCIDR string
|
||||
// ResolverConfig is the resolver configuration file used as the basis
|
||||
// for the container DNS resolution configuration."), []
|
||||
ResolverConfig string
|
||||
// cpuCFSQuota is Enable CPU CFS quota enforcement for containers that
|
||||
// specify CPU limits
|
||||
CPUCFSQuota bool
|
||||
// containerized should be set to true if kubelet is running in a container.
|
||||
Containerized bool
|
||||
// maxOpenFiles is Number of files that can be opened by Kubelet process.
|
||||
MaxOpenFiles int64
|
||||
// registerSchedulable tells the kubelet to register the node as
|
||||
// schedulable. Won't have any effect if register-node is false.
|
||||
// DEPRECATED: use registerWithTaints instead
|
||||
RegisterSchedulable bool
|
||||
// registerWithTaints are an array of taints to add to a node object when
|
||||
// the kubelet registers itself. This only takes effect when registerNode
|
||||
// is true and upon the initial registration of the node.
|
||||
RegisterWithTaints []api.Taint
|
||||
// contentType is contentType of requests sent to apiserver.
|
||||
ContentType string
|
||||
// kubeAPIQPS is the QPS to use while talking with kubernetes apiserver
|
||||
KubeAPIQPS int32
|
||||
// kubeAPIBurst is the burst to allow while talking with kubernetes
|
||||
// apiserver
|
||||
KubeAPIBurst int32
|
||||
// serializeImagePulls when enabled, tells the Kubelet to pull images one
|
||||
// at a time. We recommend *not* changing the default value on nodes that
|
||||
// run docker daemon with version < 1.9 or an Aufs storage backend.
|
||||
// Issue #10959 has more details.
|
||||
SerializeImagePulls bool
|
||||
// nodeLabels to add when registering the node in the cluster.
|
||||
NodeLabels map[string]string
|
||||
// nonMasqueradeCIDR configures masquerading: traffic to IPs outside this range will use IP masquerade.
|
||||
NonMasqueradeCIDR string
|
||||
// enable gathering custom metrics.
|
||||
EnableCustomMetrics bool
|
||||
// Comma-delimited list of hard eviction expressions. For example, 'memory.available<300Mi'.
|
||||
// +optional
|
||||
EvictionHard string
|
||||
// Comma-delimited list of soft eviction expressions. For example, 'memory.available<300Mi'.
|
||||
// +optional
|
||||
EvictionSoft string
|
||||
// Comma-delimeted list of grace periods for each soft eviction signal. For example, 'memory.available=30s'.
|
||||
// +optional
|
||||
EvictionSoftGracePeriod string
|
||||
// Duration for which the kubelet has to wait before transitioning out of an eviction pressure condition.
|
||||
// +optional
|
||||
EvictionPressureTransitionPeriod metav1.Duration
|
||||
// Maximum allowed grace period (in seconds) to use when terminating pods in response to a soft eviction threshold being met.
|
||||
// +optional
|
||||
EvictionMaxPodGracePeriod int32
|
||||
// Comma-delimited list of minimum reclaims (e.g. imagefs.available=2Gi) that describes the minimum amount of resource the kubelet will reclaim when performing a pod eviction if that resource is under pressure.
|
||||
// +optional
|
||||
EvictionMinimumReclaim string
|
||||
// If enabled, the kubelet will integrate with the kernel memcg notification to determine if memory eviction thresholds are crossed rather than polling.
|
||||
// +optional
|
||||
ExperimentalKernelMemcgNotification bool
|
||||
// Maximum number of pods per core. Cannot exceed MaxPods
|
||||
PodsPerCore int32
|
||||
// enableControllerAttachDetach enables the Attach/Detach controller to
|
||||
// manage attachment/detachment of volumes scheduled to this node, and
|
||||
// disables kubelet from executing any attach/detach operations
|
||||
EnableControllerAttachDetach bool
|
||||
// A set of ResourceName=Percentage (e.g. memory=50%) pairs that describe
|
||||
// how pod resource requests are reserved at the QoS level.
|
||||
// Currently only memory is supported. [default=none]"
|
||||
ExperimentalQOSReserved ConfigurationMap
|
||||
// Default behaviour for kernel tuning
|
||||
ProtectKernelDefaults bool
|
||||
// If true, Kubelet ensures a set of iptables rules are present on host.
|
||||
// These rules will serve as utility for various components, e.g. kube-proxy.
|
||||
// The rules will be created based on IPTablesMasqueradeBit and IPTablesDropBit.
|
||||
MakeIPTablesUtilChains bool
|
||||
// iptablesMasqueradeBit is the bit of the iptables fwmark space to use for SNAT
|
||||
// Values must be within the range [0, 31].
|
||||
// Warning: Please match the value of corresponding parameter in kube-proxy
|
||||
// TODO: clean up IPTablesMasqueradeBit in kube-proxy
|
||||
IPTablesMasqueradeBit int32
|
||||
// iptablesDropBit is the bit of the iptables fwmark space to use for dropping packets. Kubelet will ensure iptables mark and drop rules.
|
||||
// Values must be within the range [0, 31]. Must be different from IPTablesMasqueradeBit
|
||||
IPTablesDropBit int32
|
||||
// Whitelist of unsafe sysctls or sysctl patterns (ending in *).
|
||||
// +optional
|
||||
AllowedUnsafeSysctls []string
|
||||
// featureGates is a string of comma-separated key=value pairs that describe feature
|
||||
// gates for alpha/experimental features.
|
||||
FeatureGates string
|
||||
// Tells the Kubelet to fail to start if swap is enabled on the node.
|
||||
FailSwapOn bool
|
||||
// This flag, if set, enables a check prior to mount operations to verify that the required components
|
||||
// (binaries, etc.) to mount the volume are available on the underlying node. If the check is enabled
|
||||
// and fails the mount operation fails.
|
||||
ExperimentalCheckNodeCapabilitiesBeforeMount bool
|
||||
// This flag, if set, instructs the kubelet to keep volumes from terminated pods mounted to the node.
|
||||
// This can be useful for debugging volume related issues.
|
||||
KeepTerminatedPodVolumes bool
|
||||
|
||||
/* following flags are meant for Node Allocatable */
|
||||
|
||||
// A set of ResourceName=ResourceQuantity (e.g. cpu=200m,memory=150G) pairs
|
||||
// that describe resources reserved for non-kubernetes components.
|
||||
// Currently only cpu and memory are supported. [default=none]
|
||||
// See http://kubernetes.io/docs/user-guide/compute-resources for more detail.
|
||||
SystemReserved ConfigurationMap
|
||||
// A set of ResourceName=ResourceQuantity (e.g. cpu=200m,memory=150G) pairs
|
||||
// that describe resources reserved for kubernetes system components.
|
||||
// Currently cpu, memory and local storage for root file system are supported. [default=none]
|
||||
// See http://kubernetes.io/docs/user-guide/compute-resources for more detail.
|
||||
KubeReserved ConfigurationMap
|
||||
// This flag helps kubelet identify absolute name of top level cgroup used to enforce `SystemReserved` compute resource reservation for OS system daemons.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
SystemReservedCgroup string
|
||||
// This flag helps kubelet identify absolute name of top level cgroup used to enforce `KubeReserved` compute resource reservation for Kubernetes node system daemons.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
KubeReservedCgroup string
|
||||
// This flag specifies the various Node Allocatable enforcements that Kubelet needs to perform.
|
||||
// This flag accepts a list of options. Acceptable options are `pods`, `system-reserved` & `kube-reserved`.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
EnforceNodeAllocatable []string
|
||||
// This flag, if set, will avoid including `EvictionHard` limits while computing Node Allocatable.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
ExperimentalNodeAllocatableIgnoreEvictionThreshold bool
|
||||
}
|
||||
|
||||
type KubeletAuthorizationMode string
|
||||
|
||||
const (
|
||||
// KubeletAuthorizationModeAlwaysAllow authorizes all authenticated requests
|
||||
KubeletAuthorizationModeAlwaysAllow KubeletAuthorizationMode = "AlwaysAllow"
|
||||
// KubeletAuthorizationModeWebhook uses the SubjectAccessReview API to determine authorization
|
||||
KubeletAuthorizationModeWebhook KubeletAuthorizationMode = "Webhook"
|
||||
)
|
||||
|
||||
type KubeletAuthorization struct {
|
||||
// mode is the authorization mode to apply to requests to the kubelet server.
|
||||
// Valid values are AlwaysAllow and Webhook.
|
||||
// Webhook mode uses the SubjectAccessReview API to determine authorization.
|
||||
Mode KubeletAuthorizationMode
|
||||
|
||||
// webhook contains settings related to Webhook authorization.
|
||||
Webhook KubeletWebhookAuthorization
|
||||
}
|
||||
|
||||
type KubeletWebhookAuthorization struct {
|
||||
// cacheAuthorizedTTL is the duration to cache 'authorized' responses from the webhook authorizer.
|
||||
CacheAuthorizedTTL metav1.Duration
|
||||
// cacheUnauthorizedTTL is the duration to cache 'unauthorized' responses from the webhook authorizer.
|
||||
CacheUnauthorizedTTL metav1.Duration
|
||||
}
|
||||
|
||||
type KubeletAuthentication struct {
|
||||
// x509 contains settings related to x509 client certificate authentication
|
||||
X509 KubeletX509Authentication
|
||||
// webhook contains settings related to webhook bearer token authentication
|
||||
Webhook KubeletWebhookAuthentication
|
||||
// anonymous contains settings related to anonymous authentication
|
||||
Anonymous KubeletAnonymousAuthentication
|
||||
}
|
||||
|
||||
type KubeletX509Authentication struct {
|
||||
// clientCAFile is the path to a PEM-encoded certificate bundle. If set, any request presenting a client certificate
|
||||
// signed by one of the authorities in the bundle is authenticated with a username corresponding to the CommonName,
|
||||
// and groups corresponding to the Organization in the client certificate.
|
||||
ClientCAFile string
|
||||
}
|
||||
|
||||
type KubeletWebhookAuthentication struct {
|
||||
// enabled allows bearer token authentication backed by the tokenreviews.authentication.k8s.io API
|
||||
Enabled bool
|
||||
// cacheTTL enables caching of authentication results
|
||||
CacheTTL metav1.Duration
|
||||
}
|
||||
|
||||
type KubeletAnonymousAuthentication struct {
|
||||
// enabled allows anonymous requests to the kubelet server.
|
||||
// Requests that are not rejected by another authentication method are treated as anonymous requests.
|
||||
// Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type ConfigurationMap map[string]string
|
||||
|
||||
func (m *ConfigurationMap) String() string {
|
||||
pairs := []string{}
|
||||
for k, v := range *m {
|
||||
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
sort.Strings(pairs)
|
||||
return strings.Join(pairs, ",")
|
||||
}
|
||||
|
||||
func (m *ConfigurationMap) Set(value string) error {
|
||||
for _, s := range strings.Split(value, ",") {
|
||||
if len(s) == 0 {
|
||||
continue
|
||||
}
|
||||
arr := strings.SplitN(s, "=", 2)
|
||||
if len(arr) == 2 {
|
||||
(*m)[strings.TrimSpace(arr[0])] = strings.TrimSpace(arr[1])
|
||||
} else {
|
||||
(*m)[strings.TrimSpace(arr[0])] = ""
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*ConfigurationMap) Type() string {
|
||||
return "mapStringString"
|
||||
}
|
||||
48
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/BUILD
generated
vendored
Normal file
48
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/qos:go_default_library",
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//pkg/master/ports:go_default_library",
|
||||
"//pkg/util/pointer:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
286
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/defaults.go
generated
vendored
Normal file
286
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/defaults.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
Copyright 2015 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 v1alpha1
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/kubernetes/pkg/master/ports"
|
||||
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultRootDir = "/var/lib/kubelet"
|
||||
|
||||
// DEPRECATED: auto detecting cloud providers goes against the initiative
|
||||
// for out-of-tree cloud providers as we'll now depend on cAdvisor integrations
|
||||
// with cloud providers instead of in the core repo.
|
||||
// More details here: https://github.com/kubernetes/kubernetes/issues/50986
|
||||
AutoDetectCloudProvider = "auto-detect"
|
||||
|
||||
defaultIPTablesMasqueradeBit = 14
|
||||
defaultIPTablesDropBit = 15
|
||||
)
|
||||
|
||||
var (
|
||||
zeroDuration = metav1.Duration{}
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
defaultNodeAllocatableEnforcement = []string{"pods"}
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *kruntime.Scheme) error {
|
||||
return RegisterDefaults(scheme)
|
||||
}
|
||||
|
||||
func SetDefaults_KubeletConfiguration(obj *KubeletConfiguration) {
|
||||
// pointer because the zeroDuration is valid - if you want to skip the trial period
|
||||
if obj.ConfigTrialDuration == nil {
|
||||
obj.ConfigTrialDuration = &metav1.Duration{Duration: 10 * time.Minute}
|
||||
}
|
||||
if obj.Authentication.Anonymous.Enabled == nil {
|
||||
obj.Authentication.Anonymous.Enabled = boolVar(true)
|
||||
}
|
||||
if obj.Authentication.Webhook.Enabled == nil {
|
||||
obj.Authentication.Webhook.Enabled = boolVar(false)
|
||||
}
|
||||
if obj.Authentication.Webhook.CacheTTL == zeroDuration {
|
||||
obj.Authentication.Webhook.CacheTTL = metav1.Duration{Duration: 2 * time.Minute}
|
||||
}
|
||||
if obj.Authorization.Mode == "" {
|
||||
obj.Authorization.Mode = KubeletAuthorizationModeAlwaysAllow
|
||||
}
|
||||
if obj.Authorization.Webhook.CacheAuthorizedTTL == zeroDuration {
|
||||
obj.Authorization.Webhook.CacheAuthorizedTTL = metav1.Duration{Duration: 5 * time.Minute}
|
||||
}
|
||||
if obj.Authorization.Webhook.CacheUnauthorizedTTL == zeroDuration {
|
||||
obj.Authorization.Webhook.CacheUnauthorizedTTL = metav1.Duration{Duration: 30 * time.Second}
|
||||
}
|
||||
|
||||
if obj.Address == "" {
|
||||
obj.Address = "0.0.0.0"
|
||||
}
|
||||
if obj.CAdvisorPort == nil {
|
||||
obj.CAdvisorPort = utilpointer.Int32Ptr(4194)
|
||||
}
|
||||
if obj.VolumeStatsAggPeriod == zeroDuration {
|
||||
obj.VolumeStatsAggPeriod = metav1.Duration{Duration: time.Minute}
|
||||
}
|
||||
if obj.ContainerRuntime == "" {
|
||||
obj.ContainerRuntime = kubetypes.DockerContainerRuntime
|
||||
}
|
||||
if obj.RuntimeRequestTimeout == zeroDuration {
|
||||
obj.RuntimeRequestTimeout = metav1.Duration{Duration: 2 * time.Minute}
|
||||
}
|
||||
if obj.CPUCFSQuota == nil {
|
||||
obj.CPUCFSQuota = boolVar(true)
|
||||
}
|
||||
if obj.EventBurst == 0 {
|
||||
obj.EventBurst = 10
|
||||
}
|
||||
if obj.EventRecordQPS == nil {
|
||||
temp := int32(5)
|
||||
obj.EventRecordQPS = &temp
|
||||
}
|
||||
if obj.EnableControllerAttachDetach == nil {
|
||||
obj.EnableControllerAttachDetach = boolVar(true)
|
||||
}
|
||||
if obj.EnableDebuggingHandlers == nil {
|
||||
obj.EnableDebuggingHandlers = boolVar(true)
|
||||
}
|
||||
if obj.EnableServer == nil {
|
||||
obj.EnableServer = boolVar(true)
|
||||
}
|
||||
if obj.FileCheckFrequency == zeroDuration {
|
||||
obj.FileCheckFrequency = metav1.Duration{Duration: 20 * time.Second}
|
||||
}
|
||||
if obj.HealthzBindAddress == "" {
|
||||
obj.HealthzBindAddress = "127.0.0.1"
|
||||
}
|
||||
if obj.HealthzPort == nil {
|
||||
obj.HealthzPort = utilpointer.Int32Ptr(10248)
|
||||
}
|
||||
if obj.HostNetworkSources == nil {
|
||||
obj.HostNetworkSources = []string{kubetypes.AllSource}
|
||||
}
|
||||
if obj.HostPIDSources == nil {
|
||||
obj.HostPIDSources = []string{kubetypes.AllSource}
|
||||
}
|
||||
if obj.HostIPCSources == nil {
|
||||
obj.HostIPCSources = []string{kubetypes.AllSource}
|
||||
}
|
||||
if obj.HTTPCheckFrequency == zeroDuration {
|
||||
obj.HTTPCheckFrequency = metav1.Duration{Duration: 20 * time.Second}
|
||||
}
|
||||
if obj.ImageMinimumGCAge == zeroDuration {
|
||||
obj.ImageMinimumGCAge = metav1.Duration{Duration: 2 * time.Minute}
|
||||
}
|
||||
if obj.ImageGCHighThresholdPercent == nil {
|
||||
// default is below docker's default dm.min_free_space of 90%
|
||||
temp := int32(85)
|
||||
obj.ImageGCHighThresholdPercent = &temp
|
||||
}
|
||||
if obj.ImageGCLowThresholdPercent == nil {
|
||||
temp := int32(80)
|
||||
obj.ImageGCLowThresholdPercent = &temp
|
||||
}
|
||||
if obj.MasterServiceNamespace == "" {
|
||||
obj.MasterServiceNamespace = metav1.NamespaceDefault
|
||||
}
|
||||
if obj.MaxContainerCount == nil {
|
||||
temp := int32(-1)
|
||||
obj.MaxContainerCount = &temp
|
||||
}
|
||||
if obj.MaxPerPodContainerCount == 0 {
|
||||
obj.MaxPerPodContainerCount = 1
|
||||
}
|
||||
if obj.MaxOpenFiles == 0 {
|
||||
obj.MaxOpenFiles = 1000000
|
||||
}
|
||||
if obj.MaxPods == 0 {
|
||||
obj.MaxPods = 110
|
||||
}
|
||||
if obj.MinimumGCAge == zeroDuration {
|
||||
obj.MinimumGCAge = metav1.Duration{Duration: 0}
|
||||
}
|
||||
if obj.NonMasqueradeCIDR == "" {
|
||||
obj.NonMasqueradeCIDR = "10.0.0.0/8"
|
||||
}
|
||||
if obj.VolumePluginDir == "" {
|
||||
obj.VolumePluginDir = "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/"
|
||||
}
|
||||
if obj.NodeStatusUpdateFrequency == zeroDuration {
|
||||
obj.NodeStatusUpdateFrequency = metav1.Duration{Duration: 10 * time.Second}
|
||||
}
|
||||
if obj.CPUManagerPolicy == "" {
|
||||
obj.CPUManagerPolicy = "none"
|
||||
}
|
||||
if obj.CPUManagerReconcilePeriod == zeroDuration {
|
||||
obj.CPUManagerReconcilePeriod = obj.NodeStatusUpdateFrequency
|
||||
}
|
||||
if obj.OOMScoreAdj == nil {
|
||||
temp := int32(qos.KubeletOOMScoreAdj)
|
||||
obj.OOMScoreAdj = &temp
|
||||
}
|
||||
if obj.Port == 0 {
|
||||
obj.Port = ports.KubeletPort
|
||||
}
|
||||
if obj.ReadOnlyPort == nil {
|
||||
obj.ReadOnlyPort = utilpointer.Int32Ptr(ports.KubeletReadOnlyPort)
|
||||
}
|
||||
if obj.RegisterNode == nil {
|
||||
obj.RegisterNode = boolVar(true)
|
||||
}
|
||||
if obj.RegisterSchedulable == nil {
|
||||
obj.RegisterSchedulable = boolVar(true)
|
||||
}
|
||||
if obj.RegistryBurst == 0 {
|
||||
obj.RegistryBurst = 10
|
||||
}
|
||||
if obj.RegistryPullQPS == nil {
|
||||
temp := int32(5)
|
||||
obj.RegistryPullQPS = &temp
|
||||
}
|
||||
if obj.ResolverConfig == "" {
|
||||
obj.ResolverConfig = kubetypes.ResolvConfDefault
|
||||
}
|
||||
if obj.SerializeImagePulls == nil {
|
||||
obj.SerializeImagePulls = boolVar(true)
|
||||
}
|
||||
if obj.SeccompProfileRoot == "" {
|
||||
obj.SeccompProfileRoot = filepath.Join(DefaultRootDir, "seccomp")
|
||||
}
|
||||
if obj.StreamingConnectionIdleTimeout == zeroDuration {
|
||||
obj.StreamingConnectionIdleTimeout = metav1.Duration{Duration: 4 * time.Hour}
|
||||
}
|
||||
if obj.SyncFrequency == zeroDuration {
|
||||
obj.SyncFrequency = metav1.Duration{Duration: 1 * time.Minute}
|
||||
}
|
||||
if obj.ContentType == "" {
|
||||
obj.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
}
|
||||
if obj.KubeAPIQPS == nil {
|
||||
temp := int32(5)
|
||||
obj.KubeAPIQPS = &temp
|
||||
}
|
||||
if obj.KubeAPIBurst == 0 {
|
||||
obj.KubeAPIBurst = 10
|
||||
}
|
||||
if string(obj.HairpinMode) == "" {
|
||||
obj.HairpinMode = PromiscuousBridge
|
||||
}
|
||||
if obj.EvictionHard == nil {
|
||||
temp := "memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%"
|
||||
obj.EvictionHard = &temp
|
||||
}
|
||||
if obj.EvictionPressureTransitionPeriod == zeroDuration {
|
||||
obj.EvictionPressureTransitionPeriod = metav1.Duration{Duration: 5 * time.Minute}
|
||||
}
|
||||
if obj.ExperimentalKernelMemcgNotification == nil {
|
||||
obj.ExperimentalKernelMemcgNotification = boolVar(false)
|
||||
}
|
||||
if obj.SystemReserved == nil {
|
||||
obj.SystemReserved = make(map[string]string)
|
||||
}
|
||||
if obj.KubeReserved == nil {
|
||||
obj.KubeReserved = make(map[string]string)
|
||||
}
|
||||
if obj.ExperimentalQOSReserved == nil {
|
||||
obj.ExperimentalQOSReserved = make(map[string]string)
|
||||
}
|
||||
if obj.MakeIPTablesUtilChains == nil {
|
||||
obj.MakeIPTablesUtilChains = boolVar(true)
|
||||
}
|
||||
if obj.IPTablesMasqueradeBit == nil {
|
||||
temp := int32(defaultIPTablesMasqueradeBit)
|
||||
obj.IPTablesMasqueradeBit = &temp
|
||||
}
|
||||
if obj.IPTablesDropBit == nil {
|
||||
temp := int32(defaultIPTablesDropBit)
|
||||
obj.IPTablesDropBit = &temp
|
||||
}
|
||||
if obj.CgroupsPerQOS == nil {
|
||||
temp := true
|
||||
obj.CgroupsPerQOS = &temp
|
||||
}
|
||||
if obj.CgroupDriver == "" {
|
||||
obj.CgroupDriver = "cgroupfs"
|
||||
}
|
||||
if obj.EnforceNodeAllocatable == nil {
|
||||
obj.EnforceNodeAllocatable = defaultNodeAllocatableEnforcement
|
||||
}
|
||||
if obj.RemoteRuntimeEndpoint == "" {
|
||||
if runtime.GOOS == "linux" {
|
||||
obj.RemoteRuntimeEndpoint = "unix:///var/run/dockershim.sock"
|
||||
} else if runtime.GOOS == "windows" {
|
||||
obj.RemoteRuntimeEndpoint = "tcp://localhost:3735"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func boolVar(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
var (
|
||||
defaultCfg = KubeletConfiguration{}
|
||||
)
|
||||
22
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/doc.go
generated
vendored
Normal file
22
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
package v1alpha1 // import "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1"
|
||||
50
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/register.go
generated
vendored
Normal file
50
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/register.go
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2015 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 v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "kubeletconfig"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
|
||||
var (
|
||||
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&KubeletConfiguration{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
415
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/types.go
generated
vendored
Normal file
415
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
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 v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// HairpinMode denotes how the kubelet should configure networking to handle
|
||||
// hairpin packets.
|
||||
type HairpinMode string
|
||||
|
||||
// Enum settings for different ways to handle hairpin packets.
|
||||
const (
|
||||
// Set the hairpin flag on the veth of containers in the respective
|
||||
// container runtime.
|
||||
HairpinVeth = "hairpin-veth"
|
||||
// Make the container bridge promiscuous. This will force it to accept
|
||||
// hairpin packets, even if the flag isn't set on ports of the bridge.
|
||||
PromiscuousBridge = "promiscuous-bridge"
|
||||
// Neither of the above. If the kubelet is started in this hairpin mode
|
||||
// and kube-proxy is running in iptables mode, hairpin packets will be
|
||||
// dropped by the container bridge.
|
||||
HairpinNone = "none"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// A configuration field should go in KubeletFlags instead of KubeletConfiguration if any of these are true:
|
||||
// - its value will never, or cannot safely be changed during the lifetime of a node
|
||||
// - its value cannot be safely shared between nodes at the same time (e.g. a hostname)
|
||||
// KubeletConfiguration is intended to be shared between nodes
|
||||
// In general, please try to avoid adding flags or configuration fields,
|
||||
// we already have a confusingly large amount of them.
|
||||
type KubeletConfiguration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Only used for dynamic configuration.
|
||||
// The length of the trial period for this configuration. This configuration will become the last-known-good after this duration.
|
||||
ConfigTrialDuration *metav1.Duration `json:"configTrialDuration"`
|
||||
// podManifestPath is the path to the directory containing pod manifests to
|
||||
// run, or the path to a single manifest file
|
||||
PodManifestPath string `json:"podManifestPath"`
|
||||
// syncFrequency is the max period between synchronizing running
|
||||
// containers and config
|
||||
SyncFrequency metav1.Duration `json:"syncFrequency"`
|
||||
// fileCheckFrequency is the duration between checking config files for
|
||||
// new data
|
||||
FileCheckFrequency metav1.Duration `json:"fileCheckFrequency"`
|
||||
// httpCheckFrequency is the duration between checking http for new data
|
||||
HTTPCheckFrequency metav1.Duration `json:"httpCheckFrequency"`
|
||||
// manifestURL is the URL for accessing the container manifest
|
||||
ManifestURL string `json:"manifestURL"`
|
||||
// manifestURLHeader is the HTTP header to use when accessing the manifest
|
||||
// URL, with the key separated from the value with a ':', as in 'key:value'
|
||||
ManifestURLHeader string `json:"manifestURLHeader"`
|
||||
// enableServer enables the Kubelet's server
|
||||
EnableServer *bool `json:"enableServer"`
|
||||
// address is the IP address for the Kubelet to serve on (set to 0.0.0.0
|
||||
// for all interfaces)
|
||||
Address string `json:"address"`
|
||||
// port is the port for the Kubelet to serve on.
|
||||
Port int32 `json:"port"`
|
||||
// readOnlyPort is the read-only port for the Kubelet to serve on with
|
||||
// no authentication/authorization (set to 0 to disable)
|
||||
ReadOnlyPort *int32 `json:"readOnlyPort"`
|
||||
// tlsCertFile is the file containing x509 Certificate for HTTPS. (CA cert,
|
||||
// if any, concatenated after server cert). If tlsCertFile and
|
||||
// tlsPrivateKeyFile are not provided, a self-signed certificate
|
||||
// and key are generated for the public address and saved to the directory
|
||||
// passed to certDir.
|
||||
TLSCertFile string `json:"tlsCertFile"`
|
||||
// tlsPrivateKeyFile is the ile containing x509 private key matching
|
||||
// tlsCertFile.
|
||||
TLSPrivateKeyFile string `json:"tlsPrivateKeyFile"`
|
||||
// authentication specifies how requests to the Kubelet's server are authenticated
|
||||
Authentication KubeletAuthentication `json:"authentication"`
|
||||
// authorization specifies how requests to the Kubelet's server are authorized
|
||||
Authorization KubeletAuthorization `json:"authorization"`
|
||||
// seccompProfileRoot is the directory path for seccomp profiles.
|
||||
SeccompProfileRoot string `json:"seccompProfileRoot"`
|
||||
// allowPrivileged enables containers to request privileged mode.
|
||||
// Defaults to false.
|
||||
AllowPrivileged *bool `json:"allowPrivileged"`
|
||||
// hostNetworkSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use of host network. Defaults to "*". Valid
|
||||
// options are "file", "http", "api", and "*" (all sources).
|
||||
HostNetworkSources []string `json:"hostNetworkSources"`
|
||||
// hostPIDSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use the host pid namespace. Defaults to "*".
|
||||
HostPIDSources []string `json:"hostPIDSources"`
|
||||
// hostIPCSources is a comma-separated list of sources from which the
|
||||
// Kubelet allows pods to use the host ipc namespace. Defaults to "*".
|
||||
HostIPCSources []string `json:"hostIPCSources"`
|
||||
// registryPullQPS is the limit of registry pulls per second. If 0,
|
||||
// unlimited. Set to 0 for no limit. Defaults to 5.0.
|
||||
RegistryPullQPS *int32 `json:"registryPullQPS"`
|
||||
// registryBurst is the maximum size of a bursty pulls, temporarily allows
|
||||
// pulls to burst to this number, while still not exceeding registryQps.
|
||||
// Only used if registryQPS > 0.
|
||||
RegistryBurst int32 `json:"registryBurst"`
|
||||
// eventRecordQPS is the maximum event creations per second. If 0, there
|
||||
// is no limit enforced.
|
||||
EventRecordQPS *int32 `json:"eventRecordQPS"`
|
||||
// eventBurst is the maximum size of a bursty event records, temporarily
|
||||
// allows event records to burst to this number, while still not exceeding
|
||||
// event-qps. Only used if eventQps > 0
|
||||
EventBurst int32 `json:"eventBurst"`
|
||||
// enableDebuggingHandlers enables server endpoints for log collection
|
||||
// and local running of containers and commands
|
||||
EnableDebuggingHandlers *bool `json:"enableDebuggingHandlers"`
|
||||
// enableContentionProfiling enables lock contention profiling, if enableDebuggingHandlers is true.
|
||||
EnableContentionProfiling bool `json:"enableContentionProfiling"`
|
||||
// minimumGCAge is the minimum age for a finished container before it is
|
||||
// garbage collected.
|
||||
MinimumGCAge metav1.Duration `json:"minimumGCAge"`
|
||||
// maxPerPodContainerCount is the maximum number of old instances to
|
||||
// retain per container. Each container takes up some disk space.
|
||||
MaxPerPodContainerCount int32 `json:"maxPerPodContainerCount"`
|
||||
// maxContainerCount is the maximum number of old instances of containers
|
||||
// to retain globally. Each container takes up some disk space.
|
||||
MaxContainerCount *int32 `json:"maxContainerCount"`
|
||||
// cAdvisorPort is the port of the localhost cAdvisor endpoint (set to 0 to disable)
|
||||
CAdvisorPort *int32 `json:"cAdvisorPort"`
|
||||
// healthzPort is the port of the localhost healthz endpoint (set to 0 to disable)
|
||||
HealthzPort *int32 `json:"healthzPort"`
|
||||
// healthzBindAddress is the IP address for the healthz server to serve
|
||||
// on.
|
||||
HealthzBindAddress string `json:"healthzBindAddress"`
|
||||
// oomScoreAdj is The oom-score-adj value for kubelet process. Values
|
||||
// must be within the range [-1000, 1000].
|
||||
OOMScoreAdj *int32 `json:"oomScoreAdj"`
|
||||
// registerNode enables automatic registration with the apiserver.
|
||||
RegisterNode *bool `json:"registerNode"`
|
||||
// clusterDomain is the DNS domain for this cluster. If set, kubelet will
|
||||
// configure all containers to search this domain in addition to the
|
||||
// host's search domains.
|
||||
ClusterDomain string `json:"clusterDomain"`
|
||||
// masterServiceNamespace is The namespace from which the kubernetes
|
||||
// master services should be injected into pods.
|
||||
MasterServiceNamespace string `json:"masterServiceNamespace"`
|
||||
// clusterDNS is a list of IP address for the cluster DNS server. If set,
|
||||
// kubelet will configure all containers to use this for DNS resolution
|
||||
// instead of the host's DNS servers
|
||||
ClusterDNS []string `json:"clusterDNS"`
|
||||
// streamingConnectionIdleTimeout is the maximum time a streaming connection
|
||||
// can be idle before the connection is automatically closed.
|
||||
StreamingConnectionIdleTimeout metav1.Duration `json:"streamingConnectionIdleTimeout"`
|
||||
// nodeStatusUpdateFrequency is the frequency that kubelet posts node
|
||||
// status to master. Note: be cautious when changing the constant, it
|
||||
// must work with nodeMonitorGracePeriod in nodecontroller.
|
||||
NodeStatusUpdateFrequency metav1.Duration `json:"nodeStatusUpdateFrequency"`
|
||||
// imageMinimumGCAge is the minimum age for an unused image before it is
|
||||
// garbage collected.
|
||||
ImageMinimumGCAge metav1.Duration `json:"imageMinimumGCAge"`
|
||||
// imageGCHighThresholdPercent is the percent of disk usage after which
|
||||
// image garbage collection is always run. The percent is calculated as
|
||||
// this field value out of 100.
|
||||
ImageGCHighThresholdPercent *int32 `json:"imageGCHighThresholdPercent"`
|
||||
// imageGCLowThresholdPercent is the percent of disk usage before which
|
||||
// image garbage collection is never run. Lowest disk usage to garbage
|
||||
// collect to. The percent is calculated as this field value out of 100.
|
||||
ImageGCLowThresholdPercent *int32 `json:"imageGCLowThresholdPercent"`
|
||||
// How frequently to calculate and cache volume disk usage for all pods
|
||||
VolumeStatsAggPeriod metav1.Duration `json:"volumeStatsAggPeriod"`
|
||||
// volumePluginDir is the full path of the directory in which to search
|
||||
// for additional third party volume plugins
|
||||
VolumePluginDir string `json:"volumePluginDir"`
|
||||
// kubeletCgroups is the absolute name of cgroups to isolate the kubelet in.
|
||||
KubeletCgroups string `json:"kubeletCgroups"`
|
||||
// runtimeCgroups are cgroups that container runtime is expected to be isolated in.
|
||||
RuntimeCgroups string `json:"runtimeCgroups"`
|
||||
// systemCgroups is absolute name of cgroups in which to place
|
||||
// all non-kernel processes that are not already in a container. Empty
|
||||
// for no container. Rolling back the flag requires a reboot.
|
||||
SystemCgroups string `json:"systemCgroups"`
|
||||
// cgroupRoot is the root cgroup to use for pods. This is handled by the
|
||||
// container runtime on a best effort basis.
|
||||
CgroupRoot string `json:"cgroupRoot"`
|
||||
// Enable QoS based Cgroup hierarchy: top level cgroups for QoS Classes
|
||||
// And all Burstable and BestEffort pods are brought up under their
|
||||
// specific top level QoS cgroup.
|
||||
// +optional
|
||||
CgroupsPerQOS *bool `json:"cgroupsPerQOS,omitempty"`
|
||||
// driver that the kubelet uses to manipulate cgroups on the host (cgroupfs or systemd)
|
||||
// +optional
|
||||
CgroupDriver string `json:"cgroupDriver,omitempty"`
|
||||
// containerRuntime is the container runtime to use.
|
||||
ContainerRuntime string `json:"containerRuntime"`
|
||||
// remoteRuntimeEndpoint is the endpoint of remote runtime service
|
||||
RemoteRuntimeEndpoint string `json:"remoteRuntimeEndpoint"`
|
||||
// remoteImageEndpoint is the endpoint of remote image service
|
||||
RemoteImageEndpoint string `json:"remoteImageEndpoint"`
|
||||
// CPUManagerPolicy is the name of the policy to use.
|
||||
CPUManagerPolicy string `json:"cpuManagerPolicy"`
|
||||
// CPU Manager reconciliation period.
|
||||
CPUManagerReconcilePeriod metav1.Duration `json:"cpuManagerReconcilePeriod"`
|
||||
// runtimeRequestTimeout is the timeout for all runtime requests except long running
|
||||
// requests - pull, logs, exec and attach.
|
||||
RuntimeRequestTimeout metav1.Duration `json:"runtimeRequestTimeout"`
|
||||
// experimentalMounterPath is the path to mounter binary. If not set, kubelet will attempt to use mount
|
||||
// binary that is available via $PATH,
|
||||
ExperimentalMounterPath string `json:"experimentalMounterPath,omitempty"`
|
||||
// lockFilePath is the path that kubelet will use to as a lock file.
|
||||
// It uses this file as a lock to synchronize with other kubelet processes
|
||||
// that may be running.
|
||||
LockFilePath *string `json:"lockFilePath"`
|
||||
// ExitOnLockContention is a flag that signifies to the kubelet that it is running
|
||||
// in "bootstrap" mode. This requires that 'LockFilePath' has been set.
|
||||
// This will cause the kubelet to listen to inotify events on the lock file,
|
||||
// releasing it and exiting when another process tries to open that file.
|
||||
ExitOnLockContention bool `json:"exitOnLockContention"`
|
||||
// How should the kubelet configure the container bridge for hairpin packets.
|
||||
// Setting this flag allows endpoints in a Service to loadbalance back to
|
||||
// themselves if they should try to access their own Service. Values:
|
||||
// "promiscuous-bridge": make the container bridge promiscuous.
|
||||
// "hairpin-veth": set the hairpin flag on container veth interfaces.
|
||||
// "none": do nothing.
|
||||
// Generally, one must set --hairpin-mode=veth-flag to achieve hairpin NAT,
|
||||
// because promiscous-bridge assumes the existence of a container bridge named cbr0.
|
||||
HairpinMode string `json:"hairpinMode"`
|
||||
// maxPods is the number of pods that can run on this Kubelet.
|
||||
MaxPods int32 `json:"maxPods"`
|
||||
// The CIDR to use for pod IP addresses, only used in standalone mode.
|
||||
// In cluster mode, this is obtained from the master.
|
||||
PodCIDR string `json:"podCIDR"`
|
||||
// ResolverConfig is the resolver configuration file used as the basis
|
||||
// for the container DNS resolution configuration."), []
|
||||
ResolverConfig string `json:"resolvConf"`
|
||||
// cpuCFSQuota is Enable CPU CFS quota enforcement for containers that
|
||||
// specify CPU limits
|
||||
CPUCFSQuota *bool `json:"cpuCFSQuota"`
|
||||
// containerized should be set to true if kubelet is running in a container.
|
||||
Containerized *bool `json:"containerized"`
|
||||
// maxOpenFiles is Number of files that can be opened by Kubelet process.
|
||||
MaxOpenFiles int64 `json:"maxOpenFiles"`
|
||||
// registerSchedulable tells the kubelet to register the node as
|
||||
// schedulable. Won't have any effect if register-node is false.
|
||||
// DEPRECATED: use registerWithTaints instead
|
||||
RegisterSchedulable *bool `json:"registerSchedulable"`
|
||||
// registerWithTaints are an array of taints to add to a node object when
|
||||
// the kubelet registers itself. This only takes effect when registerNode
|
||||
// is true and upon the initial registration of the node.
|
||||
RegisterWithTaints []v1.Taint `json:"registerWithTaints"`
|
||||
// contentType is contentType of requests sent to apiserver.
|
||||
ContentType string `json:"contentType"`
|
||||
// kubeAPIQPS is the QPS to use while talking with kubernetes apiserver
|
||||
KubeAPIQPS *int32 `json:"kubeAPIQPS"`
|
||||
// kubeAPIBurst is the burst to allow while talking with kubernetes
|
||||
// apiserver
|
||||
KubeAPIBurst int32 `json:"kubeAPIBurst"`
|
||||
// serializeImagePulls when enabled, tells the Kubelet to pull images one
|
||||
// at a time. We recommend *not* changing the default value on nodes that
|
||||
// run docker daemon with version < 1.9 or an Aufs storage backend.
|
||||
// Issue #10959 has more details.
|
||||
SerializeImagePulls *bool `json:"serializeImagePulls"`
|
||||
// nodeLabels to add when registering the node in the cluster.
|
||||
NodeLabels map[string]string `json:"nodeLabels"`
|
||||
// nonMasqueradeCIDR configures masquerading: traffic to IPs outside this range will use IP masquerade.
|
||||
NonMasqueradeCIDR string `json:"nonMasqueradeCIDR"`
|
||||
// enable gathering custom metrics.
|
||||
EnableCustomMetrics bool `json:"enableCustomMetrics"`
|
||||
// Comma-delimited list of hard eviction expressions. For example, 'memory.available<300Mi'.
|
||||
EvictionHard *string `json:"evictionHard"`
|
||||
// Comma-delimited list of soft eviction expressions. For example, 'memory.available<300Mi'.
|
||||
EvictionSoft string `json:"evictionSoft"`
|
||||
// Comma-delimeted list of grace periods for each soft eviction signal. For example, 'memory.available=30s'.
|
||||
EvictionSoftGracePeriod string `json:"evictionSoftGracePeriod"`
|
||||
// Duration for which the kubelet has to wait before transitioning out of an eviction pressure condition.
|
||||
EvictionPressureTransitionPeriod metav1.Duration `json:"evictionPressureTransitionPeriod"`
|
||||
// Maximum allowed grace period (in seconds) to use when terminating pods in response to a soft eviction threshold being met.
|
||||
EvictionMaxPodGracePeriod int32 `json:"evictionMaxPodGracePeriod"`
|
||||
// Comma-delimited list of minimum reclaims (e.g. imagefs.available=2Gi) that describes the minimum amount of resource the kubelet will reclaim when performing a pod eviction if that resource is under pressure.
|
||||
EvictionMinimumReclaim string `json:"evictionMinimumReclaim"`
|
||||
// If enabled, the kubelet will integrate with the kernel memcg notification to determine if memory eviction thresholds are crossed rather than polling.
|
||||
ExperimentalKernelMemcgNotification *bool `json:"experimentalKernelMemcgNotification"`
|
||||
// Maximum number of pods per core. Cannot exceed MaxPods
|
||||
PodsPerCore int32 `json:"podsPerCore"`
|
||||
// enableControllerAttachDetach enables the Attach/Detach controller to
|
||||
// manage attachment/detachment of volumes scheduled to this node, and
|
||||
// disables kubelet from executing any attach/detach operations
|
||||
EnableControllerAttachDetach *bool `json:"enableControllerAttachDetach"`
|
||||
// A set of ResourceName=Percentage (e.g. memory=50%) pairs that describe
|
||||
// how pod resource requests are reserved at the QoS level.
|
||||
// Currently only memory is supported. [default=none]"
|
||||
ExperimentalQOSReserved map[string]string `json:"experimentalQOSReserved"`
|
||||
// Default behaviour for kernel tuning
|
||||
ProtectKernelDefaults bool `json:"protectKernelDefaults"`
|
||||
// If true, Kubelet ensures a set of iptables rules are present on host.
|
||||
// These rules will serve as utility rules for various components, e.g. KubeProxy.
|
||||
// The rules will be created based on IPTablesMasqueradeBit and IPTablesDropBit.
|
||||
MakeIPTablesUtilChains *bool `json:"makeIPTablesUtilChains"`
|
||||
// iptablesMasqueradeBit is the bit of the iptables fwmark space to mark for SNAT
|
||||
// Values must be within the range [0, 31]. Must be different from other mark bits.
|
||||
// Warning: Please match the value of corresponding parameter in kube-proxy
|
||||
// TODO: clean up IPTablesMasqueradeBit in kube-proxy
|
||||
IPTablesMasqueradeBit *int32 `json:"iptablesMasqueradeBit"`
|
||||
// iptablesDropBit is the bit of the iptables fwmark space to mark for dropping packets.
|
||||
// Values must be within the range [0, 31]. Must be different from other mark bits.
|
||||
IPTablesDropBit *int32 `json:"iptablesDropBit"`
|
||||
// Whitelist of unsafe sysctls or sysctl patterns (ending in *). Use these at your own risk.
|
||||
// Resource isolation might be lacking and pod might influence each other on the same node.
|
||||
// +optional
|
||||
AllowedUnsafeSysctls []string `json:"allowedUnsafeSysctls,omitempty"`
|
||||
// featureGates is a string of comma-separated key=value pairs that describe feature
|
||||
// gates for alpha/experimental features.
|
||||
FeatureGates string `json:"featureGates,omitempty"`
|
||||
// Tells the Kubelet to fail to start if swap is enabled on the node.
|
||||
FailSwapOn bool `json:"failSwapOn,omitempty"`
|
||||
// This flag, if set, enables a check prior to mount operations to verify that the required components
|
||||
// (binaries, etc.) to mount the volume are available on the underlying node. If the check is enabled
|
||||
// and fails the mount operation fails.
|
||||
ExperimentalCheckNodeCapabilitiesBeforeMount bool `json:"experimentalCheckNodeCapabilitiesBeforeMount,omitempty"`
|
||||
// This flag, if set, instructs the kubelet to keep volumes from terminated pods mounted to the node.
|
||||
// This can be useful for debugging volume related issues.
|
||||
KeepTerminatedPodVolumes bool `json:"keepTerminatedPodVolumes,omitempty"`
|
||||
|
||||
/* following flags are meant for Node Allocatable */
|
||||
|
||||
// A set of ResourceName=ResourceQuantity (e.g. cpu=200m,memory=150G) pairs
|
||||
// that describe resources reserved for non-kubernetes components.
|
||||
// Currently only cpu and memory are supported. [default=none]
|
||||
// See http://kubernetes.io/docs/user-guide/compute-resources for more detail.
|
||||
SystemReserved map[string]string `json:"systemReserved"`
|
||||
// A set of ResourceName=ResourceQuantity (e.g. cpu=200m,memory=150G) pairs
|
||||
// that describe resources reserved for kubernetes system components.
|
||||
// Currently cpu, memory and local storage for root file system are supported. [default=none]
|
||||
// See http://kubernetes.io/docs/user-guide/compute-resources for more detail.
|
||||
KubeReserved map[string]string `json:"kubeReserved"`
|
||||
|
||||
// This flag helps kubelet identify absolute name of top level cgroup used to enforce `SystemReserved` compute resource reservation for OS system daemons.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
SystemReservedCgroup string `json:"systemReservedCgroup,omitempty"`
|
||||
// This flag helps kubelet identify absolute name of top level cgroup used to enforce `KubeReserved` compute resource reservation for Kubernetes node system daemons.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
KubeReservedCgroup string `json:"kubeReservedCgroup,omitempty"`
|
||||
// This flag specifies the various Node Allocatable enforcements that Kubelet needs to perform.
|
||||
// This flag accepts a list of options. Acceptible options are `pods`, `system-reserved` & `kube-reserved`.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
EnforceNodeAllocatable []string `json:"enforceNodeAllocatable"`
|
||||
// This flag, if set, will avoid including `EvictionHard` limits while computing Node Allocatable.
|
||||
// Refer to [Node Allocatable](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md) doc for more information.
|
||||
ExperimentalNodeAllocatableIgnoreEvictionThreshold bool `json:"experimentalNodeAllocatableIgnoreEvictionThreshold,omitempty"`
|
||||
}
|
||||
|
||||
type KubeletAuthorizationMode string
|
||||
|
||||
const (
|
||||
// KubeletAuthorizationModeAlwaysAllow authorizes all authenticated requests
|
||||
KubeletAuthorizationModeAlwaysAllow KubeletAuthorizationMode = "AlwaysAllow"
|
||||
// KubeletAuthorizationModeWebhook uses the SubjectAccessReview API to determine authorization
|
||||
KubeletAuthorizationModeWebhook KubeletAuthorizationMode = "Webhook"
|
||||
)
|
||||
|
||||
type KubeletAuthorization struct {
|
||||
// mode is the authorization mode to apply to requests to the kubelet server.
|
||||
// Valid values are AlwaysAllow and Webhook.
|
||||
// Webhook mode uses the SubjectAccessReview API to determine authorization.
|
||||
Mode KubeletAuthorizationMode `json:"mode"`
|
||||
|
||||
// webhook contains settings related to Webhook authorization.
|
||||
Webhook KubeletWebhookAuthorization `json:"webhook"`
|
||||
}
|
||||
|
||||
type KubeletWebhookAuthorization struct {
|
||||
// cacheAuthorizedTTL is the duration to cache 'authorized' responses from the webhook authorizer.
|
||||
CacheAuthorizedTTL metav1.Duration `json:"cacheAuthorizedTTL"`
|
||||
// cacheUnauthorizedTTL is the duration to cache 'unauthorized' responses from the webhook authorizer.
|
||||
CacheUnauthorizedTTL metav1.Duration `json:"cacheUnauthorizedTTL"`
|
||||
}
|
||||
|
||||
type KubeletAuthentication struct {
|
||||
// x509 contains settings related to x509 client certificate authentication
|
||||
X509 KubeletX509Authentication `json:"x509"`
|
||||
// webhook contains settings related to webhook bearer token authentication
|
||||
Webhook KubeletWebhookAuthentication `json:"webhook"`
|
||||
// anonymous contains settings related to anonymous authentication
|
||||
Anonymous KubeletAnonymousAuthentication `json:"anonymous"`
|
||||
}
|
||||
|
||||
type KubeletX509Authentication struct {
|
||||
// clientCAFile is the path to a PEM-encoded certificate bundle. If set, any request presenting a client certificate
|
||||
// signed by one of the authorities in the bundle is authenticated with a username corresponding to the CommonName,
|
||||
// and groups corresponding to the Organization in the client certificate.
|
||||
ClientCAFile string `json:"clientCAFile"`
|
||||
}
|
||||
|
||||
type KubeletWebhookAuthentication struct {
|
||||
// enabled allows bearer token authentication backed by the tokenreviews.authentication.k8s.io API
|
||||
Enabled *bool `json:"enabled"`
|
||||
// cacheTTL enables caching of authentication results
|
||||
CacheTTL metav1.Duration `json:"cacheTTL"`
|
||||
}
|
||||
|
||||
type KubeletAnonymousAuthentication struct {
|
||||
// enabled allows anonymous requests to the kubelet server.
|
||||
// Requests that are not rejected by another authentication method are treated as anonymous requests.
|
||||
// Anonymous requests have a username of system:anonymous, and a group name of system:unauthenticated.
|
||||
Enabled *bool `json:"enabled"`
|
||||
}
|
||||
540
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
540
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedConversionFuncs(
|
||||
Convert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication,
|
||||
Convert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication,
|
||||
Convert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication,
|
||||
Convert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication,
|
||||
Convert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization,
|
||||
Convert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization,
|
||||
Convert_v1alpha1_KubeletConfiguration_To_kubeletconfig_KubeletConfiguration,
|
||||
Convert_kubeletconfig_KubeletConfiguration_To_v1alpha1_KubeletConfiguration,
|
||||
Convert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication,
|
||||
Convert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication,
|
||||
Convert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization,
|
||||
Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization,
|
||||
Convert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication,
|
||||
Convert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication,
|
||||
)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication(in *KubeletAnonymousAuthentication, out *kubeletconfig.KubeletAnonymousAuthentication, s conversion.Scope) error {
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.Enabled, &out.Enabled, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication(in *KubeletAnonymousAuthentication, out *kubeletconfig.KubeletAnonymousAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication(in *kubeletconfig.KubeletAnonymousAuthentication, out *KubeletAnonymousAuthentication, s conversion.Scope) error {
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.Enabled, &out.Enabled, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication(in *kubeletconfig.KubeletAnonymousAuthentication, out *KubeletAnonymousAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication(in *KubeletAuthentication, out *kubeletconfig.KubeletAuthentication, s conversion.Scope) error {
|
||||
if err := Convert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication(&in.X509, &out.X509, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication(&in.Webhook, &out.Webhook, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_KubeletAnonymousAuthentication_To_kubeletconfig_KubeletAnonymousAuthentication(&in.Anonymous, &out.Anonymous, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication(in *KubeletAuthentication, out *kubeletconfig.KubeletAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication(in *kubeletconfig.KubeletAuthentication, out *KubeletAuthentication, s conversion.Scope) error {
|
||||
if err := Convert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication(&in.X509, &out.X509, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication(&in.Webhook, &out.Webhook, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_kubeletconfig_KubeletAnonymousAuthentication_To_v1alpha1_KubeletAnonymousAuthentication(&in.Anonymous, &out.Anonymous, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication(in *kubeletconfig.KubeletAuthentication, out *KubeletAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization(in *KubeletAuthorization, out *kubeletconfig.KubeletAuthorization, s conversion.Scope) error {
|
||||
out.Mode = kubeletconfig.KubeletAuthorizationMode(in.Mode)
|
||||
if err := Convert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization(&in.Webhook, &out.Webhook, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization(in *KubeletAuthorization, out *kubeletconfig.KubeletAuthorization, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization(in *kubeletconfig.KubeletAuthorization, out *KubeletAuthorization, s conversion.Scope) error {
|
||||
out.Mode = KubeletAuthorizationMode(in.Mode)
|
||||
if err := Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization(&in.Webhook, &out.Webhook, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization(in *kubeletconfig.KubeletAuthorization, out *KubeletAuthorization, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletConfiguration_To_kubeletconfig_KubeletConfiguration(in *KubeletConfiguration, out *kubeletconfig.KubeletConfiguration, s conversion.Scope) error {
|
||||
out.ConfigTrialDuration = (*v1.Duration)(unsafe.Pointer(in.ConfigTrialDuration))
|
||||
out.PodManifestPath = in.PodManifestPath
|
||||
out.SyncFrequency = in.SyncFrequency
|
||||
out.FileCheckFrequency = in.FileCheckFrequency
|
||||
out.HTTPCheckFrequency = in.HTTPCheckFrequency
|
||||
out.ManifestURL = in.ManifestURL
|
||||
out.ManifestURLHeader = in.ManifestURLHeader
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.EnableServer, &out.EnableServer, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Address = in.Address
|
||||
out.Port = in.Port
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.ReadOnlyPort, &out.ReadOnlyPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.TLSCertFile = in.TLSCertFile
|
||||
out.TLSPrivateKeyFile = in.TLSPrivateKeyFile
|
||||
if err := Convert_v1alpha1_KubeletAuthentication_To_kubeletconfig_KubeletAuthentication(&in.Authentication, &out.Authentication, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_KubeletAuthorization_To_kubeletconfig_KubeletAuthorization(&in.Authorization, &out.Authorization, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.SeccompProfileRoot = in.SeccompProfileRoot
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.AllowPrivileged, &out.AllowPrivileged, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.HostNetworkSources = *(*[]string)(unsafe.Pointer(&in.HostNetworkSources))
|
||||
out.HostPIDSources = *(*[]string)(unsafe.Pointer(&in.HostPIDSources))
|
||||
out.HostIPCSources = *(*[]string)(unsafe.Pointer(&in.HostIPCSources))
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.RegistryPullQPS, &out.RegistryPullQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.RegistryBurst = in.RegistryBurst
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.EventRecordQPS, &out.EventRecordQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EventBurst = in.EventBurst
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.EnableDebuggingHandlers, &out.EnableDebuggingHandlers, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EnableContentionProfiling = in.EnableContentionProfiling
|
||||
out.MinimumGCAge = in.MinimumGCAge
|
||||
out.MaxPerPodContainerCount = in.MaxPerPodContainerCount
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.MaxContainerCount, &out.MaxContainerCount, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.CAdvisorPort, &out.CAdvisorPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.HealthzPort, &out.HealthzPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.HealthzBindAddress = in.HealthzBindAddress
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.OOMScoreAdj, &out.OOMScoreAdj, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.RegisterNode, &out.RegisterNode, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ClusterDomain = in.ClusterDomain
|
||||
out.MasterServiceNamespace = in.MasterServiceNamespace
|
||||
out.ClusterDNS = *(*[]string)(unsafe.Pointer(&in.ClusterDNS))
|
||||
out.StreamingConnectionIdleTimeout = in.StreamingConnectionIdleTimeout
|
||||
out.NodeStatusUpdateFrequency = in.NodeStatusUpdateFrequency
|
||||
out.ImageMinimumGCAge = in.ImageMinimumGCAge
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.ImageGCHighThresholdPercent, &out.ImageGCHighThresholdPercent, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.ImageGCLowThresholdPercent, &out.ImageGCLowThresholdPercent, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.VolumeStatsAggPeriod = in.VolumeStatsAggPeriod
|
||||
out.VolumePluginDir = in.VolumePluginDir
|
||||
out.KubeletCgroups = in.KubeletCgroups
|
||||
out.RuntimeCgroups = in.RuntimeCgroups
|
||||
out.SystemCgroups = in.SystemCgroups
|
||||
out.CgroupRoot = in.CgroupRoot
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.CgroupsPerQOS, &out.CgroupsPerQOS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CgroupDriver = in.CgroupDriver
|
||||
out.ContainerRuntime = in.ContainerRuntime
|
||||
out.RemoteRuntimeEndpoint = in.RemoteRuntimeEndpoint
|
||||
out.RemoteImageEndpoint = in.RemoteImageEndpoint
|
||||
out.CPUManagerPolicy = in.CPUManagerPolicy
|
||||
out.CPUManagerReconcilePeriod = in.CPUManagerReconcilePeriod
|
||||
out.RuntimeRequestTimeout = in.RuntimeRequestTimeout
|
||||
out.ExperimentalMounterPath = in.ExperimentalMounterPath
|
||||
if err := v1.Convert_Pointer_string_To_string(&in.LockFilePath, &out.LockFilePath, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ExitOnLockContention = in.ExitOnLockContention
|
||||
out.HairpinMode = in.HairpinMode
|
||||
out.MaxPods = in.MaxPods
|
||||
out.PodCIDR = in.PodCIDR
|
||||
out.ResolverConfig = in.ResolverConfig
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.CPUCFSQuota, &out.CPUCFSQuota, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.Containerized, &out.Containerized, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.MaxOpenFiles = in.MaxOpenFiles
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.RegisterSchedulable, &out.RegisterSchedulable, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.RegisterWithTaints = *(*[]api.Taint)(unsafe.Pointer(&in.RegisterWithTaints))
|
||||
out.ContentType = in.ContentType
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.KubeAPIQPS, &out.KubeAPIQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.KubeAPIBurst = in.KubeAPIBurst
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.SerializeImagePulls, &out.SerializeImagePulls, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.NodeLabels = *(*map[string]string)(unsafe.Pointer(&in.NodeLabels))
|
||||
out.NonMasqueradeCIDR = in.NonMasqueradeCIDR
|
||||
out.EnableCustomMetrics = in.EnableCustomMetrics
|
||||
if err := v1.Convert_Pointer_string_To_string(&in.EvictionHard, &out.EvictionHard, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EvictionSoft = in.EvictionSoft
|
||||
out.EvictionSoftGracePeriod = in.EvictionSoftGracePeriod
|
||||
out.EvictionPressureTransitionPeriod = in.EvictionPressureTransitionPeriod
|
||||
out.EvictionMaxPodGracePeriod = in.EvictionMaxPodGracePeriod
|
||||
out.EvictionMinimumReclaim = in.EvictionMinimumReclaim
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.ExperimentalKernelMemcgNotification, &out.ExperimentalKernelMemcgNotification, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.PodsPerCore = in.PodsPerCore
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.EnableControllerAttachDetach, &out.EnableControllerAttachDetach, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ExperimentalQOSReserved = *(*kubeletconfig.ConfigurationMap)(unsafe.Pointer(&in.ExperimentalQOSReserved))
|
||||
out.ProtectKernelDefaults = in.ProtectKernelDefaults
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.MakeIPTablesUtilChains, &out.MakeIPTablesUtilChains, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.IPTablesMasqueradeBit, &out.IPTablesMasqueradeBit, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_int32_To_int32(&in.IPTablesDropBit, &out.IPTablesDropBit, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
|
||||
out.FeatureGates = in.FeatureGates
|
||||
out.FailSwapOn = in.FailSwapOn
|
||||
out.ExperimentalCheckNodeCapabilitiesBeforeMount = in.ExperimentalCheckNodeCapabilitiesBeforeMount
|
||||
out.KeepTerminatedPodVolumes = in.KeepTerminatedPodVolumes
|
||||
out.SystemReserved = *(*kubeletconfig.ConfigurationMap)(unsafe.Pointer(&in.SystemReserved))
|
||||
out.KubeReserved = *(*kubeletconfig.ConfigurationMap)(unsafe.Pointer(&in.KubeReserved))
|
||||
out.SystemReservedCgroup = in.SystemReservedCgroup
|
||||
out.KubeReservedCgroup = in.KubeReservedCgroup
|
||||
out.EnforceNodeAllocatable = *(*[]string)(unsafe.Pointer(&in.EnforceNodeAllocatable))
|
||||
out.ExperimentalNodeAllocatableIgnoreEvictionThreshold = in.ExperimentalNodeAllocatableIgnoreEvictionThreshold
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletConfiguration_To_kubeletconfig_KubeletConfiguration is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletConfiguration_To_kubeletconfig_KubeletConfiguration(in *KubeletConfiguration, out *kubeletconfig.KubeletConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletConfiguration_To_kubeletconfig_KubeletConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletConfiguration_To_v1alpha1_KubeletConfiguration(in *kubeletconfig.KubeletConfiguration, out *KubeletConfiguration, s conversion.Scope) error {
|
||||
out.ConfigTrialDuration = (*v1.Duration)(unsafe.Pointer(in.ConfigTrialDuration))
|
||||
out.PodManifestPath = in.PodManifestPath
|
||||
out.SyncFrequency = in.SyncFrequency
|
||||
out.FileCheckFrequency = in.FileCheckFrequency
|
||||
out.HTTPCheckFrequency = in.HTTPCheckFrequency
|
||||
out.ManifestURL = in.ManifestURL
|
||||
out.ManifestURLHeader = in.ManifestURLHeader
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.EnableServer, &out.EnableServer, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Address = in.Address
|
||||
out.Port = in.Port
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.ReadOnlyPort, &out.ReadOnlyPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.TLSCertFile = in.TLSCertFile
|
||||
out.TLSPrivateKeyFile = in.TLSPrivateKeyFile
|
||||
if err := Convert_kubeletconfig_KubeletAuthentication_To_v1alpha1_KubeletAuthentication(&in.Authentication, &out.Authentication, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_kubeletconfig_KubeletAuthorization_To_v1alpha1_KubeletAuthorization(&in.Authorization, &out.Authorization, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.SeccompProfileRoot = in.SeccompProfileRoot
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.AllowPrivileged, &out.AllowPrivileged, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.HostNetworkSources = *(*[]string)(unsafe.Pointer(&in.HostNetworkSources))
|
||||
out.HostPIDSources = *(*[]string)(unsafe.Pointer(&in.HostPIDSources))
|
||||
out.HostIPCSources = *(*[]string)(unsafe.Pointer(&in.HostIPCSources))
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.RegistryPullQPS, &out.RegistryPullQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.RegistryBurst = in.RegistryBurst
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.EventRecordQPS, &out.EventRecordQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EventBurst = in.EventBurst
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.EnableDebuggingHandlers, &out.EnableDebuggingHandlers, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EnableContentionProfiling = in.EnableContentionProfiling
|
||||
out.MinimumGCAge = in.MinimumGCAge
|
||||
out.MaxPerPodContainerCount = in.MaxPerPodContainerCount
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.MaxContainerCount, &out.MaxContainerCount, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.CAdvisorPort, &out.CAdvisorPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.HealthzPort, &out.HealthzPort, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.HealthzBindAddress = in.HealthzBindAddress
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.OOMScoreAdj, &out.OOMScoreAdj, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.RegisterNode, &out.RegisterNode, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ClusterDomain = in.ClusterDomain
|
||||
out.MasterServiceNamespace = in.MasterServiceNamespace
|
||||
out.ClusterDNS = *(*[]string)(unsafe.Pointer(&in.ClusterDNS))
|
||||
out.StreamingConnectionIdleTimeout = in.StreamingConnectionIdleTimeout
|
||||
out.NodeStatusUpdateFrequency = in.NodeStatusUpdateFrequency
|
||||
out.ImageMinimumGCAge = in.ImageMinimumGCAge
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.ImageGCHighThresholdPercent, &out.ImageGCHighThresholdPercent, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.ImageGCLowThresholdPercent, &out.ImageGCLowThresholdPercent, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.VolumeStatsAggPeriod = in.VolumeStatsAggPeriod
|
||||
out.VolumePluginDir = in.VolumePluginDir
|
||||
out.KubeletCgroups = in.KubeletCgroups
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.CgroupsPerQOS, &out.CgroupsPerQOS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CgroupDriver = in.CgroupDriver
|
||||
out.RuntimeCgroups = in.RuntimeCgroups
|
||||
out.SystemCgroups = in.SystemCgroups
|
||||
out.CgroupRoot = in.CgroupRoot
|
||||
out.ContainerRuntime = in.ContainerRuntime
|
||||
out.RemoteRuntimeEndpoint = in.RemoteRuntimeEndpoint
|
||||
out.RemoteImageEndpoint = in.RemoteImageEndpoint
|
||||
out.CPUManagerPolicy = in.CPUManagerPolicy
|
||||
out.CPUManagerReconcilePeriod = in.CPUManagerReconcilePeriod
|
||||
out.RuntimeRequestTimeout = in.RuntimeRequestTimeout
|
||||
out.ExperimentalMounterPath = in.ExperimentalMounterPath
|
||||
if err := v1.Convert_string_To_Pointer_string(&in.LockFilePath, &out.LockFilePath, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ExitOnLockContention = in.ExitOnLockContention
|
||||
out.HairpinMode = in.HairpinMode
|
||||
out.MaxPods = in.MaxPods
|
||||
out.PodCIDR = in.PodCIDR
|
||||
out.ResolverConfig = in.ResolverConfig
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.CPUCFSQuota, &out.CPUCFSQuota, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.Containerized, &out.Containerized, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.MaxOpenFiles = in.MaxOpenFiles
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.RegisterSchedulable, &out.RegisterSchedulable, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.RegisterWithTaints = *(*[]core_v1.Taint)(unsafe.Pointer(&in.RegisterWithTaints))
|
||||
out.ContentType = in.ContentType
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.KubeAPIQPS, &out.KubeAPIQPS, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.KubeAPIBurst = in.KubeAPIBurst
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.SerializeImagePulls, &out.SerializeImagePulls, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.NodeLabels = *(*map[string]string)(unsafe.Pointer(&in.NodeLabels))
|
||||
out.NonMasqueradeCIDR = in.NonMasqueradeCIDR
|
||||
out.EnableCustomMetrics = in.EnableCustomMetrics
|
||||
if err := v1.Convert_string_To_Pointer_string(&in.EvictionHard, &out.EvictionHard, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.EvictionSoft = in.EvictionSoft
|
||||
out.EvictionSoftGracePeriod = in.EvictionSoftGracePeriod
|
||||
out.EvictionPressureTransitionPeriod = in.EvictionPressureTransitionPeriod
|
||||
out.EvictionMaxPodGracePeriod = in.EvictionMaxPodGracePeriod
|
||||
out.EvictionMinimumReclaim = in.EvictionMinimumReclaim
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.ExperimentalKernelMemcgNotification, &out.ExperimentalKernelMemcgNotification, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.PodsPerCore = in.PodsPerCore
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.EnableControllerAttachDetach, &out.EnableControllerAttachDetach, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.ExperimentalQOSReserved = *(*map[string]string)(unsafe.Pointer(&in.ExperimentalQOSReserved))
|
||||
out.ProtectKernelDefaults = in.ProtectKernelDefaults
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.MakeIPTablesUtilChains, &out.MakeIPTablesUtilChains, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.IPTablesMasqueradeBit, &out.IPTablesMasqueradeBit, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_int32_To_Pointer_int32(&in.IPTablesDropBit, &out.IPTablesDropBit, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.AllowedUnsafeSysctls = *(*[]string)(unsafe.Pointer(&in.AllowedUnsafeSysctls))
|
||||
out.FeatureGates = in.FeatureGates
|
||||
out.FailSwapOn = in.FailSwapOn
|
||||
out.ExperimentalCheckNodeCapabilitiesBeforeMount = in.ExperimentalCheckNodeCapabilitiesBeforeMount
|
||||
out.KeepTerminatedPodVolumes = in.KeepTerminatedPodVolumes
|
||||
out.SystemReserved = *(*map[string]string)(unsafe.Pointer(&in.SystemReserved))
|
||||
out.KubeReserved = *(*map[string]string)(unsafe.Pointer(&in.KubeReserved))
|
||||
out.SystemReservedCgroup = in.SystemReservedCgroup
|
||||
out.KubeReservedCgroup = in.KubeReservedCgroup
|
||||
out.EnforceNodeAllocatable = *(*[]string)(unsafe.Pointer(&in.EnforceNodeAllocatable))
|
||||
out.ExperimentalNodeAllocatableIgnoreEvictionThreshold = in.ExperimentalNodeAllocatableIgnoreEvictionThreshold
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletConfiguration_To_v1alpha1_KubeletConfiguration is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletConfiguration_To_v1alpha1_KubeletConfiguration(in *kubeletconfig.KubeletConfiguration, out *KubeletConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletConfiguration_To_v1alpha1_KubeletConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication(in *KubeletWebhookAuthentication, out *kubeletconfig.KubeletWebhookAuthentication, s conversion.Scope) error {
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.Enabled, &out.Enabled, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CacheTTL = in.CacheTTL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication(in *KubeletWebhookAuthentication, out *kubeletconfig.KubeletWebhookAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletWebhookAuthentication_To_kubeletconfig_KubeletWebhookAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication(in *kubeletconfig.KubeletWebhookAuthentication, out *KubeletWebhookAuthentication, s conversion.Scope) error {
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.Enabled, &out.Enabled, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CacheTTL = in.CacheTTL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication(in *kubeletconfig.KubeletWebhookAuthentication, out *KubeletWebhookAuthentication, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletWebhookAuthentication_To_v1alpha1_KubeletWebhookAuthentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization(in *KubeletWebhookAuthorization, out *kubeletconfig.KubeletWebhookAuthorization, s conversion.Scope) error {
|
||||
out.CacheAuthorizedTTL = in.CacheAuthorizedTTL
|
||||
out.CacheUnauthorizedTTL = in.CacheUnauthorizedTTL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization(in *KubeletWebhookAuthorization, out *kubeletconfig.KubeletWebhookAuthorization, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletWebhookAuthorization_To_kubeletconfig_KubeletWebhookAuthorization(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization(in *kubeletconfig.KubeletWebhookAuthorization, out *KubeletWebhookAuthorization, s conversion.Scope) error {
|
||||
out.CacheAuthorizedTTL = in.CacheAuthorizedTTL
|
||||
out.CacheUnauthorizedTTL = in.CacheUnauthorizedTTL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization(in *kubeletconfig.KubeletWebhookAuthorization, out *KubeletWebhookAuthorization, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletWebhookAuthorization_To_v1alpha1_KubeletWebhookAuthorization(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication(in *KubeletX509Authentication, out *kubeletconfig.KubeletX509Authentication, s conversion.Scope) error {
|
||||
out.ClientCAFile = in.ClientCAFile
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication(in *KubeletX509Authentication, out *kubeletconfig.KubeletX509Authentication, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_KubeletX509Authentication_To_kubeletconfig_KubeletX509Authentication(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication(in *kubeletconfig.KubeletX509Authentication, out *KubeletX509Authentication, s conversion.Scope) error {
|
||||
out.ClientCAFile = in.ClientCAFile
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication is an autogenerated conversion function.
|
||||
func Convert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication(in *kubeletconfig.KubeletX509Authentication, out *KubeletX509Authentication, s conversion.Scope) error {
|
||||
return autoConvert_kubeletconfig_KubeletX509Authentication_To_v1alpha1_KubeletX509Authentication(in, out, s)
|
||||
}
|
||||
538
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
538
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
core_v1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAnonymousAuthentication).DeepCopyInto(out.(*KubeletAnonymousAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAnonymousAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAuthentication).DeepCopyInto(out.(*KubeletAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAuthorization).DeepCopyInto(out.(*KubeletAuthorization))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAuthorization{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletConfiguration).DeepCopyInto(out.(*KubeletConfiguration))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletConfiguration{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletWebhookAuthentication).DeepCopyInto(out.(*KubeletWebhookAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletWebhookAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletWebhookAuthorization).DeepCopyInto(out.(*KubeletWebhookAuthorization))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletWebhookAuthorization{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletX509Authentication).DeepCopyInto(out.(*KubeletX509Authentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletX509Authentication{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAnonymousAuthentication) DeepCopyInto(out *KubeletAnonymousAuthentication) {
|
||||
*out = *in
|
||||
if in.Enabled != nil {
|
||||
in, out := &in.Enabled, &out.Enabled
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAnonymousAuthentication.
|
||||
func (in *KubeletAnonymousAuthentication) DeepCopy() *KubeletAnonymousAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAnonymousAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAuthentication) DeepCopyInto(out *KubeletAuthentication) {
|
||||
*out = *in
|
||||
out.X509 = in.X509
|
||||
in.Webhook.DeepCopyInto(&out.Webhook)
|
||||
in.Anonymous.DeepCopyInto(&out.Anonymous)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAuthentication.
|
||||
func (in *KubeletAuthentication) DeepCopy() *KubeletAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAuthorization) DeepCopyInto(out *KubeletAuthorization) {
|
||||
*out = *in
|
||||
out.Webhook = in.Webhook
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAuthorization.
|
||||
func (in *KubeletAuthorization) DeepCopy() *KubeletAuthorization {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAuthorization)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.ConfigTrialDuration != nil {
|
||||
in, out := &in.ConfigTrialDuration, &out.ConfigTrialDuration
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.SyncFrequency = in.SyncFrequency
|
||||
out.FileCheckFrequency = in.FileCheckFrequency
|
||||
out.HTTPCheckFrequency = in.HTTPCheckFrequency
|
||||
if in.EnableServer != nil {
|
||||
in, out := &in.EnableServer, &out.EnableServer
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ReadOnlyPort != nil {
|
||||
in, out := &in.ReadOnlyPort, &out.ReadOnlyPort
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
in.Authentication.DeepCopyInto(&out.Authentication)
|
||||
out.Authorization = in.Authorization
|
||||
if in.AllowPrivileged != nil {
|
||||
in, out := &in.AllowPrivileged, &out.AllowPrivileged
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.HostNetworkSources != nil {
|
||||
in, out := &in.HostNetworkSources, &out.HostNetworkSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HostPIDSources != nil {
|
||||
in, out := &in.HostPIDSources, &out.HostPIDSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HostIPCSources != nil {
|
||||
in, out := &in.HostIPCSources, &out.HostIPCSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.RegistryPullQPS != nil {
|
||||
in, out := &in.RegistryPullQPS, &out.RegistryPullQPS
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.EventRecordQPS != nil {
|
||||
in, out := &in.EventRecordQPS, &out.EventRecordQPS
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.EnableDebuggingHandlers != nil {
|
||||
in, out := &in.EnableDebuggingHandlers, &out.EnableDebuggingHandlers
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.MinimumGCAge = in.MinimumGCAge
|
||||
if in.MaxContainerCount != nil {
|
||||
in, out := &in.MaxContainerCount, &out.MaxContainerCount
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.CAdvisorPort != nil {
|
||||
in, out := &in.CAdvisorPort, &out.CAdvisorPort
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.HealthzPort != nil {
|
||||
in, out := &in.HealthzPort, &out.HealthzPort
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.OOMScoreAdj != nil {
|
||||
in, out := &in.OOMScoreAdj, &out.OOMScoreAdj
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RegisterNode != nil {
|
||||
in, out := &in.RegisterNode, &out.RegisterNode
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ClusterDNS != nil {
|
||||
in, out := &in.ClusterDNS, &out.ClusterDNS
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.StreamingConnectionIdleTimeout = in.StreamingConnectionIdleTimeout
|
||||
out.NodeStatusUpdateFrequency = in.NodeStatusUpdateFrequency
|
||||
out.ImageMinimumGCAge = in.ImageMinimumGCAge
|
||||
if in.ImageGCHighThresholdPercent != nil {
|
||||
in, out := &in.ImageGCHighThresholdPercent, &out.ImageGCHighThresholdPercent
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ImageGCLowThresholdPercent != nil {
|
||||
in, out := &in.ImageGCLowThresholdPercent, &out.ImageGCLowThresholdPercent
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.VolumeStatsAggPeriod = in.VolumeStatsAggPeriod
|
||||
if in.CgroupsPerQOS != nil {
|
||||
in, out := &in.CgroupsPerQOS, &out.CgroupsPerQOS
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.CPUManagerReconcilePeriod = in.CPUManagerReconcilePeriod
|
||||
out.RuntimeRequestTimeout = in.RuntimeRequestTimeout
|
||||
if in.LockFilePath != nil {
|
||||
in, out := &in.LockFilePath, &out.LockFilePath
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.CPUCFSQuota != nil {
|
||||
in, out := &in.CPUCFSQuota, &out.CPUCFSQuota
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.Containerized != nil {
|
||||
in, out := &in.Containerized, &out.Containerized
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RegisterSchedulable != nil {
|
||||
in, out := &in.RegisterSchedulable, &out.RegisterSchedulable
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.RegisterWithTaints != nil {
|
||||
in, out := &in.RegisterWithTaints, &out.RegisterWithTaints
|
||||
*out = make([]core_v1.Taint, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.KubeAPIQPS != nil {
|
||||
in, out := &in.KubeAPIQPS, &out.KubeAPIQPS
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.SerializeImagePulls != nil {
|
||||
in, out := &in.SerializeImagePulls, &out.SerializeImagePulls
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.NodeLabels != nil {
|
||||
in, out := &in.NodeLabels, &out.NodeLabels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.EvictionHard != nil {
|
||||
in, out := &in.EvictionHard, &out.EvictionHard
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.EvictionPressureTransitionPeriod = in.EvictionPressureTransitionPeriod
|
||||
if in.ExperimentalKernelMemcgNotification != nil {
|
||||
in, out := &in.ExperimentalKernelMemcgNotification, &out.ExperimentalKernelMemcgNotification
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.EnableControllerAttachDetach != nil {
|
||||
in, out := &in.EnableControllerAttachDetach, &out.EnableControllerAttachDetach
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ExperimentalQOSReserved != nil {
|
||||
in, out := &in.ExperimentalQOSReserved, &out.ExperimentalQOSReserved
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.MakeIPTablesUtilChains != nil {
|
||||
in, out := &in.MakeIPTablesUtilChains, &out.MakeIPTablesUtilChains
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.IPTablesMasqueradeBit != nil {
|
||||
in, out := &in.IPTablesMasqueradeBit, &out.IPTablesMasqueradeBit
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.IPTablesDropBit != nil {
|
||||
in, out := &in.IPTablesDropBit, &out.IPTablesDropBit
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.AllowedUnsafeSysctls != nil {
|
||||
in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.SystemReserved != nil {
|
||||
in, out := &in.SystemReserved, &out.SystemReserved
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.KubeReserved != nil {
|
||||
in, out := &in.KubeReserved, &out.KubeReserved
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.EnforceNodeAllocatable != nil {
|
||||
in, out := &in.EnforceNodeAllocatable, &out.EnforceNodeAllocatable
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletConfiguration.
|
||||
func (in *KubeletConfiguration) DeepCopy() *KubeletConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *KubeletConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletWebhookAuthentication) DeepCopyInto(out *KubeletWebhookAuthentication) {
|
||||
*out = *in
|
||||
if in.Enabled != nil {
|
||||
in, out := &in.Enabled, &out.Enabled
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.CacheTTL = in.CacheTTL
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletWebhookAuthentication.
|
||||
func (in *KubeletWebhookAuthentication) DeepCopy() *KubeletWebhookAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletWebhookAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletWebhookAuthorization) DeepCopyInto(out *KubeletWebhookAuthorization) {
|
||||
*out = *in
|
||||
out.CacheAuthorizedTTL = in.CacheAuthorizedTTL
|
||||
out.CacheUnauthorizedTTL = in.CacheUnauthorizedTTL
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletWebhookAuthorization.
|
||||
func (in *KubeletWebhookAuthorization) DeepCopy() *KubeletWebhookAuthorization {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletWebhookAuthorization)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletX509Authentication) DeepCopyInto(out *KubeletX509Authentication) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletX509Authentication.
|
||||
func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletX509Authentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
37
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.defaults.go
generated
vendored
Normal file
37
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/v1alpha1/zz_generated.defaults.go
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by defaulter-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
scheme.AddTypeDefaultingFunc(&KubeletConfiguration{}, func(obj interface{}) { SetObjectDefaults_KubeletConfiguration(obj.(*KubeletConfiguration)) })
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetObjectDefaults_KubeletConfiguration(in *KubeletConfiguration) {
|
||||
SetDefaults_KubeletConfiguration(in)
|
||||
}
|
||||
44
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/BUILD
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["validation.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/cm:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["validation_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
104
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/validation.go
generated
vendored
Normal file
104
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/validation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
containermanager "k8s.io/kubernetes/pkg/kubelet/cm"
|
||||
)
|
||||
|
||||
// ValidateKubeletConfiguration validates `kc` and returns an error if it is invalid
|
||||
func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration) error {
|
||||
allErrors := []error{}
|
||||
|
||||
if !kc.CgroupsPerQOS && len(kc.EnforceNodeAllocatable) > 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("EnforceNodeAllocatable (--enforce-node-allocatable) is not supported unless CgroupsPerQOS (--cgroups-per-qos) feature is turned on"))
|
||||
}
|
||||
if kc.SystemCgroups != "" && kc.CgroupRoot == "" {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: SystemCgroups (--system-cgroups) was specified and CgroupRoot (--cgroup-root) was not specified"))
|
||||
}
|
||||
if kc.CAdvisorPort != 0 && utilvalidation.IsValidPortNum(int(kc.CAdvisorPort)) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: CAdvisorPort (--cadvisor-port) %v must be between 0 and 65535, inclusive", kc.CAdvisorPort))
|
||||
}
|
||||
if kc.EventBurst < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: EventBurst (--event-burst) %v must not be a negative number", kc.EventBurst))
|
||||
}
|
||||
if kc.EventRecordQPS < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: EventRecordQPS (--event-qps) %v must not be a negative number", kc.EventRecordQPS))
|
||||
}
|
||||
if kc.HealthzPort != 0 && utilvalidation.IsValidPortNum(int(kc.HealthzPort)) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: HealthzPort (--healthz-port) %v must be between 1 and 65535, inclusive", kc.HealthzPort))
|
||||
}
|
||||
if utilvalidation.IsInRange(int(kc.ImageGCHighThresholdPercent), 0, 100) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: ImageGCHighThresholdPercent (--image-gc-high-threshold) %v must be between 0 and 100, inclusive", kc.ImageGCHighThresholdPercent))
|
||||
}
|
||||
if utilvalidation.IsInRange(int(kc.ImageGCLowThresholdPercent), 0, 100) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: ImageGCLowThresholdPercent (--image-gc-low-threshold) %v must be between 0 and 100, inclusive", kc.ImageGCLowThresholdPercent))
|
||||
}
|
||||
if utilvalidation.IsInRange(int(kc.IPTablesDropBit), 0, 31) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: IPTablesDropBit (--iptables-drop-bit) %v must be between 0 and 31, inclusive", kc.IPTablesDropBit))
|
||||
}
|
||||
if utilvalidation.IsInRange(int(kc.IPTablesMasqueradeBit), 0, 31) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: IPTablesMasqueradeBit (--iptables-masquerade-bit) %v must be between 0 and 31, inclusive", kc.IPTablesMasqueradeBit))
|
||||
}
|
||||
if kc.KubeAPIBurst < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: KubeAPIBurst (--kube-api-burst) %v must not be a negative number", kc.KubeAPIBurst))
|
||||
}
|
||||
if kc.KubeAPIQPS < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: KubeAPIQPS (--kube-api-qps) %v must not be a negative number", kc.KubeAPIQPS))
|
||||
}
|
||||
if kc.MaxOpenFiles < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: MaxOpenFiles (--max-open-files) %v must not be a negative number", kc.MaxOpenFiles))
|
||||
}
|
||||
if kc.MaxPods < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: MaxPods (--max-pods) %v must not be a negative number", kc.MaxPods))
|
||||
}
|
||||
if utilvalidation.IsInRange(int(kc.OOMScoreAdj), -1000, 1000) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: OOMScoreAdj (--oom-score-adj) %v must be between -1000 and 1000, inclusive", kc.OOMScoreAdj))
|
||||
}
|
||||
if kc.PodsPerCore < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: PodsPerCore (--pods-per-core) %v must not be a negative number", kc.PodsPerCore))
|
||||
}
|
||||
if utilvalidation.IsValidPortNum(int(kc.Port)) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: Port (--port) %v must be between 1 and 65535, inclusive", kc.Port))
|
||||
}
|
||||
if kc.ReadOnlyPort != 0 && utilvalidation.IsValidPortNum(int(kc.ReadOnlyPort)) != nil {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: ReadOnlyPort (--read-only-port) %v must be between 0 and 65535, inclusive", kc.ReadOnlyPort))
|
||||
}
|
||||
if kc.RegistryBurst < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: RegistryBurst (--registry-burst) %v must not be a negative number", kc.RegistryBurst))
|
||||
}
|
||||
if kc.RegistryPullQPS < 0 {
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid configuration: RegistryPullQPS (--registry-qps) %v must not be a negative number", kc.RegistryPullQPS))
|
||||
}
|
||||
for _, val := range kc.EnforceNodeAllocatable {
|
||||
switch val {
|
||||
case containermanager.NodeAllocatableEnforcementKey:
|
||||
case containermanager.SystemReservedEnforcementKey:
|
||||
case containermanager.KubeReservedEnforcementKey:
|
||||
continue
|
||||
default:
|
||||
allErrors = append(allErrors, fmt.Errorf("Invalid option %q specified for EnforceNodeAllocatable (--enforce-node-allocatable) setting. Valid options are %q, %q or %q",
|
||||
val, containermanager.NodeAllocatableEnforcementKey, containermanager.SystemReservedEnforcementKey, containermanager.KubeReservedEnforcementKey))
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(allErrors)
|
||||
}
|
||||
82
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/validation_test.go
generated
vendored
Normal file
82
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/validation/validation_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
)
|
||||
|
||||
func TestValidateKubeletConfiguration(t *testing.T) {
|
||||
successCase := &kubeletconfig.KubeletConfiguration{
|
||||
CgroupsPerQOS: true,
|
||||
EnforceNodeAllocatable: []string{"pods"},
|
||||
SystemCgroups: "",
|
||||
CgroupRoot: "",
|
||||
CAdvisorPort: 0,
|
||||
EventBurst: 10,
|
||||
EventRecordQPS: 5,
|
||||
HealthzPort: 10248,
|
||||
ImageGCHighThresholdPercent: 85,
|
||||
ImageGCLowThresholdPercent: 80,
|
||||
IPTablesDropBit: 15,
|
||||
IPTablesMasqueradeBit: 14,
|
||||
KubeAPIBurst: 10,
|
||||
KubeAPIQPS: 5,
|
||||
MaxOpenFiles: 1000000,
|
||||
MaxPods: 110,
|
||||
OOMScoreAdj: -999,
|
||||
PodsPerCore: 100,
|
||||
Port: 65535,
|
||||
ReadOnlyPort: 0,
|
||||
RegistryBurst: 10,
|
||||
RegistryPullQPS: 5,
|
||||
}
|
||||
if allErrors := ValidateKubeletConfiguration(successCase); allErrors != nil {
|
||||
t.Errorf("expect no errors got %v", allErrors)
|
||||
}
|
||||
|
||||
errorCase := &kubeletconfig.KubeletConfiguration{
|
||||
CgroupsPerQOS: false,
|
||||
EnforceNodeAllocatable: []string{"pods"},
|
||||
SystemCgroups: "/",
|
||||
CgroupRoot: "",
|
||||
CAdvisorPort: -10,
|
||||
EventBurst: -10,
|
||||
EventRecordQPS: -10,
|
||||
HealthzPort: -10,
|
||||
ImageGCHighThresholdPercent: 101,
|
||||
ImageGCLowThresholdPercent: 101,
|
||||
IPTablesDropBit: -10,
|
||||
IPTablesMasqueradeBit: -10,
|
||||
KubeAPIBurst: -10,
|
||||
KubeAPIQPS: -10,
|
||||
MaxOpenFiles: -10,
|
||||
MaxPods: -10,
|
||||
OOMScoreAdj: -1001,
|
||||
PodsPerCore: -10,
|
||||
Port: 0,
|
||||
ReadOnlyPort: -10,
|
||||
RegistryBurst: -10,
|
||||
RegistryPullQPS: -10,
|
||||
}
|
||||
if allErrors := ValidateKubeletConfiguration(errorCase); len(allErrors.(utilerrors.Aggregate).Errors()) != 20 {
|
||||
t.Errorf("expect 20 errors got %v", len(allErrors.(utilerrors.Aggregate).Errors()))
|
||||
}
|
||||
}
|
||||
286
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/zz_generated.deepcopy.go
generated
vendored
Normal file
286
vendor/k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig/zz_generated.deepcopy.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package kubeletconfig
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAnonymousAuthentication).DeepCopyInto(out.(*KubeletAnonymousAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAnonymousAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAuthentication).DeepCopyInto(out.(*KubeletAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletAuthorization).DeepCopyInto(out.(*KubeletAuthorization))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletAuthorization{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletConfiguration).DeepCopyInto(out.(*KubeletConfiguration))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletConfiguration{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletWebhookAuthentication).DeepCopyInto(out.(*KubeletWebhookAuthentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletWebhookAuthentication{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletWebhookAuthorization).DeepCopyInto(out.(*KubeletWebhookAuthorization))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletWebhookAuthorization{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*KubeletX509Authentication).DeepCopyInto(out.(*KubeletX509Authentication))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&KubeletX509Authentication{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAnonymousAuthentication) DeepCopyInto(out *KubeletAnonymousAuthentication) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAnonymousAuthentication.
|
||||
func (in *KubeletAnonymousAuthentication) DeepCopy() *KubeletAnonymousAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAnonymousAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAuthentication) DeepCopyInto(out *KubeletAuthentication) {
|
||||
*out = *in
|
||||
out.X509 = in.X509
|
||||
out.Webhook = in.Webhook
|
||||
out.Anonymous = in.Anonymous
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAuthentication.
|
||||
func (in *KubeletAuthentication) DeepCopy() *KubeletAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletAuthorization) DeepCopyInto(out *KubeletAuthorization) {
|
||||
*out = *in
|
||||
out.Webhook = in.Webhook
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletAuthorization.
|
||||
func (in *KubeletAuthorization) DeepCopy() *KubeletAuthorization {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletAuthorization)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletConfiguration) DeepCopyInto(out *KubeletConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.ConfigTrialDuration != nil {
|
||||
in, out := &in.ConfigTrialDuration, &out.ConfigTrialDuration
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.SyncFrequency = in.SyncFrequency
|
||||
out.FileCheckFrequency = in.FileCheckFrequency
|
||||
out.HTTPCheckFrequency = in.HTTPCheckFrequency
|
||||
out.Authentication = in.Authentication
|
||||
out.Authorization = in.Authorization
|
||||
if in.HostNetworkSources != nil {
|
||||
in, out := &in.HostNetworkSources, &out.HostNetworkSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HostPIDSources != nil {
|
||||
in, out := &in.HostPIDSources, &out.HostPIDSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.HostIPCSources != nil {
|
||||
in, out := &in.HostIPCSources, &out.HostIPCSources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.MinimumGCAge = in.MinimumGCAge
|
||||
if in.ClusterDNS != nil {
|
||||
in, out := &in.ClusterDNS, &out.ClusterDNS
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.StreamingConnectionIdleTimeout = in.StreamingConnectionIdleTimeout
|
||||
out.NodeStatusUpdateFrequency = in.NodeStatusUpdateFrequency
|
||||
out.ImageMinimumGCAge = in.ImageMinimumGCAge
|
||||
out.VolumeStatsAggPeriod = in.VolumeStatsAggPeriod
|
||||
out.CPUManagerReconcilePeriod = in.CPUManagerReconcilePeriod
|
||||
out.RuntimeRequestTimeout = in.RuntimeRequestTimeout
|
||||
if in.RegisterWithTaints != nil {
|
||||
in, out := &in.RegisterWithTaints, &out.RegisterWithTaints
|
||||
*out = make([]api.Taint, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.NodeLabels != nil {
|
||||
in, out := &in.NodeLabels, &out.NodeLabels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.EvictionPressureTransitionPeriod = in.EvictionPressureTransitionPeriod
|
||||
if in.ExperimentalQOSReserved != nil {
|
||||
in, out := &in.ExperimentalQOSReserved, &out.ExperimentalQOSReserved
|
||||
*out = make(ConfigurationMap, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.AllowedUnsafeSysctls != nil {
|
||||
in, out := &in.AllowedUnsafeSysctls, &out.AllowedUnsafeSysctls
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.SystemReserved != nil {
|
||||
in, out := &in.SystemReserved, &out.SystemReserved
|
||||
*out = make(ConfigurationMap, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.KubeReserved != nil {
|
||||
in, out := &in.KubeReserved, &out.KubeReserved
|
||||
*out = make(ConfigurationMap, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.EnforceNodeAllocatable != nil {
|
||||
in, out := &in.EnforceNodeAllocatable, &out.EnforceNodeAllocatable
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletConfiguration.
|
||||
func (in *KubeletConfiguration) DeepCopy() *KubeletConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *KubeletConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletWebhookAuthentication) DeepCopyInto(out *KubeletWebhookAuthentication) {
|
||||
*out = *in
|
||||
out.CacheTTL = in.CacheTTL
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletWebhookAuthentication.
|
||||
func (in *KubeletWebhookAuthentication) DeepCopy() *KubeletWebhookAuthentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletWebhookAuthentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletWebhookAuthorization) DeepCopyInto(out *KubeletWebhookAuthorization) {
|
||||
*out = *in
|
||||
out.CacheAuthorizedTTL = in.CacheAuthorizedTTL
|
||||
out.CacheUnauthorizedTTL = in.CacheUnauthorizedTTL
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletWebhookAuthorization.
|
||||
func (in *KubeletWebhookAuthorization) DeepCopy() *KubeletWebhookAuthorization {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletWebhookAuthorization)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KubeletX509Authentication) DeepCopyInto(out *KubeletX509Authentication) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletX509Authentication.
|
||||
func (in *KubeletX509Authentication) DeepCopy() *KubeletX509Authentication {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KubeletX509Authentication)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
25
vendor/k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1/BUILD
generated
vendored
Normal file
25
vendor/k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["types.go"],
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
274
vendor/k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1/types.go
generated
vendored
Normal file
274
vendor/k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
Copyright 2015 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 v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Summary is a top-level container for holding NodeStats and PodStats.
|
||||
type Summary struct {
|
||||
// Overall node stats.
|
||||
Node NodeStats `json:"node"`
|
||||
// Per-pod stats.
|
||||
Pods []PodStats `json:"pods"`
|
||||
}
|
||||
|
||||
// NodeStats holds node-level unprocessed sample stats.
|
||||
type NodeStats struct {
|
||||
// Reference to the measured Node.
|
||||
NodeName string `json:"nodeName"`
|
||||
// Stats of system daemons tracked as raw containers.
|
||||
// The system containers are named according to the SystemContainer* constants.
|
||||
// +optional
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
SystemContainers []ContainerStats `json:"systemContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
// The time at which data collection for the node-scoped (i.e. aggregate) stats was (re)started.
|
||||
StartTime metav1.Time `json:"startTime"`
|
||||
// Stats pertaining to CPU resources.
|
||||
// +optional
|
||||
CPU *CPUStats `json:"cpu,omitempty"`
|
||||
// Stats pertaining to memory (RAM) resources.
|
||||
// +optional
|
||||
Memory *MemoryStats `json:"memory,omitempty"`
|
||||
// Stats pertaining to network resources.
|
||||
// +optional
|
||||
Network *NetworkStats `json:"network,omitempty"`
|
||||
// Stats pertaining to total usage of filesystem resources on the rootfs used by node k8s components.
|
||||
// NodeFs.Used is the total bytes used on the filesystem.
|
||||
// +optional
|
||||
Fs *FsStats `json:"fs,omitempty"`
|
||||
// Stats about the underlying container runtime.
|
||||
// +optional
|
||||
Runtime *RuntimeStats `json:"runtime,omitempty"`
|
||||
}
|
||||
|
||||
// RuntimeStats are stats pertaining to the underlying container runtime.
|
||||
type RuntimeStats struct {
|
||||
// Stats about the underlying filesystem where container images are stored.
|
||||
// This filesystem could be the same as the primary (root) filesystem.
|
||||
// Usage here refers to the total number of bytes occupied by images on the filesystem.
|
||||
// +optional
|
||||
ImageFs *FsStats `json:"imageFs,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// SystemContainerKubelet is the container name for the system container tracking Kubelet usage.
|
||||
SystemContainerKubelet = "kubelet"
|
||||
// SystemContainerRuntime is the container name for the system container tracking the runtime (e.g. docker or rkt) usage.
|
||||
SystemContainerRuntime = "runtime"
|
||||
// SystemContainerMisc is the container name for the system container tracking non-kubernetes processes.
|
||||
SystemContainerMisc = "misc"
|
||||
)
|
||||
|
||||
// PodStats holds pod-level unprocessed sample stats.
|
||||
type PodStats struct {
|
||||
// Reference to the measured Pod.
|
||||
PodRef PodReference `json:"podRef"`
|
||||
// The time at which data collection for the pod-scoped (e.g. network) stats was (re)started.
|
||||
StartTime metav1.Time `json:"startTime"`
|
||||
// Stats of containers in the measured pod.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
Containers []ContainerStats `json:"containers" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
// Stats pertaining to network resources.
|
||||
// +optional
|
||||
Network *NetworkStats `json:"network,omitempty"`
|
||||
// Stats pertaining to volume usage of filesystem resources.
|
||||
// VolumeStats.UsedBytes is the number of bytes used by the Volume
|
||||
// +optional
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
VolumeStats []VolumeStats `json:"volume,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// ContainerStats holds container-level unprocessed sample stats.
|
||||
type ContainerStats struct {
|
||||
// Reference to the measured container.
|
||||
Name string `json:"name"`
|
||||
// The time at which data collection for this container was (re)started.
|
||||
StartTime metav1.Time `json:"startTime"`
|
||||
// Stats pertaining to CPU resources.
|
||||
// +optional
|
||||
CPU *CPUStats `json:"cpu,omitempty"`
|
||||
// Stats pertaining to memory (RAM) resources.
|
||||
// +optional
|
||||
Memory *MemoryStats `json:"memory,omitempty"`
|
||||
// Stats pertaining to container rootfs usage of filesystem resources.
|
||||
// Rootfs.UsedBytes is the number of bytes used for the container write layer.
|
||||
// +optional
|
||||
Rootfs *FsStats `json:"rootfs,omitempty"`
|
||||
// Stats pertaining to container logs usage of filesystem resources.
|
||||
// Logs.UsedBytes is the number of bytes used for the container logs.
|
||||
// +optional
|
||||
Logs *FsStats `json:"logs,omitempty"`
|
||||
// User defined metrics that are exposed by containers in the pod. Typically, we expect only one container in the pod to be exposing user defined metrics. In the event of multiple containers exposing metrics, they will be combined here.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
UserDefinedMetrics []UserDefinedMetric `json:"userDefinedMetrics,omitmepty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||
}
|
||||
|
||||
// PodReference contains enough information to locate the referenced pod.
|
||||
type PodReference struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
UID string `json:"uid"`
|
||||
}
|
||||
|
||||
// NetworkStats contains data about network resources.
|
||||
type NetworkStats struct {
|
||||
// The time at which these stats were updated.
|
||||
Time metav1.Time `json:"time"`
|
||||
// Cumulative count of bytes received.
|
||||
// +optional
|
||||
RxBytes *uint64 `json:"rxBytes,omitempty"`
|
||||
// Cumulative count of receive errors encountered.
|
||||
// +optional
|
||||
RxErrors *uint64 `json:"rxErrors,omitempty"`
|
||||
// Cumulative count of bytes transmitted.
|
||||
// +optional
|
||||
TxBytes *uint64 `json:"txBytes,omitempty"`
|
||||
// Cumulative count of transmit errors encountered.
|
||||
// +optional
|
||||
TxErrors *uint64 `json:"txErrors,omitempty"`
|
||||
}
|
||||
|
||||
// CPUStats contains data about CPU usage.
|
||||
type CPUStats struct {
|
||||
// The time at which these stats were updated.
|
||||
Time metav1.Time `json:"time"`
|
||||
// Total CPU usage (sum of all cores) averaged over the sample window.
|
||||
// The "core" unit can be interpreted as CPU core-nanoseconds per second.
|
||||
// +optional
|
||||
UsageNanoCores *uint64 `json:"usageNanoCores,omitempty"`
|
||||
// Cumulative CPU usage (sum of all cores) since object creation.
|
||||
// +optional
|
||||
UsageCoreNanoSeconds *uint64 `json:"usageCoreNanoSeconds,omitempty"`
|
||||
}
|
||||
|
||||
// MemoryStats contains data about memory usage.
|
||||
type MemoryStats struct {
|
||||
// The time at which these stats were updated.
|
||||
Time metav1.Time `json:"time"`
|
||||
// Available memory for use. This is defined as the memory limit - workingSetBytes.
|
||||
// If memory limit is undefined, the available bytes is omitted.
|
||||
// +optional
|
||||
AvailableBytes *uint64 `json:"availableBytes,omitempty"`
|
||||
// Total memory in use. This includes all memory regardless of when it was accessed.
|
||||
// +optional
|
||||
UsageBytes *uint64 `json:"usageBytes,omitempty"`
|
||||
// The amount of working set memory. This includes recently accessed memory,
|
||||
// dirty memory, and kernel memory. WorkingSetBytes is <= UsageBytes
|
||||
// +optional
|
||||
WorkingSetBytes *uint64 `json:"workingSetBytes,omitempty"`
|
||||
// The amount of anonymous and swap cache memory (includes transparent
|
||||
// hugepages).
|
||||
// +optional
|
||||
RSSBytes *uint64 `json:"rssBytes,omitempty"`
|
||||
// Cumulative number of minor page faults.
|
||||
// +optional
|
||||
PageFaults *uint64 `json:"pageFaults,omitempty"`
|
||||
// Cumulative number of major page faults.
|
||||
// +optional
|
||||
MajorPageFaults *uint64 `json:"majorPageFaults,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeStats contains data about Volume filesystem usage.
|
||||
type VolumeStats struct {
|
||||
// Embedded FsStats
|
||||
FsStats
|
||||
// Name is the name given to the Volume
|
||||
// +optional
|
||||
Name string `json:"name,omitempty"`
|
||||
// Reference to the PVC, if one exists
|
||||
// +optional
|
||||
PVCRef *PVCReference `json:"pvcRef,omitempty"`
|
||||
}
|
||||
|
||||
// PVCReference contains enough information to describe the referenced PVC.
|
||||
type PVCReference struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// FsStats contains data about filesystem usage.
|
||||
type FsStats struct {
|
||||
// The time at which these stats were updated.
|
||||
Time metav1.Time `json:"time"`
|
||||
// AvailableBytes represents the storage space available (bytes) for the filesystem.
|
||||
// +optional
|
||||
AvailableBytes *uint64 `json:"availableBytes,omitempty"`
|
||||
// CapacityBytes represents the total capacity (bytes) of the filesystems underlying storage.
|
||||
// +optional
|
||||
CapacityBytes *uint64 `json:"capacityBytes,omitempty"`
|
||||
// UsedBytes represents the bytes used for a specific task on the filesystem.
|
||||
// This may differ from the total bytes used on the filesystem and may not equal CapacityBytes - AvailableBytes.
|
||||
// e.g. For ContainerStats.Rootfs this is the bytes used by the container rootfs on the filesystem.
|
||||
// +optional
|
||||
UsedBytes *uint64 `json:"usedBytes,omitempty"`
|
||||
// InodesFree represents the free inodes in the filesystem.
|
||||
// +optional
|
||||
InodesFree *uint64 `json:"inodesFree,omitempty"`
|
||||
// Inodes represents the total inodes in the filesystem.
|
||||
// +optional
|
||||
Inodes *uint64 `json:"inodes,omitempty"`
|
||||
// InodesUsed represents the inodes used by the filesystem
|
||||
// This may not equal Inodes - InodesFree because this filesystem may share inodes with other "filesystems"
|
||||
// e.g. For ContainerStats.Rootfs, this is the inodes used only by that container, and does not count inodes used by other containers.
|
||||
InodesUsed *uint64 `json:"inodesUsed,omitempty"`
|
||||
}
|
||||
|
||||
// UserDefinedMetricType defines how the metric should be interpreted by the user.
|
||||
type UserDefinedMetricType string
|
||||
|
||||
const (
|
||||
// MetricGauge is an instantaneous value. May increase or decrease.
|
||||
MetricGauge UserDefinedMetricType = "gauge"
|
||||
|
||||
// MetricCumulative is a counter-like value that is only expected to increase.
|
||||
MetricCumulative UserDefinedMetricType = "cumulative"
|
||||
|
||||
// MetricDelta is a rate over a time period.
|
||||
MetricDelta UserDefinedMetricType = "delta"
|
||||
)
|
||||
|
||||
// UserDefinedMetricDescriptor contains metadata that describes a user defined metric.
|
||||
type UserDefinedMetricDescriptor struct {
|
||||
// The name of the metric.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Type of the metric.
|
||||
Type UserDefinedMetricType `json:"type"`
|
||||
|
||||
// Display Units for the stats.
|
||||
Units string `json:"units"`
|
||||
|
||||
// Metadata labels associated with this metric.
|
||||
// +optional
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// UserDefinedMetric represents a metric defined and generate by users.
|
||||
type UserDefinedMetric struct {
|
||||
UserDefinedMetricDescriptor `json:",inline"`
|
||||
// The time at which these stats were updated.
|
||||
Time metav1.Time `json:"time"`
|
||||
// Value of the metric. Float64s have 53 bit precision.
|
||||
// We do not foresee any metrics exceeding that value.
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
86
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/BUILD
generated
vendored
Normal file
86
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cadvisor_unsupported.go",
|
||||
"doc.go",
|
||||
"helpers_unsupported.go",
|
||||
"types.go",
|
||||
"util.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"cadvisor_linux.go",
|
||||
"helpers_linux.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"cadvisor_windows.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
deps = [
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/events:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/cache/memory:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/container:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/fs:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/http:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/manager:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/metrics:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/utils/sysfs:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"cadvisor_linux_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
library = ":go_default_library",
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//pkg/kubelet/types:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/metrics:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/cadvisor/testing:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
252
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_linux.go
generated
vendored
Normal file
252
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
// +build cgo,linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cadvisor
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/google/cadvisor/cache/memory"
|
||||
cadvisormetrics "github.com/google/cadvisor/container"
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorhttp "github.com/google/cadvisor/http"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
"github.com/google/cadvisor/manager"
|
||||
"github.com/google/cadvisor/metrics"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||
)
|
||||
|
||||
type cadvisorClient struct {
|
||||
imageFsInfoProvider ImageFsInfoProvider
|
||||
rootPath string
|
||||
manager.Manager
|
||||
}
|
||||
|
||||
var _ Interface = new(cadvisorClient)
|
||||
|
||||
// TODO(vmarmol): Make configurable.
|
||||
// The amount of time for which to keep stats in memory.
|
||||
const statsCacheDuration = 2 * time.Minute
|
||||
const maxHousekeepingInterval = 15 * time.Second
|
||||
const defaultHousekeepingInterval = 10 * time.Second
|
||||
const allowDynamicHousekeeping = true
|
||||
|
||||
func init() {
|
||||
// Override cAdvisor flag defaults.
|
||||
flagOverrides := map[string]string{
|
||||
// Override the default cAdvisor housekeeping interval.
|
||||
"housekeeping_interval": defaultHousekeepingInterval.String(),
|
||||
// Disable event storage by default.
|
||||
"event_storage_event_limit": "default=0",
|
||||
"event_storage_age_limit": "default=0",
|
||||
}
|
||||
for name, defaultValue := range flagOverrides {
|
||||
if f := flag.Lookup(name); f != nil {
|
||||
f.DefValue = defaultValue
|
||||
f.Value.Set(defaultValue)
|
||||
} else {
|
||||
glog.Errorf("Expected cAdvisor flag %q not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func containerLabels(c *cadvisorapi.ContainerInfo) map[string]string {
|
||||
// Prometheus requires that all metrics in the same family have the same labels,
|
||||
// so we arrange to supply blank strings for missing labels
|
||||
var name, image, podName, namespace, containerName string
|
||||
if len(c.Aliases) > 0 {
|
||||
name = c.Aliases[0]
|
||||
}
|
||||
image = c.Spec.Image
|
||||
if v, ok := c.Spec.Labels[types.KubernetesPodNameLabel]; ok {
|
||||
podName = v
|
||||
}
|
||||
if v, ok := c.Spec.Labels[types.KubernetesPodNamespaceLabel]; ok {
|
||||
namespace = v
|
||||
}
|
||||
if v, ok := c.Spec.Labels[types.KubernetesContainerNameLabel]; ok {
|
||||
containerName = v
|
||||
}
|
||||
set := map[string]string{
|
||||
metrics.LabelID: c.Name,
|
||||
metrics.LabelName: name,
|
||||
metrics.LabelImage: image,
|
||||
"pod_name": podName,
|
||||
"namespace": namespace,
|
||||
"container_name": containerName,
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// New creates a cAdvisor and exports its API on the specified port if port > 0.
|
||||
func New(address string, port uint, imageFsInfoProvider ImageFsInfoProvider, rootPath string) (Interface, error) {
|
||||
sysFs := sysfs.NewRealSysFs()
|
||||
|
||||
// Create and start the cAdvisor container manager.
|
||||
m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, cadvisormetrics.MetricSet{cadvisormetrics.NetworkTcpUsageMetrics: struct{}{}, cadvisormetrics.NetworkUdpUsageMetrics: struct{}{}}, http.DefaultClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(rootPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(path.Clean(rootPath), 0750); err != nil {
|
||||
return nil, fmt.Errorf("error creating root directory %q: %v", rootPath, err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to Stat %q: %v", rootPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
cadvisorClient := &cadvisorClient{
|
||||
imageFsInfoProvider: imageFsInfoProvider,
|
||||
rootPath: rootPath,
|
||||
Manager: m,
|
||||
}
|
||||
|
||||
err = cadvisorClient.exportHTTP(address, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cadvisorClient, nil
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) Start() error {
|
||||
return cc.Manager.Start()
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) exportHTTP(address string, port uint) error {
|
||||
// Register the handlers regardless as this registers the prometheus
|
||||
// collector properly.
|
||||
mux := http.NewServeMux()
|
||||
err := cadvisorhttp.RegisterHandlers(mux, cc, "", "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cadvisorhttp.RegisterPrometheusHandler(mux, cc, "/metrics", containerLabels)
|
||||
|
||||
// Only start the http server if port > 0
|
||||
if port > 0 {
|
||||
serv := &http.Server{
|
||||
Addr: net.JoinHostPort(address, strconv.Itoa(int(port))),
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
// TODO(vmarmol): Remove this when the cAdvisor port is once again free.
|
||||
// If export failed, retry in the background until we are able to bind.
|
||||
// This allows an existing cAdvisor to be killed before this one registers.
|
||||
go func() {
|
||||
defer runtime.HandleCrash()
|
||||
|
||||
err := serv.ListenAndServe()
|
||||
for err != nil {
|
||||
glog.Infof("Failed to register cAdvisor on port %d, retrying. Error: %v", port, err)
|
||||
time.Sleep(time.Minute)
|
||||
err = serv.ListenAndServe()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
|
||||
return cc.GetContainerInfo(name, req)
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
|
||||
return cc.GetContainerInfoV2(name, options)
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
|
||||
return cc.GetVersionInfo()
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
|
||||
infos, err := cc.SubcontainersInfo(name, req)
|
||||
if err != nil && len(infos) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]*cadvisorapi.ContainerInfo, len(infos))
|
||||
for _, info := range infos {
|
||||
result[info.Name] = info
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
|
||||
return cc.GetMachineInfo()
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
label, err := cc.imageFsInfoProvider.ImageFsInfoLabel()
|
||||
if err != nil {
|
||||
return cadvisorapiv2.FsInfo{}, err
|
||||
}
|
||||
return cc.getFsInfo(label)
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cc.GetDirFsInfo(cc.rootPath)
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) {
|
||||
res, err := cc.GetFsInfo(label)
|
||||
if err != nil {
|
||||
return cadvisorapiv2.FsInfo{}, err
|
||||
}
|
||||
if len(res) == 0 {
|
||||
return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label)
|
||||
}
|
||||
// TODO(vmarmol): Handle this better when a label has more than one image filesystem.
|
||||
if len(res) > 1 {
|
||||
glog.Warningf("More than one filesystem labeled %q: %#v. Only using the first one", label, res)
|
||||
}
|
||||
|
||||
return res[0], nil
|
||||
}
|
||||
|
||||
func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
|
||||
return cc.WatchForEvents(request)
|
||||
}
|
||||
|
||||
// HasDedicatedImageFs returns true if the imagefs has a dedicated device.
|
||||
func (cc *cadvisorClient) HasDedicatedImageFs() (bool, error) {
|
||||
imageFsInfo, err := cc.ImagesFsInfo()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rootFsInfo, err := cc.RootFsInfo()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return imageFsInfo.Device != rootFsInfo.Device, nil
|
||||
}
|
||||
65
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_linux_test.go
generated
vendored
Normal file
65
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_linux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// +build cgo,linux
|
||||
|
||||
/*
|
||||
Copyright 2016 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 cadvisor
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/metrics"
|
||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||
)
|
||||
|
||||
func TestContainerLabels(t *testing.T) {
|
||||
container := &info.ContainerInfo{
|
||||
ContainerReference: info.ContainerReference{
|
||||
Name: "/docker/f81ad5335d390944e454ea19ab0924037d57337c19731524ad96eb26e74b6c6d",
|
||||
Aliases: []string{"k8s_POD.639b2af2_foo-web-315473031-e40e2_foobar_a369ace2-5fa9-11e6-b10f-c81f66e5e84d_851a97fd"},
|
||||
},
|
||||
Spec: info.ContainerSpec{
|
||||
Image: "qux/foo:latest",
|
||||
Labels: map[string]string{
|
||||
"io.kubernetes.container.hash": "639b2af2",
|
||||
types.KubernetesContainerNameLabel: "POD",
|
||||
"io.kubernetes.container.restartCount": "0",
|
||||
"io.kubernetes.container.terminationMessagePath": "",
|
||||
types.KubernetesPodNameLabel: "foo-web-315473031-e40e2",
|
||||
types.KubernetesPodNamespaceLabel: "foobar",
|
||||
"io.kubernetes.pod.terminationGracePeriod": "30",
|
||||
types.KubernetesPodUIDLabel: "a369ace2-5fa9-11e6-b10f-c81f66e5e84d",
|
||||
},
|
||||
Envs: map[string]string{
|
||||
"foo+env": "prod",
|
||||
},
|
||||
},
|
||||
}
|
||||
want := map[string]string{
|
||||
metrics.LabelID: "/docker/f81ad5335d390944e454ea19ab0924037d57337c19731524ad96eb26e74b6c6d",
|
||||
metrics.LabelName: "k8s_POD.639b2af2_foo-web-315473031-e40e2_foobar_a369ace2-5fa9-11e6-b10f-c81f66e5e84d_851a97fd",
|
||||
metrics.LabelImage: "qux/foo:latest",
|
||||
"namespace": "foobar",
|
||||
"container_name": "POD",
|
||||
"pod_name": "foo-web-315473031-e40e2",
|
||||
}
|
||||
|
||||
if have := containerLabels(container); !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("want %v, have %v", want, have)
|
||||
}
|
||||
}
|
||||
86
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_unsupported.go
generated
vendored
Normal file
86
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// +build !linux,!windows linux,!cgo
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cadvisor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
)
|
||||
|
||||
type cadvisorUnsupported struct {
|
||||
}
|
||||
|
||||
var _ Interface = new(cadvisorUnsupported)
|
||||
|
||||
func New(address string, port uint, imageFsInfoProvider ImageFsInfoProvider, rootPath string) (Interface, error) {
|
||||
return &cadvisorUnsupported{}, nil
|
||||
}
|
||||
|
||||
var unsupportedErr = errors.New("cAdvisor is unsupported in this build")
|
||||
|
||||
func (cu *cadvisorUnsupported) Start() error {
|
||||
return unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error) {
|
||||
return cadvisorapi.ContainerInfo{}, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) MachineInfo() (*cadvisorapi.MachineInfo, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) VersionInfo() (*cadvisorapi.VersionInfo, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) WatchEvents(request *events.Request) (*events.EventChannel, error) {
|
||||
return nil, unsupportedErr
|
||||
}
|
||||
|
||||
func (cu *cadvisorUnsupported) HasDedicatedImageFs() (bool, error) {
|
||||
return false, unsupportedErr
|
||||
}
|
||||
|
||||
func (c *cadvisorUnsupported) GetFsInfoByFsUUID(uuid string) (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
83
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_windows.go
generated
vendored
Normal file
83
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/cadvisor_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cadvisor
|
||||
|
||||
import (
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
)
|
||||
|
||||
type cadvisorClient struct {
|
||||
}
|
||||
|
||||
var _ Interface = new(cadvisorClient)
|
||||
|
||||
// New creates a cAdvisor and exports its API on the specified port if port > 0.
|
||||
func New(address string, port uint, imageFsInfoProvider ImageFsInfoProvider, rootPath string) (Interface, error) {
|
||||
return &cadvisorClient{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error) {
|
||||
return cadvisorapi.ContainerInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
|
||||
return &cadvisorapi.ContainerInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
|
||||
return make(map[string]cadvisorapiv2.ContainerInfo), nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
|
||||
return &cadvisorapi.MachineInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
|
||||
return &cadvisorapi.VersionInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
|
||||
return &events.EventChannel{}, nil
|
||||
}
|
||||
|
||||
func (cu *cadvisorClient) HasDedicatedImageFs() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *cadvisorClient) GetFsInfoByFsUUID(uuid string) (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
18
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2015 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.
|
||||
*/
|
||||
|
||||
// Kubelet interactions with cAdvisor.
|
||||
package cadvisor // import "k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
56
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/helpers_linux.go
generated
vendored
Normal file
56
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/helpers_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// +build cgo,linux
|
||||
|
||||
/*
|
||||
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 cadvisor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cadvisorfs "github.com/google/cadvisor/fs"
|
||||
)
|
||||
|
||||
// imageFsInfoProvider knows how to translate the configured runtime
|
||||
// to its file system label for images.
|
||||
type imageFsInfoProvider struct {
|
||||
runtime string
|
||||
runtimeEndpoint string
|
||||
}
|
||||
|
||||
// ImageFsInfoLabel returns the image fs label for the configured runtime.
|
||||
// For remote runtimes, it handles additional runtimes natively understood by cAdvisor.
|
||||
func (i *imageFsInfoProvider) ImageFsInfoLabel() (string, error) {
|
||||
switch i.runtime {
|
||||
case "docker":
|
||||
return cadvisorfs.LabelDockerImages, nil
|
||||
case "rkt":
|
||||
return cadvisorfs.LabelRktImages, nil
|
||||
case "remote":
|
||||
// This is a temporary workaround to get stats for cri-o from cadvisor
|
||||
// and should be removed.
|
||||
// Related to https://github.com/kubernetes/kubernetes/issues/51798
|
||||
if i.runtimeEndpoint == "/var/run/crio.sock" {
|
||||
return cadvisorfs.LabelCrioImages, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("no imagefs label for configured runtime")
|
||||
}
|
||||
|
||||
// NewImageFsInfoProvider returns a provider for the specified runtime configuration.
|
||||
func NewImageFsInfoProvider(runtime, runtimeEndpoint string) ImageFsInfoProvider {
|
||||
return &imageFsInfoProvider{runtime: runtime, runtimeEndpoint: runtimeEndpoint}
|
||||
}
|
||||
34
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/helpers_unsupported.go
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/helpers_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// +build !linux linux,!cgo
|
||||
|
||||
/*
|
||||
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 cadvisor
|
||||
|
||||
import "errors"
|
||||
|
||||
type unsupportedImageFsInfoProvider struct{}
|
||||
|
||||
// ImageFsInfoLabel returns the image fs label for the configured runtime.
|
||||
// For remote runtimes, it handles additional runtimes natively understood by cAdvisor.
|
||||
func (i *unsupportedImageFsInfoProvider) ImageFsInfoLabel() (string, error) {
|
||||
return "", errors.New("unsupported")
|
||||
}
|
||||
|
||||
// NewImageFsInfoProvider returns a provider for the specified runtime configuration.
|
||||
func NewImageFsInfoProvider(runtime, runtimeEndpoint string) ImageFsInfoProvider {
|
||||
return &unsupportedImageFsInfoProvider{}
|
||||
}
|
||||
34
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/BUILD
generated
vendored
Normal file
34
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cadvisor_fake.go",
|
||||
"cadvisor_mock.go",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/kubelet/cadvisor:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/events:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/mock:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
85
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/cadvisor_fake.go
generated
vendored
Normal file
85
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/cadvisor_fake.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright 2015 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 testing
|
||||
|
||||
import (
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
)
|
||||
|
||||
// Fake cAdvisor implementation.
|
||||
type Fake struct {
|
||||
NodeName string
|
||||
}
|
||||
|
||||
var _ cadvisor.Interface = new(Fake)
|
||||
|
||||
func (c *Fake) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Fake) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
|
||||
return new(cadvisorapi.ContainerInfo), nil
|
||||
}
|
||||
|
||||
func (c *Fake) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
|
||||
return map[string]cadvisorapiv2.ContainerInfo{}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
|
||||
return map[string]*cadvisorapi.ContainerInfo{}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error) {
|
||||
return cadvisorapi.ContainerInfo{}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) MachineInfo() (*cadvisorapi.MachineInfo, error) {
|
||||
// Simulate a matchin with 1 core and 3.75GB of memory.
|
||||
// We set it to non-zero values to make non-zero-capacity machines in Kubemark.
|
||||
return &cadvisorapi.MachineInfo{
|
||||
NumCores: 1,
|
||||
InstanceID: cadvisorapi.InstanceID(c.NodeName),
|
||||
MemoryCapacity: 4026531840,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) VersionInfo() (*cadvisorapi.VersionInfo, error) {
|
||||
return new(cadvisorapi.VersionInfo), nil
|
||||
}
|
||||
|
||||
func (c *Fake) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
|
||||
func (c *Fake) WatchEvents(request *events.Request) (*events.EventChannel, error) {
|
||||
return new(events.EventChannel), nil
|
||||
}
|
||||
|
||||
func (c *Fake) HasDedicatedImageFs() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *Fake) GetFsInfoByFsUUID(uuid string) (cadvisorapiv2.FsInfo, error) {
|
||||
return cadvisorapiv2.FsInfo{}, nil
|
||||
}
|
||||
95
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/cadvisor_mock.go
generated
vendored
Normal file
95
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/testing/cadvisor_mock.go
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2015 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 testing
|
||||
|
||||
import (
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
)
|
||||
|
||||
type Mock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
var _ cadvisor.Interface = new(Mock)
|
||||
|
||||
func (c *Mock) Start() error {
|
||||
args := c.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// ContainerInfo is a mock implementation of Interface.ContainerInfo.
|
||||
func (c *Mock) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
|
||||
args := c.Called(name, req)
|
||||
return args.Get(0).(*cadvisorapi.ContainerInfo), args.Error(1)
|
||||
}
|
||||
|
||||
// ContainerInfoV2 is a mock implementation of Interface.ContainerInfoV2.
|
||||
func (c *Mock) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
|
||||
args := c.Called(name, options)
|
||||
return args.Get(0).(map[string]cadvisorapiv2.ContainerInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
|
||||
args := c.Called(name, req)
|
||||
return args.Get(0).(map[string]*cadvisorapi.ContainerInfo), args.Error(1)
|
||||
}
|
||||
|
||||
// DockerContainer is a mock implementation of Interface.DockerContainer.
|
||||
func (c *Mock) DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error) {
|
||||
args := c.Called(name, req)
|
||||
return args.Get(0).(cadvisorapi.ContainerInfo), args.Error(1)
|
||||
}
|
||||
|
||||
// MachineInfo is a mock implementation of Interface.MachineInfo.
|
||||
func (c *Mock) MachineInfo() (*cadvisorapi.MachineInfo, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(*cadvisorapi.MachineInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) VersionInfo() (*cadvisorapi.VersionInfo, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(*cadvisorapi.VersionInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(cadvisorapiv2.FsInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(cadvisorapiv2.FsInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) WatchEvents(request *events.Request) (*events.EventChannel, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(*events.EventChannel), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) HasDedicatedImageFs() (bool, error) {
|
||||
args := c.Called()
|
||||
return args.Get(0).(bool), args.Error(1)
|
||||
}
|
||||
|
||||
func (c *Mock) GetFsInfoByFsUUID(uuid string) (cadvisorapiv2.FsInfo, error) {
|
||||
args := c.Called(uuid)
|
||||
return args.Get(0).(cadvisorapiv2.FsInfo), args.Error(1)
|
||||
}
|
||||
57
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/types.go
generated
vendored
Normal file
57
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2015 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 cadvisor
|
||||
|
||||
import (
|
||||
"github.com/google/cadvisor/events"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
|
||||
)
|
||||
|
||||
// Interface is an abstract interface for testability. It abstracts the interface to cAdvisor.
|
||||
type Interface interface {
|
||||
Start() error
|
||||
DockerContainer(name string, req *cadvisorapi.ContainerInfoRequest) (cadvisorapi.ContainerInfo, error)
|
||||
ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error)
|
||||
ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error)
|
||||
SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error)
|
||||
MachineInfo() (*cadvisorapi.MachineInfo, error)
|
||||
|
||||
VersionInfo() (*cadvisorapi.VersionInfo, error)
|
||||
|
||||
// Returns usage information about the filesystem holding container images.
|
||||
ImagesFsInfo() (cadvisorapiv2.FsInfo, error)
|
||||
|
||||
// Returns usage information about the root filesystem.
|
||||
RootFsInfo() (cadvisorapiv2.FsInfo, error)
|
||||
|
||||
// Get events streamed through passedChannel that fit the request.
|
||||
WatchEvents(request *events.Request) (*events.EventChannel, error)
|
||||
|
||||
// HasDedicatedImageFs returns true iff a dedicated image filesystem exists for storing images.
|
||||
HasDedicatedImageFs() (bool, error)
|
||||
|
||||
// GetFsInfoByFsUUID returns the stats of the filesystem with the specified
|
||||
// uuid.
|
||||
GetFsInfoByFsUUID(uuid string) (cadvisorapiv2.FsInfo, error)
|
||||
}
|
||||
|
||||
// ImageFsInfoProvider informs cAdvisor how to find imagefs for container images.
|
||||
type ImageFsInfoProvider interface {
|
||||
// ImageFsInfoLabel returns the label cAdvisor should use to find the filesystem holding container images.
|
||||
ImageFsInfoLabel() (string, error)
|
||||
}
|
||||
59
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/util.go
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/pkg/kubelet/cadvisor/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright 2015 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 cadvisor
|
||||
|
||||
import (
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
cadvisorapi2 "github.com/google/cadvisor/info/v2"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
func CapacityFromMachineInfo(info *cadvisorapi.MachineInfo) v1.ResourceList {
|
||||
c := v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewMilliQuantity(
|
||||
int64(info.NumCores*1000),
|
||||
resource.DecimalSI),
|
||||
v1.ResourceMemory: *resource.NewQuantity(
|
||||
int64(info.MemoryCapacity),
|
||||
resource.BinarySI),
|
||||
}
|
||||
|
||||
// if huge pages are enabled, we report them as a schedulable resource on the node
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.HugePages) {
|
||||
for _, hugepagesInfo := range info.HugePages {
|
||||
pageSizeBytes := int64(hugepagesInfo.PageSize * 1024)
|
||||
hugePagesBytes := pageSizeBytes * int64(hugepagesInfo.NumPages)
|
||||
pageSizeQuantity := resource.NewQuantity(pageSizeBytes, resource.BinarySI)
|
||||
c[v1helper.HugePageResourceName(*pageSizeQuantity)] = *resource.NewQuantity(hugePagesBytes, resource.BinarySI)
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func EphemeralStorageCapacityFromFsInfo(info cadvisorapi2.FsInfo) v1.ResourceList {
|
||||
c := v1.ResourceList{
|
||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(
|
||||
int64(info.Capacity),
|
||||
resource.BinarySI),
|
||||
}
|
||||
return c
|
||||
}
|
||||
69
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/BUILD
generated
vendored
Normal file
69
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"certificate_manager.go",
|
||||
"certificate_store.go",
|
||||
"kubelet.go",
|
||||
"transport.go",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/util/file:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"certificate_manager_test.go",
|
||||
"certificate_store_test.go",
|
||||
"transport_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/api/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/certificate/bootstrap:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
6
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/OWNERS
generated
vendored
Normal file
6
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
reviewers:
|
||||
- mikedanese
|
||||
- liggitt
|
||||
approvers:
|
||||
- mikedanese
|
||||
- liggitt
|
||||
45
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/BUILD
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["bootstrap_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["bootstrap.go"],
|
||||
deps = [
|
||||
"//pkg/kubelet/util/csr:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/certificates/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/cert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
152
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/bootstrap.go
generated
vendored
Normal file
152
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/bootstrap.go
generated
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Copyright 2016 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 bootstrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
certificates "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultKubeletClientCertificateFile = "kubelet-client.crt"
|
||||
defaultKubeletClientKeyFile = "kubelet-client.key"
|
||||
)
|
||||
|
||||
// LoadClientCert requests a client cert for kubelet if the kubeconfigPath file does not exist.
|
||||
// The kubeconfig at bootstrapPath is used to request a client certificate from the API server.
|
||||
// On success, a kubeconfig file referencing the generated key and obtained certificate is written to kubeconfigPath.
|
||||
// The certificate and key file are stored in certDir.
|
||||
func LoadClientCert(kubeconfigPath string, bootstrapPath string, certDir string, nodeName types.NodeName) error {
|
||||
// Short-circuit if the kubeconfig file already exists.
|
||||
// TODO: inspect the kubeconfig, ensure a rest client can be built from it, verify client cert expiration, etc.
|
||||
_, err := os.Stat(kubeconfigPath)
|
||||
if err == nil {
|
||||
glog.V(2).Infof("Kubeconfig %s exists, skipping bootstrap", kubeconfigPath)
|
||||
return nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
glog.Errorf("Error reading kubeconfig %s, skipping bootstrap: %v", kubeconfigPath, err)
|
||||
return err
|
||||
}
|
||||
|
||||
glog.V(2).Info("Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file")
|
||||
|
||||
bootstrapClientConfig, err := loadRESTClientConfig(bootstrapPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load bootstrap kubeconfig: %v", err)
|
||||
}
|
||||
bootstrapClient, err := certificates.NewForConfig(bootstrapClientConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create certificates signing request client: %v", err)
|
||||
}
|
||||
|
||||
success := false
|
||||
|
||||
// Get the private key.
|
||||
keyPath, err := filepath.Abs(filepath.Join(certDir, defaultKubeletClientKeyFile))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to build bootstrap key path: %v", err)
|
||||
}
|
||||
keyData, _, err := certutil.LoadOrGenerateKeyFile(keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the cert.
|
||||
certPath, err := filepath.Abs(filepath.Join(certDir, defaultKubeletClientCertificateFile))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to build bootstrap client cert path: %v", err)
|
||||
}
|
||||
certData, err := csr.RequestNodeCertificate(bootstrapClient.CertificateSigningRequests(), keyData, nodeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := certutil.WriteCert(certPath, certData); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if !success {
|
||||
if err := os.Remove(certPath); err != nil {
|
||||
glog.Warningf("Cannot clean up the cert file %q: %v", certPath, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Get the CA data from the bootstrap client config.
|
||||
caFile, caData := bootstrapClientConfig.CAFile, []byte{}
|
||||
if len(caFile) == 0 {
|
||||
caData = bootstrapClientConfig.CAData
|
||||
}
|
||||
|
||||
// Build resulting kubeconfig.
|
||||
kubeconfigData := clientcmdapi.Config{
|
||||
// Define a cluster stanza based on the bootstrap kubeconfig.
|
||||
Clusters: map[string]*clientcmdapi.Cluster{"default-cluster": {
|
||||
Server: bootstrapClientConfig.Host,
|
||||
InsecureSkipTLSVerify: bootstrapClientConfig.Insecure,
|
||||
CertificateAuthority: caFile,
|
||||
CertificateAuthorityData: caData,
|
||||
}},
|
||||
// Define auth based on the obtained client cert.
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{"default-auth": {
|
||||
ClientCertificate: certPath,
|
||||
ClientKey: keyPath,
|
||||
}},
|
||||
// Define a context that connects the auth info and cluster, and set it as the default
|
||||
Contexts: map[string]*clientcmdapi.Context{"default-context": {
|
||||
Cluster: "default-cluster",
|
||||
AuthInfo: "default-auth",
|
||||
Namespace: "default",
|
||||
}},
|
||||
CurrentContext: "default-context",
|
||||
}
|
||||
|
||||
// Marshal to disk
|
||||
if err := clientcmd.WriteToFile(kubeconfigData, kubeconfigPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
success = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadRESTClientConfig(kubeconfig string) (*restclient.Config, error) {
|
||||
// Load structured kubeconfig data from the given path.
|
||||
loader := &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}
|
||||
loadedConfig, err := loader.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Flatten the loaded data to a particular restclient.Config based on the current context.
|
||||
return clientcmd.NewNonInteractiveClientConfig(
|
||||
*loadedConfig,
|
||||
loadedConfig.CurrentContext,
|
||||
&clientcmd.ConfigOverrides{},
|
||||
loader,
|
||||
).ClientConfig()
|
||||
}
|
||||
85
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/bootstrap_test.go
generated
vendored
Normal file
85
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap/bootstrap_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright 2016 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 bootstrap
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
func TestLoadRESTClientConfig(t *testing.T) {
|
||||
testData := []byte(`
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority: ca-a.crt
|
||||
server: https://cluster-a.com
|
||||
name: cluster-a
|
||||
- cluster:
|
||||
certificate-authority-data: VGVzdA==
|
||||
server: https://cluster-b.com
|
||||
name: cluster-b
|
||||
contexts:
|
||||
- context:
|
||||
cluster: cluster-a
|
||||
namespace: ns-a
|
||||
user: user-a
|
||||
name: context-a
|
||||
- context:
|
||||
cluster: cluster-b
|
||||
namespace: ns-b
|
||||
user: user-b
|
||||
name: context-b
|
||||
current-context: context-b
|
||||
users:
|
||||
- name: user-a
|
||||
user:
|
||||
token: mytoken-a
|
||||
- name: user-b
|
||||
user:
|
||||
token: mytoken-b
|
||||
`)
|
||||
f, err := ioutil.TempFile("", "kubeconfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
ioutil.WriteFile(f.Name(), testData, os.FileMode(0755))
|
||||
|
||||
config, err := loadRESTClientConfig(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedConfig := &restclient.Config{
|
||||
Host: "https://cluster-b.com",
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
CAData: []byte(`Test`),
|
||||
},
|
||||
BearerToken: "mytoken-b",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(config, expectedConfig) {
|
||||
t.Errorf("Unexpected config: %s", diff.ObjectDiff(config, expectedConfig))
|
||||
}
|
||||
}
|
||||
412
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_manager.go
generated
vendored
Normal file
412
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
"k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
const (
|
||||
syncPeriod = 1 * time.Hour
|
||||
)
|
||||
|
||||
// Manager maintains and updates the certificates in use by this certificate
|
||||
// manager. In the background it communicates with the API server to get new
|
||||
// certificates for certificates about to expire.
|
||||
type Manager interface {
|
||||
// CertificateSigningRequestClient sets the client interface that is used for
|
||||
// signing new certificates generated as part of rotation.
|
||||
SetCertificateSigningRequestClient(certificatesclient.CertificateSigningRequestInterface) error
|
||||
// Start the API server status sync loop.
|
||||
Start()
|
||||
// Current returns the currently selected certificate from the
|
||||
// certificate manager, as well as the associated certificate and key data
|
||||
// in PEM format.
|
||||
Current() *tls.Certificate
|
||||
}
|
||||
|
||||
// Config is the set of configuration parameters available for a new Manager.
|
||||
type Config struct {
|
||||
// CertificateSigningRequestClient will be used for signing new certificate
|
||||
// requests generated when a key rotation occurs. It must be set either at
|
||||
// initialization or by using CertificateSigningRequestClient before
|
||||
// Manager.Start() is called.
|
||||
CertificateSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
||||
// Template is the CertificateRequest that will be used as a template for
|
||||
// generating certificate signing requests for all new keys generated as
|
||||
// part of rotation. It follows the same rules as the template parameter of
|
||||
// crypto.x509.CreateCertificateRequest in the Go standard libraries.
|
||||
Template *x509.CertificateRequest
|
||||
// Usages is the types of usages that certificates generated by the manager
|
||||
// can be used for.
|
||||
Usages []certificates.KeyUsage
|
||||
// CertificateStore is a persistent store where the current cert/key is
|
||||
// kept and future cert/key pairs will be persisted after they are
|
||||
// generated.
|
||||
CertificateStore Store
|
||||
// BootstrapCertificatePEM is the certificate data that will be returned
|
||||
// from the Manager if the CertificateStore doesn't have any cert/key pairs
|
||||
// currently available and has not yet had a chance to get a new cert/key
|
||||
// pair from the API. If the CertificateStore does have a cert/key pair,
|
||||
// this will be ignored. If there is no cert/key pair available in the
|
||||
// CertificateStore, as soon as Start is called, it will request a new
|
||||
// cert/key pair from the CertificateSigningRequestClient. This is intended
|
||||
// to allow the first boot of a component to be initialized using a
|
||||
// generic, multi-use cert/key pair which will be quickly replaced with a
|
||||
// unique cert/key pair.
|
||||
BootstrapCertificatePEM []byte
|
||||
// BootstrapKeyPEM is the key data that will be returned from the Manager
|
||||
// if the CertificateStore doesn't have any cert/key pairs currently
|
||||
// available. If the CertificateStore does have a cert/key pair, this will
|
||||
// be ignored. If the bootstrap cert/key pair are used, they will be
|
||||
// rotated at the first opportunity, possibly well in advance of expiring.
|
||||
// This is intended to allow the first boot of a component to be
|
||||
// initialized using a generic, multi-use cert/key pair which will be
|
||||
// quickly replaced with a unique cert/key pair.
|
||||
BootstrapKeyPEM []byte
|
||||
}
|
||||
|
||||
// Store is responsible for getting and updating the current certificate.
|
||||
// Depending on the concrete implementation, the backing store for this
|
||||
// behavior may vary.
|
||||
type Store interface {
|
||||
// Current returns the currently selected certificate, as well as the
|
||||
// associated certificate and key data in PEM format. If the Store doesn't
|
||||
// have a cert/key pair currently, it should return a NoCertKeyError so
|
||||
// that the Manager can recover by using bootstrap certificates to request
|
||||
// a new cert/key pair.
|
||||
Current() (*tls.Certificate, error)
|
||||
// Update accepts the PEM data for the cert/key pair and makes the new
|
||||
// cert/key pair the 'current' pair, that will be returned by future calls
|
||||
// to Current().
|
||||
Update(cert, key []byte) (*tls.Certificate, error)
|
||||
}
|
||||
|
||||
// NoCertKeyError indicates there is no cert/key currently available.
|
||||
type NoCertKeyError string
|
||||
|
||||
func (e *NoCertKeyError) Error() string { return string(*e) }
|
||||
|
||||
type manager struct {
|
||||
certSigningRequestClient certificatesclient.CertificateSigningRequestInterface
|
||||
template *x509.CertificateRequest
|
||||
usages []certificates.KeyUsage
|
||||
certStore Store
|
||||
certAccessLock sync.RWMutex
|
||||
cert *tls.Certificate
|
||||
rotationDeadline time.Time
|
||||
forceRotation bool
|
||||
}
|
||||
|
||||
// NewManager returns a new certificate manager. A certificate manager is
|
||||
// responsible for being the authoritative source of certificates in the
|
||||
// Kubelet and handling updates due to rotation.
|
||||
func NewManager(config *Config) (Manager, error) {
|
||||
cert, forceRotation, err := getCurrentCertificateOrBootstrap(
|
||||
config.CertificateStore,
|
||||
config.BootstrapCertificatePEM,
|
||||
config.BootstrapKeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := manager{
|
||||
certSigningRequestClient: config.CertificateSigningRequestClient,
|
||||
template: config.Template,
|
||||
usages: config.Usages,
|
||||
certStore: config.CertificateStore,
|
||||
cert: cert,
|
||||
forceRotation: forceRotation,
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// Current returns the currently selected certificate from the certificate
|
||||
// manager. This can be nil if the manager was initialized without a
|
||||
// certificate and has not yet received one from the
|
||||
// CertificateSigningRequestClient.
|
||||
func (m *manager) Current() *tls.Certificate {
|
||||
m.certAccessLock.RLock()
|
||||
defer m.certAccessLock.RUnlock()
|
||||
return m.cert
|
||||
}
|
||||
|
||||
// SetCertificateSigningRequestClient sets the client interface that is used
|
||||
// for signing new certificates generated as part of rotation. It must be
|
||||
// called before Start() and can not be used to change the
|
||||
// CertificateSigningRequestClient that has already been set. This method is to
|
||||
// support the one specific scenario where the CertificateSigningRequestClient
|
||||
// uses the CertificateManager.
|
||||
func (m *manager) SetCertificateSigningRequestClient(certSigningRequestClient certificatesclient.CertificateSigningRequestInterface) error {
|
||||
if m.certSigningRequestClient == nil {
|
||||
m.certSigningRequestClient = certSigningRequestClient
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("CertificateSigningRequestClient is already set.")
|
||||
}
|
||||
|
||||
// Start will start the background work of rotating the certificates.
|
||||
func (m *manager) Start() {
|
||||
// Certificate rotation depends on access to the API server certificate
|
||||
// signing API, so don't start the certificate manager if we don't have a
|
||||
// client. This will happen on the cluster master, where the kubelet is
|
||||
// responsible for bootstrapping the pods of the master components.
|
||||
if m.certSigningRequestClient == nil {
|
||||
glog.V(2).Infof("Certificate rotation is not enabled, no connection to the apiserver.")
|
||||
return
|
||||
}
|
||||
|
||||
glog.V(2).Infof("Certificate rotation is enabled.")
|
||||
|
||||
m.setRotationDeadline()
|
||||
|
||||
// Synchronously request a certificate before entering the background
|
||||
// loop to allow bootstrap scenarios, where the certificate manager
|
||||
// doesn't have a certificate at all yet.
|
||||
if m.shouldRotate() {
|
||||
glog.V(1).Infof("shouldRotate() is true, forcing immediate rotation")
|
||||
_, err := m.rotateCerts()
|
||||
if err != nil {
|
||||
glog.Errorf("Could not rotate certificates: %v", err)
|
||||
}
|
||||
}
|
||||
backoff := wait.Backoff{
|
||||
Duration: 2 * time.Second,
|
||||
Factor: 2,
|
||||
Jitter: 0.1,
|
||||
Steps: 7,
|
||||
}
|
||||
go wait.Forever(func() {
|
||||
sleepInterval := m.rotationDeadline.Sub(time.Now())
|
||||
glog.V(2).Infof("Waiting %v for next certificate rotation", sleepInterval)
|
||||
time.Sleep(sleepInterval)
|
||||
if err := wait.ExponentialBackoff(backoff, m.rotateCerts); err != nil {
|
||||
glog.Errorf("Reached backoff limit, still unable to rotate certs: %v", err)
|
||||
wait.PollInfinite(128*time.Second, m.rotateCerts)
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
|
||||
func getCurrentCertificateOrBootstrap(
|
||||
store Store,
|
||||
bootstrapCertificatePEM []byte,
|
||||
bootstrapKeyPEM []byte) (cert *tls.Certificate, shouldRotate bool, errResult error) {
|
||||
|
||||
currentCert, err := store.Current()
|
||||
if err == nil {
|
||||
return currentCert, false, nil
|
||||
}
|
||||
|
||||
if _, ok := err.(*NoCertKeyError); !ok {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if bootstrapCertificatePEM == nil || bootstrapKeyPEM == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
bootstrapCert, err := tls.X509KeyPair(bootstrapCertificatePEM, bootstrapKeyPEM)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if len(bootstrapCert.Certificate) < 1 {
|
||||
return nil, false, fmt.Errorf("no cert/key data found")
|
||||
}
|
||||
|
||||
certs, err := x509.ParseCertificates(bootstrapCert.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("unable to parse certificate data: %v", err)
|
||||
}
|
||||
bootstrapCert.Leaf = certs[0]
|
||||
return &bootstrapCert, true, nil
|
||||
}
|
||||
|
||||
// shouldRotate looks at how close the current certificate is to expiring and
|
||||
// decides if it is time to rotate or not.
|
||||
func (m *manager) shouldRotate() bool {
|
||||
m.certAccessLock.RLock()
|
||||
defer m.certAccessLock.RUnlock()
|
||||
if m.cert == nil {
|
||||
return true
|
||||
}
|
||||
if m.forceRotation {
|
||||
return true
|
||||
}
|
||||
return time.Now().After(m.rotationDeadline)
|
||||
}
|
||||
|
||||
func (m *manager) rotateCerts() (bool, error) {
|
||||
glog.V(2).Infof("Rotating certificates")
|
||||
|
||||
csrPEM, keyPEM, err := m.generateCSR()
|
||||
if err != nil {
|
||||
glog.Errorf("Unable to generate a certificate signing request: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Call the Certificate Signing Request API to get a certificate for the
|
||||
// new private key.
|
||||
crtPEM, err := requestCertificate(m.certSigningRequestClient, csrPEM, m.usages)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed while requesting a signed certificate from the master: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
cert, err := m.certStore.Update(crtPEM, keyPEM)
|
||||
if err != nil {
|
||||
glog.Errorf("Unable to store the new cert/key pair: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
m.updateCached(cert)
|
||||
m.setRotationDeadline()
|
||||
m.forceRotation = false
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// setRotationDeadline sets a cached value for the threshold at which the
|
||||
// current certificate should be rotated, 80%+/-10% of the expiration of the
|
||||
// certificate.
|
||||
func (m *manager) setRotationDeadline() {
|
||||
m.certAccessLock.RLock()
|
||||
defer m.certAccessLock.RUnlock()
|
||||
if m.cert == nil {
|
||||
m.rotationDeadline = time.Now()
|
||||
return
|
||||
}
|
||||
|
||||
notAfter := m.cert.Leaf.NotAfter
|
||||
totalDuration := float64(notAfter.Sub(m.cert.Leaf.NotBefore))
|
||||
|
||||
// Use some jitter to set the rotation threshold so each node will rotate
|
||||
// at approximately 70-90% of the total lifetime of the certificate. With
|
||||
// jitter, if a number of nodes are added to a cluster at approximately the
|
||||
// same time (such as cluster creation time), they won't all try to rotate
|
||||
// certificates at the same time for the rest of the life of the cluster.
|
||||
jitteryDuration := wait.Jitter(time.Duration(totalDuration), 0.2) - time.Duration(totalDuration*0.3)
|
||||
|
||||
m.rotationDeadline = m.cert.Leaf.NotBefore.Add(jitteryDuration)
|
||||
glog.V(2).Infof("Certificate rotation deadline is %v", m.rotationDeadline)
|
||||
}
|
||||
|
||||
func (m *manager) updateCached(cert *tls.Certificate) {
|
||||
m.certAccessLock.Lock()
|
||||
defer m.certAccessLock.Unlock()
|
||||
m.cert = cert
|
||||
}
|
||||
|
||||
func (m *manager) generateCSR() (csrPEM []byte, keyPEM []byte, err error) {
|
||||
// Generate a new private key.
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to generate a new private key: %v", err)
|
||||
}
|
||||
der, err := x509.MarshalECPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to marshal the new key to DER: %v", err)
|
||||
}
|
||||
|
||||
keyPEM = pem.EncodeToMemory(&pem.Block{Type: cert.ECPrivateKeyBlockType, Bytes: der})
|
||||
|
||||
csrPEM, err = cert.MakeCSRFromTemplate(privateKey, m.template)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to create a csr from the private key: %v", err)
|
||||
}
|
||||
return csrPEM, keyPEM, nil
|
||||
}
|
||||
|
||||
// requestCertificate will create a certificate signing request using the PEM
|
||||
// encoded CSR and send it to API server, then it will watch the object's
|
||||
// status, once approved by API server, it will return the API server's issued
|
||||
// certificate (pem-encoded). If there is any errors, or the watch timeouts, it
|
||||
// will return an error.
|
||||
//
|
||||
// NOTE This is a copy of a function with the same name in
|
||||
// k8s.io/kubernetes/pkg/kubelet/util/csr/csr.go, changing only the package that
|
||||
// CertificateSigningRequestInterface and KeyUsage are imported from.
|
||||
func requestCertificate(client certificatesclient.CertificateSigningRequestInterface, csrData []byte, usages []certificates.KeyUsage) (certData []byte, err error) {
|
||||
glog.Infof("Requesting new certificate.")
|
||||
req, err := client.Create(&certificates.CertificateSigningRequest{
|
||||
// Username, UID, Groups will be injected by API server.
|
||||
TypeMeta: metav1.TypeMeta{Kind: "CertificateSigningRequest"},
|
||||
ObjectMeta: metav1.ObjectMeta{GenerateName: "csr-"},
|
||||
|
||||
Spec: certificates.CertificateSigningRequestSpec{
|
||||
Request: csrData,
|
||||
Usages: usages,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create certificate signing request: %v", err)
|
||||
}
|
||||
|
||||
// Make a default timeout = 3600s.
|
||||
var defaultTimeoutSeconds int64 = 3600
|
||||
certWatch, err := client.Watch(metav1.ListOptions{
|
||||
Watch: true,
|
||||
TimeoutSeconds: &defaultTimeoutSeconds,
|
||||
FieldSelector: fields.OneTermEqualSelector("metadata.name", req.Name).String(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot watch on the certificate signing request: %v", err)
|
||||
}
|
||||
defer certWatch.Stop()
|
||||
ch := certWatch.ResultChan()
|
||||
|
||||
for {
|
||||
event, ok := <-ch
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
if event.Type == watch.Modified || event.Type == watch.Added {
|
||||
if event.Object.(*certificates.CertificateSigningRequest).UID != req.UID {
|
||||
continue
|
||||
}
|
||||
status := event.Object.(*certificates.CertificateSigningRequest).Status
|
||||
for _, c := range status.Conditions {
|
||||
if c.Type == certificates.CertificateDenied {
|
||||
return nil, fmt.Errorf("certificate signing request is not approved, reason: %v, message: %v", c.Reason, c.Message)
|
||||
}
|
||||
if c.Type == certificates.CertificateApproved && status.Certificate != nil {
|
||||
return status.Certificate, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("watch channel closed")
|
||||
}
|
||||
750
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_manager_test.go
generated
vendored
Normal file
750
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_manager_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
)
|
||||
|
||||
type certificateData struct {
|
||||
keyPEM []byte
|
||||
certificatePEM []byte
|
||||
certificate *tls.Certificate
|
||||
}
|
||||
|
||||
var storeCertData = newCertificateData(`-----BEGIN CERTIFICATE-----
|
||||
MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
|
||||
BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
|
||||
CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
|
||||
VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0
|
||||
MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
|
||||
BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
|
||||
VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq
|
||||
hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV
|
||||
tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV
|
||||
HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv
|
||||
0nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV
|
||||
NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl
|
||||
nkVA6wyOSDYBf3o=
|
||||
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAtBMa7NWpv3BVlKTC
|
||||
PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M
|
||||
zP2H5QIDAQABAkAS9BfXab3OKpK3bIgNNyp+DQJKrZnTJ4Q+OjsqkpXvNltPJosf
|
||||
G8GsiKu/vAt4HGqI3eU77NvRI+mL4MnHRmXBAiEA3qM4FAtKSRBbcJzPxxLEUSwg
|
||||
XSCcosCktbkXvpYrS30CIQDPDxgqlwDEJQ0uKuHkZI38/SPWWqfUmkecwlbpXABK
|
||||
iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar
|
||||
e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX
|
||||
54LzHNk/+Q==
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
var bootstrapCertData = newCertificateData(
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIICRzCCAfGgAwIBAgIJANXr+UzRFq4TMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
|
||||
BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
|
||||
CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
|
||||
VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwIBcNMTcwNDI2MjMyNzMyWhgPMjExNzA0
|
||||
MDIyMzI3MzJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
|
||||
BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
|
||||
VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwXDANBgkq
|
||||
hkiG9w0BAQEFAANLADBIAkEAqvbkN4RShH1rL37JFp4fZPnn0JUhVWWsrP8NOomJ
|
||||
pXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbMQ3ABJwIDAQABo1AwTjAdBgNV
|
||||
HQ4EFgQUEGBc6YYheEZ/5MhwqSUYYPYRj2MwHwYDVR0jBBgwFoAUEGBc6YYheEZ/
|
||||
5MhwqSUYYPYRj2MwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAIyNmznk
|
||||
5dgJY52FppEEcfQRdS5k4XFPc22SHPcz77AHf5oWZ1WG9VezOZZPp8NCiFDDlDL8
|
||||
yma33a5eMyTjLD8=
|
||||
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqvbkN4RShH1rL37J
|
||||
Fp4fZPnn0JUhVWWsrP8NOomJpXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbM
|
||||
Q3ABJwIDAQABAkBC2OBpGLMPHN8BJijIUDFkURakBvuOoX+/8MYiYk7QxEmfLCk6
|
||||
L6r+GLNFMfXwXcBmXtMKfZKAIKutKf098JaBAiEA10azfqt3G/5owrNA00plSyT6
|
||||
ZmHPzY9Uq1p/QTR/uOcCIQDLTkfBkLHm0UKeobbO/fSm6ZflhyBRDINy4FvwmZMt
|
||||
wQIgYV/tmQJeIh91q3wBepFQOClFykG8CTMoDUol/YyNqUkCIHfp6Rr7fGL3JIMq
|
||||
QQgf9DCK8SPZqq8DYXjdan0kKBJBAiEAyDb+07o2gpggo8BYUKSaiRCiyXfaq87f
|
||||
eVqgpBq/QN4=
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
var apiServerCertData = newCertificateData(
|
||||
`-----BEGIN CERTIFICATE-----
|
||||
MIICRzCCAfGgAwIBAgIJAIydTIADd+yqMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
|
||||
BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
|
||||
CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
|
||||
VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwIBcNMTcwNDI2MjMyNDU4WhgPMjExNzA0
|
||||
MDIyMzI0NThaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
|
||||
BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
|
||||
VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwXDANBgkq
|
||||
hkiG9w0BAQEFAANLADBIAkEAuiRet28DV68Dk4A8eqCaqgXmymamUEjW/DxvIQqH
|
||||
3lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrnbOHCLQIDAQABo1AwTjAdBgNV
|
||||
HQ4EFgQU0vhI4OPGEOqT+VAWwxdhVvcmgdIwHwYDVR0jBBgwFoAU0vhI4OPGEOqT
|
||||
+VAWwxdhVvcmgdIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBALNeJGDe
|
||||
nV5cXbp9W1bC12Tc8nnNXn4ypLE2JTQAvyp51zoZ8hQoSnRVx/VCY55Yu+br8gQZ
|
||||
+tW+O/PoE7B3tuY=
|
||||
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAuiRet28DV68Dk4A8
|
||||
eqCaqgXmymamUEjW/DxvIQqH3lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrn
|
||||
bOHCLQIDAQABAkEArDR1g9IqD3aUImNikDgAngbzqpAokOGyMoxeavzpEaFOgCzi
|
||||
gi7HF7yHRmZkUt8CzdEvnHSqRjFuaaB0gGA+AQIhAOc8Z1h8ElLRSqaZGgI3jCTp
|
||||
Izx9HNY//U5NGrXD2+ttAiEAzhOqkqI4+nDab7FpiD7MXI6fO549mEXeVBPvPtsS
|
||||
OcECIQCIfkpOm+ZBBpO3JXaJynoqK4gGI6ALA/ik6LSUiIlfPQIhAISjd9hlfZME
|
||||
bDQT1r8Q3Gx+h9LRqQeHgPBQ3F5ylqqBAiBaJ0hkYvrIdWxNlcLqD3065bJpHQ4S
|
||||
WQkuZUQN1M/Xvg==
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
|
||||
func newCertificateData(certificatePEM string, keyPEM string) *certificateData {
|
||||
certificate, err := tls.X509KeyPair([]byte(certificatePEM), []byte(keyPEM))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to initialize certificate: %v", err))
|
||||
}
|
||||
certs, err := x509.ParseCertificates(certificate.Certificate[0])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Unable to initialize certificate leaf: %v", err))
|
||||
}
|
||||
certificate.Leaf = certs[0]
|
||||
return &certificateData{
|
||||
keyPEM: []byte(keyPEM),
|
||||
certificatePEM: []byte(certificatePEM),
|
||||
certificate: &certificate,
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewManagerNoRotation(t *testing.T) {
|
||||
store := &fakeStore{
|
||||
cert: storeCertData.certificate,
|
||||
}
|
||||
if _, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{},
|
||||
Usages: []certificates.KeyUsage{},
|
||||
CertificateStore: store,
|
||||
}); err != nil {
|
||||
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldRotate(t *testing.T) {
|
||||
now := time.Now()
|
||||
tests := []struct {
|
||||
name string
|
||||
notBefore time.Time
|
||||
notAfter time.Time
|
||||
shouldRotate bool
|
||||
}{
|
||||
{"just issued, still good", now.Add(-1 * time.Hour), now.Add(99 * time.Hour), false},
|
||||
{"half way expired, still good", now.Add(-24 * time.Hour), now.Add(24 * time.Hour), false},
|
||||
{"mostly expired, still good", now.Add(-69 * time.Hour), now.Add(31 * time.Hour), false},
|
||||
{"just about expired, should rotate", now.Add(-91 * time.Hour), now.Add(9 * time.Hour), true},
|
||||
{"nearly expired, should rotate", now.Add(-99 * time.Hour), now.Add(1 * time.Hour), true},
|
||||
{"already expired, should rotate", now.Add(-10 * time.Hour), now.Add(-1 * time.Hour), true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
m := manager{
|
||||
cert: &tls.Certificate{
|
||||
Leaf: &x509.Certificate{
|
||||
NotBefore: test.notBefore,
|
||||
NotAfter: test.notAfter,
|
||||
},
|
||||
},
|
||||
template: &x509.CertificateRequest{},
|
||||
usages: []certificates.KeyUsage{},
|
||||
}
|
||||
m.setRotationDeadline()
|
||||
if m.shouldRotate() != test.shouldRotate {
|
||||
t.Errorf("Time %v, a certificate issued for (%v, %v) should rotate should be %t.",
|
||||
now,
|
||||
m.cert.Leaf.NotBefore,
|
||||
m.cert.Leaf.NotAfter,
|
||||
test.shouldRotate)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetRotationDeadline(t *testing.T) {
|
||||
now := time.Now()
|
||||
testCases := []struct {
|
||||
name string
|
||||
notBefore time.Time
|
||||
notAfter time.Time
|
||||
shouldRotate bool
|
||||
}{
|
||||
{"just issued, still good", now.Add(-1 * time.Hour), now.Add(99 * time.Hour), false},
|
||||
{"half way expired, still good", now.Add(-24 * time.Hour), now.Add(24 * time.Hour), false},
|
||||
{"mostly expired, still good", now.Add(-69 * time.Hour), now.Add(31 * time.Hour), false},
|
||||
{"just about expired, should rotate", now.Add(-91 * time.Hour), now.Add(9 * time.Hour), true},
|
||||
{"nearly expired, should rotate", now.Add(-99 * time.Hour), now.Add(1 * time.Hour), true},
|
||||
{"already expired, should rotate", now.Add(-10 * time.Hour), now.Add(-1 * time.Hour), true},
|
||||
{"long duration", now.Add(-6 * 30 * 24 * time.Hour), now.Add(6 * 30 * 24 * time.Hour), true},
|
||||
{"short duration", now.Add(-30 * time.Second), now.Add(30 * time.Second), true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
m := manager{
|
||||
cert: &tls.Certificate{
|
||||
Leaf: &x509.Certificate{
|
||||
NotBefore: tc.notBefore,
|
||||
NotAfter: tc.notAfter,
|
||||
},
|
||||
},
|
||||
template: &x509.CertificateRequest{},
|
||||
usages: []certificates.KeyUsage{},
|
||||
}
|
||||
lowerBound := tc.notBefore.Add(time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.7))
|
||||
upperBound := tc.notBefore.Add(time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.9))
|
||||
for i := 0; i < 1000; i++ {
|
||||
// setRotationDeadline includes jitter, so this needs to run many times for validation.
|
||||
m.setRotationDeadline()
|
||||
if m.rotationDeadline.Before(lowerBound) || m.rotationDeadline.After(upperBound) {
|
||||
t.Errorf("For notBefore %v, notAfter %v, the rotationDeadline %v should be between %v and %v.",
|
||||
tc.notBefore,
|
||||
tc.notAfter,
|
||||
m.rotationDeadline,
|
||||
lowerBound,
|
||||
upperBound)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotateCertCreateCSRError(t *testing.T) {
|
||||
now := time.Now()
|
||||
m := manager{
|
||||
cert: &tls.Certificate{
|
||||
Leaf: &x509.Certificate{
|
||||
NotBefore: now.Add(-2 * time.Hour),
|
||||
NotAfter: now.Add(-1 * time.Hour),
|
||||
},
|
||||
},
|
||||
template: &x509.CertificateRequest{},
|
||||
usages: []certificates.KeyUsage{},
|
||||
certSigningRequestClient: fakeClient{
|
||||
failureType: createError,
|
||||
},
|
||||
}
|
||||
|
||||
if success, err := m.rotateCerts(); success {
|
||||
t.Errorf("Got success from 'rotateCerts', wanted failure")
|
||||
} else if err != nil {
|
||||
t.Errorf("Got error %v from 'rotateCerts', wanted no error.", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotateCertWaitingForResultError(t *testing.T) {
|
||||
now := time.Now()
|
||||
m := manager{
|
||||
cert: &tls.Certificate{
|
||||
Leaf: &x509.Certificate{
|
||||
NotBefore: now.Add(-2 * time.Hour),
|
||||
NotAfter: now.Add(-1 * time.Hour),
|
||||
},
|
||||
},
|
||||
template: &x509.CertificateRequest{},
|
||||
usages: []certificates.KeyUsage{},
|
||||
certSigningRequestClient: fakeClient{
|
||||
failureType: watchError,
|
||||
},
|
||||
}
|
||||
|
||||
if success, err := m.rotateCerts(); success {
|
||||
t.Errorf("Got success from 'rotateCerts', wanted failure.")
|
||||
} else if err != nil {
|
||||
t.Errorf("Got error %v from 'rotateCerts', wanted no error.", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewManagerBootstrap(t *testing.T) {
|
||||
store := &fakeStore{}
|
||||
|
||||
var cm Manager
|
||||
cm, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{},
|
||||
Usages: []certificates.KeyUsage{},
|
||||
CertificateStore: store,
|
||||
BootstrapCertificatePEM: bootstrapCertData.certificatePEM,
|
||||
BootstrapKeyPEM: bootstrapCertData.keyPEM,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||
}
|
||||
|
||||
cert := cm.Current()
|
||||
|
||||
if cert == nil {
|
||||
t.Errorf("Certificate was nil, expected something.")
|
||||
}
|
||||
if m, ok := cm.(*manager); !ok {
|
||||
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||
} else if !m.shouldRotate() {
|
||||
t.Errorf("Expected rotation should happen during bootstrap, but it won't.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewManagerNoBootstrap(t *testing.T) {
|
||||
now := time.Now()
|
||||
cert, err := tls.X509KeyPair(storeCertData.certificatePEM, storeCertData.keyPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to initialize a certificate: %v", err)
|
||||
}
|
||||
cert.Leaf = &x509.Certificate{
|
||||
NotBefore: now.Add(-24 * time.Hour),
|
||||
NotAfter: now.Add(24 * time.Hour),
|
||||
}
|
||||
store := &fakeStore{
|
||||
cert: &cert,
|
||||
}
|
||||
|
||||
cm, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{},
|
||||
Usages: []certificates.KeyUsage{},
|
||||
CertificateStore: store,
|
||||
BootstrapCertificatePEM: bootstrapCertData.certificatePEM,
|
||||
BootstrapKeyPEM: bootstrapCertData.keyPEM,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize the certificate manager: %v", err)
|
||||
}
|
||||
|
||||
currentCert := cm.Current()
|
||||
|
||||
if currentCert == nil {
|
||||
t.Errorf("Certificate was nil, expected something.")
|
||||
}
|
||||
if m, ok := cm.(*manager); !ok {
|
||||
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||
} else {
|
||||
m.setRotationDeadline()
|
||||
if m.shouldRotate() {
|
||||
t.Errorf("Expected rotation should happen during bootstrap, but it won't.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrentCertificateOrBootstrap(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
storeCert *tls.Certificate
|
||||
bootstrapCertData []byte
|
||||
bootstrapKeyData []byte
|
||||
expectedCert *tls.Certificate
|
||||
expectedShouldRotate bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
"return cert from store",
|
||||
storeCertData.certificate,
|
||||
nil,
|
||||
nil,
|
||||
storeCertData.certificate,
|
||||
false,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"no cert in store and no bootstrap cert",
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
store := &fakeStore{
|
||||
cert: tc.storeCert,
|
||||
}
|
||||
|
||||
certResult, shouldRotate, err := getCurrentCertificateOrBootstrap(
|
||||
store,
|
||||
tc.bootstrapCertData,
|
||||
tc.bootstrapKeyData)
|
||||
if certResult == nil || certResult.Certificate == nil || tc.expectedCert == nil {
|
||||
if certResult != nil && tc.expectedCert != nil {
|
||||
t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
|
||||
}
|
||||
} else {
|
||||
if !certificatesEqual(certResult, tc.expectedCert) {
|
||||
t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
|
||||
}
|
||||
}
|
||||
if shouldRotate != tc.expectedShouldRotate {
|
||||
t.Errorf("Got shouldRotate %t, wanted %t", shouldRotate, tc.expectedShouldRotate)
|
||||
}
|
||||
if err == nil {
|
||||
if tc.expectedErrMsg != "" {
|
||||
t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
|
||||
}
|
||||
} else {
|
||||
if tc.expectedErrMsg == "" || !strings.Contains(err.Error(), tc.expectedErrMsg) {
|
||||
t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitializeCertificateSigningRequestClient(t *testing.T) {
|
||||
var nilCertificate = &certificateData{}
|
||||
testCases := []struct {
|
||||
description string
|
||||
storeCert *certificateData
|
||||
bootstrapCert *certificateData
|
||||
apiCert *certificateData
|
||||
expectedCertBeforeStart *certificateData
|
||||
expectedCertAfterStart *certificateData
|
||||
}{
|
||||
{
|
||||
description: "No current certificate, no bootstrap certificate",
|
||||
storeCert: nilCertificate,
|
||||
bootstrapCert: nilCertificate,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: nilCertificate,
|
||||
expectedCertAfterStart: apiServerCertData,
|
||||
},
|
||||
{
|
||||
description: "No current certificate, bootstrap certificate",
|
||||
storeCert: nilCertificate,
|
||||
bootstrapCert: bootstrapCertData,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: bootstrapCertData,
|
||||
expectedCertAfterStart: apiServerCertData,
|
||||
},
|
||||
{
|
||||
description: "Current certificate, no bootstrap certificate",
|
||||
storeCert: storeCertData,
|
||||
bootstrapCert: nilCertificate,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: storeCertData,
|
||||
expectedCertAfterStart: storeCertData,
|
||||
},
|
||||
{
|
||||
description: "Current certificate, bootstrap certificate",
|
||||
storeCert: storeCertData,
|
||||
bootstrapCert: bootstrapCertData,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: storeCertData,
|
||||
expectedCertAfterStart: storeCertData,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
certificateStore := &fakeStore{
|
||||
cert: tc.storeCert.certificate,
|
||||
}
|
||||
|
||||
certificateManager, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"system:nodes"},
|
||||
CommonName: "system:node:fake-node-name",
|
||||
},
|
||||
},
|
||||
Usages: []certificates.KeyUsage{
|
||||
certificates.UsageDigitalSignature,
|
||||
certificates.UsageKeyEncipherment,
|
||||
certificates.UsageClientAuth,
|
||||
},
|
||||
CertificateStore: certificateStore,
|
||||
BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
|
||||
BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("Got %v, wanted no error.", err)
|
||||
}
|
||||
|
||||
certificate := certificateManager.Current()
|
||||
if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
|
||||
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
|
||||
}
|
||||
if err := certificateManager.SetCertificateSigningRequestClient(&fakeClient{
|
||||
certificatePEM: tc.apiCert.certificatePEM,
|
||||
}); err != nil {
|
||||
t.Errorf("Got error %v, expected none.", err)
|
||||
}
|
||||
|
||||
if m, ok := certificateManager.(*manager); !ok {
|
||||
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||
} else {
|
||||
m.setRotationDeadline()
|
||||
if m.shouldRotate() {
|
||||
if success, err := m.rotateCerts(); !success {
|
||||
t.Errorf("Got failure from 'rotateCerts', wanted success.")
|
||||
} else if err != nil {
|
||||
t.Errorf("Got error %v, expected none.", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
certificate = certificateManager.Current()
|
||||
if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
|
||||
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitializeOtherRESTClients(t *testing.T) {
|
||||
var nilCertificate = &certificateData{}
|
||||
testCases := []struct {
|
||||
description string
|
||||
storeCert *certificateData
|
||||
bootstrapCert *certificateData
|
||||
apiCert *certificateData
|
||||
expectedCertBeforeStart *certificateData
|
||||
expectedCertAfterStart *certificateData
|
||||
}{
|
||||
{
|
||||
description: "No current certificate, no bootstrap certificate",
|
||||
storeCert: nilCertificate,
|
||||
bootstrapCert: nilCertificate,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: nilCertificate,
|
||||
expectedCertAfterStart: apiServerCertData,
|
||||
},
|
||||
{
|
||||
description: "No current certificate, bootstrap certificate",
|
||||
storeCert: nilCertificate,
|
||||
bootstrapCert: bootstrapCertData,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: bootstrapCertData,
|
||||
expectedCertAfterStart: apiServerCertData,
|
||||
},
|
||||
{
|
||||
description: "Current certificate, no bootstrap certificate",
|
||||
storeCert: storeCertData,
|
||||
bootstrapCert: nilCertificate,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: storeCertData,
|
||||
expectedCertAfterStart: storeCertData,
|
||||
},
|
||||
{
|
||||
description: "Current certificate, bootstrap certificate",
|
||||
storeCert: storeCertData,
|
||||
bootstrapCert: bootstrapCertData,
|
||||
apiCert: apiServerCertData,
|
||||
expectedCertBeforeStart: storeCertData,
|
||||
expectedCertAfterStart: storeCertData,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
certificateStore := &fakeStore{
|
||||
cert: tc.storeCert.certificate,
|
||||
}
|
||||
|
||||
certificateManager, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"system:nodes"},
|
||||
CommonName: "system:node:fake-node-name",
|
||||
},
|
||||
},
|
||||
Usages: []certificates.KeyUsage{
|
||||
certificates.UsageDigitalSignature,
|
||||
certificates.UsageKeyEncipherment,
|
||||
certificates.UsageClientAuth,
|
||||
},
|
||||
CertificateStore: certificateStore,
|
||||
BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
|
||||
BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
|
||||
CertificateSigningRequestClient: &fakeClient{
|
||||
certificatePEM: tc.apiCert.certificatePEM,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("Got %v, wanted no error.", err)
|
||||
}
|
||||
|
||||
certificate := certificateManager.Current()
|
||||
if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
|
||||
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
|
||||
}
|
||||
|
||||
if m, ok := certificateManager.(*manager); !ok {
|
||||
t.Errorf("Expected a '*manager' from 'NewManager'")
|
||||
} else {
|
||||
m.setRotationDeadline()
|
||||
if m.shouldRotate() {
|
||||
if success, err := certificateManager.(*manager).rotateCerts(); !success {
|
||||
t.Errorf("Got failure from 'rotateCerts', expected success")
|
||||
} else if err != nil {
|
||||
t.Errorf("Got error %v, expected none.", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
certificate = certificateManager.Current()
|
||||
if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
|
||||
t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fakeClientFailureType int
|
||||
|
||||
const (
|
||||
none fakeClientFailureType = iota
|
||||
createError
|
||||
watchError
|
||||
certificateSigningRequestDenied
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
certificatesclient.CertificateSigningRequestInterface
|
||||
failureType fakeClientFailureType
|
||||
certificatePEM []byte
|
||||
}
|
||||
|
||||
func (c fakeClient) Create(*certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) {
|
||||
if c.failureType == createError {
|
||||
return nil, fmt.Errorf("Create error")
|
||||
}
|
||||
csrReply := certificates.CertificateSigningRequest{}
|
||||
csrReply.UID = "fake-uid"
|
||||
return &csrReply, nil
|
||||
}
|
||||
|
||||
func (c fakeClient) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
if c.failureType == watchError {
|
||||
return nil, fmt.Errorf("Watch error")
|
||||
}
|
||||
return &fakeWatch{
|
||||
failureType: c.failureType,
|
||||
certificatePEM: c.certificatePEM,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type fakeWatch struct {
|
||||
failureType fakeClientFailureType
|
||||
certificatePEM []byte
|
||||
}
|
||||
|
||||
func (w *fakeWatch) Stop() {
|
||||
}
|
||||
|
||||
func (w *fakeWatch) ResultChan() <-chan watch.Event {
|
||||
var condition certificates.CertificateSigningRequestCondition
|
||||
if w.failureType == certificateSigningRequestDenied {
|
||||
condition = certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateDenied,
|
||||
}
|
||||
} else {
|
||||
condition = certificates.CertificateSigningRequestCondition{
|
||||
Type: certificates.CertificateApproved,
|
||||
}
|
||||
}
|
||||
|
||||
csr := certificates.CertificateSigningRequest{
|
||||
Status: certificates.CertificateSigningRequestStatus{
|
||||
Conditions: []certificates.CertificateSigningRequestCondition{
|
||||
condition,
|
||||
},
|
||||
Certificate: []byte(w.certificatePEM),
|
||||
},
|
||||
}
|
||||
csr.UID = "fake-uid"
|
||||
|
||||
c := make(chan watch.Event, 1)
|
||||
c <- watch.Event{
|
||||
Type: watch.Added,
|
||||
Object: &csr,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type fakeStore struct {
|
||||
cert *tls.Certificate
|
||||
}
|
||||
|
||||
func (s *fakeStore) Current() (*tls.Certificate, error) {
|
||||
if s.cert == nil {
|
||||
noKeyErr := NoCertKeyError("")
|
||||
return nil, &noKeyErr
|
||||
}
|
||||
return s.cert, nil
|
||||
}
|
||||
|
||||
// Accepts the PEM data for the cert/key pair and makes the new cert/key
|
||||
// pair the 'current' pair, that will be returned by future calls to
|
||||
// Current().
|
||||
func (s *fakeStore) Update(certPEM, keyPEM []byte) (*tls.Certificate, error) {
|
||||
// In order to make the mocking work, whenever a cert/key pair is passed in
|
||||
// to be updated in the mock store, assume that the certificate manager
|
||||
// generated the key, and then asked the mock CertificateSigningRequest API
|
||||
// to sign it, then the faked API returned a canned response. The canned
|
||||
// signing response will not match the generated key. In order to make
|
||||
// things work out, search here for the correct matching key and use that
|
||||
// instead of the passed in key. That way this file of test code doesn't
|
||||
// have to implement an actual certificate signing process.
|
||||
for _, tc := range []*certificateData{storeCertData, bootstrapCertData, apiServerCertData} {
|
||||
if bytes.Equal(tc.certificatePEM, certPEM) {
|
||||
keyPEM = tc.keyPEM
|
||||
}
|
||||
}
|
||||
cert, err := tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
s.cert = &cert
|
||||
s.cert.Leaf = &x509.Certificate{
|
||||
NotBefore: now.Add(-24 * time.Hour),
|
||||
NotAfter: now.Add(24 * time.Hour),
|
||||
}
|
||||
return s.cert, nil
|
||||
}
|
||||
|
||||
func certificatesEqual(c1 *tls.Certificate, c2 *tls.Certificate) bool {
|
||||
if c1 == nil || c2 == nil {
|
||||
return c1 == c2
|
||||
}
|
||||
if len(c1.Certificate) != len(c2.Certificate) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(c1.Certificate); i++ {
|
||||
if !bytes.Equal(c1.Certificate[i], c2.Certificate[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func certificateString(c *tls.Certificate) string {
|
||||
if c == nil {
|
||||
return "certificate == nil"
|
||||
}
|
||||
if c.Leaf == nil {
|
||||
return "certificate.Leaf == nil"
|
||||
}
|
||||
return c.Leaf.Subject.CommonName
|
||||
}
|
||||
309
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_store.go
generated
vendored
Normal file
309
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_store.go
generated
vendored
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
utilfile "k8s.io/kubernetes/pkg/util/file"
|
||||
)
|
||||
|
||||
const (
|
||||
keyExtension = ".key"
|
||||
certExtension = ".crt"
|
||||
pemExtension = ".pem"
|
||||
currentPair = "current"
|
||||
updatedPair = "updated"
|
||||
)
|
||||
|
||||
type fileStore struct {
|
||||
pairNamePrefix string
|
||||
certDirectory string
|
||||
keyDirectory string
|
||||
certFile string
|
||||
keyFile string
|
||||
}
|
||||
|
||||
// NewFileStore returns a concrete implementation of a Store that is based on
|
||||
// storing the cert/key pairs in a single file per pair on disk in the
|
||||
// designated directory. When starting up it will look for the currently
|
||||
// selected cert/key pair in:
|
||||
//
|
||||
// 1. ${certDirectory}/${pairNamePrefix}-current.pem - both cert and key are in the same file.
|
||||
// 2. ${certFile}, ${keyFile}
|
||||
// 3. ${certDirectory}/${pairNamePrefix}.crt, ${keyDirectory}/${pairNamePrefix}.key
|
||||
//
|
||||
// The first one found will be used. If rotation is enabled, future cert/key
|
||||
// updates will be written to the ${certDirectory} directory and
|
||||
// ${certDirectory}/${pairNamePrefix}-current.pem will be created as a soft
|
||||
// link to the currently selected cert/key pair.
|
||||
func NewFileStore(
|
||||
pairNamePrefix string,
|
||||
certDirectory string,
|
||||
keyDirectory string,
|
||||
certFile string,
|
||||
keyFile string) (Store, error) {
|
||||
|
||||
s := fileStore{
|
||||
pairNamePrefix: pairNamePrefix,
|
||||
certDirectory: certDirectory,
|
||||
keyDirectory: keyDirectory,
|
||||
certFile: certFile,
|
||||
keyFile: keyFile,
|
||||
}
|
||||
if err := s.recover(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// recover checks if there is a certificate rotation that was interrupted while
|
||||
// progress, and if so, attempts to recover to a good state.
|
||||
func (s *fileStore) recover() error {
|
||||
// If the 'current' file doesn't exist, continue on with the recovery process.
|
||||
currentPath := filepath.Join(s.certDirectory, s.filename(currentPair))
|
||||
if exists, err := utilfile.FileExists(currentPath); err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the 'updated' file exists, and it is a symbolic link, continue on
|
||||
// with the recovery process.
|
||||
updatedPath := filepath.Join(s.certDirectory, s.filename(updatedPair))
|
||||
if fi, err := os.Lstat(updatedPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
return fmt.Errorf("expected %q to be a symlink but it is a file", updatedPath)
|
||||
}
|
||||
|
||||
// Move the 'updated' symlink to 'current'.
|
||||
if err := os.Rename(updatedPath, currentPath); err != nil {
|
||||
return fmt.Errorf("unable to rename %q to %q: %v", updatedPath, currentPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *fileStore) Current() (*tls.Certificate, error) {
|
||||
pairFile := filepath.Join(s.certDirectory, s.filename(currentPair))
|
||||
if pairFileExists, err := utilfile.FileExists(pairFile); err != nil {
|
||||
return nil, err
|
||||
} else if pairFileExists {
|
||||
glog.Infof("Loading cert/key pair from %q.", pairFile)
|
||||
return loadFile(pairFile)
|
||||
}
|
||||
|
||||
certFileExists, err := utilfile.FileExists(s.certFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyFileExists, err := utilfile.FileExists(s.keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if certFileExists && keyFileExists {
|
||||
glog.Infof("Loading cert/key pair from (%q, %q).", s.certFile, s.keyFile)
|
||||
return loadX509KeyPair(s.certFile, s.keyFile)
|
||||
}
|
||||
|
||||
c := filepath.Join(s.certDirectory, s.pairNamePrefix+certExtension)
|
||||
k := filepath.Join(s.keyDirectory, s.pairNamePrefix+keyExtension)
|
||||
certFileExists, err = utilfile.FileExists(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyFileExists, err = utilfile.FileExists(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if certFileExists && keyFileExists {
|
||||
glog.Infof("Loading cert/key pair from (%q, %q).", c, k)
|
||||
return loadX509KeyPair(c, k)
|
||||
}
|
||||
|
||||
noKeyErr := NoCertKeyError(
|
||||
fmt.Sprintf("no cert/key files read at %q, (%q, %q) or (%q, %q)",
|
||||
pairFile,
|
||||
s.certFile,
|
||||
s.keyFile,
|
||||
s.certDirectory,
|
||||
s.keyDirectory))
|
||||
return nil, &noKeyErr
|
||||
}
|
||||
|
||||
func loadFile(pairFile string) (*tls.Certificate, error) {
|
||||
certBlock, keyBlock, err := loadCertKeyBlocks(pairFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert, err := tls.X509KeyPair(pem.EncodeToMemory(certBlock), pem.EncodeToMemory(keyBlock))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not convert data from %q into cert/key pair: %v", pairFile, err)
|
||||
}
|
||||
certs, err := x509.ParseCertificates(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse certificate data: %v", err)
|
||||
}
|
||||
cert.Leaf = certs[0]
|
||||
return &cert, nil
|
||||
}
|
||||
|
||||
func loadCertKeyBlocks(pairFile string) (cert *pem.Block, key *pem.Block, err error) {
|
||||
data, err := ioutil.ReadFile(pairFile)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not load cert/key pair from %q: %v", pairFile, err)
|
||||
}
|
||||
certBlock, rest := pem.Decode(data)
|
||||
if certBlock == nil {
|
||||
return nil, nil, fmt.Errorf("could not decode the first block from %q from expected PEM format", pairFile)
|
||||
}
|
||||
keyBlock, _ := pem.Decode(rest)
|
||||
if keyBlock == nil {
|
||||
return nil, nil, fmt.Errorf("could not decode the second block from %q from expected PEM format", pairFile)
|
||||
}
|
||||
return certBlock, keyBlock, nil
|
||||
}
|
||||
|
||||
func (s *fileStore) Update(certData, keyData []byte) (*tls.Certificate, error) {
|
||||
ts := time.Now().Format("2006-01-02-15-04-05")
|
||||
pemFilename := s.filename(ts)
|
||||
|
||||
if err := os.MkdirAll(s.certDirectory, 0755); err != nil {
|
||||
return nil, fmt.Errorf("could not create directory %q to store certificates: %v", s.certDirectory, err)
|
||||
}
|
||||
certPath := filepath.Join(s.certDirectory, pemFilename)
|
||||
|
||||
f, err := os.OpenFile(certPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open %q: %v", certPath, err)
|
||||
}
|
||||
defer f.Close()
|
||||
certBlock, _ := pem.Decode(certData)
|
||||
if certBlock == nil {
|
||||
return nil, fmt.Errorf("invalid certificate data")
|
||||
}
|
||||
pem.Encode(f, certBlock)
|
||||
keyBlock, _ := pem.Decode(keyData)
|
||||
if keyBlock == nil {
|
||||
return nil, fmt.Errorf("invalid key data")
|
||||
}
|
||||
pem.Encode(f, keyBlock)
|
||||
|
||||
cert, err := loadFile(certPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.updateSymlink(certPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// updateSymLink updates the current symlink to point to the file that is
|
||||
// passed it. It will fail if there is a non-symlink file exists where the
|
||||
// symlink is expected to be.
|
||||
func (s *fileStore) updateSymlink(filename string) error {
|
||||
// If the 'current' file either doesn't exist, or is already a symlink,
|
||||
// proceed. Otherwise, this is an unrecoverable error.
|
||||
currentPath := filepath.Join(s.certDirectory, s.filename(currentPair))
|
||||
currentPathExists := false
|
||||
if fi, err := os.Lstat(currentPath); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
return fmt.Errorf("expected %q to be a symlink but it is a file.", currentPath)
|
||||
} else {
|
||||
currentPathExists = true
|
||||
}
|
||||
|
||||
// If the 'updated' file doesn't exist, proceed. If it exists but it is a
|
||||
// symlink, delete it. Otherwise, this is an unrecoverable error.
|
||||
updatedPath := filepath.Join(s.certDirectory, s.filename(updatedPair))
|
||||
if fi, err := os.Lstat(updatedPath); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
return fmt.Errorf("expected %q to be a symlink but it is a file.", updatedPath)
|
||||
} else {
|
||||
if err := os.Remove(updatedPath); err != nil {
|
||||
return fmt.Errorf("unable to remove %q: %v", updatedPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the new cert/key pair file exists to avoid rotating to an
|
||||
// invalid cert/key.
|
||||
if filenameExists, err := utilfile.FileExists(filename); err != nil {
|
||||
return err
|
||||
} else if !filenameExists {
|
||||
return fmt.Errorf("file %q does not exist so it can not be used as the currently selected cert/key", filename)
|
||||
}
|
||||
|
||||
// Create the 'updated' symlink pointing to the requested file name.
|
||||
if err := os.Symlink(filename, updatedPath); err != nil {
|
||||
return fmt.Errorf("unable to create a symlink from %q to %q: %v", updatedPath, filename, err)
|
||||
}
|
||||
|
||||
// Replace the 'current' symlink.
|
||||
if currentPathExists {
|
||||
if err := os.Remove(currentPath); err != nil {
|
||||
return fmt.Errorf("unable to remove %q: %v", currentPath, err)
|
||||
}
|
||||
}
|
||||
if err := os.Rename(updatedPath, currentPath); err != nil {
|
||||
return fmt.Errorf("unable to rename %q to %q: %v", updatedPath, currentPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *fileStore) filename(qualifier string) string {
|
||||
return s.pairNamePrefix + "-" + qualifier + pemExtension
|
||||
}
|
||||
|
||||
// withoutExt returns the given filename after removing the extension. The
|
||||
// extension to remove will be the result of filepath.Ext().
|
||||
func withoutExt(filename string) string {
|
||||
return strings.TrimSuffix(filename, filepath.Ext(filename))
|
||||
}
|
||||
|
||||
func loadX509KeyPair(certFile, keyFile string) (*tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs, err := x509.ParseCertificates(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse certificate data: %v", err)
|
||||
}
|
||||
cert.Leaf = certs[0]
|
||||
return &cert, nil
|
||||
}
|
||||
505
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_store_test.go
generated
vendored
Normal file
505
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/certificate_store_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
func TestUpdateSymlinkExistingFileError(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-update-symlink")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
pairFile := filepath.Join(dir, "kubelet-current.pem")
|
||||
if err := ioutil.WriteFile(pairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
s := fileStore{
|
||||
certDirectory: dir,
|
||||
pairNamePrefix: "kubelet",
|
||||
}
|
||||
if err := s.updateSymlink(pairFile); err == nil {
|
||||
t.Errorf("Got no error, wanted to fail updating the symlink because there is a file there.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSymlinkNewFileNotExist(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-update-symlink")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
oldPairFile := filepath.Join(dir, "kubelet-oldpair.pem")
|
||||
if err := ioutil.WriteFile(oldPairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", oldPairFile, err)
|
||||
}
|
||||
|
||||
s := fileStore{
|
||||
certDirectory: dir,
|
||||
pairNamePrefix: "kubelet",
|
||||
}
|
||||
if err := s.updateSymlink(oldPairFile); err != nil {
|
||||
t.Errorf("Got %v, wanted successful update of the symlink to point to %q", err, oldPairFile)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(oldPairFile); err != nil {
|
||||
t.Errorf("Got %v, wanted file %q to be there.", oldPairFile, err)
|
||||
}
|
||||
|
||||
currentPairFile := filepath.Join(dir, "kubelet-current.pem")
|
||||
if fi, err := os.Lstat(currentPairFile); err != nil {
|
||||
t.Errorf("Got %v, wanted file %q to be there", currentPairFile, err)
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
t.Errorf("Got %q not a symlink.", currentPairFile)
|
||||
}
|
||||
|
||||
newPairFile := filepath.Join(dir, "kubelet-newpair.pem")
|
||||
if err := s.updateSymlink(newPairFile); err == nil {
|
||||
t.Errorf("Got no error, wanted to fail updating the symlink the file %q does not exist.", newPairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSymlinkNoSymlink(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-update-symlink")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
pairFile := filepath.Join(dir, "kubelet-newfile.pem")
|
||||
if err := ioutil.WriteFile(pairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
s := fileStore{
|
||||
certDirectory: dir,
|
||||
pairNamePrefix: "kubelet",
|
||||
}
|
||||
if err := s.updateSymlink(pairFile); err != nil {
|
||||
t.Errorf("Got error %v, wanted a new symlink to be created", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(pairFile); err != nil {
|
||||
t.Errorf("Got error %v, wanted file %q to be there", pairFile, err)
|
||||
}
|
||||
currentPairFile := filepath.Join(dir, "kubelet-current.pem")
|
||||
if fi, err := os.Lstat(currentPairFile); err != nil {
|
||||
t.Errorf("Got %v, wanted %q to be there", currentPairFile, err)
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
t.Errorf("%q not a symlink, wanted a symlink.", currentPairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSymlinkReplaceExistingSymlink(t *testing.T) {
|
||||
prefix := "kubelet"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-update-symlink")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
oldPairFile := filepath.Join(dir, prefix+"-oldfile.pem")
|
||||
if err := ioutil.WriteFile(oldPairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", oldPairFile, err)
|
||||
}
|
||||
newPairFile := filepath.Join(dir, prefix+"-newfile.pem")
|
||||
if err := ioutil.WriteFile(newPairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", newPairFile, err)
|
||||
}
|
||||
currentPairFile := filepath.Join(dir, prefix+"-current.pem")
|
||||
if err := os.Symlink(oldPairFile, currentPairFile); err != nil {
|
||||
t.Fatalf("unable to create a symlink from %q to %q: %v", currentPairFile, oldPairFile, err)
|
||||
}
|
||||
if resolved, err := os.Readlink(currentPairFile); err != nil {
|
||||
t.Fatalf("Got %v when attempting to resolve symlink %q", err, currentPairFile)
|
||||
} else if resolved != oldPairFile {
|
||||
t.Fatalf("Got %q as resolution of symlink %q, wanted %q", resolved, currentPairFile, oldPairFile)
|
||||
}
|
||||
|
||||
s := fileStore{
|
||||
certDirectory: dir,
|
||||
pairNamePrefix: prefix,
|
||||
}
|
||||
if err := s.updateSymlink(newPairFile); err != nil {
|
||||
t.Errorf("Got error %v, wanted a new symlink to be created", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(oldPairFile); err != nil {
|
||||
t.Errorf("Got error %v, wanted file %q to be there", oldPairFile, err)
|
||||
}
|
||||
if _, err := os.Stat(newPairFile); err != nil {
|
||||
t.Errorf("Got error %v, wanted file %q to be there", newPairFile, err)
|
||||
}
|
||||
if fi, err := os.Lstat(currentPairFile); err != nil {
|
||||
t.Errorf("Got %v, wanted %q to be there", currentPairFile, err)
|
||||
} else if fi.Mode()&os.ModeSymlink != os.ModeSymlink {
|
||||
t.Errorf("%q not a symlink, wanted a symlink.", currentPairFile)
|
||||
}
|
||||
if resolved, err := os.Readlink(currentPairFile); err != nil {
|
||||
t.Fatalf("Got %v when attempting to resolve symlink %q", err, currentPairFile)
|
||||
} else if resolved != newPairFile {
|
||||
t.Fatalf("Got %q as resolution of symlink %q, wanted %q", resolved, currentPairFile, newPairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCertKeyBlocksNoFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
pairFile := filepath.Join(dir, "kubelet-pair.pem")
|
||||
|
||||
if _, _, err := loadCertKeyBlocks(pairFile); err == nil {
|
||||
t.Errorf("Got no error, but expected %q not found.", pairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCertKeyBlocksEmptyFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
pairFile := filepath.Join(dir, "kubelet-pair.pem")
|
||||
if err := ioutil.WriteFile(pairFile, nil, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
if _, _, err := loadCertKeyBlocks(pairFile); err == nil {
|
||||
t.Errorf("Got no error, but expected %q not found.", pairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCertKeyBlocksPartialFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
pairFile := filepath.Join(dir, "kubelet-pair.pem")
|
||||
if err := ioutil.WriteFile(pairFile, storeCertData.certificatePEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
if _, _, err := loadCertKeyBlocks(pairFile); err == nil {
|
||||
t.Errorf("Got no error, but expected %q invalid.", pairFile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCertKeyBlocks(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
pairFile := filepath.Join(dir, "kubelet-pair.pem")
|
||||
data := append(storeCertData.certificatePEM, []byte("\n")...)
|
||||
data = append(data, storeCertData.keyPEM...)
|
||||
if err := ioutil.WriteFile(pairFile, data, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
certBlock, keyBlock, err := loadCertKeyBlocks(pairFile)
|
||||
if err != nil {
|
||||
t.Errorf("Got %v, but expected no error.", pairFile)
|
||||
}
|
||||
if certBlock.Type != cert.CertificateBlockType {
|
||||
t.Errorf("Got %q loaded from the pair file, expected a %q.", certBlock.Type, cert.CertificateBlockType)
|
||||
}
|
||||
if keyBlock.Type != cert.RSAPrivateKeyBlockType {
|
||||
t.Errorf("Got %q loaded from the pair file, expected a %q.", keyBlock.Type, cert.RSAPrivateKeyBlockType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-load-cert-key-blocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
pairFile := filepath.Join(dir, "kubelet-pair.pem")
|
||||
data := append(storeCertData.certificatePEM, []byte("\n")...)
|
||||
data = append(data, storeCertData.keyPEM...)
|
||||
if err := ioutil.WriteFile(pairFile, data, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
|
||||
cert, err := loadFile(pairFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load certificate from disk: %v", err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Fatalf("There was no error, but no certificate data was returned.")
|
||||
}
|
||||
if cert.Leaf == nil {
|
||||
t.Fatalf("Got an empty leaf, expected private data.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateNoRotation(t *testing.T) {
|
||||
prefix := "kubelet-server"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
keyFile := filepath.Join(dir, "kubelet.key")
|
||||
if err := ioutil.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
|
||||
}
|
||||
certFile := filepath.Join(dir, "kubelet.crt")
|
||||
if err := ioutil.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", certFile, err)
|
||||
}
|
||||
|
||||
s, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Got %v while creating a new store.", err)
|
||||
}
|
||||
|
||||
cert, err := s.Update(storeCertData.certificatePEM, storeCertData.keyPEM)
|
||||
if err != nil {
|
||||
t.Errorf("Got %v while updating certificate store.", err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Errorf("Got nil certificate, expected something real.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRotation(t *testing.T) {
|
||||
prefix := "kubelet-server"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
keyFile := filepath.Join(dir, "kubelet.key")
|
||||
if err := ioutil.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
|
||||
}
|
||||
certFile := filepath.Join(dir, "kubelet.crt")
|
||||
if err := ioutil.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", certFile, err)
|
||||
}
|
||||
|
||||
s, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Got %v while creating a new store.", err)
|
||||
}
|
||||
|
||||
cert, err := s.Update(storeCertData.certificatePEM, storeCertData.keyPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("Got %v while updating certificate store.", err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Fatalf("Got nil certificate, expected something real.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateWithBadCertKeyData(t *testing.T) {
|
||||
prefix := "kubelet-server"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
keyFile := filepath.Join(dir, "kubelet.key")
|
||||
if err := ioutil.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
|
||||
}
|
||||
certFile := filepath.Join(dir, "kubelet.crt")
|
||||
if err := ioutil.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", certFile, err)
|
||||
}
|
||||
|
||||
s, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Got %v while creating a new store.", err)
|
||||
}
|
||||
|
||||
cert, err := s.Update([]byte{0, 0}, storeCertData.keyPEM)
|
||||
if err == nil {
|
||||
t.Fatalf("Got no error while updating certificate store with invalid data.")
|
||||
}
|
||||
if cert != nil {
|
||||
t.Fatalf("Got %v certificate returned from the update, expected nil.", cert)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentPairFile(t *testing.T) {
|
||||
prefix := "kubelet-server"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
pairFile := filepath.Join(dir, prefix+"-pair.pem")
|
||||
data := append(storeCertData.certificatePEM, []byte("\n")...)
|
||||
data = append(data, storeCertData.keyPEM...)
|
||||
if err := ioutil.WriteFile(pairFile, data, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", pairFile, err)
|
||||
}
|
||||
currentFile := filepath.Join(dir, prefix+"-current.pem")
|
||||
if err := os.Symlink(pairFile, currentFile); err != nil {
|
||||
t.Fatalf("unable to create a symlink from %q to %q: %v", currentFile, pairFile, err)
|
||||
}
|
||||
|
||||
store, err := NewFileStore("kubelet-server", dir, dir, "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize certificate store: %v", err)
|
||||
}
|
||||
|
||||
cert, err := store.Current()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load certificate from disk: %v", err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Fatalf("There was no error, but no certificate data was returned.")
|
||||
}
|
||||
if cert.Leaf == nil {
|
||||
t.Fatalf("Got an empty leaf, expected private data.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentCertKeyFiles(t *testing.T) {
|
||||
prefix := "kubelet-server"
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
certFile := filepath.Join(dir, "kubelet.crt")
|
||||
if err := ioutil.WriteFile(certFile, storeCertData.certificatePEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", certFile, err)
|
||||
}
|
||||
keyFile := filepath.Join(dir, "kubelet.key")
|
||||
if err := ioutil.WriteFile(keyFile, storeCertData.keyPEM, 0600); err != nil {
|
||||
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
|
||||
}
|
||||
|
||||
store, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize certificate store: %v", err)
|
||||
}
|
||||
|
||||
cert, err := store.Current()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load certificate from disk: %v", err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Fatalf("There was no error, but no certificate data was returned.")
|
||||
}
|
||||
if cert.Leaf == nil {
|
||||
t.Fatalf("Got an empty leaf, expected private data.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentNoFiles(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
|
||||
}
|
||||
defer func() {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
|
||||
}
|
||||
}()
|
||||
|
||||
store, err := NewFileStore("kubelet-server", dir, dir, "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initialize certificate store: %v", err)
|
||||
}
|
||||
|
||||
cert, err := store.Current()
|
||||
if err == nil {
|
||||
t.Fatalf("Got no error, expected an error because the cert/key files don't exist.")
|
||||
}
|
||||
if _, ok := err.(*NoCertKeyError); !ok {
|
||||
t.Fatalf("Got error %v, expected NoCertKeyError.", err)
|
||||
}
|
||||
if cert != nil {
|
||||
t.Fatalf("Got certificate, expected no certificate because the cert/key files don't exist.")
|
||||
}
|
||||
}
|
||||
124
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/kubelet.go
generated
vendored
Normal file
124
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/kubelet.go
generated
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
certificates "k8s.io/api/certificates/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
clientcertificates "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
)
|
||||
|
||||
// NewKubeletServerCertificateManager creates a certificate manager for the kubelet when retrieving a server certificate
|
||||
// or returns an error.
|
||||
func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg *kubeletconfig.KubeletConfiguration, nodeName types.NodeName, ips []net.IP, hostnames []string, certDirectory string) (Manager, error) {
|
||||
var certSigningRequestClient clientcertificates.CertificateSigningRequestInterface
|
||||
if kubeClient != nil && kubeClient.Certificates() != nil {
|
||||
certSigningRequestClient = kubeClient.Certificates().CertificateSigningRequests()
|
||||
}
|
||||
certificateStore, err := NewFileStore(
|
||||
"kubelet-server",
|
||||
certDirectory,
|
||||
certDirectory,
|
||||
kubeCfg.TLSCertFile,
|
||||
kubeCfg.TLSPrivateKeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize server certificate store: %v", err)
|
||||
}
|
||||
m, err := NewManager(&Config{
|
||||
CertificateSigningRequestClient: certSigningRequestClient,
|
||||
Template: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: hostnames,
|
||||
IPAddresses: ips,
|
||||
},
|
||||
Usages: []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// Digital signature allows the certificate to be used to verify
|
||||
// digital signatures used during TLS negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// KeyEncipherment allows the cert/key pair to be used to encrypt
|
||||
// keys, including the symmetric keys negotiated during TLS setup
|
||||
// and used for data transfer.
|
||||
certificates.UsageKeyEncipherment,
|
||||
// ServerAuth allows the cert to be used by a TLS server to
|
||||
// authenticate itself to a TLS client.
|
||||
certificates.UsageServerAuth,
|
||||
},
|
||||
CertificateStore: certificateStore,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize server certificate manager: %v", err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// NewKubeletClientCertificateManager sets up a certificate manager without a
|
||||
// client that can be used to sign new certificates (or rotate). It answers with
|
||||
// whatever certificate it is initialized with. If a CSR client is set later, it
|
||||
// may begin rotating/renewing the client cert
|
||||
func NewKubeletClientCertificateManager(certDirectory string, nodeName types.NodeName, certData []byte, keyData []byte, certFile string, keyFile string) (Manager, error) {
|
||||
certificateStore, err := NewFileStore(
|
||||
"kubelet-client",
|
||||
certDirectory,
|
||||
certDirectory,
|
||||
certFile,
|
||||
keyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize client certificate store: %v", err)
|
||||
}
|
||||
m, err := NewManager(&Config{
|
||||
Template: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
},
|
||||
Usages: []certificates.KeyUsage{
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
//
|
||||
// DigitalSignature allows the certificate to be used to verify
|
||||
// digital signatures including signatures used during TLS
|
||||
// negotiation.
|
||||
certificates.UsageDigitalSignature,
|
||||
// KeyEncipherment allows the cert/key pair to be used to encrypt
|
||||
// keys, including the symmetric keys negotiated during TLS setup
|
||||
// and used for data transfer..
|
||||
certificates.UsageKeyEncipherment,
|
||||
// ClientAuth allows the cert to be used by a TLS client to
|
||||
// authenticate itself to the TLS server.
|
||||
certificates.UsageClientAuth,
|
||||
},
|
||||
CertificateStore: certificateStore,
|
||||
BootstrapCertificatePEM: certData,
|
||||
BootstrapKeyPEM: keyData,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize client certificate manager: %v", err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
168
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/transport.go
generated
vendored
Normal file
168
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/transport.go
generated
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// UpdateTransport instruments a restconfig with a transport that dynamically uses
|
||||
// certificates provided by the manager for TLS client auth.
|
||||
//
|
||||
// The config must not already provide an explicit transport.
|
||||
//
|
||||
// The returned transport periodically checks the manager to determine if the
|
||||
// certificate has changed. If it has, the transport shuts down all existing client
|
||||
// connections, forcing the client to re-handshake with the server and use the
|
||||
// new certificate.
|
||||
//
|
||||
// stopCh should be used to indicate when the transport is unused and doesn't need
|
||||
// to continue checking the manager.
|
||||
func UpdateTransport(stopCh <-chan struct{}, clientConfig *restclient.Config, clientCertificateManager Manager) error {
|
||||
return updateTransport(stopCh, 10*time.Second, clientConfig, clientCertificateManager)
|
||||
}
|
||||
|
||||
// updateTransport is an internal method that exposes how often this method checks that the
|
||||
// client cert has changed. Intended for testing.
|
||||
func updateTransport(stopCh <-chan struct{}, period time.Duration, clientConfig *restclient.Config, clientCertificateManager Manager) error {
|
||||
if clientConfig.Transport != nil {
|
||||
return fmt.Errorf("there is already a transport configured")
|
||||
}
|
||||
tlsConfig, err := restclient.TLSConfigFor(clientConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to configure TLS for the rest client: %v", err)
|
||||
}
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = &tls.Config{}
|
||||
}
|
||||
tlsConfig.Certificates = nil
|
||||
tlsConfig.GetClientCertificate = func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
cert := clientCertificateManager.Current()
|
||||
if cert == nil {
|
||||
return &tls.Certificate{Certificate: nil}, nil
|
||||
}
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// Custom dialer that will track all connections it creates.
|
||||
t := &connTracker{
|
||||
dialer: &net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second},
|
||||
conns: make(map[*closableConn]struct{}),
|
||||
}
|
||||
|
||||
lastCert := clientCertificateManager.Current()
|
||||
go wait.Until(func() {
|
||||
curr := clientCertificateManager.Current()
|
||||
if curr == nil || lastCert == curr {
|
||||
// Cert hasn't been rotated.
|
||||
return
|
||||
}
|
||||
lastCert = curr
|
||||
|
||||
glog.Infof("certificate rotation detected, shutting down client connections to start using new credentials")
|
||||
// The cert has been rotated. Close all existing connections to force the client
|
||||
// to reperform its TLS handshake with new cert.
|
||||
//
|
||||
// See: https://github.com/kubernetes-incubator/bootkube/pull/663#issuecomment-318506493
|
||||
t.closeAllConns()
|
||||
}, period, stopCh)
|
||||
|
||||
clientConfig.Transport = utilnet.SetTransportDefaults(&http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: tlsConfig,
|
||||
MaxIdleConnsPerHost: 25,
|
||||
DialContext: t.DialContext, // Use custom dialer.
|
||||
})
|
||||
|
||||
// Zero out all existing TLS options since our new transport enforces them.
|
||||
clientConfig.CertData = nil
|
||||
clientConfig.KeyData = nil
|
||||
clientConfig.CertFile = ""
|
||||
clientConfig.KeyFile = ""
|
||||
clientConfig.CAData = nil
|
||||
clientConfig.CAFile = ""
|
||||
clientConfig.Insecure = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// connTracker is a dialer that tracks all open connections it creates.
|
||||
type connTracker struct {
|
||||
dialer *net.Dialer
|
||||
|
||||
mu sync.Mutex
|
||||
conns map[*closableConn]struct{}
|
||||
}
|
||||
|
||||
// closeAllConns forcibly closes all tracked connections.
|
||||
func (c *connTracker) closeAllConns() {
|
||||
c.mu.Lock()
|
||||
conns := c.conns
|
||||
c.conns = make(map[*closableConn]struct{})
|
||||
c.mu.Unlock()
|
||||
|
||||
for conn := range conns {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connTracker) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
conn, err := c.dialer.DialContext(ctx, network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
closable := &closableConn{Conn: conn}
|
||||
|
||||
// Start tracking the connection
|
||||
c.mu.Lock()
|
||||
c.conns[closable] = struct{}{}
|
||||
c.mu.Unlock()
|
||||
|
||||
// When the connection is closed, remove it from the map. This will
|
||||
// be no-op if the connection isn't in the map, e.g. if closeAllConns()
|
||||
// is called.
|
||||
closable.onClose = func() {
|
||||
c.mu.Lock()
|
||||
delete(c.conns, closable)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
return closable, nil
|
||||
}
|
||||
|
||||
type closableConn struct {
|
||||
onClose func()
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (c *closableConn) Close() error {
|
||||
go c.onClose()
|
||||
return c.Conn.Close()
|
||||
}
|
||||
191
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/transport_test.go
generated
vendored
Normal file
191
vendor/k8s.io/kubernetes/pkg/kubelet/certificate/transport_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
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 certificate
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
client1CertData = newCertificateData(`-----BEGIN CERTIFICATE-----
|
||||
MIICBDCCAW2gAwIBAgIJAPgVBh+4xbGoMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
|
||||
BAMMEHdlYmhvb2tfdGVzdHNfY2EwIBcNMTcwNzI4MjMxNTI4WhgPMjI5MTA1MTMy
|
||||
MzE1MjhaMB8xHTAbBgNVBAMMFHdlYmhvb2tfdGVzdHNfY2xpZW50MIGfMA0GCSqG
|
||||
SIb3DQEBAQUAA4GNADCBiQKBgQDkGXXSm6Yun5o3Jlmx45rItcQ2pmnoDk4eZfl0
|
||||
rmPa674s2pfYo3KywkXQ1Fp3BC8GUgzPLSfJ8xXya9Lg1Wo8sHrDln0iRg5HXxGu
|
||||
uFNhRBvj2S0sIff0ZG/IatB9I6WXVOUYuQj6+A0CdULNj1vBqH9+7uWbLZ6lrD4b
|
||||
a44x/wIDAQABo0owSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B
|
||||
AQsFAAOBgQCpN27uh/LjUVCaBK7Noko25iih/JSSoWzlvc8CaipvSPofNWyGx3Vu
|
||||
OdcSwNGYX/pp4ZoAzFij/Y5u0vKTVLkWXATeTMVmlPvhmpYjj9gPkCSY6j/SiKlY
|
||||
kGy0xr+0M5UQkMBcfIh9oAp9um1fZHVWAJAGP/ikZgkcUey0LmBn8w==
|
||||
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQDkGXXSm6Yun5o3Jlmx45rItcQ2pmnoDk4eZfl0rmPa674s2pfY
|
||||
o3KywkXQ1Fp3BC8GUgzPLSfJ8xXya9Lg1Wo8sHrDln0iRg5HXxGuuFNhRBvj2S0s
|
||||
Iff0ZG/IatB9I6WXVOUYuQj6+A0CdULNj1vBqH9+7uWbLZ6lrD4ba44x/wIDAQAB
|
||||
AoGAZbWwowvCq1GBq4vPPRI3h739Uz0bRl1ymf1woYXNguXRtCB4yyH+2BTmmrrF
|
||||
6AIWkePuUEdbUaKyK5nGu3iOWM+/i6NP3kopQANtbAYJ2ray3kwvFlhqyn1bxX4n
|
||||
gl/Cbdw1If4zrDrB66y8mYDsjzK7n/gFaDNcY4GArjvOXKkCQQD9Lgv+WD73y4RP
|
||||
yS+cRarlEeLLWVsX/pg2oEBLM50jsdUnrLSW071MjBgP37oOXzqynF9SoDbP2Y5C
|
||||
x+aGux9LAkEA5qPlQPv0cv8Wc3qTI+LixZ/86PPHKWnOnwaHm3b9vQjZAkuVQg3n
|
||||
Wgg9YDmPM87t3UFH7ZbDihUreUxwr9ZjnQJAZ9Z95shMsxbOYmbSVxafu6m1Sc+R
|
||||
M+sghK7/D5jQpzYlhUspGf8n0YBX0hLhXUmjamQGGH5LXL4Owcb4/mM6twJAEVio
|
||||
SF/qva9jv+GrKVrKFXT374lOJFY53Qn/rvifEtWUhLCslCA5kzLlctRBafMZPrfH
|
||||
Mh5RrJP1BhVysDbenQJASGcc+DiF7rB6K++ZGyC11E2AP29DcZ0pgPESSV7npOGg
|
||||
+NqPRZNVCSZOiVmNuejZqmwKhZNGZnBFx1Y+ChAAgw==
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
client2CertData = newCertificateData(`-----BEGIN CERTIFICATE-----
|
||||
MIICBDCCAW2gAwIBAgIJAPgVBh+4xbGnMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
|
||||
BAMMEHdlYmhvb2tfdGVzdHNfY2EwIBcNMTcwNzI4MjMxNTI4WhgPMjI5MTA1MTMy
|
||||
MzE1MjhaMB8xHTAbBgNVBAMMFHdlYmhvb2tfdGVzdHNfY2xpZW50MIGfMA0GCSqG
|
||||
SIb3DQEBAQUAA4GNADCBiQKBgQDQQLzbrmHbtlxE7wViaoXFp5tQx7zzM2Ed7O1E
|
||||
gs3JUws5KkPbNrejLwixvLkzzU152M43UGsyKDn7HPyjXDogTZSW6C257XpYodk3
|
||||
S/gZS9oZtPss4UJuJioQk/M8X1ZjYP8kCTArOvVRJeNQL8GM7h5QQ6J5LUq+IdZb
|
||||
T0retQIDAQABo0owSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B
|
||||
AQsFAAOBgQBdAxoU5YAmp0d+5b4qg/xOGC5rKcnksQEXYoGwFBWwaKvh9oUlGGxI
|
||||
A5Ykf2TEl24br4tLmicpdxUX4H4PbkdPxOjM9ghIKlmgHo8vBRC0iVIwYgQsw1W8
|
||||
ETY34Or+PJqaeslqx/t7kUKY5UIF9DLVolsIiAHveJNR2uBWiP0KiQ==
|
||||
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDQQLzbrmHbtlxE7wViaoXFp5tQx7zzM2Ed7O1Egs3JUws5KkPb
|
||||
NrejLwixvLkzzU152M43UGsyKDn7HPyjXDogTZSW6C257XpYodk3S/gZS9oZtPss
|
||||
4UJuJioQk/M8X1ZjYP8kCTArOvVRJeNQL8GM7h5QQ6J5LUq+IdZbT0retQIDAQAB
|
||||
AoGBAMFjTL4IKvG4X+jXub1RxFXvNkkGos2Jaec7TH5xpZ4OUv7L4+We41tTYxSC
|
||||
d83GGetLzPwK3vDd8DHkEiu1incket78rwmQ89LnQNyM0B5ejaTjW2zHcvKJ0Mtn
|
||||
nM32juQfq8St9JZVweS87k8RkLt9cOrg6219MRbFO+1Vn8WhAkEA+/rqHCspBdXr
|
||||
7RL+H63k7RjqBllVEYlw1ukqTw1gp5IImmeOwgl3aRrJJfFV6gxxEqQ4CCb2vf9M
|
||||
yjrGEvP9KQJBANOTPcpskT/0dyipsAkvLFZTKjN+4fdfq37H3dVgMR6oQcMJwukd
|
||||
cEio1Hx+XzXuD0RHXighq7bUzel+IqzRuq0CQBJkzpIf1G7InuA/cq19VCi6mNq9
|
||||
yqftEH+fpab/ov6YemhLBvDDICRcADL02wCqx9ZEhpKRxZE5AbIBeFQJ24ECQG4f
|
||||
9cmnOPNRC7TengIpy6ojH5QuNu/LnDghUBYAO5D5g0FBk3JDIG6xceha3rPzdX7U
|
||||
pu28mORRX9xpCyNpBwECQQCtDNZoehdPVuZA3Wocno31Rjmuy83ajgRRuEzqv0tj
|
||||
uC6Jo2eLcSV1sSdzTjaaWdM6XeYj6yHOAm8ZBIQs7m6V
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
)
|
||||
|
||||
type fakeManager struct {
|
||||
cert atomic.Value // Always a *tls.Certificate
|
||||
}
|
||||
|
||||
func (f *fakeManager) SetCertificateSigningRequestClient(certificatesclient.CertificateSigningRequestInterface) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeManager) Start() {}
|
||||
|
||||
func (f *fakeManager) Current() *tls.Certificate {
|
||||
if val := f.cert.Load(); val != nil {
|
||||
return val.(*tls.Certificate)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeManager) setCurrent(cert *tls.Certificate) {
|
||||
f.cert.Store(cert)
|
||||
}
|
||||
|
||||
func TestRotateShutsDownConnections(t *testing.T) {
|
||||
|
||||
// This test fails if you comment out the t.closeAllConns() call in
|
||||
// transport.go and don't close connections on a rotate.
|
||||
|
||||
stop := make(chan struct{})
|
||||
defer close(stop)
|
||||
|
||||
m := new(fakeManager)
|
||||
m.setCurrent(client1CertData.certificate)
|
||||
|
||||
// The last certificate we've seen.
|
||||
lastSeenLeafCert := new(atomic.Value) // Always *x509.Certificate
|
||||
|
||||
lastSerialNumber := func() *big.Int {
|
||||
if cert := lastSeenLeafCert.Load(); cert != nil {
|
||||
return cert.(*x509.Certificate).SerialNumber
|
||||
}
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
h := func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.TLS != nil && len(r.TLS.PeerCertificates) != 0 {
|
||||
// Record the last TLS certificate the client sent.
|
||||
lastSeenLeafCert.Store(r.TLS.PeerCertificates[0])
|
||||
}
|
||||
w.Write([]byte(`{}`))
|
||||
}
|
||||
|
||||
s := httptest.NewUnstartedServer(http.HandlerFunc(h))
|
||||
s.TLS = &tls.Config{
|
||||
// Just request a cert, we don't need to verify it.
|
||||
ClientAuth: tls.RequestClientCert,
|
||||
}
|
||||
s.StartTLS()
|
||||
defer s.Close()
|
||||
|
||||
c := &rest.Config{
|
||||
Host: s.URL,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
// We don't care about the server's cert.
|
||||
Insecure: true,
|
||||
},
|
||||
ContentConfig: rest.ContentConfig{
|
||||
// This is a hack. We don't actually care about the serializer.
|
||||
NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{}),
|
||||
},
|
||||
}
|
||||
|
||||
// Check for a new cert every 10 milliseconds
|
||||
if err := updateTransport(stop, 10*time.Millisecond, c, m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client, err := rest.UnversionedRESTClientFor(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := client.Get().Do().Error(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
firstCertSerial := lastSerialNumber()
|
||||
|
||||
// Change the manager's certificate. This should cause the client to shut down
|
||||
// its connections to the server.
|
||||
m.setCurrent(client2CertData.certificate)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
client.Get().Do()
|
||||
if firstCertSerial.Cmp(lastSerialNumber()) != 0 {
|
||||
// The certificate changed!
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Errorf("certificate rotated but client never reconnected with new cert")
|
||||
}
|
||||
45
vendor/k8s.io/kubernetes/pkg/kubelet/client/BUILD
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/pkg/kubelet/client/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kubelet_client.go"],
|
||||
deps = [
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/transport:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["kubelet_client_test.go"],
|
||||
data = ["//pkg/client/testdata"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
180
vendor/k8s.io/kubernetes/pkg/kubelet/client/kubelet_client.go
generated
vendored
Normal file
180
vendor/k8s.io/kubernetes/pkg/kubelet/client/kubelet_client.go
generated
vendored
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
Copyright 2014 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 client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/transport"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
|
||||
type KubeletClientConfig struct {
|
||||
// Default port - used if no information about Kubelet port can be found in Node.NodeStatus.DaemonEndpoints.
|
||||
Port uint
|
||||
ReadOnlyPort uint
|
||||
EnableHttps bool
|
||||
|
||||
// PreferredAddressTypes - used to select an address from Node.NodeStatus.Addresses
|
||||
PreferredAddressTypes []string
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
restclient.TLSClientConfig
|
||||
|
||||
// Server requires Bearer authentication
|
||||
BearerToken string
|
||||
|
||||
// HTTPTimeout is used by the client to timeout http requests to Kubelet.
|
||||
HTTPTimeout time.Duration
|
||||
|
||||
// Dial is a custom dialer used for the client
|
||||
Dial utilnet.DialFunc
|
||||
}
|
||||
|
||||
// ConnectionInfo provides the information needed to connect to a kubelet
|
||||
type ConnectionInfo struct {
|
||||
Scheme string
|
||||
Hostname string
|
||||
Port string
|
||||
Transport http.RoundTripper
|
||||
}
|
||||
|
||||
// ConnectionInfoGetter provides ConnectionInfo for the kubelet running on a named node
|
||||
type ConnectionInfoGetter interface {
|
||||
GetConnectionInfo(nodeName types.NodeName) (*ConnectionInfo, error)
|
||||
}
|
||||
|
||||
func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
|
||||
tlsConfig, err := transport.TLSConfigFor(config.transportConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rt := http.DefaultTransport
|
||||
if config.Dial != nil || tlsConfig != nil {
|
||||
rt = utilnet.SetOldTransportDefaults(&http.Transport{
|
||||
Dial: config.Dial,
|
||||
TLSClientConfig: tlsConfig,
|
||||
})
|
||||
}
|
||||
|
||||
return transport.HTTPWrappersForConfig(config.transportConfig(), rt)
|
||||
}
|
||||
|
||||
// transportConfig converts a client config to an appropriate transport config.
|
||||
func (c *KubeletClientConfig) transportConfig() *transport.Config {
|
||||
cfg := &transport.Config{
|
||||
TLS: transport.TLSConfig{
|
||||
CAFile: c.CAFile,
|
||||
CAData: c.CAData,
|
||||
CertFile: c.CertFile,
|
||||
CertData: c.CertData,
|
||||
KeyFile: c.KeyFile,
|
||||
KeyData: c.KeyData,
|
||||
},
|
||||
BearerToken: c.BearerToken,
|
||||
}
|
||||
if c.EnableHttps && !cfg.HasCA() {
|
||||
cfg.TLS.Insecure = true
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// NodeGetter defines an interface for looking up a node by name
|
||||
type NodeGetter interface {
|
||||
Get(name string, options metav1.GetOptions) (*v1.Node, error)
|
||||
}
|
||||
|
||||
// NodeGetterFunc allows implementing NodeGetter with a function
|
||||
type NodeGetterFunc func(name string, options metav1.GetOptions) (*v1.Node, error)
|
||||
|
||||
func (f NodeGetterFunc) Get(name string, options metav1.GetOptions) (*v1.Node, error) {
|
||||
return f(name, options)
|
||||
}
|
||||
|
||||
// NodeConnectionInfoGetter obtains connection info from the status of a Node API object
|
||||
type NodeConnectionInfoGetter struct {
|
||||
// nodes is used to look up Node objects
|
||||
nodes NodeGetter
|
||||
// scheme is the scheme to use to connect to all kubelets
|
||||
scheme string
|
||||
// defaultPort is the port to use if no Kubelet endpoint port is recorded in the node status
|
||||
defaultPort int
|
||||
// transport is the transport to use to send a request to all kubelets
|
||||
transport http.RoundTripper
|
||||
// preferredAddressTypes specifies the preferred order to use to find a node address
|
||||
preferredAddressTypes []v1.NodeAddressType
|
||||
}
|
||||
|
||||
func NewNodeConnectionInfoGetter(nodes NodeGetter, config KubeletClientConfig) (ConnectionInfoGetter, error) {
|
||||
scheme := "http"
|
||||
if config.EnableHttps {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
transport, err := MakeTransport(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
types := []v1.NodeAddressType{}
|
||||
for _, t := range config.PreferredAddressTypes {
|
||||
types = append(types, v1.NodeAddressType(t))
|
||||
}
|
||||
|
||||
return &NodeConnectionInfoGetter{
|
||||
nodes: nodes,
|
||||
scheme: scheme,
|
||||
defaultPort: int(config.Port),
|
||||
transport: transport,
|
||||
|
||||
preferredAddressTypes: types,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k *NodeConnectionInfoGetter) GetConnectionInfo(nodeName types.NodeName) (*ConnectionInfo, error) {
|
||||
node, err := k.nodes.Get(string(nodeName), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Find a kubelet-reported address, using preferred address type
|
||||
host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Use the kubelet-reported port, if present
|
||||
port := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port)
|
||||
if port <= 0 {
|
||||
port = k.defaultPort
|
||||
}
|
||||
|
||||
return &ConnectionInfo{
|
||||
Scheme: k.scheme,
|
||||
Hostname: host,
|
||||
Port: strconv.Itoa(port),
|
||||
Transport: k.transport,
|
||||
}, nil
|
||||
}
|
||||
70
vendor/k8s.io/kubernetes/pkg/kubelet/client/kubelet_client_test.go
generated
vendored
Normal file
70
vendor/k8s.io/kubernetes/pkg/kubelet/client/kubelet_client_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright 2014 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 client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// Ensure a node client can be used as a NodeGetter.
|
||||
// This allows anyone with a node client to easily construct a NewNodeConnectionInfoGetter.
|
||||
var _ = NodeGetter(v1core.NodeInterface(nil))
|
||||
|
||||
func TestMakeTransportInvalid(t *testing.T) {
|
||||
config := &KubeletClientConfig{
|
||||
EnableHttps: true,
|
||||
//Invalid certificate and key path
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
CertFile: "../../client/testdata/mycertinvalid.cer",
|
||||
KeyFile: "../../client/testdata/mycertinvalid.key",
|
||||
CAFile: "../../client/testdata/myCA.cer",
|
||||
},
|
||||
}
|
||||
|
||||
rt, err := MakeTransport(config)
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error")
|
||||
}
|
||||
if rt != nil {
|
||||
t.Error("rt should be nil as we provided invalid cert file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeTransportValid(t *testing.T) {
|
||||
config := &KubeletClientConfig{
|
||||
Port: 1234,
|
||||
EnableHttps: true,
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
CertFile: "../../client/testdata/mycertvalid.cer",
|
||||
// TLS Configuration, only applies if EnableHttps is true.
|
||||
KeyFile: "../../client/testdata/mycertvalid.key",
|
||||
// TLS Configuration, only applies if EnableHttps is true.
|
||||
CAFile: "../../client/testdata/myCA.cer",
|
||||
},
|
||||
}
|
||||
|
||||
rt, err := MakeTransport(config)
|
||||
if err != nil {
|
||||
t.Errorf("Not expecting an error #%v", err)
|
||||
}
|
||||
if rt == nil {
|
||||
t.Error("rt should not be nil")
|
||||
}
|
||||
}
|
||||
131
vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD
generated
vendored
Normal file
131
vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cgroup_manager_unsupported.go",
|
||||
"container_manager.go",
|
||||
"container_manager_stub.go",
|
||||
"container_manager_unsupported.go",
|
||||
"device_plugin_handler.go",
|
||||
"device_plugin_handler_stub.go",
|
||||
"fake_internal_container_lifecycle.go",
|
||||
"helpers_unsupported.go",
|
||||
"internal_container_lifecycle.go",
|
||||
"pod_container_manager_stub.go",
|
||||
"pod_container_manager_unsupported.go",
|
||||
"types.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"cgroup_manager_linux.go",
|
||||
"container_manager_linux.go",
|
||||
"helpers_linux.go",
|
||||
"node_container_manager.go",
|
||||
"pod_container_manager_linux.go",
|
||||
"qos_container_manager_linux.go",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"container_manager_windows.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/kubelet/apis/cri:go_default_library",
|
||||
"//pkg/kubelet/apis/deviceplugin/v1alpha1:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/cadvisor:go_default_library",
|
||||
"//pkg/kubelet/cm/cpumanager:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/deviceplugin:go_default_library",
|
||||
"//pkg/kubelet/eviction/api:go_default_library",
|
||||
"//pkg/kubelet/status:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/api/v1/helper/qos:go_default_library",
|
||||
"//pkg/api/v1/resource:go_default_library",
|
||||
"//pkg/kubelet/cm/util:go_default_library",
|
||||
"//pkg/kubelet/events:go_default_library",
|
||||
"//pkg/kubelet/metrics:go_default_library",
|
||||
"//pkg/kubelet/qos:go_default_library",
|
||||
"//pkg/util/file:go_default_library",
|
||||
"//pkg/util/oom:go_default_library",
|
||||
"//pkg/util/procfs:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//vendor/github.com/docker/go-units:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd:go_default_library",
|
||||
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"container_manager_unsupported_test.go",
|
||||
"device_plugin_handler_test.go",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"cgroup_manager_linux_test.go",
|
||||
"cgroup_manager_test.go",
|
||||
"container_manager_linux_test.go",
|
||||
"helpers_linux_test.go",
|
||||
"node_container_manager_test.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/deviceplugin/v1alpha1:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/eviction/api:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/cm/cpumanager:all-srcs",
|
||||
"//pkg/kubelet/cm/cpuset:all-srcs",
|
||||
"//pkg/kubelet/cm/util:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
570
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_linux.go
generated
vendored
Normal file
570
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
Copyright 2016 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 cm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/golang/glog"
|
||||
libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
cgroupsystemd "github.com/opencontainers/runc/libcontainer/cgroups/systemd"
|
||||
libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
kubefeatures "k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/kubelet/metrics"
|
||||
)
|
||||
|
||||
// libcontainerCgroupManagerType defines how to interface with libcontainer
|
||||
type libcontainerCgroupManagerType string
|
||||
|
||||
const (
|
||||
// libcontainerCgroupfs means use libcontainer with cgroupfs
|
||||
libcontainerCgroupfs libcontainerCgroupManagerType = "cgroupfs"
|
||||
// libcontainerSystemd means use libcontainer with systemd
|
||||
libcontainerSystemd libcontainerCgroupManagerType = "systemd"
|
||||
)
|
||||
|
||||
// hugePageSizeList is useful for converting to the hugetlb canonical unit
|
||||
// which is what is expected when interacting with libcontainer
|
||||
var hugePageSizeList = []string{"B", "kB", "MB", "GB", "TB", "PB"}
|
||||
|
||||
// ConvertCgroupNameToSystemd converts the internal cgroup name to a systemd name.
|
||||
// For example, the name /Burstable/pod_123-456 becomes Burstable-pod_123_456.slice
|
||||
// If outputToCgroupFs is true, it expands the systemd name into the cgroupfs form.
|
||||
// For example, it will return /Burstable.slice/Burstable-pod_123_456.slice in above scenario.
|
||||
func ConvertCgroupNameToSystemd(cgroupName CgroupName, outputToCgroupFs bool) string {
|
||||
name := string(cgroupName)
|
||||
result := ""
|
||||
if name != "" && name != "/" {
|
||||
parts := strings.Split(name, "/")
|
||||
results := []string{}
|
||||
for _, part := range parts {
|
||||
// ignore leading stuff
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
// detect if we are given a systemd style name.
|
||||
// if so, we do not want to do double encoding.
|
||||
if strings.HasSuffix(part, ".slice") {
|
||||
part = strings.TrimSuffix(part, ".slice")
|
||||
separatorIndex := strings.LastIndex(part, "-")
|
||||
if separatorIndex >= 0 && separatorIndex < len(part) {
|
||||
part = part[separatorIndex+1:]
|
||||
}
|
||||
} else {
|
||||
// systemd treats - as a step in the hierarchy, we convert all - to _
|
||||
part = strings.Replace(part, "-", "_", -1)
|
||||
}
|
||||
results = append(results, part)
|
||||
}
|
||||
// each part is appended with systemd style -
|
||||
result = strings.Join(results, "-")
|
||||
} else {
|
||||
// root converts to -
|
||||
result = "-"
|
||||
}
|
||||
// always have a .slice suffix
|
||||
if !strings.HasSuffix(result, ".slice") {
|
||||
result = result + ".slice"
|
||||
}
|
||||
|
||||
// if the caller desired the result in cgroupfs format...
|
||||
if outputToCgroupFs {
|
||||
var err error
|
||||
result, err = cgroupsystemd.ExpandSlice(result)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("error adapting cgroup name, input: %v, err: %v", name, err))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ConvertCgroupFsNameToSystemd converts an expanded cgroupfs name to its systemd name.
|
||||
// For example, it will convert test.slice/test-a.slice/test-a-b.slice to become test-a-b.slice
|
||||
// NOTE: this is public right now to allow its usage in dockermanager and dockershim, ideally both those
|
||||
// code areas could use something from libcontainer if we get this style function upstream.
|
||||
func ConvertCgroupFsNameToSystemd(cgroupfsName string) (string, error) {
|
||||
// TODO: see if libcontainer systemd implementation could use something similar, and if so, move
|
||||
// this function up to that library. At that time, it would most likely do validation specific to systemd
|
||||
// above and beyond the simple assumption here that the base of the path encodes the hierarchy
|
||||
// per systemd convention.
|
||||
return path.Base(cgroupfsName), nil
|
||||
}
|
||||
|
||||
// libcontainerAdapter provides a simplified interface to libcontainer based on libcontainer type.
|
||||
type libcontainerAdapter struct {
|
||||
// cgroupManagerType defines how to interface with libcontainer
|
||||
cgroupManagerType libcontainerCgroupManagerType
|
||||
}
|
||||
|
||||
// newLibcontainerAdapter returns a configured libcontainerAdapter for specified manager.
|
||||
// it does any initialization required by that manager to function.
|
||||
func newLibcontainerAdapter(cgroupManagerType libcontainerCgroupManagerType) *libcontainerAdapter {
|
||||
return &libcontainerAdapter{cgroupManagerType: cgroupManagerType}
|
||||
}
|
||||
|
||||
// newManager returns an implementation of cgroups.Manager
|
||||
func (l *libcontainerAdapter) newManager(cgroups *libcontainerconfigs.Cgroup, paths map[string]string) (libcontainercgroups.Manager, error) {
|
||||
switch l.cgroupManagerType {
|
||||
case libcontainerCgroupfs:
|
||||
return &cgroupfs.Manager{
|
||||
Cgroups: cgroups,
|
||||
Paths: paths,
|
||||
}, nil
|
||||
case libcontainerSystemd:
|
||||
// this means you asked systemd to manage cgroups, but systemd was not on the host, so all you can do is panic...
|
||||
if !cgroupsystemd.UseSystemd() {
|
||||
panic("systemd cgroup manager not available")
|
||||
}
|
||||
return &cgroupsystemd.Manager{
|
||||
Cgroups: cgroups,
|
||||
Paths: paths,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid cgroup manager configuration")
|
||||
}
|
||||
|
||||
func (l *libcontainerAdapter) revertName(name string) CgroupName {
|
||||
if l.cgroupManagerType != libcontainerSystemd {
|
||||
return CgroupName(name)
|
||||
}
|
||||
|
||||
driverName, err := ConvertCgroupFsNameToSystemd(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
driverName = strings.TrimSuffix(driverName, ".slice")
|
||||
driverName = strings.Replace(driverName, "-", "/", -1)
|
||||
driverName = strings.Replace(driverName, "_", "-", -1)
|
||||
return CgroupName(driverName)
|
||||
}
|
||||
|
||||
// adaptName converts a CgroupName identifier to a driver specific conversion value.
|
||||
// if outputToCgroupFs is true, the result is returned in the cgroupfs format rather than the driver specific form.
|
||||
func (l *libcontainerAdapter) adaptName(cgroupName CgroupName, outputToCgroupFs bool) string {
|
||||
if l.cgroupManagerType != libcontainerSystemd {
|
||||
name := string(cgroupName)
|
||||
return name
|
||||
}
|
||||
return ConvertCgroupNameToSystemd(cgroupName, outputToCgroupFs)
|
||||
}
|
||||
|
||||
// CgroupSubsystems holds information about the mounted cgroup subsystems
|
||||
type CgroupSubsystems struct {
|
||||
// Cgroup subsystem mounts.
|
||||
// e.g.: "/sys/fs/cgroup/cpu" -> ["cpu", "cpuacct"]
|
||||
Mounts []libcontainercgroups.Mount
|
||||
|
||||
// Cgroup subsystem to their mount location.
|
||||
// e.g.: "cpu" -> "/sys/fs/cgroup/cpu"
|
||||
MountPoints map[string]string
|
||||
}
|
||||
|
||||
// cgroupManagerImpl implements the CgroupManager interface.
|
||||
// Its a stateless object which can be used to
|
||||
// update,create or delete any number of cgroups
|
||||
// It uses the Libcontainer raw fs cgroup manager for cgroup management.
|
||||
type cgroupManagerImpl struct {
|
||||
// subsystems holds information about all the
|
||||
// mounted cgroup subsystems on the node
|
||||
subsystems *CgroupSubsystems
|
||||
// simplifies interaction with libcontainer and its cgroup managers
|
||||
adapter *libcontainerAdapter
|
||||
}
|
||||
|
||||
// Make sure that cgroupManagerImpl implements the CgroupManager interface
|
||||
var _ CgroupManager = &cgroupManagerImpl{}
|
||||
|
||||
// NewCgroupManager is a factory method that returns a CgroupManager
|
||||
func NewCgroupManager(cs *CgroupSubsystems, cgroupDriver string) CgroupManager {
|
||||
managerType := libcontainerCgroupfs
|
||||
if cgroupDriver == string(libcontainerSystemd) {
|
||||
managerType = libcontainerSystemd
|
||||
}
|
||||
return &cgroupManagerImpl{
|
||||
subsystems: cs,
|
||||
adapter: newLibcontainerAdapter(managerType),
|
||||
}
|
||||
}
|
||||
|
||||
// Name converts the cgroup to the driver specific value in cgroupfs form.
|
||||
func (m *cgroupManagerImpl) Name(name CgroupName) string {
|
||||
return m.adapter.adaptName(name, true)
|
||||
}
|
||||
|
||||
// CgroupName converts the literal cgroupfs name on the host to an internal identifier.
|
||||
func (m *cgroupManagerImpl) CgroupName(name string) CgroupName {
|
||||
return m.adapter.revertName(name)
|
||||
}
|
||||
|
||||
// buildCgroupPaths builds a path to each cgroup subsystem for the specified name.
|
||||
func (m *cgroupManagerImpl) buildCgroupPaths(name CgroupName) map[string]string {
|
||||
cgroupFsAdaptedName := m.Name(name)
|
||||
cgroupPaths := make(map[string]string, len(m.subsystems.MountPoints))
|
||||
for key, val := range m.subsystems.MountPoints {
|
||||
cgroupPaths[key] = path.Join(val, cgroupFsAdaptedName)
|
||||
}
|
||||
return cgroupPaths
|
||||
}
|
||||
|
||||
// Exists checks if all subsystem cgroups already exist
|
||||
func (m *cgroupManagerImpl) Exists(name CgroupName) bool {
|
||||
// Get map of all cgroup paths on the system for the particular cgroup
|
||||
cgroupPaths := m.buildCgroupPaths(name)
|
||||
|
||||
// the presence of alternative control groups not known to runc confuses
|
||||
// the kubelet existence checks.
|
||||
// ideally, we would have a mechanism in runc to support Exists() logic
|
||||
// scoped to the set control groups it understands. this is being discussed
|
||||
// in https://github.com/opencontainers/runc/issues/1440
|
||||
// once resolved, we can remove this code.
|
||||
whitelistControllers := sets.NewString("cpu", "cpuacct", "cpuset", "memory", "systemd")
|
||||
|
||||
// If even one cgroup path doesn't exist, then the cgroup doesn't exist.
|
||||
for controller, path := range cgroupPaths {
|
||||
// ignore mounts we don't care about
|
||||
if !whitelistControllers.Has(controller) {
|
||||
continue
|
||||
}
|
||||
if !libcontainercgroups.PathExists(path) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Destroy destroys the specified cgroup
|
||||
func (m *cgroupManagerImpl) Destroy(cgroupConfig *CgroupConfig) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
metrics.CgroupManagerLatency.WithLabelValues("destroy").Observe(metrics.SinceInMicroseconds(start))
|
||||
}()
|
||||
|
||||
cgroupPaths := m.buildCgroupPaths(cgroupConfig.Name)
|
||||
|
||||
// we take the location in traditional cgroupfs format.
|
||||
abstractCgroupFsName := string(cgroupConfig.Name)
|
||||
abstractParent := CgroupName(path.Dir(abstractCgroupFsName))
|
||||
abstractName := CgroupName(path.Base(abstractCgroupFsName))
|
||||
|
||||
driverParent := m.adapter.adaptName(abstractParent, false)
|
||||
driverName := m.adapter.adaptName(abstractName, false)
|
||||
|
||||
// this is an ugly abstraction bleed, but systemd cgroup driver requires full paths...
|
||||
if m.adapter.cgroupManagerType == libcontainerSystemd {
|
||||
driverName = m.adapter.adaptName(cgroupConfig.Name, false)
|
||||
}
|
||||
|
||||
// Initialize libcontainer's cgroup config with driver specific naming.
|
||||
libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
|
||||
Name: driverName,
|
||||
Parent: driverParent,
|
||||
}
|
||||
|
||||
manager, err := m.adapter.newManager(libcontainerCgroupConfig, cgroupPaths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete cgroups using libcontainers Managers Destroy() method
|
||||
if err = manager.Destroy(); err != nil {
|
||||
return fmt.Errorf("Unable to destroy cgroup paths for cgroup %v : %v", cgroupConfig.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type subsystem interface {
|
||||
// Name returns the name of the subsystem.
|
||||
Name() string
|
||||
// Set the cgroup represented by cgroup.
|
||||
Set(path string, cgroup *libcontainerconfigs.Cgroup) error
|
||||
// GetStats returns the statistics associated with the cgroup
|
||||
GetStats(path string, stats *libcontainercgroups.Stats) error
|
||||
}
|
||||
|
||||
// getSupportedSubsystems returns list of subsystems supported
|
||||
func getSupportedSubsystems() []subsystem {
|
||||
supportedSubsystems := []subsystem{
|
||||
&cgroupfs.MemoryGroup{},
|
||||
&cgroupfs.CpuGroup{},
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.HugePages) {
|
||||
supportedSubsystems = append(supportedSubsystems, &cgroupfs.HugetlbGroup{})
|
||||
}
|
||||
return supportedSubsystems
|
||||
}
|
||||
|
||||
// setSupportedSubsystems sets cgroup resource limits only on the supported
|
||||
// subsystems. ie. cpu and memory. We don't use libcontainer's cgroup/fs/Set()
|
||||
// method as it doesn't allow us to skip updates on the devices cgroup
|
||||
// Allowing or denying all devices by writing 'a' to devices.allow or devices.deny is
|
||||
// not possible once the device cgroups has children. Once the pod level cgroup are
|
||||
// created under the QOS level cgroup we cannot update the QOS level device cgroup.
|
||||
// We would like to skip setting any values on the device cgroup in this case
|
||||
// but this is not possible with libcontainers Set() method
|
||||
// See https://github.com/opencontainers/runc/issues/932
|
||||
func setSupportedSubsystems(cgroupConfig *libcontainerconfigs.Cgroup) error {
|
||||
for _, sys := range getSupportedSubsystems() {
|
||||
if _, ok := cgroupConfig.Paths[sys.Name()]; !ok {
|
||||
return fmt.Errorf("Failed to find subsystem mount for subsystem: %v", sys.Name())
|
||||
}
|
||||
if err := sys.Set(cgroupConfig.Paths[sys.Name()], cgroupConfig); err != nil {
|
||||
return fmt.Errorf("Failed to set config for supported subsystems : %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcontainerconfigs.Resources {
|
||||
resources := &libcontainerconfigs.Resources{}
|
||||
if resourceConfig == nil {
|
||||
return resources
|
||||
}
|
||||
if resourceConfig.Memory != nil {
|
||||
resources.Memory = *resourceConfig.Memory
|
||||
}
|
||||
if resourceConfig.CpuShares != nil {
|
||||
resources.CpuShares = *resourceConfig.CpuShares
|
||||
}
|
||||
if resourceConfig.CpuQuota != nil {
|
||||
resources.CpuQuota = *resourceConfig.CpuQuota
|
||||
}
|
||||
if resourceConfig.CpuPeriod != nil {
|
||||
resources.CpuPeriod = *resourceConfig.CpuPeriod
|
||||
}
|
||||
|
||||
// if huge pages are enabled, we set them in libcontainer
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.HugePages) {
|
||||
// for each page size enumerated, set that value
|
||||
pageSizes := sets.NewString()
|
||||
for pageSize, limit := range resourceConfig.HugePageLimit {
|
||||
sizeString := units.CustomSize("%g%s", float64(pageSize), 1024.0, hugePageSizeList)
|
||||
resources.HugetlbLimit = append(resources.HugetlbLimit, &libcontainerconfigs.HugepageLimit{
|
||||
Pagesize: sizeString,
|
||||
Limit: uint64(limit),
|
||||
})
|
||||
pageSizes.Insert(sizeString)
|
||||
}
|
||||
// for each page size omitted, limit to 0
|
||||
for _, pageSize := range cgroupfs.HugePageSizes {
|
||||
if pageSizes.Has(pageSize) {
|
||||
continue
|
||||
}
|
||||
resources.HugetlbLimit = append(resources.HugetlbLimit, &libcontainerconfigs.HugepageLimit{
|
||||
Pagesize: pageSize,
|
||||
Limit: uint64(0),
|
||||
})
|
||||
}
|
||||
}
|
||||
return resources
|
||||
}
|
||||
|
||||
// Update updates the cgroup with the specified Cgroup Configuration
|
||||
func (m *cgroupManagerImpl) Update(cgroupConfig *CgroupConfig) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
metrics.CgroupManagerLatency.WithLabelValues("update").Observe(metrics.SinceInMicroseconds(start))
|
||||
}()
|
||||
|
||||
// Extract the cgroup resource parameters
|
||||
resourceConfig := cgroupConfig.ResourceParameters
|
||||
resources := m.toResources(resourceConfig)
|
||||
|
||||
cgroupPaths := m.buildCgroupPaths(cgroupConfig.Name)
|
||||
|
||||
// we take the location in traditional cgroupfs format.
|
||||
abstractCgroupFsName := string(cgroupConfig.Name)
|
||||
abstractParent := CgroupName(path.Dir(abstractCgroupFsName))
|
||||
abstractName := CgroupName(path.Base(abstractCgroupFsName))
|
||||
|
||||
driverParent := m.adapter.adaptName(abstractParent, false)
|
||||
driverName := m.adapter.adaptName(abstractName, false)
|
||||
|
||||
// this is an ugly abstraction bleed, but systemd cgroup driver requires full paths...
|
||||
if m.adapter.cgroupManagerType == libcontainerSystemd {
|
||||
driverName = m.adapter.adaptName(cgroupConfig.Name, false)
|
||||
}
|
||||
|
||||
// Initialize libcontainer's cgroup config
|
||||
libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
|
||||
Name: driverName,
|
||||
Parent: driverParent,
|
||||
Resources: resources,
|
||||
Paths: cgroupPaths,
|
||||
}
|
||||
|
||||
if err := setSupportedSubsystems(libcontainerCgroupConfig); err != nil {
|
||||
return fmt.Errorf("failed to set supported cgroup subsystems for cgroup %v: %v", cgroupConfig.Name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create creates the specified cgroup
|
||||
func (m *cgroupManagerImpl) Create(cgroupConfig *CgroupConfig) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
metrics.CgroupManagerLatency.WithLabelValues("create").Observe(metrics.SinceInMicroseconds(start))
|
||||
}()
|
||||
|
||||
// we take the location in traditional cgroupfs format.
|
||||
abstractCgroupFsName := string(cgroupConfig.Name)
|
||||
abstractParent := CgroupName(path.Dir(abstractCgroupFsName))
|
||||
abstractName := CgroupName(path.Base(abstractCgroupFsName))
|
||||
|
||||
driverParent := m.adapter.adaptName(abstractParent, false)
|
||||
driverName := m.adapter.adaptName(abstractName, false)
|
||||
// this is an ugly abstraction bleed, but systemd cgroup driver requires full paths...
|
||||
if m.adapter.cgroupManagerType == libcontainerSystemd {
|
||||
driverName = m.adapter.adaptName(cgroupConfig.Name, false)
|
||||
}
|
||||
|
||||
resources := m.toResources(cgroupConfig.ResourceParameters)
|
||||
// Initialize libcontainer's cgroup config with driver specific naming.
|
||||
libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{
|
||||
Name: driverName,
|
||||
Parent: driverParent,
|
||||
Resources: resources,
|
||||
}
|
||||
|
||||
// get the manager with the specified cgroup configuration
|
||||
manager, err := m.adapter.newManager(libcontainerCgroupConfig, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply(-1) is a hack to create the cgroup directories for each resource
|
||||
// subsystem. The function [cgroups.Manager.apply()] applies cgroup
|
||||
// configuration to the process with the specified pid.
|
||||
// It creates cgroup files for each subsystems and writes the pid
|
||||
// in the tasks file. We use the function to create all the required
|
||||
// cgroup files but not attach any "real" pid to the cgroup.
|
||||
if err := manager.Apply(-1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// it may confuse why we call set after we do apply, but the issue is that runc
|
||||
// follows a similar pattern. it's needed to ensure cpu quota is set properly.
|
||||
m.Update(cgroupConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scans through all subsystems to find pids associated with specified cgroup.
|
||||
func (m *cgroupManagerImpl) Pids(name CgroupName) []int {
|
||||
// we need the driver specific name
|
||||
cgroupFsName := m.Name(name)
|
||||
|
||||
// Get a list of processes that we need to kill
|
||||
pidsToKill := sets.NewInt()
|
||||
var pids []int
|
||||
for _, val := range m.subsystems.MountPoints {
|
||||
dir := path.Join(val, cgroupFsName)
|
||||
_, err := os.Stat(dir)
|
||||
if os.IsNotExist(err) {
|
||||
// The subsystem pod cgroup is already deleted
|
||||
// do nothing, continue
|
||||
continue
|
||||
}
|
||||
// Get a list of pids that are still charged to the pod's cgroup
|
||||
pids, err = getCgroupProcs(dir)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
pidsToKill.Insert(pids...)
|
||||
|
||||
// WalkFunc which is called for each file and directory in the pod cgroup dir
|
||||
visitor := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
glog.V(4).Infof("cgroup manager encountered error scanning cgroup path %q: %v", path, err)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
pids, err = getCgroupProcs(path)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("cgroup manager encountered error getting procs for cgroup path %q: %v", path, err)
|
||||
return filepath.SkipDir
|
||||
}
|
||||
pidsToKill.Insert(pids...)
|
||||
return nil
|
||||
}
|
||||
// Walk through the pod cgroup directory to check if
|
||||
// container cgroups haven't been GCed yet. Get attached processes to
|
||||
// all such unwanted containers under the pod cgroup
|
||||
if err = filepath.Walk(dir, visitor); err != nil {
|
||||
glog.V(4).Infof("cgroup manager encountered error scanning pids for directory: %q: %v", dir, err)
|
||||
}
|
||||
}
|
||||
return pidsToKill.List()
|
||||
}
|
||||
|
||||
// ReduceCPULimits reduces the cgroup's cpu shares to the lowest possible value
|
||||
func (m *cgroupManagerImpl) ReduceCPULimits(cgroupName CgroupName) error {
|
||||
// Set lowest possible CpuShares value for the cgroup
|
||||
minimumCPUShares := uint64(MinShares)
|
||||
resources := &ResourceConfig{
|
||||
CpuShares: &minimumCPUShares,
|
||||
}
|
||||
containerConfig := &CgroupConfig{
|
||||
Name: cgroupName,
|
||||
ResourceParameters: resources,
|
||||
}
|
||||
return m.Update(containerConfig)
|
||||
}
|
||||
|
||||
func getStatsSupportedSubsystems(cgroupPaths map[string]string) (*libcontainercgroups.Stats, error) {
|
||||
stats := libcontainercgroups.NewStats()
|
||||
for _, sys := range getSupportedSubsystems() {
|
||||
if _, ok := cgroupPaths[sys.Name()]; !ok {
|
||||
return nil, fmt.Errorf("Failed to find subsystem mount for subsystem: %v", sys.Name())
|
||||
}
|
||||
if err := sys.GetStats(cgroupPaths[sys.Name()], stats); err != nil {
|
||||
return nil, fmt.Errorf("Failed to get stats for supported subsystems : %v", err)
|
||||
}
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func toResourceStats(stats *libcontainercgroups.Stats) *ResourceStats {
|
||||
return &ResourceStats{
|
||||
MemoryStats: &MemoryStats{
|
||||
Usage: int64(stats.MemoryStats.Usage.Usage),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Get sets the ResourceParameters of the specified cgroup as read from the cgroup fs
|
||||
func (m *cgroupManagerImpl) GetResourceStats(name CgroupName) (*ResourceStats, error) {
|
||||
cgroupPaths := m.buildCgroupPaths(name)
|
||||
stats, err := getStatsSupportedSubsystems(cgroupPaths)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get stats supported cgroup subsystems for cgroup %v: %v", name, err)
|
||||
}
|
||||
return toResourceStats(stats), nil
|
||||
}
|
||||
101
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_linux_test.go
generated
vendored
Normal file
101
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_linux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2016 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 cm
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLibcontainerAdapterAdaptToSystemd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "/",
|
||||
expected: "-.slice",
|
||||
},
|
||||
{
|
||||
input: "/system.slice",
|
||||
expected: "system.slice",
|
||||
},
|
||||
{
|
||||
input: "/system.slice/Burstable",
|
||||
expected: "system-Burstable.slice",
|
||||
},
|
||||
{
|
||||
input: "/Burstable.slice/Burstable-pod_123.slice",
|
||||
expected: "Burstable-pod_123.slice",
|
||||
},
|
||||
{
|
||||
input: "/test.slice/test-a.slice/test-a-b.slice",
|
||||
expected: "test-a-b.slice",
|
||||
},
|
||||
{
|
||||
input: "/test.slice/test-a.slice/test-a-b.slice/Burstable",
|
||||
expected: "test-a-b-Burstable.slice",
|
||||
},
|
||||
{
|
||||
input: "/Burstable",
|
||||
expected: "Burstable.slice",
|
||||
},
|
||||
{
|
||||
input: "/Burstable/pod_123",
|
||||
expected: "Burstable-pod_123.slice",
|
||||
},
|
||||
{
|
||||
input: "/BestEffort/pod_6c1a4e95-6bb6-11e6-bc26-28d2444e470d",
|
||||
expected: "BestEffort-pod_6c1a4e95_6bb6_11e6_bc26_28d2444e470d.slice",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
f := newLibcontainerAdapter(libcontainerSystemd)
|
||||
if actual := f.adaptName(CgroupName(testCase.input), false); actual != testCase.expected {
|
||||
t.Errorf("Unexpected result, input: %v, expected: %v, actual: %v", testCase.input, testCase.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLibcontainerAdapterAdaptToSystemdAsCgroupFs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "/",
|
||||
expected: "/",
|
||||
},
|
||||
{
|
||||
input: "/Burstable",
|
||||
expected: "Burstable.slice/",
|
||||
},
|
||||
{
|
||||
input: "/Burstable/pod_123",
|
||||
expected: "Burstable.slice/Burstable-pod_123.slice/",
|
||||
},
|
||||
{
|
||||
input: "/BestEffort/pod_6c1a4e95-6bb6-11e6-bc26-28d2444e470d",
|
||||
expected: "BestEffort.slice/BestEffort-pod_6c1a4e95_6bb6_11e6_bc26_28d2444e470d.slice/",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
f := newLibcontainerAdapter(libcontainerSystemd)
|
||||
if actual := f.adaptName(CgroupName(testCase.input), true); actual != testCase.expected {
|
||||
t.Errorf("Unexpected result, input: %v, expected: %v, actual: %v", testCase.input, testCase.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
83
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_test.go
generated
vendored
Normal file
83
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2016 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 cm
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected *map[v1.ResourceName]int64
|
||||
}{
|
||||
{
|
||||
input: "memory",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
input: "memory=a",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
input: "memory=a%",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
input: "memory=200%",
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
input: "memory=0%",
|
||||
expected: &map[v1.ResourceName]int64{
|
||||
v1.ResourceMemory: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "memory=100%",
|
||||
expected: &map[v1.ResourceName]int64{
|
||||
v1.ResourceMemory: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
// need to change this when CPU is added as a supported resource
|
||||
input: "memory=100%,cpu=50%",
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
m := kubeletconfig.ConfigurationMap{}
|
||||
m.Set(test.input)
|
||||
actual, err := ParseQOSReserved(m)
|
||||
if actual != nil && test.expected == nil {
|
||||
t.Errorf("Unexpected success, input: %v, expected: %v, actual: %v, err: %v", test.input, test.expected, actual, err)
|
||||
}
|
||||
if actual == nil && test.expected != nil {
|
||||
t.Errorf("Unexpected failure, input: %v, expected: %v, actual: %v, err: %v", test.input, test.expected, actual, err)
|
||||
}
|
||||
if (actual == nil && test.expected == nil) || reflect.DeepEqual(*actual, *test.expected) {
|
||||
continue
|
||||
}
|
||||
t.Errorf("Unexpected result, input: %v, expected: %v, actual: %v, err: %v", test.input, test.expected, actual, err)
|
||||
}
|
||||
}
|
||||
79
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_unsupported.go
generated
vendored
Normal file
79
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cgroup_manager_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2016 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 cm
|
||||
|
||||
import "fmt"
|
||||
|
||||
type unsupportedCgroupManager struct{}
|
||||
|
||||
// Make sure that unsupportedCgroupManager implements the CgroupManager interface
|
||||
var _ CgroupManager = &unsupportedCgroupManager{}
|
||||
|
||||
type CgroupSubsystems struct {
|
||||
Mounts []interface{}
|
||||
MountPoints map[string]string
|
||||
}
|
||||
|
||||
func NewCgroupManager(_ interface{}) CgroupManager {
|
||||
return &unsupportedCgroupManager{}
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Name(_ CgroupName) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Exists(_ CgroupName) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Destroy(_ *CgroupConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Update(_ *CgroupConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Create(_ *CgroupConfig) error {
|
||||
return fmt.Errorf("Cgroup Manager is not supported in this build")
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) GetResourceStats(name CgroupName) (*ResourceStats, error) {
|
||||
return nil, fmt.Errorf("Cgroup Manager is not supported in this build")
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) Pids(_ CgroupName) []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) CgroupName(name string) CgroupName {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *unsupportedCgroupManager) ReduceCPULimits(cgroupName CgroupName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConvertCgroupFsNameToSystemd(cgroupfsName string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func ConvertCgroupNameToSystemd(cgroupName CgroupName, outputToCgroupFs bool) string {
|
||||
return ""
|
||||
}
|
||||
154
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager.go
generated
vendored
Normal file
154
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
// TODO: Migrate kubelet to either use its own internal objects or client library.
|
||||
"k8s.io/api/core/v1"
|
||||
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ActivePodsFunc func() []*v1.Pod
|
||||
|
||||
// Manages the containers running on a machine.
|
||||
type ContainerManager interface {
|
||||
// Runs the container manager's housekeeping.
|
||||
// - Ensures that the Docker daemon is in a container.
|
||||
// - Creates the system container where all non-containerized processes run.
|
||||
Start(*v1.Node, ActivePodsFunc, status.PodStatusProvider, internalapi.RuntimeService) error
|
||||
|
||||
// Returns resources allocated to system cgroups in the machine.
|
||||
// These cgroups include the system and Kubernetes services.
|
||||
SystemCgroupsLimit() v1.ResourceList
|
||||
|
||||
// Returns a NodeConfig that is being used by the container manager.
|
||||
GetNodeConfig() NodeConfig
|
||||
|
||||
// Returns internal Status.
|
||||
Status() Status
|
||||
|
||||
// NewPodContainerManager is a factory method which returns a podContainerManager object
|
||||
// Returns a noop implementation if qos cgroup hierarchy is not enabled
|
||||
NewPodContainerManager() PodContainerManager
|
||||
|
||||
// GetMountedSubsystems returns the mounted cgroup subsystems on the node
|
||||
GetMountedSubsystems() *CgroupSubsystems
|
||||
|
||||
// GetQOSContainersInfo returns the names of top level QoS containers
|
||||
GetQOSContainersInfo() QOSContainersInfo
|
||||
|
||||
// GetNodeAllocatable returns the amount of compute resources that have to be reserved from scheduling.
|
||||
GetNodeAllocatableReservation() v1.ResourceList
|
||||
|
||||
// GetCapacity returns the amount of compute resources tracked by container manager available on the node.
|
||||
GetCapacity() v1.ResourceList
|
||||
|
||||
// UpdateQOSCgroups performs housekeeping updates to ensure that the top
|
||||
// level QoS containers have their desired state in a thread-safe way
|
||||
UpdateQOSCgroups() error
|
||||
|
||||
// Returns RunContainerOptions with devices, mounts, and env fields populated for
|
||||
// extended resources required by container.
|
||||
GetResources(pod *v1.Pod, container *v1.Container, activePods []*v1.Pod) (*kubecontainer.RunContainerOptions, error)
|
||||
|
||||
InternalContainerLifecycle() InternalContainerLifecycle
|
||||
}
|
||||
|
||||
type NodeConfig struct {
|
||||
RuntimeCgroupsName string
|
||||
SystemCgroupsName string
|
||||
KubeletCgroupsName string
|
||||
ContainerRuntime string
|
||||
CgroupsPerQOS bool
|
||||
CgroupRoot string
|
||||
CgroupDriver string
|
||||
ProtectKernelDefaults bool
|
||||
NodeAllocatableConfig
|
||||
ExperimentalQOSReserved map[v1.ResourceName]int64
|
||||
ExperimentalCPUManagerPolicy string
|
||||
ExperimentalCPUManagerReconcilePeriod time.Duration
|
||||
}
|
||||
|
||||
type NodeAllocatableConfig struct {
|
||||
KubeReservedCgroupName string
|
||||
SystemReservedCgroupName string
|
||||
EnforceNodeAllocatable sets.String
|
||||
KubeReserved v1.ResourceList
|
||||
SystemReserved v1.ResourceList
|
||||
HardEvictionThresholds []evictionapi.Threshold
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
// Any soft requirements that were unsatisfied.
|
||||
SoftRequirements error
|
||||
}
|
||||
|
||||
const (
|
||||
// Uer visible keys for managing node allocatable enforcement on the node.
|
||||
NodeAllocatableEnforcementKey = "pods"
|
||||
SystemReservedEnforcementKey = "system-reserved"
|
||||
KubeReservedEnforcementKey = "kube-reserved"
|
||||
)
|
||||
|
||||
// containerManager for the kubelet is currently an injected dependency.
|
||||
// We need to parse the --qos-reserve-requests option in
|
||||
// cmd/kubelet/app/server.go and there isn't really a good place to put
|
||||
// the code. If/When the kubelet dependency injection gets worked out,
|
||||
// maybe there will be a better place for it.
|
||||
func parsePercentage(v string) (int64, error) {
|
||||
if !strings.HasSuffix(v, "%") {
|
||||
return 0, fmt.Errorf("percentage expected, got '%s'", v)
|
||||
}
|
||||
percentage, err := strconv.ParseInt(strings.TrimRight(v, "%"), 10, 0)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid number in percentage '%s'", v)
|
||||
}
|
||||
if percentage < 0 || percentage > 100 {
|
||||
return 0, fmt.Errorf("percentage must be between 0 and 100")
|
||||
}
|
||||
return percentage, nil
|
||||
}
|
||||
|
||||
// ParseQOSReserved parses the --qos-reserve-requests option
|
||||
func ParseQOSReserved(m kubeletconfig.ConfigurationMap) (*map[v1.ResourceName]int64, error) {
|
||||
reservations := make(map[v1.ResourceName]int64)
|
||||
for k, v := range m {
|
||||
switch v1.ResourceName(k) {
|
||||
// Only memory resources are supported.
|
||||
case v1.ResourceMemory:
|
||||
q, err := parsePercentage(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reservations[v1.ResourceName(k)] = q
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot reserve %q resource", k)
|
||||
}
|
||||
}
|
||||
return &reservations, nil
|
||||
}
|
||||
959
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go
generated
vendored
Normal file
959
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,959 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/record"
|
||||
kubefeatures "k8s.io/kubernetes/pkg/features"
|
||||
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager"
|
||||
cmutil "k8s.io/kubernetes/pkg/kubelet/cm/util"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
utilfile "k8s.io/kubernetes/pkg/util/file"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/util/oom"
|
||||
"k8s.io/kubernetes/pkg/util/procfs"
|
||||
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
)
|
||||
|
||||
const (
|
||||
// The percent of the machine memory capacity. The value is used to calculate
|
||||
// docker memory resource container's hardlimit to workaround docker memory
|
||||
// leakage issue. Please see kubernetes/issues/9881 for more detail.
|
||||
DockerMemoryLimitThresholdPercent = 70
|
||||
// The minimum memory limit allocated to docker container: 150Mi
|
||||
MinDockerMemoryLimit = 150 * 1024 * 1024
|
||||
|
||||
dockerProcessName = "docker"
|
||||
dockerPidFile = "/var/run/docker.pid"
|
||||
containerdProcessName = "docker-containerd"
|
||||
containerdPidFile = "/run/docker/libcontainerd/docker-containerd.pid"
|
||||
)
|
||||
|
||||
var (
|
||||
// The docker version in which containerd was introduced.
|
||||
containerdAPIVersion = utilversion.MustParseGeneric("1.23")
|
||||
)
|
||||
|
||||
// A non-user container tracked by the Kubelet.
|
||||
type systemContainer struct {
|
||||
// Absolute name of the container.
|
||||
name string
|
||||
|
||||
// CPU limit in millicores.
|
||||
cpuMillicores int64
|
||||
|
||||
// Function that ensures the state of the container.
|
||||
// m is the cgroup manager for the specified container.
|
||||
ensureStateFunc func(m *fs.Manager) error
|
||||
|
||||
// Manager for the cgroups of the external container.
|
||||
manager *fs.Manager
|
||||
}
|
||||
|
||||
func newSystemCgroups(containerName string) *systemContainer {
|
||||
return &systemContainer{
|
||||
name: containerName,
|
||||
manager: createManager(containerName),
|
||||
}
|
||||
}
|
||||
|
||||
type containerManagerImpl struct {
|
||||
sync.RWMutex
|
||||
cadvisorInterface cadvisor.Interface
|
||||
mountUtil mount.Interface
|
||||
NodeConfig
|
||||
status Status
|
||||
// External containers being managed.
|
||||
systemContainers []*systemContainer
|
||||
qosContainers QOSContainersInfo
|
||||
// Tasks that are run periodically
|
||||
periodicTasks []func()
|
||||
// holds all the mounted cgroup subsystems
|
||||
subsystems *CgroupSubsystems
|
||||
nodeInfo *v1.Node
|
||||
// Interface for cgroup management
|
||||
cgroupManager CgroupManager
|
||||
// Capacity of this node.
|
||||
capacity v1.ResourceList
|
||||
// Absolute cgroupfs path to a cgroup that Kubelet needs to place all pods under.
|
||||
// This path include a top level container for enforcing Node Allocatable.
|
||||
cgroupRoot string
|
||||
// Event recorder interface.
|
||||
recorder record.EventRecorder
|
||||
// Interface for QoS cgroup management
|
||||
qosContainerManager QOSContainerManager
|
||||
// Interface for exporting and allocating devices reported by device plugins.
|
||||
devicePluginHandler DevicePluginHandler
|
||||
// Interface for CPU affinity management.
|
||||
cpuManager cpumanager.Manager
|
||||
}
|
||||
|
||||
type features struct {
|
||||
cpuHardcapping bool
|
||||
}
|
||||
|
||||
var _ ContainerManager = &containerManagerImpl{}
|
||||
|
||||
// checks if the required cgroups subsystems are mounted.
|
||||
// As of now, only 'cpu' and 'memory' are required.
|
||||
// cpu quota is a soft requirement.
|
||||
func validateSystemRequirements(mountUtil mount.Interface) (features, error) {
|
||||
const (
|
||||
cgroupMountType = "cgroup"
|
||||
localErr = "system validation failed"
|
||||
)
|
||||
var (
|
||||
cpuMountPoint string
|
||||
f features
|
||||
)
|
||||
mountPoints, err := mountUtil.List()
|
||||
if err != nil {
|
||||
return f, fmt.Errorf("%s - %v", localErr, err)
|
||||
}
|
||||
|
||||
expectedCgroups := sets.NewString("cpu", "cpuacct", "cpuset", "memory")
|
||||
for _, mountPoint := range mountPoints {
|
||||
if mountPoint.Type == cgroupMountType {
|
||||
for _, opt := range mountPoint.Opts {
|
||||
if expectedCgroups.Has(opt) {
|
||||
expectedCgroups.Delete(opt)
|
||||
}
|
||||
if opt == "cpu" {
|
||||
cpuMountPoint = mountPoint.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if expectedCgroups.Len() > 0 {
|
||||
return f, fmt.Errorf("%s - Following Cgroup subsystem not mounted: %v", localErr, expectedCgroups.List())
|
||||
}
|
||||
|
||||
// Check if cpu quota is available.
|
||||
// CPU cgroup is required and so it expected to be mounted at this point.
|
||||
periodExists, err := utilfile.FileExists(path.Join(cpuMountPoint, "cpu.cfs_period_us"))
|
||||
if err != nil {
|
||||
glog.Errorf("failed to detect if CPU cgroup cpu.cfs_period_us is available - %v", err)
|
||||
}
|
||||
quotaExists, err := utilfile.FileExists(path.Join(cpuMountPoint, "cpu.cfs_quota_us"))
|
||||
if err != nil {
|
||||
glog.Errorf("failed to detect if CPU cgroup cpu.cfs_quota_us is available - %v", err)
|
||||
}
|
||||
if quotaExists && periodExists {
|
||||
f.cpuHardcapping = true
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// TODO(vmarmol): Add limits to the system containers.
|
||||
// Takes the absolute name of the specified containers.
|
||||
// Empty container name disables use of the specified container.
|
||||
func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.Interface, nodeConfig NodeConfig, failSwapOn bool, devicePluginEnabled bool, recorder record.EventRecorder) (ContainerManager, error) {
|
||||
subsystems, err := GetCgroupSubsystems()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get mounted cgroup subsystems: %v", err)
|
||||
}
|
||||
|
||||
// Check whether swap is enabled. The Kubelet does not support running with swap enabled.
|
||||
cmd := exec.Command("cat", "/proc/swaps")
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf []string
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() { // Splits on newlines by default
|
||||
buf = append(buf, scanner.Text())
|
||||
}
|
||||
if err := cmd.Wait(); err != nil { // Clean up
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Running with swap enabled should be considered an error, but in order to maintain legacy
|
||||
// behavior we have to require an opt-in to this error for a period of time.
|
||||
// If there is more than one line (table headers) in /proc/swaps, swap is enabled and we should
|
||||
// error out unless --fail-swap-on is set to false.
|
||||
if len(buf) > 1 {
|
||||
if failSwapOn {
|
||||
return nil, fmt.Errorf("Running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: %v", buf)
|
||||
}
|
||||
}
|
||||
var capacity = v1.ResourceList{}
|
||||
// It is safe to invoke `MachineInfo` on cAdvisor before logically initializing cAdvisor here because
|
||||
// machine info is computed and cached once as part of cAdvisor object creation.
|
||||
// But `RootFsInfo` and `ImagesFsInfo` are not available at this moment so they will be called later during manager starts
|
||||
machineInfo, err := cadvisorInterface.MachineInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
capacity = cadvisor.CapacityFromMachineInfo(machineInfo)
|
||||
|
||||
cgroupRoot := nodeConfig.CgroupRoot
|
||||
cgroupManager := NewCgroupManager(subsystems, nodeConfig.CgroupDriver)
|
||||
// Check if Cgroup-root actually exists on the node
|
||||
if nodeConfig.CgroupsPerQOS {
|
||||
// this does default to / when enabled, but this tests against regressions.
|
||||
if nodeConfig.CgroupRoot == "" {
|
||||
return nil, fmt.Errorf("invalid configuration: cgroups-per-qos was specified and cgroup-root was not specified. To enable the QoS cgroup hierarchy you need to specify a valid cgroup-root")
|
||||
}
|
||||
|
||||
// we need to check that the cgroup root actually exists for each subsystem
|
||||
// of note, we always use the cgroupfs driver when performing this check since
|
||||
// the input is provided in that format.
|
||||
// this is important because we do not want any name conversion to occur.
|
||||
if !cgroupManager.Exists(CgroupName(cgroupRoot)) {
|
||||
return nil, fmt.Errorf("invalid configuration: cgroup-root %q doesn't exist: %v", cgroupRoot, err)
|
||||
}
|
||||
glog.Infof("container manager verified user specified cgroup-root exists: %v", cgroupRoot)
|
||||
// Include the the top level cgroup for enforcing node allocatable into cgroup-root.
|
||||
// This way, all sub modules can avoid having to understand the concept of node allocatable.
|
||||
cgroupRoot = path.Join(cgroupRoot, defaultNodeAllocatableCgroupName)
|
||||
}
|
||||
glog.Infof("Creating Container Manager object based on Node Config: %+v", nodeConfig)
|
||||
|
||||
qosContainerManager, err := NewQOSContainerManager(subsystems, cgroupRoot, nodeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cm := &containerManagerImpl{
|
||||
cadvisorInterface: cadvisorInterface,
|
||||
mountUtil: mountUtil,
|
||||
NodeConfig: nodeConfig,
|
||||
subsystems: subsystems,
|
||||
cgroupManager: cgroupManager,
|
||||
capacity: capacity,
|
||||
cgroupRoot: cgroupRoot,
|
||||
recorder: recorder,
|
||||
qosContainerManager: qosContainerManager,
|
||||
}
|
||||
|
||||
updateDeviceCapacityFunc := func(updates v1.ResourceList) {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
for k, v := range updates {
|
||||
if v.Value() <= 0 {
|
||||
delete(cm.capacity, k)
|
||||
} else {
|
||||
cm.capacity[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glog.Infof("Creating device plugin handler: %t", devicePluginEnabled)
|
||||
if devicePluginEnabled {
|
||||
cm.devicePluginHandler, err = NewDevicePluginHandlerImpl(updateDeviceCapacityFunc)
|
||||
} else {
|
||||
cm.devicePluginHandler, err = NewDevicePluginHandlerStub()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize CPU manager
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUManager) {
|
||||
cm.cpuManager, err = cpumanager.NewManager(
|
||||
nodeConfig.ExperimentalCPUManagerPolicy,
|
||||
nodeConfig.ExperimentalCPUManagerReconcilePeriod,
|
||||
machineInfo,
|
||||
cm.GetNodeAllocatableReservation(),
|
||||
)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to initialize cpu manager: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return cm, nil
|
||||
}
|
||||
|
||||
// NewPodContainerManager is a factory method returns a PodContainerManager object
|
||||
// If qosCgroups are enabled then it returns the general pod container manager
|
||||
// otherwise it returns a no-op manager which essentially does nothing
|
||||
func (cm *containerManagerImpl) NewPodContainerManager() PodContainerManager {
|
||||
if cm.NodeConfig.CgroupsPerQOS {
|
||||
return &podContainerManagerImpl{
|
||||
qosContainersInfo: cm.GetQOSContainersInfo(),
|
||||
subsystems: cm.subsystems,
|
||||
cgroupManager: cm.cgroupManager,
|
||||
}
|
||||
}
|
||||
return &podContainerManagerNoop{
|
||||
cgroupRoot: CgroupName(cm.cgroupRoot),
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) InternalContainerLifecycle() InternalContainerLifecycle {
|
||||
return &internalContainerLifecycleImpl{cm.cpuManager}
|
||||
}
|
||||
|
||||
// Create a cgroup container manager.
|
||||
func createManager(containerName string) *fs.Manager {
|
||||
allowAllDevices := true
|
||||
return &fs.Manager{
|
||||
Cgroups: &configs.Cgroup{
|
||||
Parent: "/",
|
||||
Name: containerName,
|
||||
Resources: &configs.Resources{
|
||||
AllowAllDevices: &allowAllDevices,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type KernelTunableBehavior string
|
||||
|
||||
const (
|
||||
KernelTunableWarn KernelTunableBehavior = "warn"
|
||||
KernelTunableError KernelTunableBehavior = "error"
|
||||
KernelTunableModify KernelTunableBehavior = "modify"
|
||||
)
|
||||
|
||||
// setupKernelTunables validates kernel tunable flags are set as expected
|
||||
// depending upon the specified option, it will either warn, error, or modify the kernel tunable flags
|
||||
func setupKernelTunables(option KernelTunableBehavior) error {
|
||||
desiredState := map[string]int{
|
||||
utilsysctl.VmOvercommitMemory: utilsysctl.VmOvercommitMemoryAlways,
|
||||
utilsysctl.VmPanicOnOOM: utilsysctl.VmPanicOnOOMInvokeOOMKiller,
|
||||
utilsysctl.KernelPanic: utilsysctl.KernelPanicRebootTimeout,
|
||||
utilsysctl.KernelPanicOnOops: utilsysctl.KernelPanicOnOopsAlways,
|
||||
utilsysctl.RootMaxKeys: utilsysctl.RootMaxKeysSetting,
|
||||
utilsysctl.RootMaxBytes: utilsysctl.RootMaxBytesSetting,
|
||||
}
|
||||
|
||||
sysctl := utilsysctl.New()
|
||||
|
||||
errList := []error{}
|
||||
for flag, expectedValue := range desiredState {
|
||||
val, err := sysctl.GetSysctl(flag)
|
||||
if err != nil {
|
||||
errList = append(errList, err)
|
||||
continue
|
||||
}
|
||||
if val == expectedValue {
|
||||
continue
|
||||
}
|
||||
|
||||
switch option {
|
||||
case KernelTunableError:
|
||||
errList = append(errList, fmt.Errorf("Invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val))
|
||||
case KernelTunableWarn:
|
||||
glog.V(2).Infof("Invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
|
||||
case KernelTunableModify:
|
||||
glog.V(2).Infof("Updating kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
|
||||
err = sysctl.SetSysctl(flag, expectedValue)
|
||||
if err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) setupNode(activePods ActivePodsFunc) error {
|
||||
f, err := validateSystemRequirements(cm.mountUtil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !f.cpuHardcapping {
|
||||
cm.status.SoftRequirements = fmt.Errorf("CPU hardcapping unsupported")
|
||||
}
|
||||
b := KernelTunableModify
|
||||
if cm.GetNodeConfig().ProtectKernelDefaults {
|
||||
b = KernelTunableError
|
||||
}
|
||||
if err := setupKernelTunables(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup top level qos containers only if CgroupsPerQOS flag is specified as true
|
||||
if cm.NodeConfig.CgroupsPerQOS {
|
||||
if err := cm.createNodeAllocatableCgroups(); err != nil {
|
||||
return err
|
||||
}
|
||||
err = cm.qosContainerManager.Start(cm.getNodeAllocatableAbsolute, activePods)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize top level QOS containers: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce Node Allocatable (if required)
|
||||
if err := cm.enforceNodeAllocatableCgroups(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
systemContainers := []*systemContainer{}
|
||||
if cm.ContainerRuntime == "docker" {
|
||||
// With the docker-CRI integration, dockershim will manage the cgroups
|
||||
// and oom score for the docker processes.
|
||||
// In the future, NodeSpec should mandate the cgroup that the
|
||||
// runtime processes need to be in. For now, we still check the
|
||||
// cgroup for docker periodically, so that kubelet can recognize
|
||||
// the cgroup for docker and serve stats for the runtime.
|
||||
// TODO(#27097): Fix this after NodeSpec is clearly defined.
|
||||
cm.periodicTasks = append(cm.periodicTasks, func() {
|
||||
glog.V(4).Infof("[ContainerManager]: Adding periodic tasks for docker CRI integration")
|
||||
cont, err := getContainerNameForProcess(dockerProcessName, dockerPidFile)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
glog.V(2).Infof("[ContainerManager]: Discovered runtime cgroups name: %s", cont)
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
cm.RuntimeCgroupsName = cont
|
||||
})
|
||||
}
|
||||
|
||||
if cm.SystemCgroupsName != "" {
|
||||
if cm.SystemCgroupsName == "/" {
|
||||
return fmt.Errorf("system container cannot be root (\"/\")")
|
||||
}
|
||||
cont := newSystemCgroups(cm.SystemCgroupsName)
|
||||
cont.ensureStateFunc = func(manager *fs.Manager) error {
|
||||
return ensureSystemCgroups("/", manager)
|
||||
}
|
||||
systemContainers = append(systemContainers, cont)
|
||||
}
|
||||
|
||||
if cm.KubeletCgroupsName != "" {
|
||||
cont := newSystemCgroups(cm.KubeletCgroupsName)
|
||||
allowAllDevices := true
|
||||
manager := fs.Manager{
|
||||
Cgroups: &configs.Cgroup{
|
||||
Parent: "/",
|
||||
Name: cm.KubeletCgroupsName,
|
||||
Resources: &configs.Resources{
|
||||
AllowAllDevices: &allowAllDevices,
|
||||
},
|
||||
},
|
||||
}
|
||||
cont.ensureStateFunc = func(_ *fs.Manager) error {
|
||||
return ensureProcessInContainerWithOOMScore(os.Getpid(), qos.KubeletOOMScoreAdj, &manager)
|
||||
}
|
||||
systemContainers = append(systemContainers, cont)
|
||||
} else {
|
||||
cm.periodicTasks = append(cm.periodicTasks, func() {
|
||||
if err := ensureProcessInContainerWithOOMScore(os.Getpid(), qos.KubeletOOMScoreAdj, nil); err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
cont, err := getContainer(os.Getpid())
|
||||
if err != nil {
|
||||
glog.Errorf("failed to find cgroups of kubelet - %v", err)
|
||||
return
|
||||
}
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
cm.KubeletCgroupsName = cont
|
||||
})
|
||||
}
|
||||
|
||||
cm.systemContainers = systemContainers
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainerNameForProcess(name, pidFile string) (string, error) {
|
||||
pids, err := getPidsForProcess(name, pidFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to detect process id for %q - %v", name, err)
|
||||
}
|
||||
if len(pids) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
cont, err := getContainer(pids[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cont, nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) GetNodeConfig() NodeConfig {
|
||||
cm.RLock()
|
||||
defer cm.RUnlock()
|
||||
return cm.NodeConfig
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) GetMountedSubsystems() *CgroupSubsystems {
|
||||
return cm.subsystems
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) GetQOSContainersInfo() QOSContainersInfo {
|
||||
return cm.qosContainerManager.GetQOSContainersInfo()
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) UpdateQOSCgroups() error {
|
||||
return cm.qosContainerManager.UpdateCgroups()
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) Status() Status {
|
||||
cm.RLock()
|
||||
defer cm.RUnlock()
|
||||
return cm.status
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) Start(node *v1.Node,
|
||||
activePods ActivePodsFunc,
|
||||
podStatusProvider status.PodStatusProvider,
|
||||
runtimeService internalapi.RuntimeService) error {
|
||||
|
||||
// Initialize CPU manager
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUManager) {
|
||||
cm.cpuManager.Start(cpumanager.ActivePodsFunc(activePods), podStatusProvider, runtimeService)
|
||||
}
|
||||
|
||||
// cache the node Info including resource capacity and
|
||||
// allocatable of the node
|
||||
cm.nodeInfo = node
|
||||
|
||||
// Ensure that node allocatable configuration is valid.
|
||||
if err := cm.validateNodeAllocatable(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup the node
|
||||
if err := cm.setupNode(activePods); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Don't run a background thread if there are no ensureStateFuncs.
|
||||
hasEnsureStateFuncs := false
|
||||
for _, cont := range cm.systemContainers {
|
||||
if cont.ensureStateFunc != nil {
|
||||
hasEnsureStateFuncs = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasEnsureStateFuncs {
|
||||
// Run ensure state functions every minute.
|
||||
go wait.Until(func() {
|
||||
for _, cont := range cm.systemContainers {
|
||||
if cont.ensureStateFunc != nil {
|
||||
if err := cont.ensureStateFunc(cont.manager); err != nil {
|
||||
glog.Warningf("[ContainerManager] Failed to ensure state of %q: %v", cont.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, time.Minute, wait.NeverStop)
|
||||
|
||||
}
|
||||
|
||||
if len(cm.periodicTasks) > 0 {
|
||||
go wait.Until(func() {
|
||||
for _, task := range cm.periodicTasks {
|
||||
if task != nil {
|
||||
task()
|
||||
}
|
||||
}
|
||||
}, 5*time.Minute, wait.NeverStop)
|
||||
}
|
||||
|
||||
// Local storage filesystem information from `RootFsInfo` and `ImagesFsInfo` is available at a later time
|
||||
// depending on the time when cadvisor manager updates container stats. Therefore use a go routine to keep
|
||||
// retrieving the information until it is available.
|
||||
stopChan := make(chan struct{})
|
||||
go wait.Until(func() {
|
||||
if err := cm.setFsCapacity(); err != nil {
|
||||
glog.Errorf("[ContainerManager]: %v", err)
|
||||
return
|
||||
}
|
||||
close(stopChan)
|
||||
}, time.Second, stopChan)
|
||||
|
||||
// Starts device plugin manager.
|
||||
if err := cm.devicePluginHandler.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) setFsCapacity() error {
|
||||
rootfs, err := cm.cadvisorInterface.RootFsInfo()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Fail to get rootfs information %v", err)
|
||||
}
|
||||
|
||||
cm.Lock()
|
||||
for rName, rCap := range cadvisor.EphemeralStorageCapacityFromFsInfo(rootfs) {
|
||||
cm.capacity[rName] = rCap
|
||||
}
|
||||
cm.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: move the GetResources logic to PodContainerManager.
|
||||
func (cm *containerManagerImpl) GetResources(pod *v1.Pod, container *v1.Container, activePods []*v1.Pod) (*kubecontainer.RunContainerOptions, error) {
|
||||
opts := &kubecontainer.RunContainerOptions{}
|
||||
// Gets devices, mounts, and envs from device plugin handler.
|
||||
glog.V(3).Infof("Calling devicePluginHandler AllocateDevices")
|
||||
// Maps to detect duplicate settings.
|
||||
devsMap := make(map[string]string)
|
||||
mountsMap := make(map[string]string)
|
||||
envsMap := make(map[string]string)
|
||||
allocResps, err := cm.devicePluginHandler.Allocate(pod, container, activePods)
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
// Loops through AllocationResponses of all required extended resources.
|
||||
for _, resp := range allocResps {
|
||||
// Loops through runtime spec of all devices of the given resource.
|
||||
for _, devRuntime := range resp.Spec {
|
||||
// Updates RunContainerOptions.Devices.
|
||||
for _, dev := range devRuntime.Devices {
|
||||
if d, ok := devsMap[dev.ContainerPath]; ok {
|
||||
glog.V(3).Infof("skip existing device %s %s", dev.ContainerPath, dev.HostPath)
|
||||
if d != dev.HostPath {
|
||||
glog.Errorf("Container device %s has conflicting mapping host devices: %s and %s",
|
||||
dev.ContainerPath, d, dev.HostPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
devsMap[dev.ContainerPath] = dev.HostPath
|
||||
opts.Devices = append(opts.Devices, kubecontainer.DeviceInfo{
|
||||
PathOnHost: dev.HostPath,
|
||||
PathInContainer: dev.ContainerPath,
|
||||
Permissions: dev.Permissions,
|
||||
})
|
||||
}
|
||||
// Updates RunContainerOptions.Mounts.
|
||||
for _, mount := range devRuntime.Mounts {
|
||||
if m, ok := mountsMap[mount.ContainerPath]; ok {
|
||||
glog.V(3).Infof("skip existing mount %s %s", mount.ContainerPath, mount.HostPath)
|
||||
if m != mount.HostPath {
|
||||
glog.Errorf("Container mount %s has conflicting mapping host mounts: %s and %s",
|
||||
mount.ContainerPath, m, mount.HostPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
mountsMap[mount.ContainerPath] = mount.HostPath
|
||||
opts.Mounts = append(opts.Mounts, kubecontainer.Mount{
|
||||
Name: mount.ContainerPath,
|
||||
ContainerPath: mount.ContainerPath,
|
||||
HostPath: mount.HostPath,
|
||||
ReadOnly: mount.ReadOnly,
|
||||
SELinuxRelabel: false,
|
||||
})
|
||||
}
|
||||
// Updates RunContainerOptions.Envs.
|
||||
for k, v := range devRuntime.Envs {
|
||||
if e, ok := envsMap[k]; ok {
|
||||
glog.V(3).Infof("skip existing envs %s %s", k, v)
|
||||
if e != v {
|
||||
glog.Errorf("Environment variable %s has conflicting setting: %s and %s", k, e, v)
|
||||
}
|
||||
continue
|
||||
}
|
||||
envsMap[k] = v
|
||||
opts.Envs = append(opts.Envs, kubecontainer.EnvVar{Name: k, Value: v})
|
||||
}
|
||||
}
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) SystemCgroupsLimit() v1.ResourceList {
|
||||
cpuLimit := int64(0)
|
||||
|
||||
// Sum up resources of all external containers.
|
||||
for _, cont := range cm.systemContainers {
|
||||
cpuLimit += cont.cpuMillicores
|
||||
}
|
||||
|
||||
return v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewMilliQuantity(
|
||||
cpuLimit,
|
||||
resource.DecimalSI),
|
||||
}
|
||||
}
|
||||
|
||||
func isProcessRunningInHost(pid int) (bool, error) {
|
||||
// Get init pid namespace.
|
||||
initPidNs, err := os.Readlink("/proc/1/ns/pid")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to find pid namespace of init process")
|
||||
}
|
||||
glog.V(10).Infof("init pid ns is %q", initPidNs)
|
||||
processPidNs, err := os.Readlink(fmt.Sprintf("/proc/%d/ns/pid", pid))
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to find pid namespace of process %q", pid)
|
||||
}
|
||||
glog.V(10).Infof("Pid %d pid ns is %q", pid, processPidNs)
|
||||
return initPidNs == processPidNs, nil
|
||||
}
|
||||
|
||||
func getPidFromPidFile(pidFile string) (int, error) {
|
||||
file, err := os.Open(pidFile)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error opening pid file %s: %v", pidFile, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error reading pid file %s: %v", pidFile, err)
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error parsing %s as a number: %v", string(data), err)
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
func getPidsForProcess(name, pidFile string) ([]int, error) {
|
||||
if len(pidFile) == 0 {
|
||||
return procfs.PidOf(name)
|
||||
}
|
||||
|
||||
pid, err := getPidFromPidFile(pidFile)
|
||||
if err == nil {
|
||||
return []int{pid}, nil
|
||||
}
|
||||
|
||||
// Try to lookup pid by process name
|
||||
pids, err2 := procfs.PidOf(name)
|
||||
if err2 == nil {
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
// Return error from getPidFromPidFile since that should have worked
|
||||
// and is the real source of the problem.
|
||||
glog.V(4).Infof("unable to get pid from %s: %v", pidFile, err)
|
||||
return []int{}, err
|
||||
}
|
||||
|
||||
// Ensures that the Docker daemon is in the desired container.
|
||||
// Temporarily export the function to be used by dockershim.
|
||||
// TODO(yujuhong): Move this function to dockershim once kubelet migrates to
|
||||
// dockershim as the default.
|
||||
func EnsureDockerInContainer(dockerAPIVersion *utilversion.Version, oomScoreAdj int, manager *fs.Manager) error {
|
||||
type process struct{ name, file string }
|
||||
dockerProcs := []process{{dockerProcessName, dockerPidFile}}
|
||||
if dockerAPIVersion.AtLeast(containerdAPIVersion) {
|
||||
dockerProcs = append(dockerProcs, process{containerdProcessName, containerdPidFile})
|
||||
}
|
||||
var errs []error
|
||||
for _, proc := range dockerProcs {
|
||||
pids, err := getPidsForProcess(proc.name, proc.file)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to get pids for %q: %v", proc.name, err))
|
||||
continue
|
||||
}
|
||||
|
||||
// Move if the pid is not already in the desired container.
|
||||
for _, pid := range pids {
|
||||
if err := ensureProcessInContainerWithOOMScore(pid, oomScoreAdj, manager); err != nil {
|
||||
errs = append(errs, fmt.Errorf("errors moving %q pid: %v", proc.name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func ensureProcessInContainerWithOOMScore(pid int, oomScoreAdj int, manager *fs.Manager) error {
|
||||
if runningInHost, err := isProcessRunningInHost(pid); err != nil {
|
||||
// Err on the side of caution. Avoid moving the docker daemon unless we are able to identify its context.
|
||||
return err
|
||||
} else if !runningInHost {
|
||||
// Process is running inside a container. Don't touch that.
|
||||
glog.V(2).Infof("pid %d is not running in the host namespaces", pid)
|
||||
return nil
|
||||
}
|
||||
|
||||
var errs []error
|
||||
if manager != nil {
|
||||
cont, err := getContainer(pid)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to find container of PID %d: %v", pid, err))
|
||||
}
|
||||
|
||||
if cont != manager.Cgroups.Name {
|
||||
err = manager.Apply(pid)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to move PID %d (in %q) to %q: %v", pid, cont, manager.Cgroups.Name, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also apply oom-score-adj to processes
|
||||
oomAdjuster := oom.NewOOMAdjuster()
|
||||
glog.V(5).Infof("attempting to apply oom_score_adj of %d to pid %d", oomScoreAdj, pid)
|
||||
if err := oomAdjuster.ApplyOOMScoreAdj(pid, oomScoreAdj); err != nil {
|
||||
glog.V(3).Infof("Failed to apply oom_score_adj %d for pid %d: %v", oomScoreAdj, pid, err)
|
||||
errs = append(errs, fmt.Errorf("failed to apply oom score %d to PID %d: %v", oomScoreAdj, pid, err))
|
||||
}
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// getContainer returns the cgroup associated with the specified pid.
|
||||
// It enforces a unified hierarchy for memory and cpu cgroups.
|
||||
// On systemd environments, it uses the name=systemd cgroup for the specified pid.
|
||||
func getContainer(pid int) (string, error) {
|
||||
cgs, err := cgroups.ParseCgroupFile(fmt.Sprintf("/proc/%d/cgroup", pid))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cpu, found := cgs["cpu"]
|
||||
if !found {
|
||||
return "", cgroups.NewNotFoundError("cpu")
|
||||
}
|
||||
memory, found := cgs["memory"]
|
||||
if !found {
|
||||
return "", cgroups.NewNotFoundError("memory")
|
||||
}
|
||||
|
||||
// since we use this container for accounting, we need to ensure its a unified hierarchy.
|
||||
if cpu != memory {
|
||||
return "", fmt.Errorf("cpu and memory cgroup hierarchy not unified. cpu: %s, memory: %s", cpu, memory)
|
||||
}
|
||||
|
||||
// on systemd, every pid is in a unified cgroup hierarchy (name=systemd as seen in systemd-cgls)
|
||||
// cpu and memory accounting is off by default, users may choose to enable it per unit or globally.
|
||||
// users could enable CPU and memory accounting globally via /etc/systemd/system.conf (DefaultCPUAccounting=true DefaultMemoryAccounting=true).
|
||||
// users could also enable CPU and memory accounting per unit via CPUAccounting=true and MemoryAccounting=true
|
||||
// we only warn if accounting is not enabled for CPU or memory so as to not break local development flows where kubelet is launched in a terminal.
|
||||
// for example, the cgroup for the user session will be something like /user.slice/user-X.slice/session-X.scope, but the cpu and memory
|
||||
// cgroup will be the closest ancestor where accounting is performed (most likely /) on systems that launch docker containers.
|
||||
// as a result, on those systems, you will not get cpu or memory accounting statistics for kubelet.
|
||||
// in addition, you would not get memory or cpu accounting for the runtime unless accounting was enabled on its unit (or globally).
|
||||
if systemd, found := cgs["name=systemd"]; found {
|
||||
if systemd != cpu {
|
||||
glog.Warningf("CPUAccounting not enabled for pid: %d", pid)
|
||||
}
|
||||
if systemd != memory {
|
||||
glog.Warningf("MemoryAccounting not enabled for pid: %d", pid)
|
||||
}
|
||||
return systemd, nil
|
||||
}
|
||||
|
||||
return cpu, nil
|
||||
}
|
||||
|
||||
// Ensures the system container is created and all non-kernel threads and process 1
|
||||
// without a container are moved to it.
|
||||
//
|
||||
// The reason of leaving kernel threads at root cgroup is that we don't want to tie the
|
||||
// execution of these threads with to-be defined /system quota and create priority inversions.
|
||||
//
|
||||
func ensureSystemCgroups(rootCgroupPath string, manager *fs.Manager) error {
|
||||
// Move non-kernel PIDs to the system container.
|
||||
attemptsRemaining := 10
|
||||
var errs []error
|
||||
for attemptsRemaining >= 0 {
|
||||
// Only keep errors on latest attempt.
|
||||
errs = []error{}
|
||||
attemptsRemaining--
|
||||
|
||||
allPids, err := cmutil.GetPids(rootCgroupPath)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to list PIDs for root: %v", err))
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove kernel pids and other protected PIDs (pid 1, PIDs already in system & kubelet containers)
|
||||
pids := make([]int, 0, len(allPids))
|
||||
for _, pid := range allPids {
|
||||
if pid == 1 || isKernelPid(pid) {
|
||||
continue
|
||||
}
|
||||
|
||||
pids = append(pids, pid)
|
||||
}
|
||||
glog.Infof("Found %d PIDs in root, %d of them are not to be moved", len(allPids), len(allPids)-len(pids))
|
||||
|
||||
// Check if we have moved all the non-kernel PIDs.
|
||||
if len(pids) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
glog.Infof("Moving non-kernel processes: %v", pids)
|
||||
for _, pid := range pids {
|
||||
err := manager.Apply(pid)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to move PID %d into the system container %q: %v", pid, manager.Cgroups.Name, err))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if attemptsRemaining < 0 {
|
||||
errs = append(errs, fmt.Errorf("ran out of attempts to create system containers %q", manager.Cgroups.Name))
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
// Determines whether the specified PID is a kernel PID.
|
||||
func isKernelPid(pid int) bool {
|
||||
// Kernel threads have no associated executable.
|
||||
_, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
|
||||
return err != nil
|
||||
}
|
||||
|
||||
// Helper for getting the docker API version.
|
||||
func getDockerAPIVersion(cadvisor cadvisor.Interface) *utilversion.Version {
|
||||
versions, err := cadvisor.VersionInfo()
|
||||
if err != nil {
|
||||
glog.Errorf("Error requesting cAdvisor VersionInfo: %v", err)
|
||||
return utilversion.MustParseSemantic("0.0")
|
||||
}
|
||||
dockerAPIVersion, err := utilversion.ParseGeneric(versions.DockerAPIVersion)
|
||||
if err != nil {
|
||||
glog.Errorf("Error parsing docker version %q: %v", versions.DockerVersion, err)
|
||||
return utilversion.MustParseSemantic("0.0")
|
||||
}
|
||||
return dockerAPIVersion
|
||||
}
|
||||
|
||||
func (cm *containerManagerImpl) GetCapacity() v1.ResourceList {
|
||||
cm.RLock()
|
||||
defer cm.RUnlock()
|
||||
return cm.capacity
|
||||
}
|
||||
193
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go
generated
vendored
Normal file
193
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
type fakeMountInterface struct {
|
||||
mountPoints []mount.MountPoint
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) Mount(source string, target string, fstype string, options []string) error {
|
||||
return fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) Unmount(target string) error {
|
||||
return fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) List() ([]mount.MountPoint, error) {
|
||||
return mi.mountPoints, nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) IsNotMountPoint(dir string) (bool, error) {
|
||||
return false, fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return false, fmt.Errorf("unsupported")
|
||||
}
|
||||
func (mi *fakeMountInterface) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) DeviceOpened(pathname string) (bool, error) {
|
||||
for _, mp := range mi.mountPoints {
|
||||
if mp.Device == pathname {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fakeContainerMgrMountInt() mount.Interface {
|
||||
return &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuset"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpu"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "memory"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgroupMountValidationSuccess(t *testing.T) {
|
||||
f, err := validateSystemRequirements(fakeContainerMgrMountInt())
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, f.cpuHardcapping, "cpu hardcapping is expected to be disabled")
|
||||
}
|
||||
|
||||
func TestCgroupMountValidationMemoryMissing(t *testing.T) {
|
||||
mountInt := &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuset"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpu"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := validateSystemRequirements(mountInt)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCgroupMountValidationMultipleSubsystem(t *testing.T) {
|
||||
mountInt := &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuset", "memory"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpu"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := validateSystemRequirements(mountInt)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSoftRequirementsValidationSuccess(t *testing.T) {
|
||||
req := require.New(t)
|
||||
tempDir, err := ioutil.TempDir("", "")
|
||||
req.NoError(err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
req.NoError(ioutil.WriteFile(path.Join(tempDir, "cpu.cfs_period_us"), []byte("0"), os.ModePerm))
|
||||
req.NoError(ioutil.WriteFile(path.Join(tempDir, "cpu.cfs_quota_us"), []byte("0"), os.ModePerm))
|
||||
mountInt := &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuset"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpu"},
|
||||
Path: tempDir,
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuacct", "memory"},
|
||||
},
|
||||
},
|
||||
}
|
||||
f, err := validateSystemRequirements(mountInt)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, f.cpuHardcapping, "cpu hardcapping is expected to be enabled")
|
||||
}
|
||||
84
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_stub.go
generated
vendored
Normal file
84
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_stub.go
generated
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
)
|
||||
|
||||
type containerManagerStub struct{}
|
||||
|
||||
var _ ContainerManager = &containerManagerStub{}
|
||||
|
||||
func (cm *containerManagerStub) Start(_ *v1.Node, _ ActivePodsFunc, _ status.PodStatusProvider, _ internalapi.RuntimeService) error {
|
||||
glog.V(2).Infof("Starting stub container manager")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) SystemCgroupsLimit() v1.ResourceList {
|
||||
return v1.ResourceList{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetNodeConfig() NodeConfig {
|
||||
return NodeConfig{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetMountedSubsystems() *CgroupSubsystems {
|
||||
return &CgroupSubsystems{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetQOSContainersInfo() QOSContainersInfo {
|
||||
return QOSContainersInfo{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) UpdateQOSCgroups() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) Status() Status {
|
||||
return Status{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetNodeAllocatableReservation() v1.ResourceList {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetCapacity() v1.ResourceList {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) NewPodContainerManager() PodContainerManager {
|
||||
return &podContainerManagerStub{}
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) GetResources(pod *v1.Pod, container *v1.Container, activePods []*v1.Pod) (*kubecontainer.RunContainerOptions, error) {
|
||||
return &kubecontainer.RunContainerOptions{}, nil
|
||||
}
|
||||
|
||||
func (cm *containerManagerStub) InternalContainerLifecycle() InternalContainerLifecycle {
|
||||
return &internalContainerLifecycleImpl{cpumanager.NewFakeManager()}
|
||||
}
|
||||
|
||||
func NewStubContainerManager() ContainerManager {
|
||||
return &containerManagerStub{}
|
||||
}
|
||||
89
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported.go
generated
vendored
Normal file
89
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// +build !linux,!windows
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
type unsupportedContainerManager struct {
|
||||
}
|
||||
|
||||
var _ ContainerManager = &unsupportedContainerManager{}
|
||||
|
||||
func (unsupportedContainerManager) Start(_ *v1.Node, _ ActivePodsFunc, _ status.PodStatusProvider, _ internalapi.RuntimeService) error {
|
||||
return fmt.Errorf("Container Manager is unsupported in this build")
|
||||
}
|
||||
|
||||
func (unsupportedContainerManager) SystemCgroupsLimit() v1.ResourceList {
|
||||
return v1.ResourceList{}
|
||||
}
|
||||
|
||||
func (unsupportedContainerManager) GetNodeConfig() NodeConfig {
|
||||
return NodeConfig{}
|
||||
}
|
||||
|
||||
func (unsupportedContainerManager) GetMountedSubsystems() *CgroupSubsystems {
|
||||
return &CgroupSubsystems{}
|
||||
}
|
||||
|
||||
func (unsupportedContainerManager) GetQOSContainersInfo() QOSContainersInfo {
|
||||
return QOSContainersInfo{}
|
||||
}
|
||||
|
||||
func (unsupportedContainerManager) UpdateQOSCgroups() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) Status() Status {
|
||||
return Status{}
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) GetNodeAllocatableReservation() v1.ResourceList {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) GetCapacity() v1.ResourceList {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) NewPodContainerManager() PodContainerManager {
|
||||
return &unsupportedPodContainerManager{}
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) GetResources(pod *v1.Pod, container *v1.Container, activePods []*v1.Pod) (*kubecontainer.RunContainerOptions, error) {
|
||||
return &kubecontainer.RunContainerOptions{}, nil
|
||||
}
|
||||
|
||||
func (cm *unsupportedContainerManager) InternalContainerLifecycle() InternalContainerLifecycle {
|
||||
return &internalContainerLifecycleImpl{cpumanager.NewFakeManager()}
|
||||
}
|
||||
|
||||
func NewContainerManager(_ mount.Interface, _ cadvisor.Interface, _ NodeConfig, failSwapOn bool, devicePluginEnabled bool, recorder record.EventRecorder) (ContainerManager, error) {
|
||||
return &unsupportedContainerManager{}, nil
|
||||
}
|
||||
101
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go
generated
vendored
Normal file
101
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// +build !linux,!windows
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
type fakeMountInterface struct {
|
||||
mountPoints []mount.MountPoint
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) Mount(source string, target string, fstype string, options []string) error {
|
||||
return fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) Unmount(target string) error {
|
||||
return fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) List() ([]mount.MountPoint, error) {
|
||||
return mi.mountPoints, nil
|
||||
}
|
||||
|
||||
func (f *fakeMountInterface) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
|
||||
return (mp.Path == dir)
|
||||
}
|
||||
|
||||
func (f *fakeMountInterface) IsNotMountPoint(dir string) (bool, error) {
|
||||
return false, fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) IsLikelyNotMountPoint(file string) (bool, error) {
|
||||
return false, fmt.Errorf("unsupported")
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) DeviceOpened(pathname string) (bool, error) {
|
||||
for _, mp := range mi.mountPoints {
|
||||
if mp.Device == pathname {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) PathIsDevice(pathname string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (mi *fakeMountInterface) MakeRShared(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fakeContainerMgrMountInt() mount.Interface {
|
||||
return &fakeMountInterface{
|
||||
[]mount.MountPoint{
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuset"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpu"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "cpuacct"},
|
||||
},
|
||||
{
|
||||
Device: "cgroup",
|
||||
Type: "cgroup",
|
||||
Opts: []string{"rw", "relatime", "memory"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
45
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_windows.go
generated
vendored
Normal file
45
vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2015 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 cm
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
type containerManagerImpl struct {
|
||||
containerManagerStub
|
||||
}
|
||||
|
||||
var _ ContainerManager = &containerManagerImpl{}
|
||||
|
||||
func (cm *containerManagerImpl) Start(_ *v1.Node, _ ActivePodsFunc, _ status.PodStatusProvider, _ internalapi.RuntimeService) error {
|
||||
glog.V(2).Infof("Starting Windows stub container manager")
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.Interface, nodeConfig NodeConfig, failSwapOn bool, devicePluginEnabled bool, recorder record.EventRecorder) (ContainerManager, error) {
|
||||
return &containerManagerImpl{}, nil
|
||||
}
|
||||
68
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/BUILD
generated
vendored
Normal file
68
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cpu_assignment.go",
|
||||
"cpu_manager.go",
|
||||
"fake_cpu_manager.go",
|
||||
"policy.go",
|
||||
"policy_none.go",
|
||||
"policy_static.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/v1/helper/qos:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/cm/cpumanager/state:go_default_library",
|
||||
"//pkg/kubelet/cm/cpumanager/topology:go_default_library",
|
||||
"//pkg/kubelet/cm/cpuset:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/status:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cpu_assignment_test.go",
|
||||
"cpu_manager_test.go",
|
||||
"policy_none_test.go",
|
||||
"policy_static_test.go",
|
||||
"policy_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/cm/cpumanager/state:go_default_library",
|
||||
"//pkg/kubelet/cm/cpumanager/topology:go_default_library",
|
||||
"//pkg/kubelet/cm/cpuset:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/kubelet/cm/cpumanager/state:all-srcs",
|
||||
"//pkg/kubelet/cm/cpumanager/topology:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
6
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/OWNERS
generated
vendored
Normal file
6
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
approvers:
|
||||
- derekwaynecarr
|
||||
- vishh
|
||||
- ConnorDoyle
|
||||
- sjenning
|
||||
- balajismaniam
|
||||
197
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment.go
generated
vendored
Normal file
197
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment.go
generated
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
type cpuAccumulator struct {
|
||||
topo *topology.CPUTopology
|
||||
details topology.CPUDetails
|
||||
numCPUsNeeded int
|
||||
result cpuset.CPUSet
|
||||
}
|
||||
|
||||
func newCPUAccumulator(topo *topology.CPUTopology, availableCPUs cpuset.CPUSet, numCPUs int) *cpuAccumulator {
|
||||
return &cpuAccumulator{
|
||||
topo: topo,
|
||||
details: topo.CPUDetails.KeepOnly(availableCPUs),
|
||||
numCPUsNeeded: numCPUs,
|
||||
result: cpuset.NewCPUSet(),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *cpuAccumulator) take(cpus cpuset.CPUSet) {
|
||||
a.result = a.result.Union(cpus)
|
||||
a.details = a.details.KeepOnly(a.details.CPUs().Difference(a.result))
|
||||
a.numCPUsNeeded -= cpus.Size()
|
||||
}
|
||||
|
||||
// Returns true if the supplied socket is fully available in `topoDetails`.
|
||||
func (a *cpuAccumulator) isSocketFree(socketID int) bool {
|
||||
return a.details.CPUsInSocket(socketID).Size() == a.topo.CPUsPerSocket()
|
||||
}
|
||||
|
||||
// Returns true if the supplied core is fully available in `topoDetails`.
|
||||
func (a *cpuAccumulator) isCoreFree(coreID int) bool {
|
||||
return a.details.CPUsInCore(coreID).Size() == a.topo.CPUsPerCore()
|
||||
}
|
||||
|
||||
// Returns free socket IDs as a slice sorted by:
|
||||
// - socket ID, ascending.
|
||||
func (a *cpuAccumulator) freeSockets() []int {
|
||||
return a.details.Sockets().Filter(a.isSocketFree).ToSlice()
|
||||
}
|
||||
|
||||
// Returns core IDs as a slice sorted by:
|
||||
// - the number of whole available cores on the socket, ascending
|
||||
// - socket ID, ascending
|
||||
// - core ID, ascending
|
||||
func (a *cpuAccumulator) freeCores() []int {
|
||||
socketIDs := a.details.Sockets().ToSlice()
|
||||
sort.Slice(socketIDs,
|
||||
func(i, j int) bool {
|
||||
iCores := a.details.CoresInSocket(socketIDs[i]).Filter(a.isCoreFree)
|
||||
jCores := a.details.CoresInSocket(socketIDs[j]).Filter(a.isCoreFree)
|
||||
return iCores.Size() < jCores.Size() || socketIDs[i] < socketIDs[j]
|
||||
})
|
||||
|
||||
coreIDs := []int{}
|
||||
for _, s := range socketIDs {
|
||||
coreIDs = append(coreIDs, a.details.CoresInSocket(s).Filter(a.isCoreFree).ToSlice()...)
|
||||
}
|
||||
return coreIDs
|
||||
}
|
||||
|
||||
// Returns CPU IDs as a slice sorted by:
|
||||
// - socket affinity with result
|
||||
// - number of CPUs available on the same sockett
|
||||
// - number of CPUs available on the same core
|
||||
// - socket ID.
|
||||
// - core ID.
|
||||
func (a *cpuAccumulator) freeCPUs() []int {
|
||||
result := []int{}
|
||||
cores := a.details.Cores().ToSlice()
|
||||
|
||||
sort.Slice(
|
||||
cores,
|
||||
func(i, j int) bool {
|
||||
iCore := cores[i]
|
||||
jCore := cores[j]
|
||||
|
||||
iCPUs := a.topo.CPUDetails.CPUsInCore(iCore).ToSlice()
|
||||
jCPUs := a.topo.CPUDetails.CPUsInCore(jCore).ToSlice()
|
||||
|
||||
iSocket := a.topo.CPUDetails[iCPUs[0]].SocketID
|
||||
jSocket := a.topo.CPUDetails[jCPUs[0]].SocketID
|
||||
|
||||
// Compute the number of CPUs in the result reside on the same socket
|
||||
// as each core.
|
||||
iSocketColoScore := a.topo.CPUDetails.CPUsInSocket(iSocket).Intersection(a.result).Size()
|
||||
jSocketColoScore := a.topo.CPUDetails.CPUsInSocket(jSocket).Intersection(a.result).Size()
|
||||
|
||||
// Compute the number of available CPUs available on the same socket
|
||||
// as each core.
|
||||
iSocketFreeScore := a.details.CPUsInSocket(iSocket).Size()
|
||||
jSocketFreeScore := a.details.CPUsInSocket(jSocket).Size()
|
||||
|
||||
// Compute the number of available CPUs on each core.
|
||||
iCoreFreeScore := a.details.CPUsInCore(iCore).Size()
|
||||
jCoreFreeScore := a.details.CPUsInCore(jCore).Size()
|
||||
|
||||
return iSocketColoScore > jSocketColoScore ||
|
||||
iSocketFreeScore < jSocketFreeScore ||
|
||||
iCoreFreeScore < jCoreFreeScore ||
|
||||
iSocket < jSocket ||
|
||||
iCore < jCore
|
||||
})
|
||||
|
||||
// For each core, append sorted CPU IDs to result.
|
||||
for _, core := range cores {
|
||||
result = append(result, a.details.CPUsInCore(core).ToSlice()...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (a *cpuAccumulator) needs(n int) bool {
|
||||
return a.numCPUsNeeded >= n
|
||||
}
|
||||
|
||||
func (a *cpuAccumulator) isSatisfied() bool {
|
||||
return a.numCPUsNeeded < 1
|
||||
}
|
||||
|
||||
func (a *cpuAccumulator) isFailed() bool {
|
||||
return a.numCPUsNeeded > a.details.CPUs().Size()
|
||||
}
|
||||
|
||||
func takeByTopology(topo *topology.CPUTopology, availableCPUs cpuset.CPUSet, numCPUs int) (cpuset.CPUSet, error) {
|
||||
acc := newCPUAccumulator(topo, availableCPUs, numCPUs)
|
||||
if acc.isSatisfied() {
|
||||
return acc.result, nil
|
||||
}
|
||||
if acc.isFailed() {
|
||||
return cpuset.NewCPUSet(), fmt.Errorf("not enough cpus available to satisfy request")
|
||||
}
|
||||
|
||||
// Algorithm: topology-aware best-fit
|
||||
// 1. Acquire whole sockets, if available and the container requires at
|
||||
// least a socket's-worth of CPUs.
|
||||
for _, s := range acc.freeSockets() {
|
||||
if acc.needs(acc.topo.CPUsPerSocket()) {
|
||||
glog.V(4).Infof("[cpumanager] takeByTopology: claiming socket [%d]", s)
|
||||
acc.take(acc.details.CPUsInSocket(s))
|
||||
if acc.isSatisfied() {
|
||||
return acc.result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Acquire whole cores, if available and the container requires at least
|
||||
// a core's-worth of CPUs.
|
||||
for _, c := range acc.freeCores() {
|
||||
if acc.needs(acc.topo.CPUsPerCore()) {
|
||||
glog.V(4).Infof("[cpumanager] takeByTopology: claiming core [%d]", c)
|
||||
acc.take(acc.details.CPUsInCore(c))
|
||||
if acc.isSatisfied() {
|
||||
return acc.result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Acquire single threads, preferring to fill partially-allocated cores
|
||||
// on the same sockets as the whole cores we have already taken in this
|
||||
// allocation.
|
||||
for _, c := range acc.freeCPUs() {
|
||||
glog.V(4).Infof("[cpumanager] takeByTopology: claiming CPU [%d]", c)
|
||||
if acc.needs(1) {
|
||||
acc.take(cpuset.NewCPUSet(c))
|
||||
}
|
||||
if acc.isSatisfied() {
|
||||
return acc.result, nil
|
||||
}
|
||||
}
|
||||
|
||||
return cpuset.NewCPUSet(), fmt.Errorf("failed to allocate cpus")
|
||||
}
|
||||
385
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go
generated
vendored
Normal file
385
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
func TestCPUAccumulatorFreeSockets(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
availableCPUs cpuset.CPUSet
|
||||
expect []int
|
||||
}{
|
||||
{
|
||||
"single socket HT, 1 socket free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]int{0},
|
||||
},
|
||||
{
|
||||
"single socket HT, 0 sockets free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
|
||||
[]int{},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 2 sockets free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
[]int{0, 1},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 1 socket free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11),
|
||||
[]int{1},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 0 sockets free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 2, 3, 4, 5, 6, 7, 8, 9, 11),
|
||||
[]int{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
acc := newCPUAccumulator(tc.topo, tc.availableCPUs, 0)
|
||||
result := acc.freeSockets()
|
||||
if !reflect.DeepEqual(result, tc.expect) {
|
||||
t.Errorf("[%s] expected %v to equal %v", tc.description, result, tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUAccumulatorFreeCores(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
availableCPUs cpuset.CPUSet
|
||||
expect []int
|
||||
}{
|
||||
{
|
||||
"single socket HT, 4 cores free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]int{0, 1, 2, 3},
|
||||
},
|
||||
{
|
||||
"single socket HT, 3 cores free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 4, 5, 6),
|
||||
[]int{0, 1, 2},
|
||||
},
|
||||
{
|
||||
"single socket HT, 3 cores free (1 partially consumed)",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6),
|
||||
[]int{0, 1, 2},
|
||||
},
|
||||
{
|
||||
"single socket HT, 0 cores free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(),
|
||||
[]int{},
|
||||
},
|
||||
{
|
||||
"single socket HT, 0 cores free (4 partially consumed)",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3),
|
||||
[]int{},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 6 cores free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
[]int{0, 2, 4, 1, 3, 5},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 5 cores free (1 consumed from socket 0)",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(2, 1, 3, 4, 5, 7, 8, 9, 10, 11),
|
||||
[]int{2, 4, 1, 3, 5},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 4 cores free (1 consumed from each socket)",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(2, 3, 4, 5, 8, 9, 10, 11),
|
||||
[]int{2, 4, 3, 5},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
acc := newCPUAccumulator(tc.topo, tc.availableCPUs, 0)
|
||||
result := acc.freeCores()
|
||||
if !reflect.DeepEqual(result, tc.expect) {
|
||||
t.Errorf("[%s] expected %v to equal %v", tc.description, result, tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUAccumulatorFreeCPUs(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
availableCPUs cpuset.CPUSet
|
||||
expect []int
|
||||
}{
|
||||
{
|
||||
"single socket HT, 8 cpus free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]int{0, 4, 1, 5, 2, 6, 3, 7},
|
||||
},
|
||||
{
|
||||
"single socket HT, 5 cpus free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(3, 4, 5, 6, 7),
|
||||
[]int{4, 5, 6, 3, 7},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 12 cpus free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
[]int{0, 6, 2, 8, 4, 10, 1, 7, 3, 9, 5, 11},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 11 cpus free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
[]int{6, 2, 8, 4, 10, 1, 7, 3, 9, 5, 11},
|
||||
},
|
||||
{
|
||||
"dual socket HT, 10 cpus free",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
|
||||
[]int{2, 8, 4, 10, 1, 7, 3, 9, 5, 11},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
acc := newCPUAccumulator(tc.topo, tc.availableCPUs, 0)
|
||||
result := acc.freeCPUs()
|
||||
if !reflect.DeepEqual(result, tc.expect) {
|
||||
t.Errorf("[%s] expected %v to equal %v", tc.description, result, tc.expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUAccumulatorTake(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
availableCPUs cpuset.CPUSet
|
||||
takeCPUs []cpuset.CPUSet
|
||||
numCPUs int
|
||||
expectSatisfied bool
|
||||
expectFailed bool
|
||||
}{
|
||||
{
|
||||
"take 0 cpus from a single socket HT, require 1",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]cpuset.CPUSet{cpuset.NewCPUSet()},
|
||||
1,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"take 0 cpus from a single socket HT, require 1, none available",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(),
|
||||
[]cpuset.CPUSet{cpuset.NewCPUSet()},
|
||||
1,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"take 1 cpu from a single socket HT, require 1",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]cpuset.CPUSet{cpuset.NewCPUSet(0)},
|
||||
1,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"take 1 cpu from a single socket HT, require 2",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]cpuset.CPUSet{cpuset.NewCPUSet(0)},
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"take 2 cpu from a single socket HT, require 4, expect failed",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2),
|
||||
[]cpuset.CPUSet{cpuset.NewCPUSet(0), cpuset.NewCPUSet(1)},
|
||||
4,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"take all cpus one at a time from a single socket HT, require 8",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
[]cpuset.CPUSet{
|
||||
cpuset.NewCPUSet(0),
|
||||
cpuset.NewCPUSet(1),
|
||||
cpuset.NewCPUSet(2),
|
||||
cpuset.NewCPUSet(3),
|
||||
cpuset.NewCPUSet(4),
|
||||
cpuset.NewCPUSet(5),
|
||||
cpuset.NewCPUSet(6),
|
||||
cpuset.NewCPUSet(7),
|
||||
},
|
||||
8,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
acc := newCPUAccumulator(tc.topo, tc.availableCPUs, tc.numCPUs)
|
||||
totalTaken := 0
|
||||
for _, cpus := range tc.takeCPUs {
|
||||
acc.take(cpus)
|
||||
totalTaken += cpus.Size()
|
||||
}
|
||||
if tc.expectSatisfied != acc.isSatisfied() {
|
||||
t.Errorf("[%s] expected acc.isSatisfied() to be %t", tc.description, tc.expectSatisfied)
|
||||
}
|
||||
if tc.expectFailed != acc.isFailed() {
|
||||
t.Errorf("[%s] expected acc.isFailed() to be %t", tc.description, tc.expectFailed)
|
||||
}
|
||||
for _, cpus := range tc.takeCPUs {
|
||||
availableCPUs := acc.details.CPUs()
|
||||
if cpus.Intersection(availableCPUs).Size() > 0 {
|
||||
t.Errorf("[%s] expected intersection of taken cpus [%s] and acc.details.CPUs() [%s] to be empty", tc.description, cpus, availableCPUs)
|
||||
}
|
||||
if !cpus.IsSubsetOf(acc.result) {
|
||||
t.Errorf("[%s] expected [%s] to be a subset of acc.result [%s]", tc.description, cpus, acc.result)
|
||||
}
|
||||
}
|
||||
expNumCPUsNeeded := tc.numCPUs - totalTaken
|
||||
if acc.numCPUsNeeded != expNumCPUsNeeded {
|
||||
t.Errorf("[%s] expected acc.numCPUsNeeded to be %d (got %d)", tc.description, expNumCPUsNeeded, acc.numCPUsNeeded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTakeByTopology(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
availableCPUs cpuset.CPUSet
|
||||
numCPUs int
|
||||
expErr string
|
||||
expResult cpuset.CPUSet
|
||||
}{
|
||||
{
|
||||
"take more cpus than are available from single socket with HT",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 2, 4, 6),
|
||||
5,
|
||||
"not enough cpus available to satisfy request",
|
||||
cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
"take zero cpus from single socket with HT",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
0,
|
||||
"",
|
||||
cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
"take one cpu from single socket with HT",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
1,
|
||||
"",
|
||||
cpuset.NewCPUSet(0),
|
||||
},
|
||||
{
|
||||
"take one cpu from single socket with HT, some cpus are taken",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(1, 3, 5, 6, 7),
|
||||
1,
|
||||
"",
|
||||
cpuset.NewCPUSet(6),
|
||||
},
|
||||
{
|
||||
"take two cpus from single socket with HT",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
2,
|
||||
"",
|
||||
cpuset.NewCPUSet(0, 4),
|
||||
},
|
||||
{
|
||||
"take all cpus from single socket with HT",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
8,
|
||||
"",
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
},
|
||||
{
|
||||
"take two cpus from single socket with HT, only one core totally free",
|
||||
topoSingleSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 6),
|
||||
2,
|
||||
"",
|
||||
cpuset.NewCPUSet(2, 6),
|
||||
},
|
||||
{
|
||||
"take three cpus from dual socket with HT - core from Socket 0",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(1, 2, 3, 4, 5, 7, 8, 9, 10, 11),
|
||||
1,
|
||||
"",
|
||||
cpuset.NewCPUSet(2),
|
||||
},
|
||||
{
|
||||
"take a socket of cpus from dual socket with HT",
|
||||
topoDualSocketHT,
|
||||
cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
6,
|
||||
"",
|
||||
cpuset.NewCPUSet(0, 2, 4, 6, 8, 10),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
result, err := takeByTopology(tc.topo, tc.availableCPUs, tc.numCPUs)
|
||||
if tc.expErr != "" && err.Error() != tc.expErr {
|
||||
t.Errorf("expected error to be [%v] but it was [%v] in test \"%s\"", tc.expErr, err, tc.description)
|
||||
}
|
||||
if !result.Equals(tc.expResult) {
|
||||
t.Errorf("expected result [%s] to equal [%s] in test \"%s\"", result, tc.expResult, tc.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
276
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_manager.go
generated
vendored
Normal file
276
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
)
|
||||
|
||||
// ActivePodsFunc is a function that returns a list of pods to reconcile.
|
||||
type ActivePodsFunc func() []*v1.Pod
|
||||
|
||||
type runtimeService interface {
|
||||
UpdateContainerResources(id string, resources *runtimeapi.LinuxContainerResources) error
|
||||
}
|
||||
|
||||
type policyName string
|
||||
|
||||
// Manager interface provides methods for Kubelet to manage pod cpus.
|
||||
type Manager interface {
|
||||
// Start is called during Kubelet initialization.
|
||||
Start(activePods ActivePodsFunc, podStatusProvider status.PodStatusProvider, containerRuntime runtimeService)
|
||||
|
||||
// AddContainer is called between container create and container start
|
||||
// so that initial CPU affinity settings can be written through to the
|
||||
// container runtime before the first process begins to execute.
|
||||
AddContainer(p *v1.Pod, c *v1.Container, containerID string) error
|
||||
|
||||
// RemoveContainer is called after Kubelet decides to kill or delete a
|
||||
// container. After this call, the CPU manager stops trying to reconcile
|
||||
// that container and any CPUs dedicated to the container are freed.
|
||||
RemoveContainer(containerID string) error
|
||||
|
||||
// State returns a read-only interface to the internal CPU manager state.
|
||||
State() state.Reader
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
sync.Mutex
|
||||
policy Policy
|
||||
|
||||
// reconcilePeriod is the duration between calls to reconcileState.
|
||||
reconcilePeriod time.Duration
|
||||
|
||||
// state allows pluggable CPU assignment policies while sharing a common
|
||||
// representation of state for the system to inspect and reconcile.
|
||||
state state.State
|
||||
|
||||
// containerRuntime is the container runtime service interface needed
|
||||
// to make UpdateContainerResources() calls against the containers.
|
||||
containerRuntime runtimeService
|
||||
|
||||
// activePods is a method for listing active pods on the node
|
||||
// so all the containers can be updated in the reconciliation loop.
|
||||
activePods ActivePodsFunc
|
||||
|
||||
// podStatusProvider provides a method for obtaining pod statuses
|
||||
// and the containerID of their containers
|
||||
podStatusProvider status.PodStatusProvider
|
||||
|
||||
machineInfo *cadvisorapi.MachineInfo
|
||||
|
||||
nodeAllocatableReservation v1.ResourceList
|
||||
}
|
||||
|
||||
var _ Manager = &manager{}
|
||||
|
||||
// NewManager creates new cpu manager based on provided policy
|
||||
func NewManager(
|
||||
cpuPolicyName string,
|
||||
reconcilePeriod time.Duration,
|
||||
machineInfo *cadvisorapi.MachineInfo,
|
||||
nodeAllocatableReservation v1.ResourceList,
|
||||
) (Manager, error) {
|
||||
var policy Policy
|
||||
|
||||
switch policyName(cpuPolicyName) {
|
||||
|
||||
case PolicyNone:
|
||||
policy = NewNonePolicy()
|
||||
|
||||
case PolicyStatic:
|
||||
topo, err := topology.Discover(machineInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.Infof("[cpumanager] detected CPU topology: %v", topo)
|
||||
reservedCPUs, ok := nodeAllocatableReservation[v1.ResourceCPU]
|
||||
if !ok {
|
||||
// The static policy cannot initialize without this information. Panic!
|
||||
panic("[cpumanager] unable to determine reserved CPU resources for static policy")
|
||||
}
|
||||
if reservedCPUs.IsZero() {
|
||||
// Panic!
|
||||
//
|
||||
// The static policy requires this to be nonzero. Zero CPU reservation
|
||||
// would allow the shared pool to be completely exhausted. At that point
|
||||
// either we would violate our guarantee of exclusivity or need to evict
|
||||
// any pod that has at least one container that requires zero CPUs.
|
||||
// See the comments in policy_static.go for more details.
|
||||
panic("[cpumanager] the static policy requires systemreserved.cpu + kubereserved.cpu to be greater than zero")
|
||||
}
|
||||
|
||||
// Take the ceiling of the reservation, since fractional CPUs cannot be
|
||||
// exclusively allocated.
|
||||
reservedCPUsFloat := float64(reservedCPUs.MilliValue()) / 1000
|
||||
numReservedCPUs := int(math.Ceil(reservedCPUsFloat))
|
||||
policy = NewStaticPolicy(topo, numReservedCPUs)
|
||||
|
||||
default:
|
||||
glog.Errorf("[cpumanager] Unknown policy \"%s\", falling back to default policy \"%s\"", cpuPolicyName, PolicyNone)
|
||||
policy = NewNonePolicy()
|
||||
}
|
||||
|
||||
manager := &manager{
|
||||
policy: policy,
|
||||
reconcilePeriod: reconcilePeriod,
|
||||
state: state.NewMemoryState(),
|
||||
machineInfo: machineInfo,
|
||||
nodeAllocatableReservation: nodeAllocatableReservation,
|
||||
}
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
func (m *manager) Start(activePods ActivePodsFunc, podStatusProvider status.PodStatusProvider, containerRuntime runtimeService) {
|
||||
glog.Infof("[cpumanger] starting with %s policy", m.policy.Name())
|
||||
glog.Infof("[cpumanger] reconciling every %v", m.reconcilePeriod)
|
||||
|
||||
m.activePods = activePods
|
||||
m.podStatusProvider = podStatusProvider
|
||||
m.containerRuntime = containerRuntime
|
||||
|
||||
m.policy.Start(m.state)
|
||||
if m.policy.Name() == string(PolicyNone) {
|
||||
return
|
||||
}
|
||||
go wait.Until(func() { m.reconcileState() }, m.reconcilePeriod, wait.NeverStop)
|
||||
}
|
||||
|
||||
func (m *manager) AddContainer(p *v1.Pod, c *v1.Container, containerID string) error {
|
||||
m.Lock()
|
||||
err := m.policy.AddContainer(m.state, p, c, containerID)
|
||||
if err != nil {
|
||||
glog.Errorf("[cpumanager] AddContainer error: %v", err)
|
||||
m.Unlock()
|
||||
return err
|
||||
}
|
||||
cpus := m.state.GetCPUSetOrDefault(containerID)
|
||||
m.Unlock()
|
||||
|
||||
err = m.updateContainerCPUSet(containerID, cpus)
|
||||
if err != nil {
|
||||
glog.Errorf("[cpumanager] AddContainer error: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) RemoveContainer(containerID string) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
err := m.policy.RemoveContainer(m.state, containerID)
|
||||
if err != nil {
|
||||
glog.Errorf("[cpumanager] RemoveContainer error: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) State() state.Reader {
|
||||
return m.state
|
||||
}
|
||||
|
||||
type reconciledContainer struct {
|
||||
podName string
|
||||
containerName string
|
||||
containerID string
|
||||
}
|
||||
|
||||
func (m *manager) reconcileState() (success []reconciledContainer, failure []reconciledContainer) {
|
||||
success = []reconciledContainer{}
|
||||
failure = []reconciledContainer{}
|
||||
|
||||
for _, pod := range m.activePods() {
|
||||
allContainers := pod.Spec.InitContainers
|
||||
allContainers = append(allContainers, pod.Spec.Containers...)
|
||||
for _, container := range allContainers {
|
||||
status, ok := m.podStatusProvider.GetPodStatus(pod.UID)
|
||||
if !ok {
|
||||
glog.Warningf("[cpumanager] reconcileState: skipping pod; status not found (pod: %s, container: %s)", pod.Name, container.Name)
|
||||
failure = append(failure, reconciledContainer{pod.Name, container.Name, ""})
|
||||
break
|
||||
}
|
||||
|
||||
containerID, err := findContainerIDByName(&status, container.Name)
|
||||
if err != nil {
|
||||
glog.Warningf("[cpumanager] reconcileState: skipping container; ID not found in status (pod: %s, container: %s, error: %v)", pod.Name, container.Name, err)
|
||||
failure = append(failure, reconciledContainer{pod.Name, container.Name, ""})
|
||||
continue
|
||||
}
|
||||
|
||||
cset := m.state.GetCPUSetOrDefault(containerID)
|
||||
if cset.IsEmpty() {
|
||||
// NOTE: This should not happen outside of tests.
|
||||
glog.Infof("[cpumanager] reconcileState: skipping container; assigned cpuset is empty (pod: %s, container: %s)", pod.Name, container.Name)
|
||||
failure = append(failure, reconciledContainer{pod.Name, container.Name, containerID})
|
||||
continue
|
||||
}
|
||||
|
||||
glog.Infof("[cpumanager] reconcileState: updating container (pod: %s, container: %s, container id: %s, cpuset: \"%v\")", pod.Name, container.Name, containerID, cset)
|
||||
err = m.updateContainerCPUSet(containerID, cset)
|
||||
if err != nil {
|
||||
glog.Errorf("[cpumanager] reconcileState: failed to update container (pod: %s, container: %s, container id: %s, cpuset: \"%v\", error: %v)", pod.Name, container.Name, containerID, cset, err)
|
||||
failure = append(failure, reconciledContainer{pod.Name, container.Name, containerID})
|
||||
continue
|
||||
}
|
||||
success = append(success, reconciledContainer{pod.Name, container.Name, containerID})
|
||||
}
|
||||
}
|
||||
return success, failure
|
||||
}
|
||||
|
||||
func findContainerIDByName(status *v1.PodStatus, name string) (string, error) {
|
||||
for _, container := range status.ContainerStatuses {
|
||||
if container.Name == name && container.ContainerID != "" {
|
||||
cid := &kubecontainer.ContainerID{}
|
||||
err := cid.ParseString(container.ContainerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cid.ID, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("unable to find ID for container with name %v in pod status (it may not be running)", name)
|
||||
}
|
||||
|
||||
func (m *manager) updateContainerCPUSet(containerID string, cpus cpuset.CPUSet) error {
|
||||
// TODO: Consider adding a `ResourceConfigForContainer` helper in
|
||||
// helpers_linux.go similar to what exists for pods.
|
||||
// It would be better to pass the full container resources here instead of
|
||||
// this patch-like partial resources.
|
||||
return m.containerRuntime.UpdateContainerResources(
|
||||
containerID,
|
||||
&runtimeapi.LinuxContainerResources{
|
||||
CpusetCpus: cpus.String(),
|
||||
})
|
||||
}
|
||||
452
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_manager_test.go
generated
vendored
Normal file
452
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/cpu_manager_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
type mockState struct {
|
||||
assignments map[string]cpuset.CPUSet
|
||||
defaultCPUSet cpuset.CPUSet
|
||||
}
|
||||
|
||||
func (s *mockState) GetCPUSet(containerID string) (cpuset.CPUSet, bool) {
|
||||
res, ok := s.assignments[containerID]
|
||||
return res.Clone(), ok
|
||||
}
|
||||
|
||||
func (s *mockState) GetDefaultCPUSet() cpuset.CPUSet {
|
||||
return s.defaultCPUSet.Clone()
|
||||
}
|
||||
|
||||
func (s *mockState) GetCPUSetOrDefault(containerID string) cpuset.CPUSet {
|
||||
if res, ok := s.GetCPUSet(containerID); ok {
|
||||
return res
|
||||
}
|
||||
return s.GetDefaultCPUSet()
|
||||
}
|
||||
|
||||
func (s *mockState) SetCPUSet(containerID string, cset cpuset.CPUSet) {
|
||||
s.assignments[containerID] = cset
|
||||
}
|
||||
|
||||
func (s *mockState) SetDefaultCPUSet(cset cpuset.CPUSet) {
|
||||
s.defaultCPUSet = cset
|
||||
}
|
||||
|
||||
func (s *mockState) Delete(containerID string) {
|
||||
delete(s.assignments, containerID)
|
||||
}
|
||||
|
||||
type mockPolicy struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (p *mockPolicy) Name() string {
|
||||
return "mock"
|
||||
}
|
||||
|
||||
func (p *mockPolicy) Start(s state.State) {
|
||||
}
|
||||
|
||||
func (p *mockPolicy) AddContainer(s state.State, pod *v1.Pod, container *v1.Container, containerID string) error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
func (p *mockPolicy) RemoveContainer(s state.State, containerID string) error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
type mockRuntimeService struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (rt mockRuntimeService) UpdateContainerResources(id string, resources *runtimeapi.LinuxContainerResources) error {
|
||||
return rt.err
|
||||
}
|
||||
|
||||
type mockPodStatusProvider struct {
|
||||
podStatus v1.PodStatus
|
||||
found bool
|
||||
}
|
||||
|
||||
func (psp mockPodStatusProvider) GetPodStatus(uid types.UID) (v1.PodStatus, bool) {
|
||||
return psp.podStatus, psp.found
|
||||
}
|
||||
|
||||
type mockPodKiller struct {
|
||||
killedPods []*v1.Pod
|
||||
}
|
||||
|
||||
func (f *mockPodKiller) killPodNow(pod *v1.Pod, status v1.PodStatus, gracePeriodOverride *int64) error {
|
||||
f.killedPods = append(f.killedPods, pod)
|
||||
return nil
|
||||
}
|
||||
|
||||
type mockPodProvider struct {
|
||||
pods []*v1.Pod
|
||||
}
|
||||
|
||||
func (f *mockPodProvider) getPods() []*v1.Pod {
|
||||
return f.pods
|
||||
}
|
||||
|
||||
type mockRecorder struct{}
|
||||
|
||||
func (r *mockRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func makePod(cpuRequest, cpuLimit string) *v1.Pod {
|
||||
return &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse(cpuRequest),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("1G"),
|
||||
},
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceName(v1.ResourceCPU): resource.MustParse(cpuLimit),
|
||||
v1.ResourceName(v1.ResourceMemory): resource.MustParse("1G"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CpuAllocatable must be <= CpuCapacity
|
||||
func prepareCPUNodeStatus(CPUCapacity, CPUAllocatable string) v1.NodeStatus {
|
||||
nodestatus := v1.NodeStatus{
|
||||
Capacity: make(v1.ResourceList, 1),
|
||||
Allocatable: make(v1.ResourceList, 1),
|
||||
}
|
||||
cpucap, _ := resource.ParseQuantity(CPUCapacity)
|
||||
cpuall, _ := resource.ParseQuantity(CPUAllocatable)
|
||||
|
||||
nodestatus.Capacity[v1.ResourceCPU] = cpucap
|
||||
nodestatus.Allocatable[v1.ResourceCPU] = cpuall
|
||||
return nodestatus
|
||||
}
|
||||
|
||||
func TestCPUManagerAdd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
regErr error
|
||||
updateErr error
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
description: "cpu manager add - no error",
|
||||
regErr: nil,
|
||||
updateErr: nil,
|
||||
expErr: nil,
|
||||
},
|
||||
{
|
||||
description: "cpu manager add - policy add container error",
|
||||
regErr: fmt.Errorf("fake reg error"),
|
||||
updateErr: nil,
|
||||
expErr: fmt.Errorf("fake reg error"),
|
||||
},
|
||||
{
|
||||
description: "cpu manager add - container update error",
|
||||
regErr: nil,
|
||||
updateErr: fmt.Errorf("fake update error"),
|
||||
expErr: fmt.Errorf("fake update error"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
mgr := &manager{
|
||||
policy: &mockPolicy{
|
||||
err: testCase.regErr,
|
||||
},
|
||||
state: &mockState{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
containerRuntime: mockRuntimeService{
|
||||
err: testCase.updateErr,
|
||||
},
|
||||
activePods: func() []*v1.Pod { return nil },
|
||||
podStatusProvider: mockPodStatusProvider{},
|
||||
}
|
||||
|
||||
pod := makePod("1000", "1000")
|
||||
container := &pod.Spec.Containers[0]
|
||||
err := mgr.AddContainer(pod, container, "fakeID")
|
||||
if !reflect.DeepEqual(err, testCase.expErr) {
|
||||
t.Errorf("CPU Manager AddContainer() error (%v). expected error: %v but got: %v",
|
||||
testCase.description, testCase.expErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUManagerRemove(t *testing.T) {
|
||||
mgr := &manager{
|
||||
policy: &mockPolicy{
|
||||
err: nil,
|
||||
},
|
||||
state: &mockState{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
containerRuntime: mockRuntimeService{},
|
||||
activePods: func() []*v1.Pod { return nil },
|
||||
podStatusProvider: mockPodStatusProvider{},
|
||||
}
|
||||
|
||||
err := mgr.RemoveContainer("fakeID")
|
||||
if err != nil {
|
||||
t.Errorf("CPU Manager RemoveContainer() error. expected error to be nil but got: %v", err)
|
||||
}
|
||||
|
||||
mgr = &manager{
|
||||
policy: &mockPolicy{
|
||||
err: fmt.Errorf("fake error"),
|
||||
},
|
||||
state: state.NewMemoryState(),
|
||||
containerRuntime: mockRuntimeService{},
|
||||
activePods: func() []*v1.Pod { return nil },
|
||||
podStatusProvider: mockPodStatusProvider{},
|
||||
}
|
||||
|
||||
err = mgr.RemoveContainer("fakeID")
|
||||
if !reflect.DeepEqual(err, fmt.Errorf("fake error")) {
|
||||
t.Errorf("CPU Manager RemoveContainer() error. expected error: fake error but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReconcileState(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
activePods []*v1.Pod
|
||||
pspPS v1.PodStatus
|
||||
pspFound bool
|
||||
stAssignments map[string]cpuset.CPUSet
|
||||
stDefaultCPUSet cpuset.CPUSet
|
||||
updateErr error
|
||||
expectFailedContainerName string
|
||||
}{
|
||||
{
|
||||
description: "cpu manager reconclie - no error",
|
||||
activePods: []*v1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fakePodName",
|
||||
UID: "fakeUID",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fakeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pspPS: v1.PodStatus{
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "fakeName",
|
||||
ContainerID: "docker://fakeID",
|
||||
},
|
||||
},
|
||||
},
|
||||
pspFound: true,
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID": cpuset.NewCPUSet(1, 2),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(3, 4, 5, 6, 7),
|
||||
updateErr: nil,
|
||||
expectFailedContainerName: "",
|
||||
},
|
||||
{
|
||||
description: "cpu manager reconclie - pod status not found",
|
||||
activePods: []*v1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fakePodName",
|
||||
UID: "fakeUID",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fakeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pspPS: v1.PodStatus{},
|
||||
pspFound: false,
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(),
|
||||
updateErr: nil,
|
||||
expectFailedContainerName: "fakeName",
|
||||
},
|
||||
{
|
||||
description: "cpu manager reconclie - container id not found",
|
||||
activePods: []*v1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fakePodName",
|
||||
UID: "fakeUID",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fakeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pspPS: v1.PodStatus{
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "fakeName1",
|
||||
ContainerID: "docker://fakeID",
|
||||
},
|
||||
},
|
||||
},
|
||||
pspFound: true,
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(),
|
||||
updateErr: nil,
|
||||
expectFailedContainerName: "fakeName",
|
||||
},
|
||||
{
|
||||
description: "cpu manager reconclie - cpuset is empty",
|
||||
activePods: []*v1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fakePodName",
|
||||
UID: "fakeUID",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fakeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pspPS: v1.PodStatus{
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "fakeName",
|
||||
ContainerID: "docker://fakeID",
|
||||
},
|
||||
},
|
||||
},
|
||||
pspFound: true,
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID": cpuset.NewCPUSet(),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
|
||||
updateErr: nil,
|
||||
expectFailedContainerName: "fakeName",
|
||||
},
|
||||
{
|
||||
description: "cpu manager reconclie - container update error",
|
||||
activePods: []*v1.Pod{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fakePodName",
|
||||
UID: "fakeUID",
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "fakeName",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pspPS: v1.PodStatus{
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "fakeName",
|
||||
ContainerID: "docker://fakeID",
|
||||
},
|
||||
},
|
||||
},
|
||||
pspFound: true,
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID": cpuset.NewCPUSet(1, 2),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(3, 4, 5, 6, 7),
|
||||
updateErr: fmt.Errorf("fake container update error"),
|
||||
expectFailedContainerName: "fakeName",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
mgr := &manager{
|
||||
policy: &mockPolicy{
|
||||
err: nil,
|
||||
},
|
||||
state: &mockState{
|
||||
assignments: testCase.stAssignments,
|
||||
defaultCPUSet: testCase.stDefaultCPUSet,
|
||||
},
|
||||
containerRuntime: mockRuntimeService{
|
||||
err: testCase.updateErr,
|
||||
},
|
||||
activePods: func() []*v1.Pod {
|
||||
return testCase.activePods
|
||||
},
|
||||
podStatusProvider: mockPodStatusProvider{
|
||||
podStatus: testCase.pspPS,
|
||||
found: testCase.pspFound,
|
||||
},
|
||||
}
|
||||
|
||||
_, failure := mgr.reconcileState()
|
||||
|
||||
if testCase.expectFailedContainerName != "" {
|
||||
// Search failed reconciled containers for the supplied name.
|
||||
foundFailedContainer := false
|
||||
for _, reconciled := range failure {
|
||||
if reconciled.containerName == testCase.expectFailedContainerName {
|
||||
foundFailedContainer = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundFailedContainer {
|
||||
t.Errorf("Expected reconciliation failure for container: %s", testCase.expectFailedContainerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/fake_cpu_manager.go
generated
vendored
Normal file
58
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/fake_cpu_manager.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
"k8s.io/kubernetes/pkg/kubelet/status"
|
||||
)
|
||||
|
||||
type fakeManager struct {
|
||||
state state.State
|
||||
}
|
||||
|
||||
func (m *fakeManager) Start(activePods ActivePodsFunc, podStatusProvider status.PodStatusProvider, containerRuntime runtimeService) {
|
||||
glog.Info("[fake cpumanager] Start()")
|
||||
}
|
||||
|
||||
func (m *fakeManager) Policy() Policy {
|
||||
glog.Info("[fake cpumanager] Policy()")
|
||||
return NewNonePolicy()
|
||||
}
|
||||
|
||||
func (m *fakeManager) AddContainer(pod *v1.Pod, container *v1.Container, containerID string) error {
|
||||
glog.Infof("[fake cpumanager] AddContainer (pod: %s, container: %s, container id: %s)", pod.Name, container.Name, containerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *fakeManager) RemoveContainer(containerID string) error {
|
||||
glog.Infof("[fake cpumanager] RemoveContainer (container id: %s)", containerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *fakeManager) State() state.Reader {
|
||||
return m.state
|
||||
}
|
||||
|
||||
// NewFakeManager creates empty/fake cpu manager
|
||||
func NewFakeManager() Manager {
|
||||
return &fakeManager{
|
||||
state: state.NewMemoryState(),
|
||||
}
|
||||
}
|
||||
30
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy.go
generated
vendored
Normal file
30
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
)
|
||||
|
||||
// Policy implements logic for pod container to CPU assignment.
|
||||
type Policy interface {
|
||||
Name() string
|
||||
Start(s state.State)
|
||||
AddContainer(s state.State, pod *v1.Pod, container *v1.Container, containerID string) error
|
||||
RemoveContainer(s state.State, containerID string) error
|
||||
}
|
||||
51
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_none.go
generated
vendored
Normal file
51
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_none.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
)
|
||||
|
||||
type nonePolicy struct{}
|
||||
|
||||
var _ Policy = &nonePolicy{}
|
||||
|
||||
// PolicyNone name of none policy
|
||||
const PolicyNone policyName = "none"
|
||||
|
||||
// NewNonePolicy returns a cupset manager policy that does nothing
|
||||
func NewNonePolicy() Policy {
|
||||
return &nonePolicy{}
|
||||
}
|
||||
|
||||
func (p *nonePolicy) Name() string {
|
||||
return string(PolicyNone)
|
||||
}
|
||||
|
||||
func (p *nonePolicy) Start(s state.State) {
|
||||
glog.Info("[cpumanager] none policy: Start")
|
||||
}
|
||||
|
||||
func (p *nonePolicy) AddContainer(s state.State, pod *v1.Pod, container *v1.Container, containerID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *nonePolicy) RemoveContainer(s state.State, containerID string) error {
|
||||
return nil
|
||||
}
|
||||
64
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_none_test.go
generated
vendored
Normal file
64
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_none_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
func TestNonePolicyName(t *testing.T) {
|
||||
policy := &nonePolicy{}
|
||||
|
||||
policyName := policy.Name()
|
||||
if policyName != "none" {
|
||||
t.Errorf("NonePolicy Name() error. expected: none, returned: %v",
|
||||
policyName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonePolicyAdd(t *testing.T) {
|
||||
policy := &nonePolicy{}
|
||||
|
||||
st := &mockState{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
|
||||
}
|
||||
|
||||
testPod := makePod("1000m", "1000m")
|
||||
|
||||
container := &testPod.Spec.Containers[0]
|
||||
err := policy.AddContainer(st, testPod, container, "fakeID")
|
||||
if err != nil {
|
||||
t.Errorf("NonePolicy AddContainer() error. expected no error but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonePolicyRemove(t *testing.T) {
|
||||
policy := &nonePolicy{}
|
||||
|
||||
st := &mockState{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
|
||||
}
|
||||
|
||||
err := policy.RemoveContainer(st, "fakeID")
|
||||
if err != nil {
|
||||
t.Errorf("NonePolicy RemoveContainer() error. expected no error but got %v", err)
|
||||
}
|
||||
}
|
||||
172
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_static.go
generated
vendored
Normal file
172
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_static.go
generated
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
v1qos "k8s.io/kubernetes/pkg/api/v1/helper/qos"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
// PolicyStatic is the name of the static policy
|
||||
const PolicyStatic policyName = "static"
|
||||
|
||||
var _ Policy = &staticPolicy{}
|
||||
|
||||
// staticPolicy is a CPU manager policy that does not change CPU
|
||||
// assignments for exclusively pinned guaranteed containers after the main
|
||||
// container process starts.
|
||||
//
|
||||
// This policy allocates CPUs exclusively for a container if all the following
|
||||
// conditions are met:
|
||||
//
|
||||
// - The pod QoS class is Guaranteed.
|
||||
// - The CPU request is a positive integer.
|
||||
//
|
||||
// The static policy maintains the following sets of logical CPUs:
|
||||
//
|
||||
// - SHARED: Burstable, BestEffort, and non-integral Guaranteed containers
|
||||
// run here. Initially this contains all CPU IDs on the system. As
|
||||
// exclusive allocations are created and destroyed, this CPU set shrinks
|
||||
// and grows, accordingly. This is stored in the state as the default
|
||||
// CPU set.
|
||||
//
|
||||
// - RESERVED: A subset of the shared pool which is not exclusively
|
||||
// allocatable. The membership of this pool is static for the lifetime of
|
||||
// the Kubelet. The size of the reserved pool is
|
||||
// ceil(systemreserved.cpu + kubereserved.cpu).
|
||||
// Reserved CPUs are taken topologically starting with lowest-indexed
|
||||
// physical core, as reported by cAdvisor.
|
||||
//
|
||||
// - ASSIGNABLE: Equal to SHARED - RESERVED. Exclusive CPUs are allocated
|
||||
// from this pool.
|
||||
//
|
||||
// - EXCLUSIVE ALLOCATIONS: CPU sets assigned exclusively to one container.
|
||||
// These are stored as explicit assignments in the state.
|
||||
//
|
||||
// When an exclusive allocation is made, the static policy also updates the
|
||||
// default cpuset in the state abstraction. The CPU manager's periodic
|
||||
// reconcile loop takes care of rewriting the cpuset in cgroupfs for any
|
||||
// containers that may be running in the shared pool. For this reason,
|
||||
// applications running within exclusively-allocated containers must tolerate
|
||||
// potentially sharing their allocated CPUs for up to the CPU manager
|
||||
// reconcile period.
|
||||
type staticPolicy struct {
|
||||
// cpu socket topology
|
||||
topology *topology.CPUTopology
|
||||
// set of CPUs that is not available for exclusive assignment
|
||||
reserved cpuset.CPUSet
|
||||
}
|
||||
|
||||
// Ensure staticPolicy implements Policy interface
|
||||
var _ Policy = &staticPolicy{}
|
||||
|
||||
// NewStaticPolicy returns a CPU manager policy that does not change CPU
|
||||
// assignments for exclusively pinned guaranteed containers after the main
|
||||
// container process starts.
|
||||
func NewStaticPolicy(topology *topology.CPUTopology, numReservedCPUs int) Policy {
|
||||
allCPUs := topology.CPUDetails.CPUs()
|
||||
// takeByTopology allocates CPUs associated with low-numbered cores from
|
||||
// allCPUs.
|
||||
//
|
||||
// For example: Given a system with 8 CPUs available and HT enabled,
|
||||
// if numReservedCPUs=2, then reserved={0,4}
|
||||
reserved, _ := takeByTopology(topology, allCPUs, numReservedCPUs)
|
||||
|
||||
if reserved.Size() != numReservedCPUs {
|
||||
panic(fmt.Sprintf("[cpumanager] unable to reserve the required amount of CPUs (size of %s did not equal %d)", reserved, numReservedCPUs))
|
||||
}
|
||||
|
||||
glog.Infof("[cpumanager] reserved %d CPUs (\"%s\") not available for exclusive assignment", reserved.Size(), reserved)
|
||||
|
||||
return &staticPolicy{
|
||||
topology: topology,
|
||||
reserved: reserved,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *staticPolicy) Name() string {
|
||||
return string(PolicyStatic)
|
||||
}
|
||||
|
||||
func (p *staticPolicy) Start(s state.State) {
|
||||
// Configure the shared pool to include all detected CPU IDs.
|
||||
allCPUs := p.topology.CPUDetails.CPUs()
|
||||
s.SetDefaultCPUSet(allCPUs)
|
||||
}
|
||||
|
||||
// assignableCPUs returns the set of unassigned CPUs minus the reserved set.
|
||||
func (p *staticPolicy) assignableCPUs(s state.State) cpuset.CPUSet {
|
||||
return s.GetDefaultCPUSet().Difference(p.reserved)
|
||||
}
|
||||
|
||||
func (p *staticPolicy) AddContainer(s state.State, pod *v1.Pod, container *v1.Container, containerID string) error {
|
||||
glog.Infof("[cpumanager] static policy: AddContainer (pod: %s, container: %s, container id: %s)", pod.Name, container.Name, containerID)
|
||||
if numCPUs := guaranteedCPUs(pod, container); numCPUs != 0 {
|
||||
// container belongs in an exclusively allocated pool
|
||||
cpuset, err := p.allocateCPUs(s, numCPUs)
|
||||
if err != nil {
|
||||
glog.Errorf("[cpumanager] unable to allocate %d CPUs (container id: %s, error: %v)", numCPUs, containerID, err)
|
||||
return err
|
||||
}
|
||||
s.SetCPUSet(containerID, cpuset)
|
||||
}
|
||||
// container belongs in the shared pool (nothing to do; use default cpuset)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *staticPolicy) RemoveContainer(s state.State, containerID string) error {
|
||||
glog.Infof("[cpumanager] static policy: RemoveContainer (container id: %s)", containerID)
|
||||
if toRelease, ok := s.GetCPUSet(containerID); ok {
|
||||
s.Delete(containerID)
|
||||
// Mutate the shared pool, adding released cpus.
|
||||
s.SetDefaultCPUSet(s.GetDefaultCPUSet().Union(toRelease))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *staticPolicy) allocateCPUs(s state.State, numCPUs int) (cpuset.CPUSet, error) {
|
||||
glog.Infof("[cpumanager] allocateCpus: (numCPUs: %d)", numCPUs)
|
||||
result, err := takeByTopology(p.topology, p.assignableCPUs(s), numCPUs)
|
||||
if err != nil {
|
||||
return cpuset.NewCPUSet(), err
|
||||
}
|
||||
// Remove allocated CPUs from the shared CPUSet.
|
||||
s.SetDefaultCPUSet(s.GetDefaultCPUSet().Difference(result))
|
||||
|
||||
glog.Infof("[cpumanager] allocateCPUs: returning \"%v\"", result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func guaranteedCPUs(pod *v1.Pod, container *v1.Container) int {
|
||||
if v1qos.GetPodQOS(pod) != v1.PodQOSGuaranteed {
|
||||
return 0
|
||||
}
|
||||
cpuQuantity := container.Resources.Requests[v1.ResourceCPU]
|
||||
if cpuQuantity.Value()*1000 != cpuQuantity.MilliValue() {
|
||||
return 0
|
||||
}
|
||||
// Safe downcast to do for all systems with < 2.1 billion CPUs.
|
||||
// Per the language spec, `int` is guaranteed to be at least 32 bits wide.
|
||||
// https://golang.org/ref/spec#Numeric_types
|
||||
return int(cpuQuantity.Value())
|
||||
}
|
||||
437
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_static_test.go
generated
vendored
Normal file
437
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_static_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
type staticPolicyTest struct {
|
||||
description string
|
||||
topo *topology.CPUTopology
|
||||
numReservedCPUs int
|
||||
containerID string
|
||||
stAssignments map[string]cpuset.CPUSet
|
||||
stDefaultCPUSet cpuset.CPUSet
|
||||
pod *v1.Pod
|
||||
expErr error
|
||||
expCPUAlloc bool
|
||||
expCSet cpuset.CPUSet
|
||||
}
|
||||
|
||||
func TestStaticPolicyName(t *testing.T) {
|
||||
policy := NewStaticPolicy(topoSingleSocketHT, 1)
|
||||
|
||||
policyName := policy.Name()
|
||||
if policyName != "static" {
|
||||
t.Errorf("StaticPolicy Name() error. expected: static, returned: %v",
|
||||
policyName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticPolicyStart(t *testing.T) {
|
||||
policy := NewStaticPolicy(topoSingleSocketHT, 1).(*staticPolicy)
|
||||
|
||||
st := &mockState{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(),
|
||||
}
|
||||
|
||||
policy.Start(st)
|
||||
for cpuid := 1; cpuid < policy.topology.NumCPUs; cpuid++ {
|
||||
if !st.defaultCPUSet.Contains(cpuid) {
|
||||
t.Errorf("StaticPolicy Start() error. expected cpuid %d to be present in defaultCPUSet", cpuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticPolicyAdd(t *testing.T) {
|
||||
largeTopoBuilder := cpuset.NewBuilder()
|
||||
largeTopoSock0Builder := cpuset.NewBuilder()
|
||||
largeTopoSock1Builder := cpuset.NewBuilder()
|
||||
largeTopo := *topoQuadSocketFourWayHT
|
||||
for cpuid, val := range largeTopo.CPUDetails {
|
||||
largeTopoBuilder.Add(cpuid)
|
||||
if val.SocketID == 0 {
|
||||
largeTopoSock0Builder.Add(cpuid)
|
||||
} else if val.SocketID == 1 {
|
||||
largeTopoSock1Builder.Add(cpuid)
|
||||
}
|
||||
}
|
||||
largeTopoCPUSet := largeTopoBuilder.Result()
|
||||
largeTopoSock0CPUSet := largeTopoSock0Builder.Result()
|
||||
largeTopoSock1CPUSet := largeTopoSock1Builder.Result()
|
||||
|
||||
testCases := []staticPolicyTest{
|
||||
{
|
||||
description: "GuPodSingleCore, SingleSocketHT, ExpectError",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID2",
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
pod: makePod("8000m", "8000m"),
|
||||
expErr: fmt.Errorf("not enough cpus available to satisfy request"),
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
description: "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID2",
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
pod: makePod("1000m", "1000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(4), // expect sibling of partial core
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, SingleSocketHT, ExpectAllocOneCore",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID3",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(2, 3, 6, 7),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 4, 5),
|
||||
pod: makePod("2000m", "2000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(1, 5),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocket",
|
||||
topo: topoDualSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID3",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(2),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
pod: makePod("6000m", "6000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(1, 3, 5, 7, 9, 11),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketHT, ExpectAllocThreeCores",
|
||||
topo: topoDualSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID3",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(1, 5),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 2, 3, 4, 6, 7, 8, 9, 10, 11),
|
||||
pod: makePod("6000m", "6000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(2, 3, 4, 8, 9, 10),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketNoHT, ExpectAllocOneSocket",
|
||||
topo: topoDualSocketNoHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7),
|
||||
pod: makePod("4000m", "4000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(4, 5, 6, 7),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketNoHT, ExpectAllocFourCores",
|
||||
topo: topoDualSocketNoHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(4, 5),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 6, 7),
|
||||
pod: makePod("4000m", "4000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(1, 3, 6, 7),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocketOneCore",
|
||||
topo: topoDualSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID3",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(2),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
pod: makePod("8000m", "8000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(1, 3, 4, 5, 7, 9, 10, 11),
|
||||
},
|
||||
{
|
||||
description: "NonGuPod, SingleSocketHT, NoAlloc",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
pod: makePod("1000m", "2000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
description: "GuPodNonIntegerCore, SingleSocketHT, NoAlloc",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID4",
|
||||
stAssignments: map[string]cpuset.CPUSet{},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
|
||||
pod: makePod("977m", "977m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, SingleSocketHT, NoAllocExpectError",
|
||||
topo: topoSingleSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(1, 2, 3, 4, 5, 6),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 7),
|
||||
pod: makePod("2000m", "2000m"),
|
||||
expErr: fmt.Errorf("not enough cpus available to satisfy request"),
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
description: "GuPodMultipleCores, DualSocketHT, NoAllocExpectError",
|
||||
topo: topoDualSocketHT,
|
||||
numReservedCPUs: 1,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(1, 2, 3),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(0, 4, 5, 6, 7, 8, 9, 10, 11),
|
||||
pod: makePod("10000m", "10000m"),
|
||||
expErr: fmt.Errorf("not enough cpus available to satisfy request"),
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
{
|
||||
// All the CPUs from Socket 0 are available. Some CPUs from each
|
||||
// Socket have been already assigned.
|
||||
// Expect all CPUs from Socket 0.
|
||||
description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocSock0",
|
||||
topo: topoQuadSocketFourWayHT,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": cpuset.NewCPUSet(3, 11, 4, 5, 6, 7),
|
||||
},
|
||||
stDefaultCPUSet: largeTopoCPUSet.Difference(cpuset.NewCPUSet(3, 11, 4, 5, 6, 7)),
|
||||
pod: makePod("72000m", "72000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: largeTopoSock0CPUSet,
|
||||
},
|
||||
{
|
||||
// Only 2 full cores from three Sockets and some partial cores are available.
|
||||
// Expect CPUs from the 2 full cores available from the three Sockets.
|
||||
description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllFullCoresFromThreeSockets",
|
||||
topo: topoQuadSocketFourWayHT,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51,
|
||||
53, 173, 113, 233, 54, 61)),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51, 53, 173, 113, 233, 54, 61),
|
||||
pod: makePod("12000m", "12000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(1, 25, 13, 38, 11, 35, 23, 48, 53, 173, 113, 233),
|
||||
},
|
||||
{
|
||||
// All CPUs from Socket 1, 1 full core and some partial cores are available.
|
||||
// Expect all CPUs from Socket 1 and the hyper-threads from the full core.
|
||||
description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllSock1+FullCore",
|
||||
topo: topoQuadSocketFourWayHT,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": largeTopoCPUSet.Difference(largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47, 53,
|
||||
173, 61, 181, 108, 228, 115, 235))),
|
||||
},
|
||||
stDefaultCPUSet: largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47, 53, 173, 61, 181, 108, 228,
|
||||
115, 235)),
|
||||
pod: makePod("76000m", "76000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47)),
|
||||
},
|
||||
{
|
||||
// Only partial cores are available in the entire system.
|
||||
// Expect allocation of all the CPUs from the partial cores.
|
||||
description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocCPUs",
|
||||
topo: topoQuadSocketFourWayHT,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52)),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(10, 11, 53, 67, 52),
|
||||
pod: makePod("5000m", "5000m"),
|
||||
expErr: nil,
|
||||
expCPUAlloc: true,
|
||||
expCSet: cpuset.NewCPUSet(10, 11, 53, 67, 52),
|
||||
},
|
||||
{
|
||||
// Only 7 CPUs are available.
|
||||
// Pod requests 76 cores.
|
||||
// Error is expect since available CPUs are less than the request.
|
||||
description: "GuPodMultipleCores, topoQuadSocketFourWayHT, NoAlloc",
|
||||
topo: topoQuadSocketFourWayHT,
|
||||
containerID: "fakeID5",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52)),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52),
|
||||
pod: makePod("76000m", "76000m"),
|
||||
expErr: fmt.Errorf("not enough cpus available to satisfy request"),
|
||||
expCPUAlloc: false,
|
||||
expCSet: cpuset.NewCPUSet(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
policy := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs)
|
||||
|
||||
st := &mockState{
|
||||
assignments: testCase.stAssignments,
|
||||
defaultCPUSet: testCase.stDefaultCPUSet,
|
||||
}
|
||||
|
||||
container := &testCase.pod.Spec.Containers[0]
|
||||
err := policy.AddContainer(st, testCase.pod, container, testCase.containerID)
|
||||
if !reflect.DeepEqual(err, testCase.expErr) {
|
||||
t.Errorf("StaticPolicy AddContainer() error (%v). expected add error: %v but got: %v",
|
||||
testCase.description, testCase.expErr, err)
|
||||
}
|
||||
|
||||
if testCase.expCPUAlloc {
|
||||
cset, found := st.assignments[testCase.containerID]
|
||||
if !found {
|
||||
t.Errorf("StaticPolicy AddContainer() error (%v). expected container id %v to be present in assignments %v",
|
||||
testCase.description, testCase.containerID, st.assignments)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cset, testCase.expCSet) {
|
||||
t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v but got %v",
|
||||
testCase.description, testCase.expCSet, cset)
|
||||
}
|
||||
|
||||
if !cset.Intersection(st.defaultCPUSet).IsEmpty() {
|
||||
t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v to be disoint from the shared cpuset %v",
|
||||
testCase.description, cset, st.defaultCPUSet)
|
||||
}
|
||||
}
|
||||
|
||||
if !testCase.expCPUAlloc {
|
||||
_, found := st.assignments[testCase.containerID]
|
||||
if found {
|
||||
t.Errorf("StaticPolicy AddContainer() error (%v). Did not expect container id %v to be present in assignments %v",
|
||||
testCase.description, testCase.containerID, st.assignments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticPolicyRemove(t *testing.T) {
|
||||
testCases := []staticPolicyTest{
|
||||
{
|
||||
description: "SingleSocketHT, DeAllocOneContainer",
|
||||
topo: topoSingleSocketHT,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID1": cpuset.NewCPUSet(1, 2, 3),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(4, 5, 6, 7),
|
||||
expCSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
|
||||
},
|
||||
{
|
||||
description: "SingleSocketHT, DeAllocOneContainer, BeginEmpty",
|
||||
topo: topoSingleSocketHT,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID1": cpuset.NewCPUSet(1, 2, 3),
|
||||
"fakeID2": cpuset.NewCPUSet(4, 5, 6, 7),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(),
|
||||
expCSet: cpuset.NewCPUSet(1, 2, 3),
|
||||
},
|
||||
{
|
||||
description: "SingleSocketHT, DeAllocTwoContainer",
|
||||
topo: topoSingleSocketHT,
|
||||
containerID: "fakeID1",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID1": cpuset.NewCPUSet(1, 3, 5),
|
||||
"fakeID2": cpuset.NewCPUSet(2, 4),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(6, 7),
|
||||
expCSet: cpuset.NewCPUSet(1, 3, 5, 6, 7),
|
||||
},
|
||||
{
|
||||
description: "SingleSocketHT, NoDeAlloc",
|
||||
topo: topoSingleSocketHT,
|
||||
containerID: "fakeID2",
|
||||
stAssignments: map[string]cpuset.CPUSet{
|
||||
"fakeID1": cpuset.NewCPUSet(1, 3, 5),
|
||||
},
|
||||
stDefaultCPUSet: cpuset.NewCPUSet(2, 4, 6, 7),
|
||||
expCSet: cpuset.NewCPUSet(2, 4, 6, 7),
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
policy := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs)
|
||||
|
||||
st := &mockState{
|
||||
assignments: testCase.stAssignments,
|
||||
defaultCPUSet: testCase.stDefaultCPUSet,
|
||||
}
|
||||
|
||||
policy.RemoveContainer(st, testCase.containerID)
|
||||
|
||||
if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSet) {
|
||||
t.Errorf("StaticPolicy RemoveContainer() error (%v). expected default cpuset %v but got %v",
|
||||
testCase.description, testCase.expCSet, st.defaultCPUSet)
|
||||
}
|
||||
|
||||
if _, found := st.assignments[testCase.containerID]; found {
|
||||
t.Errorf("StaticPolicy RemoveContainer() error (%v). expected containerID %v not be in assignments %v",
|
||||
testCase.description, testCase.containerID, st.assignments)
|
||||
}
|
||||
}
|
||||
}
|
||||
390
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_test.go
generated
vendored
Normal file
390
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/policy_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
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 cpumanager
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
)
|
||||
|
||||
var (
|
||||
topoSingleSocketHT = &topology.CPUTopology{
|
||||
NumCPUs: 8,
|
||||
NumSockets: 1,
|
||||
NumCores: 4,
|
||||
CPUDetails: map[int]topology.CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
1: {CoreID: 1, SocketID: 0},
|
||||
2: {CoreID: 2, SocketID: 0},
|
||||
3: {CoreID: 3, SocketID: 0},
|
||||
4: {CoreID: 0, SocketID: 0},
|
||||
5: {CoreID: 1, SocketID: 0},
|
||||
6: {CoreID: 2, SocketID: 0},
|
||||
7: {CoreID: 3, SocketID: 0},
|
||||
},
|
||||
}
|
||||
|
||||
topoDualSocketHT = &topology.CPUTopology{
|
||||
NumCPUs: 12,
|
||||
NumSockets: 2,
|
||||
NumCores: 6,
|
||||
CPUDetails: map[int]topology.CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
1: {CoreID: 1, SocketID: 1},
|
||||
2: {CoreID: 2, SocketID: 0},
|
||||
3: {CoreID: 3, SocketID: 1},
|
||||
4: {CoreID: 4, SocketID: 0},
|
||||
5: {CoreID: 5, SocketID: 1},
|
||||
6: {CoreID: 0, SocketID: 0},
|
||||
7: {CoreID: 1, SocketID: 1},
|
||||
8: {CoreID: 2, SocketID: 0},
|
||||
9: {CoreID: 3, SocketID: 1},
|
||||
10: {CoreID: 4, SocketID: 0},
|
||||
11: {CoreID: 5, SocketID: 1},
|
||||
},
|
||||
}
|
||||
|
||||
topoDualSocketNoHT = &topology.CPUTopology{
|
||||
NumCPUs: 8,
|
||||
NumSockets: 2,
|
||||
NumCores: 8,
|
||||
CPUDetails: map[int]topology.CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
1: {CoreID: 1, SocketID: 0},
|
||||
2: {CoreID: 2, SocketID: 0},
|
||||
3: {CoreID: 3, SocketID: 0},
|
||||
4: {CoreID: 4, SocketID: 1},
|
||||
5: {CoreID: 5, SocketID: 1},
|
||||
6: {CoreID: 6, SocketID: 1},
|
||||
7: {CoreID: 7, SocketID: 1},
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
Topology from https://www.open-mpi.org/projects/hwloc/lstopo/images/KNL.SNC4.H50.v1.11.png.
|
||||
Socket0:
|
||||
0-2,9-10,13-14,21-22,25-26,33-34,38-39,46-47,50,57-58,71-72,79-80,87-88,95-96,103-104,109-110,117-118,
|
||||
131-132,139-140,147-148,155-156,163-164,169-170,177-178,191-192,199-200,207-208,215-216,223-224,229-230,
|
||||
237-238,251-252,259-260,267-268,275-276,283-284
|
||||
Socket1:
|
||||
3-4,11-12,15-16,23-24,27-28,35-36,40-41,48-49,51-52,59-60,65-66,73-74,81-82,89-90,97-98,111-112,119-120,125-126,
|
||||
133-134,141-142,149-150,157-158,171-172,179-180,185-186,193-194,201-202,209-210,217-218,231-232,239-240,245-246,
|
||||
253-254,261-262,269-270,277-278
|
||||
Socket2:
|
||||
5-6,17-18,29-30,42-43,53-54,61-62,67-68,75-76,83-84,91-92,99-100,105-106,113-114,121-122,127-128,135-136,
|
||||
143-144,151-152,159-160,165-166,173-174,181-182,187-188,195-196,203-204,211-212,219-220,225-226,233-234,241-242,
|
||||
247-248,255-256,263-264,271-272,279-280,285-286
|
||||
Socket3:
|
||||
7-8,19-20,31-32,37,44-45,55-56,63-64,69-70,77-78,85-86,93-94,101-102,107-108,115-116,123-124,129-130,137-138,
|
||||
145-146,153-154,161-162,167-168,175-176,183-184,189-190,197-198,205-206,213-214,221-222,227-228,235-236,243-244,
|
||||
249-250,257-258,265-266,273-274,281-282,287
|
||||
*/
|
||||
topoQuadSocketFourWayHT = &topology.CPUTopology{
|
||||
NumCPUs: 288,
|
||||
NumSockets: 4,
|
||||
NumCores: 72,
|
||||
CPUDetails: map[int]topology.CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
169: {CoreID: 0, SocketID: 0},
|
||||
109: {CoreID: 0, SocketID: 0},
|
||||
229: {CoreID: 0, SocketID: 0},
|
||||
50: {CoreID: 1, SocketID: 0},
|
||||
170: {CoreID: 1, SocketID: 0},
|
||||
110: {CoreID: 1, SocketID: 0},
|
||||
230: {CoreID: 1, SocketID: 0},
|
||||
1: {CoreID: 64, SocketID: 0},
|
||||
25: {CoreID: 64, SocketID: 0},
|
||||
13: {CoreID: 64, SocketID: 0},
|
||||
38: {CoreID: 64, SocketID: 0},
|
||||
2: {CoreID: 65, SocketID: 0},
|
||||
26: {CoreID: 65, SocketID: 0},
|
||||
14: {CoreID: 65, SocketID: 0},
|
||||
39: {CoreID: 65, SocketID: 0},
|
||||
9: {CoreID: 72, SocketID: 0},
|
||||
33: {CoreID: 72, SocketID: 0},
|
||||
21: {CoreID: 72, SocketID: 0},
|
||||
46: {CoreID: 72, SocketID: 0},
|
||||
10: {CoreID: 73, SocketID: 0},
|
||||
34: {CoreID: 73, SocketID: 0},
|
||||
22: {CoreID: 73, SocketID: 0},
|
||||
47: {CoreID: 73, SocketID: 0},
|
||||
57: {CoreID: 8, SocketID: 0},
|
||||
177: {CoreID: 8, SocketID: 0},
|
||||
117: {CoreID: 8, SocketID: 0},
|
||||
237: {CoreID: 8, SocketID: 0},
|
||||
58: {CoreID: 9, SocketID: 0},
|
||||
178: {CoreID: 9, SocketID: 0},
|
||||
118: {CoreID: 9, SocketID: 0},
|
||||
238: {CoreID: 9, SocketID: 0},
|
||||
71: {CoreID: 24, SocketID: 0},
|
||||
191: {CoreID: 24, SocketID: 0},
|
||||
131: {CoreID: 24, SocketID: 0},
|
||||
251: {CoreID: 24, SocketID: 0},
|
||||
72: {CoreID: 25, SocketID: 0},
|
||||
192: {CoreID: 25, SocketID: 0},
|
||||
132: {CoreID: 25, SocketID: 0},
|
||||
252: {CoreID: 25, SocketID: 0},
|
||||
79: {CoreID: 32, SocketID: 0},
|
||||
199: {CoreID: 32, SocketID: 0},
|
||||
139: {CoreID: 32, SocketID: 0},
|
||||
259: {CoreID: 32, SocketID: 0},
|
||||
80: {CoreID: 33, SocketID: 0},
|
||||
200: {CoreID: 33, SocketID: 0},
|
||||
140: {CoreID: 33, SocketID: 0},
|
||||
260: {CoreID: 33, SocketID: 0},
|
||||
87: {CoreID: 40, SocketID: 0},
|
||||
207: {CoreID: 40, SocketID: 0},
|
||||
147: {CoreID: 40, SocketID: 0},
|
||||
267: {CoreID: 40, SocketID: 0},
|
||||
88: {CoreID: 41, SocketID: 0},
|
||||
208: {CoreID: 41, SocketID: 0},
|
||||
148: {CoreID: 41, SocketID: 0},
|
||||
268: {CoreID: 41, SocketID: 0},
|
||||
95: {CoreID: 48, SocketID: 0},
|
||||
215: {CoreID: 48, SocketID: 0},
|
||||
155: {CoreID: 48, SocketID: 0},
|
||||
275: {CoreID: 48, SocketID: 0},
|
||||
96: {CoreID: 49, SocketID: 0},
|
||||
216: {CoreID: 49, SocketID: 0},
|
||||
156: {CoreID: 49, SocketID: 0},
|
||||
276: {CoreID: 49, SocketID: 0},
|
||||
103: {CoreID: 56, SocketID: 0},
|
||||
223: {CoreID: 56, SocketID: 0},
|
||||
163: {CoreID: 56, SocketID: 0},
|
||||
283: {CoreID: 56, SocketID: 0},
|
||||
104: {CoreID: 57, SocketID: 0},
|
||||
224: {CoreID: 57, SocketID: 0},
|
||||
164: {CoreID: 57, SocketID: 0},
|
||||
284: {CoreID: 57, SocketID: 0},
|
||||
3: {CoreID: 66, SocketID: 1},
|
||||
27: {CoreID: 66, SocketID: 1},
|
||||
15: {CoreID: 66, SocketID: 1},
|
||||
40: {CoreID: 66, SocketID: 1},
|
||||
4: {CoreID: 67, SocketID: 1},
|
||||
28: {CoreID: 67, SocketID: 1},
|
||||
16: {CoreID: 67, SocketID: 1},
|
||||
41: {CoreID: 67, SocketID: 1},
|
||||
11: {CoreID: 74, SocketID: 1},
|
||||
35: {CoreID: 74, SocketID: 1},
|
||||
23: {CoreID: 74, SocketID: 1},
|
||||
48: {CoreID: 74, SocketID: 1},
|
||||
12: {CoreID: 75, SocketID: 1},
|
||||
36: {CoreID: 75, SocketID: 1},
|
||||
24: {CoreID: 75, SocketID: 1},
|
||||
49: {CoreID: 75, SocketID: 1},
|
||||
51: {CoreID: 2, SocketID: 1},
|
||||
171: {CoreID: 2, SocketID: 1},
|
||||
111: {CoreID: 2, SocketID: 1},
|
||||
231: {CoreID: 2, SocketID: 1},
|
||||
52: {CoreID: 3, SocketID: 1},
|
||||
172: {CoreID: 3, SocketID: 1},
|
||||
112: {CoreID: 3, SocketID: 1},
|
||||
232: {CoreID: 3, SocketID: 1},
|
||||
59: {CoreID: 10, SocketID: 1},
|
||||
179: {CoreID: 10, SocketID: 1},
|
||||
119: {CoreID: 10, SocketID: 1},
|
||||
239: {CoreID: 10, SocketID: 1},
|
||||
60: {CoreID: 11, SocketID: 1},
|
||||
180: {CoreID: 11, SocketID: 1},
|
||||
120: {CoreID: 11, SocketID: 1},
|
||||
240: {CoreID: 11, SocketID: 1},
|
||||
65: {CoreID: 18, SocketID: 1},
|
||||
185: {CoreID: 18, SocketID: 1},
|
||||
125: {CoreID: 18, SocketID: 1},
|
||||
245: {CoreID: 18, SocketID: 1},
|
||||
66: {CoreID: 19, SocketID: 1},
|
||||
186: {CoreID: 19, SocketID: 1},
|
||||
126: {CoreID: 19, SocketID: 1},
|
||||
246: {CoreID: 19, SocketID: 1},
|
||||
73: {CoreID: 26, SocketID: 1},
|
||||
193: {CoreID: 26, SocketID: 1},
|
||||
133: {CoreID: 26, SocketID: 1},
|
||||
253: {CoreID: 26, SocketID: 1},
|
||||
74: {CoreID: 27, SocketID: 1},
|
||||
194: {CoreID: 27, SocketID: 1},
|
||||
134: {CoreID: 27, SocketID: 1},
|
||||
254: {CoreID: 27, SocketID: 1},
|
||||
81: {CoreID: 34, SocketID: 1},
|
||||
201: {CoreID: 34, SocketID: 1},
|
||||
141: {CoreID: 34, SocketID: 1},
|
||||
261: {CoreID: 34, SocketID: 1},
|
||||
82: {CoreID: 35, SocketID: 1},
|
||||
202: {CoreID: 35, SocketID: 1},
|
||||
142: {CoreID: 35, SocketID: 1},
|
||||
262: {CoreID: 35, SocketID: 1},
|
||||
89: {CoreID: 42, SocketID: 1},
|
||||
209: {CoreID: 42, SocketID: 1},
|
||||
149: {CoreID: 42, SocketID: 1},
|
||||
269: {CoreID: 42, SocketID: 1},
|
||||
90: {CoreID: 43, SocketID: 1},
|
||||
210: {CoreID: 43, SocketID: 1},
|
||||
150: {CoreID: 43, SocketID: 1},
|
||||
270: {CoreID: 43, SocketID: 1},
|
||||
97: {CoreID: 50, SocketID: 1},
|
||||
217: {CoreID: 50, SocketID: 1},
|
||||
157: {CoreID: 50, SocketID: 1},
|
||||
277: {CoreID: 50, SocketID: 1},
|
||||
98: {CoreID: 51, SocketID: 1},
|
||||
218: {CoreID: 51, SocketID: 1},
|
||||
158: {CoreID: 51, SocketID: 1},
|
||||
278: {CoreID: 51, SocketID: 1},
|
||||
5: {CoreID: 68, SocketID: 2},
|
||||
29: {CoreID: 68, SocketID: 2},
|
||||
17: {CoreID: 68, SocketID: 2},
|
||||
42: {CoreID: 68, SocketID: 2},
|
||||
6: {CoreID: 69, SocketID: 2},
|
||||
30: {CoreID: 69, SocketID: 2},
|
||||
18: {CoreID: 69, SocketID: 2},
|
||||
43: {CoreID: 69, SocketID: 2},
|
||||
53: {CoreID: 4, SocketID: 2},
|
||||
173: {CoreID: 4, SocketID: 2},
|
||||
113: {CoreID: 4, SocketID: 2},
|
||||
233: {CoreID: 4, SocketID: 2},
|
||||
54: {CoreID: 5, SocketID: 2},
|
||||
174: {CoreID: 5, SocketID: 2},
|
||||
114: {CoreID: 5, SocketID: 2},
|
||||
234: {CoreID: 5, SocketID: 2},
|
||||
61: {CoreID: 12, SocketID: 2},
|
||||
181: {CoreID: 12, SocketID: 2},
|
||||
121: {CoreID: 12, SocketID: 2},
|
||||
241: {CoreID: 12, SocketID: 2},
|
||||
62: {CoreID: 13, SocketID: 2},
|
||||
182: {CoreID: 13, SocketID: 2},
|
||||
122: {CoreID: 13, SocketID: 2},
|
||||
242: {CoreID: 13, SocketID: 2},
|
||||
67: {CoreID: 20, SocketID: 2},
|
||||
187: {CoreID: 20, SocketID: 2},
|
||||
127: {CoreID: 20, SocketID: 2},
|
||||
247: {CoreID: 20, SocketID: 2},
|
||||
68: {CoreID: 21, SocketID: 2},
|
||||
188: {CoreID: 21, SocketID: 2},
|
||||
128: {CoreID: 21, SocketID: 2},
|
||||
248: {CoreID: 21, SocketID: 2},
|
||||
75: {CoreID: 28, SocketID: 2},
|
||||
195: {CoreID: 28, SocketID: 2},
|
||||
135: {CoreID: 28, SocketID: 2},
|
||||
255: {CoreID: 28, SocketID: 2},
|
||||
76: {CoreID: 29, SocketID: 2},
|
||||
196: {CoreID: 29, SocketID: 2},
|
||||
136: {CoreID: 29, SocketID: 2},
|
||||
256: {CoreID: 29, SocketID: 2},
|
||||
83: {CoreID: 36, SocketID: 2},
|
||||
203: {CoreID: 36, SocketID: 2},
|
||||
143: {CoreID: 36, SocketID: 2},
|
||||
263: {CoreID: 36, SocketID: 2},
|
||||
84: {CoreID: 37, SocketID: 2},
|
||||
204: {CoreID: 37, SocketID: 2},
|
||||
144: {CoreID: 37, SocketID: 2},
|
||||
264: {CoreID: 37, SocketID: 2},
|
||||
91: {CoreID: 44, SocketID: 2},
|
||||
211: {CoreID: 44, SocketID: 2},
|
||||
151: {CoreID: 44, SocketID: 2},
|
||||
271: {CoreID: 44, SocketID: 2},
|
||||
92: {CoreID: 45, SocketID: 2},
|
||||
212: {CoreID: 45, SocketID: 2},
|
||||
152: {CoreID: 45, SocketID: 2},
|
||||
272: {CoreID: 45, SocketID: 2},
|
||||
99: {CoreID: 52, SocketID: 2},
|
||||
219: {CoreID: 52, SocketID: 2},
|
||||
159: {CoreID: 52, SocketID: 2},
|
||||
279: {CoreID: 52, SocketID: 2},
|
||||
100: {CoreID: 53, SocketID: 2},
|
||||
220: {CoreID: 53, SocketID: 2},
|
||||
160: {CoreID: 53, SocketID: 2},
|
||||
280: {CoreID: 53, SocketID: 2},
|
||||
105: {CoreID: 60, SocketID: 2},
|
||||
225: {CoreID: 60, SocketID: 2},
|
||||
165: {CoreID: 60, SocketID: 2},
|
||||
285: {CoreID: 60, SocketID: 2},
|
||||
106: {CoreID: 61, SocketID: 2},
|
||||
226: {CoreID: 61, SocketID: 2},
|
||||
166: {CoreID: 61, SocketID: 2},
|
||||
286: {CoreID: 61, SocketID: 2},
|
||||
7: {CoreID: 70, SocketID: 3},
|
||||
31: {CoreID: 70, SocketID: 3},
|
||||
19: {CoreID: 70, SocketID: 3},
|
||||
44: {CoreID: 70, SocketID: 3},
|
||||
8: {CoreID: 71, SocketID: 3},
|
||||
32: {CoreID: 71, SocketID: 3},
|
||||
20: {CoreID: 71, SocketID: 3},
|
||||
45: {CoreID: 71, SocketID: 3},
|
||||
37: {CoreID: 63, SocketID: 3},
|
||||
168: {CoreID: 63, SocketID: 3},
|
||||
108: {CoreID: 63, SocketID: 3},
|
||||
228: {CoreID: 63, SocketID: 3},
|
||||
107: {CoreID: 62, SocketID: 3},
|
||||
227: {CoreID: 62, SocketID: 3},
|
||||
167: {CoreID: 62, SocketID: 3},
|
||||
287: {CoreID: 62, SocketID: 3},
|
||||
55: {CoreID: 6, SocketID: 3},
|
||||
175: {CoreID: 6, SocketID: 3},
|
||||
115: {CoreID: 6, SocketID: 3},
|
||||
235: {CoreID: 6, SocketID: 3},
|
||||
56: {CoreID: 7, SocketID: 3},
|
||||
176: {CoreID: 7, SocketID: 3},
|
||||
116: {CoreID: 7, SocketID: 3},
|
||||
236: {CoreID: 7, SocketID: 3},
|
||||
63: {CoreID: 14, SocketID: 3},
|
||||
183: {CoreID: 14, SocketID: 3},
|
||||
123: {CoreID: 14, SocketID: 3},
|
||||
243: {CoreID: 14, SocketID: 3},
|
||||
64: {CoreID: 15, SocketID: 3},
|
||||
184: {CoreID: 15, SocketID: 3},
|
||||
124: {CoreID: 15, SocketID: 3},
|
||||
244: {CoreID: 15, SocketID: 3},
|
||||
69: {CoreID: 22, SocketID: 3},
|
||||
189: {CoreID: 22, SocketID: 3},
|
||||
129: {CoreID: 22, SocketID: 3},
|
||||
249: {CoreID: 22, SocketID: 3},
|
||||
70: {CoreID: 23, SocketID: 3},
|
||||
190: {CoreID: 23, SocketID: 3},
|
||||
130: {CoreID: 23, SocketID: 3},
|
||||
250: {CoreID: 23, SocketID: 3},
|
||||
77: {CoreID: 30, SocketID: 3},
|
||||
197: {CoreID: 30, SocketID: 3},
|
||||
137: {CoreID: 30, SocketID: 3},
|
||||
257: {CoreID: 30, SocketID: 3},
|
||||
78: {CoreID: 31, SocketID: 3},
|
||||
198: {CoreID: 31, SocketID: 3},
|
||||
138: {CoreID: 31, SocketID: 3},
|
||||
258: {CoreID: 31, SocketID: 3},
|
||||
85: {CoreID: 38, SocketID: 3},
|
||||
205: {CoreID: 38, SocketID: 3},
|
||||
145: {CoreID: 38, SocketID: 3},
|
||||
265: {CoreID: 38, SocketID: 3},
|
||||
86: {CoreID: 39, SocketID: 3},
|
||||
206: {CoreID: 39, SocketID: 3},
|
||||
146: {CoreID: 39, SocketID: 3},
|
||||
266: {CoreID: 39, SocketID: 3},
|
||||
93: {CoreID: 46, SocketID: 3},
|
||||
213: {CoreID: 46, SocketID: 3},
|
||||
153: {CoreID: 46, SocketID: 3},
|
||||
273: {CoreID: 46, SocketID: 3},
|
||||
94: {CoreID: 47, SocketID: 3},
|
||||
214: {CoreID: 47, SocketID: 3},
|
||||
154: {CoreID: 47, SocketID: 3},
|
||||
274: {CoreID: 47, SocketID: 3},
|
||||
101: {CoreID: 54, SocketID: 3},
|
||||
221: {CoreID: 54, SocketID: 3},
|
||||
161: {CoreID: 54, SocketID: 3},
|
||||
281: {CoreID: 54, SocketID: 3},
|
||||
102: {CoreID: 55, SocketID: 3},
|
||||
222: {CoreID: 55, SocketID: 3},
|
||||
162: {CoreID: 55, SocketID: 3},
|
||||
282: {CoreID: 55, SocketID: 3},
|
||||
},
|
||||
}
|
||||
)
|
||||
28
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/BUILD
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"state.go",
|
||||
"state_mem.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/kubelet/cm/cpuset:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
40
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/state.go
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/state.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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 state
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
// Reader interface used to read current cpu/pod assignment state
|
||||
type Reader interface {
|
||||
GetCPUSet(containerID string) (cpuset.CPUSet, bool)
|
||||
GetDefaultCPUSet() cpuset.CPUSet
|
||||
GetCPUSetOrDefault(containerID string) cpuset.CPUSet
|
||||
}
|
||||
|
||||
type writer interface {
|
||||
SetCPUSet(containerID string, cpuset cpuset.CPUSet)
|
||||
SetDefaultCPUSet(cpuset cpuset.CPUSet)
|
||||
Delete(containerID string)
|
||||
}
|
||||
|
||||
// State interface provides methods for tracking and setting cpu/pod assignment
|
||||
type State interface {
|
||||
Reader
|
||||
writer
|
||||
}
|
||||
90
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/state_mem.go
generated
vendored
Normal file
90
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/state_mem.go
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
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 state
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
type stateMemory struct {
|
||||
sync.RWMutex
|
||||
assignments map[string]cpuset.CPUSet
|
||||
defaultCPUSet cpuset.CPUSet
|
||||
}
|
||||
|
||||
var _ State = &stateMemory{}
|
||||
|
||||
// NewMemoryState creates new State for keeping track of cpu/pod assignment
|
||||
func NewMemoryState() State {
|
||||
glog.Infof("[cpumanager] initializing new in-memory state store")
|
||||
return &stateMemory{
|
||||
assignments: map[string]cpuset.CPUSet{},
|
||||
defaultCPUSet: cpuset.NewCPUSet(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stateMemory) GetCPUSet(containerID string) (cpuset.CPUSet, bool) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
res, ok := s.assignments[containerID]
|
||||
return res.Clone(), ok
|
||||
}
|
||||
|
||||
func (s *stateMemory) GetDefaultCPUSet() cpuset.CPUSet {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
return s.defaultCPUSet.Clone()
|
||||
}
|
||||
|
||||
func (s *stateMemory) GetCPUSetOrDefault(containerID string) cpuset.CPUSet {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
if res, ok := s.GetCPUSet(containerID); ok {
|
||||
return res
|
||||
}
|
||||
return s.GetDefaultCPUSet()
|
||||
}
|
||||
|
||||
func (s *stateMemory) SetCPUSet(containerID string, cset cpuset.CPUSet) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.assignments[containerID] = cset
|
||||
glog.Infof("[cpumanager] updated desired cpuset (container id: %s, cpuset: \"%s\")", containerID, cset)
|
||||
}
|
||||
|
||||
func (s *stateMemory) SetDefaultCPUSet(cset cpuset.CPUSet) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.defaultCPUSet = cset
|
||||
glog.Infof("[cpumanager] updated default cpuset: \"%s\"", cset)
|
||||
}
|
||||
|
||||
func (s *stateMemory) Delete(containerID string) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
delete(s.assignments, containerID)
|
||||
glog.V(2).Infof("[cpumanager] deleted cpuset assignment (container id: %s)", containerID)
|
||||
}
|
||||
35
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/BUILD
generated
vendored
Normal file
35
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"topology.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/kubelet/cm/cpuset:go_default_library",
|
||||
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["topology_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = ["//vendor/github.com/google/cadvisor/info/v1:go_default_library"],
|
||||
)
|
||||
18
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
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 topology contains helpers for the CPU manager.
|
||||
package topology // import "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
|
||||
169
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/topology.go
generated
vendored
Normal file
169
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/topology.go
generated
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
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 topology
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
||||
)
|
||||
|
||||
// CPUDetails is a map from CPU ID to Core ID and Socket ID.
|
||||
type CPUDetails map[int]CPUInfo
|
||||
|
||||
// CPUTopology contains details of node cpu, where :
|
||||
// CPU - logical CPU, cadvisor - thread
|
||||
// Core - physical CPU, cadvisor - Core
|
||||
// Socket - socket, cadvisor - Node
|
||||
type CPUTopology struct {
|
||||
NumCPUs int
|
||||
NumCores int
|
||||
NumSockets int
|
||||
CPUDetails CPUDetails
|
||||
}
|
||||
|
||||
// CPUsPerCore returns the number of logical CPUs are associated with
|
||||
// each core.
|
||||
func (topo *CPUTopology) CPUsPerCore() int {
|
||||
if topo.NumCores == 0 {
|
||||
return 0
|
||||
}
|
||||
return topo.NumCPUs / topo.NumCores
|
||||
}
|
||||
|
||||
// CPUsPerSocket returns the number of logical CPUs are associated with
|
||||
// each socket.
|
||||
func (topo *CPUTopology) CPUsPerSocket() int {
|
||||
if topo.NumSockets == 0 {
|
||||
return 0
|
||||
}
|
||||
return topo.NumCPUs / topo.NumSockets
|
||||
}
|
||||
|
||||
// CPUInfo contains the socket and core IDs associated with a CPU.
|
||||
type CPUInfo struct {
|
||||
SocketID int
|
||||
CoreID int
|
||||
}
|
||||
|
||||
// KeepOnly returns a new CPUDetails object with only the supplied cpus.
|
||||
func (d CPUDetails) KeepOnly(cpus cpuset.CPUSet) CPUDetails {
|
||||
result := CPUDetails{}
|
||||
for cpu, info := range d {
|
||||
if cpus.Contains(cpu) {
|
||||
result[cpu] = info
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Sockets returns all of the socket IDs associated with the CPUs in this
|
||||
// CPUDetails.
|
||||
func (d CPUDetails) Sockets() cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for _, info := range d {
|
||||
b.Add(info.SocketID)
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// CPUsInSocket returns all of the logical CPU IDs associated with the
|
||||
// given socket ID in this CPUDetails.
|
||||
func (d CPUDetails) CPUsInSocket(id int) cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for cpu, info := range d {
|
||||
if info.SocketID == id {
|
||||
b.Add(cpu)
|
||||
}
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// Cores returns all of the core IDs associated with the CPUs in this
|
||||
// CPUDetails.
|
||||
func (d CPUDetails) Cores() cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for _, info := range d {
|
||||
b.Add(info.CoreID)
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// CoresInSocket returns all of the core IDs associated with the given
|
||||
// socket ID in this CPUDetails.
|
||||
func (d CPUDetails) CoresInSocket(id int) cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for _, info := range d {
|
||||
if info.SocketID == id {
|
||||
b.Add(info.CoreID)
|
||||
}
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// CPUs returns all of the logical CPU IDs in this CPUDetails.
|
||||
func (d CPUDetails) CPUs() cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for cpuID := range d {
|
||||
b.Add(cpuID)
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// CPUsInCore returns all of the logical CPU IDs associated with the
|
||||
// given core ID in this CPUDetails.
|
||||
func (d CPUDetails) CPUsInCore(id int) cpuset.CPUSet {
|
||||
b := cpuset.NewBuilder()
|
||||
for cpu, info := range d {
|
||||
if info.CoreID == id {
|
||||
b.Add(cpu)
|
||||
}
|
||||
}
|
||||
return b.Result()
|
||||
}
|
||||
|
||||
// Discover returns CPUTopology based on cadvisor node info
|
||||
func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) {
|
||||
|
||||
if machineInfo.NumCores == 0 {
|
||||
return nil, fmt.Errorf("could not detect number of cpus")
|
||||
}
|
||||
|
||||
CPUDetails := CPUDetails{}
|
||||
|
||||
numCPUs := machineInfo.NumCores
|
||||
numPhysicalCores := 0
|
||||
for _, socket := range machineInfo.Topology {
|
||||
numPhysicalCores += len(socket.Cores)
|
||||
for _, core := range socket.Cores {
|
||||
for _, cpu := range core.Threads {
|
||||
CPUDetails[cpu] = CPUInfo{
|
||||
CoreID: core.Id,
|
||||
SocketID: socket.Id,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &CPUTopology{
|
||||
NumCPUs: numCPUs,
|
||||
NumSockets: len(machineInfo.Topology),
|
||||
NumCores: numPhysicalCores,
|
||||
CPUDetails: CPUDetails,
|
||||
}, nil
|
||||
}
|
||||
123
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/topology_test.go
generated
vendored
Normal file
123
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology/topology_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
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 topology
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
cadvisorapi "github.com/google/cadvisor/info/v1"
|
||||
)
|
||||
|
||||
func Test_Discover(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args *cadvisorapi.MachineInfo
|
||||
want *CPUTopology
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "FailNumCores",
|
||||
args: &cadvisorapi.MachineInfo{
|
||||
NumCores: 0,
|
||||
},
|
||||
want: &CPUTopology{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "OneSocketHT",
|
||||
args: &cadvisorapi.MachineInfo{
|
||||
NumCores: 8,
|
||||
Topology: []cadvisorapi.Node{
|
||||
{Id: 0,
|
||||
Cores: []cadvisorapi.Core{
|
||||
{Id: 0, Threads: []int{0, 4}},
|
||||
{Id: 1, Threads: []int{1, 5}},
|
||||
{Id: 2, Threads: []int{2, 6}},
|
||||
{Id: 3, Threads: []int{3, 7}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &CPUTopology{
|
||||
NumCPUs: 8,
|
||||
NumSockets: 1,
|
||||
NumCores: 4,
|
||||
CPUDetails: map[int]CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
1: {CoreID: 1, SocketID: 0},
|
||||
2: {CoreID: 2, SocketID: 0},
|
||||
3: {CoreID: 3, SocketID: 0},
|
||||
4: {CoreID: 0, SocketID: 0},
|
||||
5: {CoreID: 1, SocketID: 0},
|
||||
6: {CoreID: 2, SocketID: 0},
|
||||
7: {CoreID: 3, SocketID: 0},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "DualSocketNoHT",
|
||||
args: &cadvisorapi.MachineInfo{
|
||||
NumCores: 4,
|
||||
Topology: []cadvisorapi.Node{
|
||||
{Id: 0,
|
||||
Cores: []cadvisorapi.Core{
|
||||
{Id: 0, Threads: []int{0}},
|
||||
{Id: 2, Threads: []int{2}},
|
||||
},
|
||||
},
|
||||
{Id: 1,
|
||||
Cores: []cadvisorapi.Core{
|
||||
{Id: 1, Threads: []int{1}},
|
||||
{Id: 3, Threads: []int{3}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &CPUTopology{
|
||||
NumCPUs: 4,
|
||||
NumSockets: 2,
|
||||
NumCores: 4,
|
||||
CPUDetails: map[int]CPUInfo{
|
||||
0: {CoreID: 0, SocketID: 0},
|
||||
1: {CoreID: 1, SocketID: 1},
|
||||
2: {CoreID: 2, SocketID: 0},
|
||||
3: {CoreID: 3, SocketID: 1},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Discover(tt.args)
|
||||
if err != nil {
|
||||
if tt.wantErr {
|
||||
t.Logf("Discover() expected error = %v", err)
|
||||
} else {
|
||||
t.Errorf("Discover() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Discover() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
28
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpuset/BUILD
generated
vendored
Normal file
28
vendor/k8s.io/kubernetes/pkg/kubelet/cm/cpuset/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["cpuset.go"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/golang/glog:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["cpuset_test.go"],
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue