mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
Migrate from snapClient.VolumesnapshotV1alpha1Client to
snapClient.SnapshotV1alpha1Client and also update kube dependency Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
committed by
mergify[bot]
parent
3bc6771df8
commit
22ff5c0911
44
vendor/k8s.io/kubernetes/pkg/kubelet/util/boottime_util_darwin.go
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/kubelet/util/boottime_util_darwin.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// +build darwin
|
||||
|
||||
/*
|
||||
Copyright 2018 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetBootTime returns the time at which the machine was started, truncated to the nearest second
|
||||
func GetBootTime() (time.Time, error) {
|
||||
output, err := unix.SysctlRaw("kern.boottime")
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
var timeval syscall.Timeval
|
||||
if len(output) != int(unsafe.Sizeof(timeval)) {
|
||||
return time.Time{}, fmt.Errorf("unexpected output when calling syscall kern.bootime. Expected len(output) to be %v, but got %v",
|
||||
int(unsafe.Sizeof(timeval)), len(output))
|
||||
}
|
||||
timeval = *(*syscall.Timeval)(unsafe.Pointer(&output[0]))
|
||||
sec, nsec := timeval.Unix()
|
||||
return time.Unix(sec, nsec).Truncate(time.Second), nil
|
||||
}
|
36
vendor/k8s.io/kubernetes/pkg/kubelet/util/boottime_util_linux.go
generated
vendored
Normal file
36
vendor/k8s.io/kubernetes/pkg/kubelet/util/boottime_util_linux.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// +build freebsd linux
|
||||
|
||||
/*
|
||||
Copyright 2018 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetBootTime returns the time at which the machine was started, truncated to the nearest second
|
||||
func GetBootTime() (time.Time, error) {
|
||||
currentTime := time.Now()
|
||||
var info unix.Sysinfo_t
|
||||
if err := unix.Sysinfo(&info); err != nil {
|
||||
return time.Time{}, fmt.Errorf("error getting system uptime: %s", err)
|
||||
}
|
||||
return currentTime.Add(-time.Duration(info.Uptime) * time.Second).Truncate(time.Second), nil
|
||||
}
|
18
vendor/k8s.io/kubernetes/pkg/kubelet/util/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/pkg/kubelet/util/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.
|
||||
*/
|
||||
|
||||
// Package util holds utility functions.
|
||||
package util // import "k8s.io/kubernetes/pkg/kubelet/util"
|
272
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/cache_based_manager.go
generated
vendored
Normal file
272
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/cache_based_manager.go
generated
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
Copyright 2018 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 manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
storageetcd "k8s.io/apiserver/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// GetObjectTTLFunc defines a function to get value of TTL.
|
||||
type GetObjectTTLFunc func() (time.Duration, bool)
|
||||
|
||||
// GetObjectFunc defines a function to get object with a given namespace and name.
|
||||
type GetObjectFunc func(string, string, metav1.GetOptions) (runtime.Object, error)
|
||||
|
||||
type objectKey struct {
|
||||
namespace string
|
||||
name string
|
||||
}
|
||||
|
||||
// objectStoreItems is a single item stored in objectStore.
|
||||
type objectStoreItem struct {
|
||||
refCount int
|
||||
data *objectData
|
||||
}
|
||||
|
||||
type objectData struct {
|
||||
sync.Mutex
|
||||
|
||||
object runtime.Object
|
||||
err error
|
||||
lastUpdateTime time.Time
|
||||
}
|
||||
|
||||
// objectStore is a local cache of objects.
|
||||
type objectStore struct {
|
||||
getObject GetObjectFunc
|
||||
clock clock.Clock
|
||||
|
||||
lock sync.Mutex
|
||||
items map[objectKey]*objectStoreItem
|
||||
|
||||
defaultTTL time.Duration
|
||||
getTTL GetObjectTTLFunc
|
||||
}
|
||||
|
||||
// NewObjectStore returns a new ttl-based instance of Store interface.
|
||||
func NewObjectStore(getObject GetObjectFunc, clock clock.Clock, getTTL GetObjectTTLFunc, ttl time.Duration) Store {
|
||||
return &objectStore{
|
||||
getObject: getObject,
|
||||
clock: clock,
|
||||
items: make(map[objectKey]*objectStoreItem),
|
||||
defaultTTL: ttl,
|
||||
getTTL: getTTL,
|
||||
}
|
||||
}
|
||||
|
||||
func isObjectOlder(newObject, oldObject runtime.Object) bool {
|
||||
if newObject == nil || oldObject == nil {
|
||||
return false
|
||||
}
|
||||
newVersion, _ := storageetcd.Versioner.ObjectResourceVersion(newObject)
|
||||
oldVersion, _ := storageetcd.Versioner.ObjectResourceVersion(oldObject)
|
||||
return newVersion < oldVersion
|
||||
}
|
||||
|
||||
func (s *objectStore) AddReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
// AddReference is called from RegisterPod, thus it needs to be efficient.
|
||||
// Thus Add() is only increasing refCount and generation of a given object.
|
||||
// Then Get() is responsible for fetching if needed.
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
item, exists := s.items[key]
|
||||
if !exists {
|
||||
item = &objectStoreItem{
|
||||
refCount: 0,
|
||||
data: &objectData{},
|
||||
}
|
||||
s.items[key] = item
|
||||
}
|
||||
|
||||
item.refCount++
|
||||
// This will trigger fetch on the next Get() operation.
|
||||
item.data = nil
|
||||
}
|
||||
|
||||
func (s *objectStore) DeleteReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if item, ok := s.items[key]; ok {
|
||||
item.refCount--
|
||||
if item.refCount == 0 {
|
||||
delete(s.items, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetObjectTTLFromNodeFunc returns a function that returns TTL value
|
||||
// from a given Node object.
|
||||
func GetObjectTTLFromNodeFunc(getNode func() (*v1.Node, error)) GetObjectTTLFunc {
|
||||
return func() (time.Duration, bool) {
|
||||
node, err := getNode()
|
||||
if err != nil {
|
||||
return time.Duration(0), false
|
||||
}
|
||||
if node != nil && node.Annotations != nil {
|
||||
if value, ok := node.Annotations[v1.ObjectTTLAnnotationKey]; ok {
|
||||
if intValue, err := strconv.Atoi(value); err == nil {
|
||||
return time.Duration(intValue) * time.Second, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return time.Duration(0), false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *objectStore) isObjectFresh(data *objectData) bool {
|
||||
objectTTL := s.defaultTTL
|
||||
if ttl, ok := s.getTTL(); ok {
|
||||
objectTTL = ttl
|
||||
}
|
||||
return s.clock.Now().Before(data.lastUpdateTime.Add(objectTTL))
|
||||
}
|
||||
|
||||
func (s *objectStore) Get(namespace, name string) (runtime.Object, error) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
data := func() *objectData {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
item, exists := s.items[key]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if item.data == nil {
|
||||
item.data = &objectData{}
|
||||
}
|
||||
return item.data
|
||||
}()
|
||||
if data == nil {
|
||||
return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
|
||||
}
|
||||
|
||||
// After updating data in objectStore, lock the data, fetch object if
|
||||
// needed and return data.
|
||||
data.Lock()
|
||||
defer data.Unlock()
|
||||
if data.err != nil || !s.isObjectFresh(data) {
|
||||
opts := metav1.GetOptions{}
|
||||
if data.object != nil && data.err == nil {
|
||||
// This is just a periodic refresh of an object we successfully fetched previously.
|
||||
// In this case, server data from apiserver cache to reduce the load on both
|
||||
// etcd and apiserver (the cache is eventually consistent).
|
||||
util.FromApiserverCache(&opts)
|
||||
}
|
||||
|
||||
object, err := s.getObject(namespace, name, opts)
|
||||
if err != nil && !apierrors.IsNotFound(err) && data.object == nil && data.err == nil {
|
||||
// Couldn't fetch the latest object, but there is no cached data to return.
|
||||
// Return the fetch result instead.
|
||||
return object, err
|
||||
}
|
||||
if (err == nil && !isObjectOlder(object, data.object)) || apierrors.IsNotFound(err) {
|
||||
// If the fetch succeeded with a newer version of the object, or if the
|
||||
// object could not be found in the apiserver, update the cached data to
|
||||
// reflect the current status.
|
||||
data.object = object
|
||||
data.err = err
|
||||
data.lastUpdateTime = s.clock.Now()
|
||||
}
|
||||
}
|
||||
return data.object, data.err
|
||||
}
|
||||
|
||||
// cacheBasedManager keeps a store with objects necessary
|
||||
// for registered pods. Different implementations of the store
|
||||
// may result in different semantics for freshness of objects
|
||||
// (e.g. ttl-based implementation vs watch-based implementation).
|
||||
type cacheBasedManager struct {
|
||||
objectStore Store
|
||||
getReferencedObjects func(*v1.Pod) sets.String
|
||||
|
||||
lock sync.Mutex
|
||||
registeredPods map[objectKey]*v1.Pod
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) GetObject(namespace, name string) (runtime.Object, error) {
|
||||
return c.objectStore.Get(namespace, name)
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) RegisterPod(pod *v1.Pod) {
|
||||
names := c.getReferencedObjects(pod)
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
for name := range names {
|
||||
c.objectStore.AddReference(pod.Namespace, name)
|
||||
}
|
||||
var prev *v1.Pod
|
||||
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
||||
prev = c.registeredPods[key]
|
||||
c.registeredPods[key] = pod
|
||||
if prev != nil {
|
||||
for name := range c.getReferencedObjects(prev) {
|
||||
// On an update, the .Add() call above will have re-incremented the
|
||||
// ref count of any existing object, so any objects that are in both
|
||||
// names and prev need to have their ref counts decremented. Any that
|
||||
// are only in prev need to be completely removed. This unconditional
|
||||
// call takes care of both cases.
|
||||
c.objectStore.DeleteReference(prev.Namespace, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cacheBasedManager) UnregisterPod(pod *v1.Pod) {
|
||||
var prev *v1.Pod
|
||||
key := objectKey{namespace: pod.Namespace, name: pod.Name}
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
prev = c.registeredPods[key]
|
||||
delete(c.registeredPods, key)
|
||||
if prev != nil {
|
||||
for name := range c.getReferencedObjects(prev) {
|
||||
c.objectStore.DeleteReference(prev.Namespace, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCacheBasedManager creates a manager that keeps a cache of all objects
|
||||
// necessary for registered pods.
|
||||
// It implements the following logic:
|
||||
// - whenever a pod is created or updated, the cached versions of all objects
|
||||
// is referencing are invalidated
|
||||
// - every GetObject() call tries to fetch the value from local cache; if it is
|
||||
// not there, invalidated or too old, we fetch it from apiserver and refresh the
|
||||
// value in cache; otherwise it is just fetched from cache
|
||||
func NewCacheBasedManager(objectStore Store, getReferencedObjects func(*v1.Pod) sets.String) Manager {
|
||||
return &cacheBasedManager{
|
||||
objectStore: objectStore,
|
||||
getReferencedObjects: getReferencedObjects,
|
||||
registeredPods: make(map[objectKey]*v1.Pod),
|
||||
}
|
||||
}
|
60
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/manager.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/manager.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2018 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 manager
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Manager is the interface for registering and unregistering
|
||||
// objects referenced by pods in the underlying cache and
|
||||
// extracting those from that cache if needed.
|
||||
type Manager interface {
|
||||
// Get object by its namespace and name.
|
||||
GetObject(namespace, name string) (runtime.Object, error)
|
||||
|
||||
// WARNING: Register/UnregisterPod functions should be efficient,
|
||||
// i.e. should not block on network operations.
|
||||
|
||||
// RegisterPod registers all objects referenced from a given pod.
|
||||
//
|
||||
// NOTE: All implementations of RegisterPod should be idempotent.
|
||||
RegisterPod(pod *v1.Pod)
|
||||
|
||||
// UnregisterPod unregisters objects referenced from a given pod that are not
|
||||
// used by any other registered pod.
|
||||
//
|
||||
// NOTE: All implementations of UnregisterPod should be idempotent.
|
||||
UnregisterPod(pod *v1.Pod)
|
||||
}
|
||||
|
||||
// Store is the interface for a object cache that
|
||||
// can be used by cacheBasedManager.
|
||||
type Store interface {
|
||||
// AddReference adds a reference to the object to the store.
|
||||
// Note that multiple additions to the store has to be allowed
|
||||
// in the implementations and effectively treated as refcounted.
|
||||
AddReference(namespace, name string)
|
||||
// DeleteReference deletes reference to the object from the store.
|
||||
// Note that object should be deleted only when there was a
|
||||
// corresponding Delete call for each of Add calls (effectively
|
||||
// when refcount was reduced to zero).
|
||||
DeleteReference(namespace, name string)
|
||||
// Get an object from a store.
|
||||
Get(namespace, name string) (runtime.Object, error)
|
||||
}
|
194
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/watch_based_manager.go
generated
vendored
Normal file
194
vendor/k8s.io/kubernetes/pkg/kubelet/util/manager/watch_based_manager.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// TODO: We did some scalability tests and using watchBasedManager
|
||||
// seems to help with apiserver performance at scale visibly.
|
||||
// No issues we also observed at the scale of ~200k watchers with a
|
||||
// single apiserver.
|
||||
// However, we need to perform more extensive testing before we
|
||||
// enable this in production setups.
|
||||
|
||||
package manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
type listObjectFunc func(string, metav1.ListOptions) (runtime.Object, error)
|
||||
type watchObjectFunc func(string, metav1.ListOptions) (watch.Interface, error)
|
||||
type newObjectFunc func() runtime.Object
|
||||
|
||||
// objectCacheItem is a single item stored in objectCache.
|
||||
type objectCacheItem struct {
|
||||
refCount int
|
||||
store cache.Store
|
||||
hasSynced func() (bool, error)
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// objectCache is a local cache of objects propagated via
|
||||
// individual watches.
|
||||
type objectCache struct {
|
||||
listObject listObjectFunc
|
||||
watchObject watchObjectFunc
|
||||
newObject newObjectFunc
|
||||
groupResource schema.GroupResource
|
||||
|
||||
lock sync.Mutex
|
||||
items map[objectKey]*objectCacheItem
|
||||
}
|
||||
|
||||
// NewObjectCache returns a new watch-based instance of Store interface.
|
||||
func NewObjectCache(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource) Store {
|
||||
return &objectCache{
|
||||
listObject: listObject,
|
||||
watchObject: watchObject,
|
||||
newObject: newObject,
|
||||
groupResource: groupResource,
|
||||
items: make(map[objectKey]*objectCacheItem),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *objectCache) newStore() cache.Store {
|
||||
// TODO: We may consider created a dedicated store keeping just a single
|
||||
// item, instead of using a generic store implementation for this purpose.
|
||||
// However, simple benchmarks show that memory overhead in that case is
|
||||
// decrease from ~600B to ~300B per object. So we are not optimizing it
|
||||
// until we will see a good reason for that.
|
||||
return cache.NewStore(cache.MetaNamespaceKeyFunc)
|
||||
}
|
||||
|
||||
func (c *objectCache) newReflector(namespace, name string) *objectCacheItem {
|
||||
fieldSelector := fields.Set{"metadata.name": name}.AsSelector().String()
|
||||
listFunc := func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
options.FieldSelector = fieldSelector
|
||||
return c.listObject(namespace, options)
|
||||
}
|
||||
watchFunc := func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
options.FieldSelector = fieldSelector
|
||||
return c.watchObject(namespace, options)
|
||||
}
|
||||
store := c.newStore()
|
||||
reflector := cache.NewNamedReflector(
|
||||
fmt.Sprintf("object-%q/%q", namespace, name),
|
||||
&cache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc},
|
||||
c.newObject(),
|
||||
store,
|
||||
0,
|
||||
)
|
||||
stopCh := make(chan struct{})
|
||||
go reflector.Run(stopCh)
|
||||
return &objectCacheItem{
|
||||
refCount: 0,
|
||||
store: store,
|
||||
hasSynced: func() (bool, error) { return reflector.LastSyncResourceVersion() != "", nil },
|
||||
stopCh: stopCh,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *objectCache) AddReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
// AddReference is called from RegisterPod thus it needs to be efficient.
|
||||
// Thus, it is only increaisng refCount and in case of first registration
|
||||
// of a given object it starts corresponding reflector.
|
||||
// It's responsibility of the first Get operation to wait until the
|
||||
// reflector propagated the store.
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
item, exists := c.items[key]
|
||||
if !exists {
|
||||
item = c.newReflector(namespace, name)
|
||||
c.items[key] = item
|
||||
}
|
||||
item.refCount++
|
||||
}
|
||||
|
||||
func (c *objectCache) DeleteReference(namespace, name string) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if item, ok := c.items[key]; ok {
|
||||
item.refCount--
|
||||
if item.refCount == 0 {
|
||||
// Stop the underlying reflector.
|
||||
close(item.stopCh)
|
||||
delete(c.items, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// key returns key of an object with a given name and namespace.
|
||||
// This has to be in-sync with cache.MetaNamespaceKeyFunc.
|
||||
func (c *objectCache) key(namespace, name string) string {
|
||||
if len(namespace) > 0 {
|
||||
return namespace + "/" + name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (c *objectCache) Get(namespace, name string) (runtime.Object, error) {
|
||||
key := objectKey{namespace: namespace, name: name}
|
||||
|
||||
c.lock.Lock()
|
||||
item, exists := c.items[key]
|
||||
c.lock.Unlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("object %q/%q not registered", namespace, name)
|
||||
}
|
||||
if err := wait.PollImmediate(10*time.Millisecond, time.Second, item.hasSynced); err != nil {
|
||||
return nil, fmt.Errorf("couldn't propagate object cache: %v", err)
|
||||
}
|
||||
|
||||
obj, exists, err := item.store.GetByKey(c.key(namespace, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, apierrors.NewNotFound(c.groupResource, name)
|
||||
}
|
||||
if object, ok := obj.(runtime.Object); ok {
|
||||
return object, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected object type: %v", obj)
|
||||
}
|
||||
|
||||
// NewWatchBasedManager creates a manager that keeps a cache of all objects
|
||||
// necessary for registered pods.
|
||||
// It implements the following logic:
|
||||
// - whenever a pod is created or updated, we start individual watches for all
|
||||
// referenced objects that aren't referenced from other registered pods
|
||||
// - every GetObject() returns a value from local cache propagated via watches
|
||||
func NewWatchBasedManager(listObject listObjectFunc, watchObject watchObjectFunc, newObject newObjectFunc, groupResource schema.GroupResource, getReferencedObjects func(*v1.Pod) sets.String) Manager {
|
||||
objectStore := NewObjectCache(listObject, watchObject, newObject, groupResource)
|
||||
return NewCacheBasedManager(objectStore, getReferencedObjects)
|
||||
}
|
18
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/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.
|
||||
*/
|
||||
|
||||
// Package store hosts a Store interface and its implementations.
|
||||
package store // import "k8s.io/kubernetes/pkg/kubelet/util/store"
|
167
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/filestore.go
generated
vendored
Normal file
167
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/filestore.go
generated
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
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 store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
utilfs "k8s.io/kubernetes/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
const (
|
||||
// Name prefix for the temporary files.
|
||||
tmpPrefix = "."
|
||||
)
|
||||
|
||||
// FileStore is an implementation of the Store interface which stores data in files.
|
||||
type FileStore struct {
|
||||
// Absolute path to the base directory for storing data files.
|
||||
directoryPath string
|
||||
|
||||
// filesystem to use.
|
||||
filesystem utilfs.Filesystem
|
||||
}
|
||||
|
||||
// NewFileStore returns an instance of FileStore.
|
||||
func NewFileStore(path string, fs utilfs.Filesystem) (Store, error) {
|
||||
if err := ensureDirectory(fs, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FileStore{directoryPath: path, filesystem: fs}, nil
|
||||
}
|
||||
|
||||
// Write writes the given data to a file named key.
|
||||
func (f *FileStore) Write(key string, data []byte) error {
|
||||
if err := ValidateKey(key); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureDirectory(f.filesystem, f.directoryPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeFile(f.filesystem, f.getPathByKey(key), data)
|
||||
}
|
||||
|
||||
// Read reads the data from the file named key.
|
||||
func (f *FileStore) Read(key string) ([]byte, error) {
|
||||
if err := ValidateKey(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bytes, err := f.filesystem.ReadFile(f.getPathByKey(key))
|
||||
if os.IsNotExist(err) {
|
||||
return bytes, ErrKeyNotFound
|
||||
}
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
// Delete deletes the key file.
|
||||
func (f *FileStore) Delete(key string) error {
|
||||
if err := ValidateKey(key); err != nil {
|
||||
return err
|
||||
}
|
||||
return removePath(f.filesystem, f.getPathByKey(key))
|
||||
}
|
||||
|
||||
// List returns all keys in the store.
|
||||
func (f *FileStore) List() ([]string, error) {
|
||||
keys := make([]string, 0)
|
||||
files, err := f.filesystem.ReadDir(f.directoryPath)
|
||||
if err != nil {
|
||||
return keys, err
|
||||
}
|
||||
for _, f := range files {
|
||||
if !strings.HasPrefix(f.Name(), tmpPrefix) {
|
||||
keys = append(keys, f.Name())
|
||||
}
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// getPathByKey returns the full path of the file for the key.
|
||||
func (f *FileStore) getPathByKey(key string) string {
|
||||
return filepath.Join(f.directoryPath, key)
|
||||
}
|
||||
|
||||
// ensureDirectory creates the directory if it does not exist.
|
||||
func ensureDirectory(fs utilfs.Filesystem, path string) error {
|
||||
if _, err := fs.Stat(path); err != nil {
|
||||
// MkdirAll returns nil if directory already exists.
|
||||
return fs.MkdirAll(path, 0755)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeFile writes data to path in a single transaction.
|
||||
func writeFile(fs utilfs.Filesystem, path string, data []byte) (retErr error) {
|
||||
// Create a temporary file in the base directory of `path` with a prefix.
|
||||
tmpFile, err := fs.TempFile(filepath.Dir(path), tmpPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpPath := tmpFile.Name()
|
||||
shouldClose := true
|
||||
|
||||
defer func() {
|
||||
// Close the file.
|
||||
if shouldClose {
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
if retErr == nil {
|
||||
retErr = fmt.Errorf("close error: %v", err)
|
||||
} else {
|
||||
retErr = fmt.Errorf("failed to close temp file after error %v; close error: %v", retErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the temp file on error.
|
||||
if retErr != nil && tmpPath != "" {
|
||||
if err := removePath(fs, tmpPath); err != nil {
|
||||
retErr = fmt.Errorf("failed to remove the temporary file (%q) after error %v; remove error: %v", tmpPath, retErr, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Write data.
|
||||
if _, err := tmpFile.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync file.
|
||||
if err := tmpFile.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Closing the file before renaming.
|
||||
err = tmpFile.Close()
|
||||
shouldClose = false
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fs.Rename(tmpPath, path)
|
||||
}
|
||||
|
||||
func removePath(fs utilfs.Filesystem, path string) error {
|
||||
if err := fs.Remove(path); err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
64
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/store.go
generated
vendored
Normal file
64
vendor/k8s.io/kubernetes/pkg/kubelet/util/store/store.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 store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const (
|
||||
keyMaxLength = 250
|
||||
|
||||
keyCharFmt string = "[A-Za-z0-9]"
|
||||
keyExtCharFmt string = "[-A-Za-z0-9_.]"
|
||||
qualifiedKeyFmt string = "(" + keyCharFmt + keyExtCharFmt + "*)?" + keyCharFmt
|
||||
)
|
||||
|
||||
var (
|
||||
// Key must consist of alphanumeric characters, '-', '_' or '.', and must start
|
||||
// and end with an alphanumeric character.
|
||||
keyRegex = regexp.MustCompile("^" + qualifiedKeyFmt + "$")
|
||||
|
||||
// ErrKeyNotFound is the error returned if key is not found in Store.
|
||||
ErrKeyNotFound = fmt.Errorf("key is not found")
|
||||
)
|
||||
|
||||
// Store provides the interface for storing keyed data.
|
||||
// Store must be thread-safe
|
||||
type Store interface {
|
||||
// key must contain one or more characters in [A-Za-z0-9]
|
||||
// Write writes data with key.
|
||||
Write(key string, data []byte) error
|
||||
// Read retrieves data with key
|
||||
// Read must return ErrKeyNotFound if key is not found.
|
||||
Read(key string) ([]byte, error)
|
||||
// Delete deletes data by key
|
||||
// Delete must not return error if key does not exist
|
||||
Delete(key string) error
|
||||
// List lists all existing keys.
|
||||
List() ([]string, error)
|
||||
}
|
||||
|
||||
// ValidateKey returns an error if the given key does not meet the requirement
|
||||
// of the key format and length.
|
||||
func ValidateKey(key string) error {
|
||||
if len(key) <= keyMaxLength && keyRegex.MatchString(key) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid key: %q", key)
|
||||
}
|
27
vendor/k8s.io/kubernetes/pkg/kubelet/util/util.go
generated
vendored
Normal file
27
vendor/k8s.io/kubernetes/pkg/kubelet/util/util.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// FromApiserverCache modifies <opts> so that the GET request will
|
||||
// be served from apiserver cache instead of from etcd.
|
||||
func FromApiserverCache(opts *metav1.GetOptions) {
|
||||
opts.ResourceVersion = "0"
|
||||
}
|
137
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_unix.go
generated
vendored
Normal file
137
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_unix.go
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
// +build freebsd linux darwin
|
||||
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const (
|
||||
// unixProtocol is the network protocol of unix socket.
|
||||
unixProtocol = "unix"
|
||||
)
|
||||
|
||||
// CreateListener creates a listener on the specified endpoint.
|
||||
func CreateListener(endpoint string) (net.Listener, error) {
|
||||
protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if protocol != unixProtocol {
|
||||
return nil, fmt.Errorf("only support unix socket endpoint")
|
||||
}
|
||||
|
||||
// Unlink to cleanup the previous socket file.
|
||||
err = unix.Unlink(addr)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("failed to unlink socket file %q: %v", addr, err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(addr), 0750); err != nil {
|
||||
return nil, fmt.Errorf("error creating socket directory %q: %v", filepath.Dir(addr), err)
|
||||
}
|
||||
|
||||
// Create the socket on a tempfile and move it to the destination socket to handle improprer cleanup
|
||||
file, err := ioutil.TempFile(filepath.Dir(addr), "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create temporary file: %v", err)
|
||||
}
|
||||
|
||||
if err := os.Remove(file.Name()); err != nil {
|
||||
return nil, fmt.Errorf("failed to remove temporary file: %v", err)
|
||||
}
|
||||
|
||||
l, err := net.Listen(protocol, file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = os.Rename(file.Name(), addr); err != nil {
|
||||
return nil, fmt.Errorf("failed to move temporary file to addr %q: %v", addr, err)
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetAddressAndDialer returns the address parsed from the given endpoint and a dialer.
|
||||
func GetAddressAndDialer(endpoint string) (string, func(addr string, timeout time.Duration) (net.Conn, error), error) {
|
||||
protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, unixProtocol)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if protocol != unixProtocol {
|
||||
return "", nil, fmt.Errorf("only support unix socket endpoint")
|
||||
}
|
||||
|
||||
return addr, dial, nil
|
||||
}
|
||||
|
||||
func dial(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout(unixProtocol, addr, timeout)
|
||||
}
|
||||
|
||||
func parseEndpointWithFallbackProtocol(endpoint string, fallbackProtocol string) (protocol string, addr string, err error) {
|
||||
if protocol, addr, err = parseEndpoint(endpoint); err != nil && protocol == "" {
|
||||
fallbackEndpoint := fallbackProtocol + "://" + endpoint
|
||||
protocol, addr, err = parseEndpoint(fallbackEndpoint)
|
||||
if err == nil {
|
||||
klog.Warningf("Using %q as endpoint is deprecated, please consider using full url format %q.", endpoint, fallbackEndpoint)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseEndpoint(endpoint string) (string, string, error) {
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
switch u.Scheme {
|
||||
case "tcp":
|
||||
return "tcp", u.Host, nil
|
||||
|
||||
case "unix":
|
||||
return "unix", u.Path, nil
|
||||
|
||||
case "":
|
||||
return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint)
|
||||
|
||||
default:
|
||||
return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
// LocalEndpoint returns the full path to a unix socket at the given endpoint
|
||||
func LocalEndpoint(path, file string) (string, error) {
|
||||
u := url.URL{
|
||||
Scheme: unixProtocol,
|
||||
Path: path,
|
||||
}
|
||||
return filepath.Join(u.String(), file+".sock"), nil
|
||||
}
|
54
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_unsupported.go
generated
vendored
Normal file
54
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
// +build !freebsd,!linux,!windows,!darwin
|
||||
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateListener creates a listener on the specified endpoint.
|
||||
func CreateListener(endpoint string) (net.Listener, error) {
|
||||
return nil, fmt.Errorf("CreateListener is unsupported in this build")
|
||||
}
|
||||
|
||||
// GetAddressAndDialer returns the address parsed from the given endpoint and a dialer.
|
||||
func GetAddressAndDialer(endpoint string) (string, func(addr string, timeout time.Duration) (net.Conn, error), error) {
|
||||
return "", nil, fmt.Errorf("GetAddressAndDialer is unsupported in this build")
|
||||
}
|
||||
|
||||
// LockAndCheckSubPath empty implementation
|
||||
func LockAndCheckSubPath(volumePath, subPath string) ([]uintptr, error) {
|
||||
return []uintptr{}, nil
|
||||
}
|
||||
|
||||
// UnlockPath empty implementation
|
||||
func UnlockPath(fileHandles []uintptr) {
|
||||
}
|
||||
|
||||
// LocalEndpoint empty implementation
|
||||
func LocalEndpoint(path, file string) (string, error) {
|
||||
return "", fmt.Errorf("LocalEndpoints are unsupported in this build")
|
||||
}
|
||||
|
||||
// GetBootTime empty implementation
|
||||
func GetBootTime() (time.Time, error) {
|
||||
return time.Time{}, fmt.Errorf("GetBootTime is unsupported in this build")
|
||||
}
|
125
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_windows.go
generated
vendored
Normal file
125
vendor/k8s.io/kubernetes/pkg/kubelet/util/util_windows.go
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/go-winio"
|
||||
)
|
||||
|
||||
const (
|
||||
tcpProtocol = "tcp"
|
||||
npipeProtocol = "npipe"
|
||||
)
|
||||
|
||||
// CreateListener creates a listener on the specified endpoint.
|
||||
func CreateListener(endpoint string) (net.Listener, error) {
|
||||
protocol, addr, err := parseEndpoint(endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch protocol {
|
||||
case tcpProtocol:
|
||||
return net.Listen(tcpProtocol, addr)
|
||||
|
||||
case npipeProtocol:
|
||||
return winio.ListenPipe(addr, nil)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("only support tcp and npipe endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
// GetAddressAndDialer returns the address parsed from the given endpoint and a dialer.
|
||||
func GetAddressAndDialer(endpoint string) (string, func(addr string, timeout time.Duration) (net.Conn, error), error) {
|
||||
protocol, addr, err := parseEndpoint(endpoint)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if protocol == tcpProtocol {
|
||||
return addr, tcpDial, nil
|
||||
}
|
||||
|
||||
if protocol == npipeProtocol {
|
||||
return addr, npipeDial, nil
|
||||
}
|
||||
|
||||
return "", nil, fmt.Errorf("only support tcp and npipe endpoint")
|
||||
}
|
||||
|
||||
func tcpDial(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout(tcpProtocol, addr, timeout)
|
||||
}
|
||||
|
||||
func npipeDial(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return winio.DialPipe(addr, &timeout)
|
||||
}
|
||||
|
||||
func parseEndpoint(endpoint string) (string, string, error) {
|
||||
// url.Parse doesn't recognize \, so replace with / first.
|
||||
endpoint = strings.Replace(endpoint, "\\", "/", -1)
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if u.Scheme == "tcp" {
|
||||
return "tcp", u.Host, nil
|
||||
} else if u.Scheme == "npipe" {
|
||||
if strings.HasPrefix(u.Path, "//./pipe") {
|
||||
return "npipe", u.Path, nil
|
||||
}
|
||||
|
||||
// fallback host if not provided.
|
||||
host := u.Host
|
||||
if host == "" {
|
||||
host = "."
|
||||
}
|
||||
return "npipe", fmt.Sprintf("//%s%s", host, u.Path), nil
|
||||
} else if u.Scheme == "" {
|
||||
return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint)
|
||||
} else {
|
||||
return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
// LocalEndpoint empty implementation
|
||||
func LocalEndpoint(path, file string) (string, error) {
|
||||
return "", fmt.Errorf("LocalEndpoints are unsupported in this build")
|
||||
}
|
||||
|
||||
var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")
|
||||
|
||||
// GetBootTime returns the time at which the machine was started, truncated to the nearest second
|
||||
func GetBootTime() (time.Time, error) {
|
||||
currentTime := time.Now()
|
||||
output, _, err := tickCount.Call()
|
||||
if errno, ok := err.(syscall.Errno); !ok || errno != 0 {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return currentTime.Add(-time.Duration(output) * time.Millisecond).Truncate(time.Second), nil
|
||||
}
|
Reference in New Issue
Block a user