From c0f3b093c704da85252044b3a177dbabab63c49a Mon Sep 17 00:00:00 2001 From: HuabingZhao Date: Thu, 31 Aug 2017 11:59:47 +0800 Subject: add vendor package Issue-Id: OOM-61 Change-Id: I251336e3b711b14f8ae9a8b0bf6055011a1d9bc8 Signed-off-by: HuabingZhao --- .../kubernetes/pkg/client/cache/delta_fifo.go | 613 +++++++++++ .../k8s.io/kubernetes/pkg/client/cache/doc.go | 24 + .../pkg/client/cache/expiration_cache.go | 208 ++++ .../pkg/client/cache/expiration_cache_fakes.go | 54 + .../pkg/client/cache/fake_custom_store.go | 102 ++ .../k8s.io/kubernetes/pkg/client/cache/fifo.go | 321 ++++++ .../k8s.io/kubernetes/pkg/client/cache/index.go | 82 ++ .../k8s.io/kubernetes/pkg/client/cache/listers.go | 672 ++++++++++++ .../kubernetes/pkg/client/cache/listwatch.go | 86 ++ .../kubernetes/pkg/client/cache/reflector.go | 423 ++++++++ .../k8s.io/kubernetes/pkg/client/cache/store.go | 240 +++++ .../pkg/client/cache/thread_safe_store.go | 288 ++++++ .../kubernetes/pkg/client/cache/undelta_store.go | 83 ++ .../kubernetes/pkg/client/metrics/metrics.go | 67 ++ .../kubernetes/pkg/client/restclient/client.go | 224 ++++ .../kubernetes/pkg/client/restclient/config.go | 328 ++++++ .../kubernetes/pkg/client/restclient/plugin.go | 73 ++ .../kubernetes/pkg/client/restclient/request.go | 1086 ++++++++++++++++++++ .../kubernetes/pkg/client/restclient/transport.go | 94 ++ .../kubernetes/pkg/client/restclient/url_utils.go | 93 ++ .../kubernetes/pkg/client/restclient/urlbackoff.go | 107 ++ .../kubernetes/pkg/client/restclient/versions.go | 88 ++ .../kubernetes/pkg/client/transport/cache.go | 88 ++ .../kubernetes/pkg/client/transport/config.go | 84 ++ .../pkg/client/transport/round_trippers.go | 337 ++++++ .../kubernetes/pkg/client/transport/transport.go | 140 +++ .../pkg/client/typed/discovery/discovery_client.go | 317 ++++++ .../kubernetes/pkg/client/unversioned/apps.go | 76 ++ .../pkg/client/unversioned/auth/clientauth.go | 125 +++ .../pkg/client/unversioned/autoscaling.go | 77 ++ .../kubernetes/pkg/client/unversioned/batch.go | 107 ++ .../pkg/client/unversioned/certificates.go | 86 ++ .../unversioned/certificatesigningrequests.go | 104 ++ .../kubernetes/pkg/client/unversioned/client.go | 179 ++++ .../client/unversioned/clientcmd/api/helpers.go | 183 ++++ .../unversioned/clientcmd/api/latest/latest.go | 54 + .../client/unversioned/clientcmd/api/register.go | 43 + .../pkg/client/unversioned/clientcmd/api/types.go | 152 +++ .../unversioned/clientcmd/api/v1/conversion.go | 231 +++++ .../unversioned/clientcmd/api/v1/register.go | 40 + .../client/unversioned/clientcmd/api/v1/types.go | 145 +++ .../client/unversioned/clientcmd/auth_loaders.go | 91 ++ .../client/unversioned/clientcmd/client_config.go | 411 ++++++++ .../pkg/client/unversioned/clientcmd/config.go | 472 +++++++++ .../pkg/client/unversioned/clientcmd/doc.go | 37 + .../pkg/client/unversioned/clientcmd/loader.go | 585 +++++++++++ .../unversioned/clientcmd/merged_client_builder.go | 122 +++ .../pkg/client/unversioned/clientcmd/overrides.go | 198 ++++ .../pkg/client/unversioned/clientcmd/validation.go | 270 +++++ .../pkg/client/unversioned/clusterrolebindings.go | 92 ++ .../pkg/client/unversioned/clusterroles.go | 92 ++ .../pkg/client/unversioned/componentstatuses.go | 60 ++ .../pkg/client/unversioned/conditions.go | 240 +++++ .../kubernetes/pkg/client/unversioned/configmap.go | 122 +++ .../pkg/client/unversioned/containerinfo.go | 123 +++ .../pkg/client/unversioned/daemon_sets.go | 100 ++ .../pkg/client/unversioned/deployment.go | 111 ++ .../kubernetes/pkg/client/unversioned/doc.go | 57 + .../kubernetes/pkg/client/unversioned/endpoints.go | 101 ++ .../kubernetes/pkg/client/unversioned/events.go | 219 ++++ .../pkg/client/unversioned/extensions.go | 131 +++ .../kubernetes/pkg/client/unversioned/flags.go | 31 + .../kubernetes/pkg/client/unversioned/helper.go | 273 +++++ .../client/unversioned/horizontalpodautoscaler.go | 103 ++ .../client/unversioned/import_known_versions.go | 41 + .../kubernetes/pkg/client/unversioned/ingress.go | 100 ++ .../kubernetes/pkg/client/unversioned/jobs.go | 167 +++ .../pkg/client/unversioned/limit_ranges.go | 94 ++ .../pkg/client/unversioned/namespaces.go | 116 +++ .../pkg/client/unversioned/network_policys.go | 92 ++ .../kubernetes/pkg/client/unversioned/nodes.go | 111 ++ .../client/unversioned/persistentvolumeclaim.go | 99 ++ .../pkg/client/unversioned/persistentvolumes.go | 93 ++ .../kubernetes/pkg/client/unversioned/pet_sets.go | 100 ++ .../client/unversioned/pod_disruption_budgets.go | 100 ++ .../pkg/client/unversioned/pod_templates.go | 94 ++ .../kubernetes/pkg/client/unversioned/pods.go | 115 +++ .../pkg/client/unversioned/podsecuritypolicy.go | 111 ++ .../kubernetes/pkg/client/unversioned/policy.go | 76 ++ .../kubernetes/pkg/client/unversioned/rbac.go | 96 ++ .../pkg/client/unversioned/replica_sets.go | 100 ++ .../client/unversioned/replication_controllers.go | 99 ++ .../pkg/client/unversioned/resource_quotas.go | 102 ++ .../pkg/client/unversioned/rolebindings.go | 95 ++ .../kubernetes/pkg/client/unversioned/roles.go | 95 ++ .../kubernetes/pkg/client/unversioned/scale.go | 77 ++ .../pkg/client/unversioned/scheduledjobs.go | 103 ++ .../kubernetes/pkg/client/unversioned/secrets.go | 120 +++ .../pkg/client/unversioned/service_accounts.go | 120 +++ .../kubernetes/pkg/client/unversioned/services.go | 121 +++ .../pkg/client/unversioned/thirdpartyresources.go | 98 ++ .../kubernetes/pkg/client/unversioned/util.go | 79 ++ 92 files changed, 14779 insertions(+) create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/delta_fifo.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/doc.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache_fakes.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fake_custom_store.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fifo.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/index.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listers.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listwatch.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/reflector.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/store.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/thread_safe_store.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/undelta_store.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/metrics/metrics.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/client.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/config.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/plugin.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/request.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/transport.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/url_utils.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/urlbackoff.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/versions.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/cache.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/config.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/round_trippers.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/transport.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/typed/discovery/discovery_client.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/apps.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/auth/clientauth.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/autoscaling.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/batch.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificates.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificatesigningrequests.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/client.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/helpers.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest/latest.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/register.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/types.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/conversion.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/register.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/types.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/auth_loaders.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/client_config.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/config.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/doc.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/loader.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/merged_client_builder.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/overrides.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/validation.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterrolebindings.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterroles.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/componentstatuses.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/conditions.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/configmap.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/containerinfo.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/daemon_sets.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/deployment.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/doc.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/endpoints.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/events.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/extensions.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/flags.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/helper.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/horizontalpodautoscaler.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/import_known_versions.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/ingress.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/jobs.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/limit_ranges.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/namespaces.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/network_policys.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/nodes.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumeclaim.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumes.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pet_sets.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_disruption_budgets.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_templates.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pods.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/podsecuritypolicy.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/policy.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rbac.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replica_sets.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replication_controllers.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/resource_quotas.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rolebindings.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/roles.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scale.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scheduledjobs.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/secrets.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/service_accounts.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/services.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/thirdpartyresources.go create mode 100644 kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/util.go (limited to 'kube2msb/src/vendor/k8s.io/kubernetes/pkg/client') diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/delta_fifo.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/delta_fifo.go new file mode 100644 index 0000000..5a7f4a9 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/delta_fifo.go @@ -0,0 +1,613 @@ +/* +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 cache + +import ( + "errors" + "fmt" + "sync" + + "k8s.io/kubernetes/pkg/util/sets" + + "github.com/golang/glog" +) + +// NewDeltaFIFO returns a Store which can be used process changes to items. +// +// keyFunc is used to figure out what key an object should have. (It's +// exposed in the returned DeltaFIFO's KeyOf() method, with bonus features.) +// +// 'compressor' may compress as many or as few items as it wants +// (including returning an empty slice), but it should do what it +// does quickly since it is called while the queue is locked. +// 'compressor' may be nil if you don't want any delta compression. +// +// 'keyLister' is expected to return a list of keys that the consumer of +// this queue "knows about". It is used to decide which items are missing +// when Replace() is called; 'Deleted' deltas are produced for these items. +// It may be nil if you don't need to detect all deletions. +// TODO: consider merging keyLister with this object, tracking a list of +// "known" keys when Pop() is called. Have to think about how that +// affects error retrying. +// TODO(lavalamp): I believe there is a possible race only when using an +// external known object source that the above TODO would +// fix. +// +// Also see the comment on DeltaFIFO. +func NewDeltaFIFO(keyFunc KeyFunc, compressor DeltaCompressor, knownObjects KeyListerGetter) *DeltaFIFO { + f := &DeltaFIFO{ + items: map[string]Deltas{}, + queue: []string{}, + keyFunc: keyFunc, + deltaCompressor: compressor, + knownObjects: knownObjects, + } + f.cond.L = &f.lock + return f +} + +// DeltaFIFO is like FIFO, but allows you to process deletes. +// +// DeltaFIFO is a producer-consumer queue, where a Reflector is +// intended to be the producer, and the consumer is whatever calls +// the Pop() method. +// +// DeltaFIFO solves this use case: +// * You want to process every object change (delta) at most once. +// * When you process an object, you want to see everything +// that's happened to it since you last processed it. +// * You want to process the deletion of objects. +// * You might want to periodically reprocess objects. +// +// DeltaFIFO's Pop(), Get(), and GetByKey() methods return +// interface{} to satisfy the Store/Queue interfaces, but it +// will always return an object of type Deltas. +// +// A note on threading: If you call Pop() in parallel from multiple +// threads, you could end up with multiple threads processing slightly +// different versions of the same object. +// +// A note on the KeyLister used by the DeltaFIFO: It's main purpose is +// to list keys that are "known", for the purpose of figuring out which +// items have been deleted when Replace() or Delete() are called. The deleted +// object will be included in the DeleteFinalStateUnknown markers. These objects +// could be stale. +// +// You may provide a function to compress deltas (e.g., represent a +// series of Updates as a single Update). +type DeltaFIFO struct { + // lock/cond protects access to 'items' and 'queue'. + lock sync.RWMutex + cond sync.Cond + + // We depend on the property that items in the set are in + // the queue and vice versa, and that all Deltas in this + // map have at least one Delta. + items map[string]Deltas + queue []string + + // populated is true if the first batch of items inserted by Replace() has been populated + // or Delete/Add/Update was called first. + populated bool + // initialPopulationCount is the number of items inserted by the first call of Replace() + initialPopulationCount int + + // keyFunc is used to make the key used for queued item + // insertion and retrieval, and should be deterministic. + keyFunc KeyFunc + + // deltaCompressor tells us how to combine two or more + // deltas. It may be nil. + deltaCompressor DeltaCompressor + + // knownObjects list keys that are "known", for the + // purpose of figuring out which items have been deleted + // when Replace() or Delete() is called. + knownObjects KeyListerGetter +} + +var ( + _ = Queue(&DeltaFIFO{}) // DeltaFIFO is a Queue +) + +var ( + // ErrZeroLengthDeltasObject is returned in a KeyError if a Deltas + // object with zero length is encountered (should be impossible, + // even if such an object is accidentally produced by a DeltaCompressor-- + // but included for completeness). + ErrZeroLengthDeltasObject = errors.New("0 length Deltas object; can't get key") +) + +// KeyOf exposes f's keyFunc, but also detects the key of a Deltas object or +// DeletedFinalStateUnknown objects. +func (f *DeltaFIFO) KeyOf(obj interface{}) (string, error) { + if d, ok := obj.(Deltas); ok { + if len(d) == 0 { + return "", KeyError{obj, ErrZeroLengthDeltasObject} + } + obj = d.Newest().Object + } + if d, ok := obj.(DeletedFinalStateUnknown); ok { + return d.Key, nil + } + return f.keyFunc(obj) +} + +// Return true if an Add/Update/Delete/AddIfNotPresent are called first, +// or an Update called first but the first batch of items inserted by Replace() has been popped +func (f *DeltaFIFO) HasSynced() bool { + f.lock.Lock() + defer f.lock.Unlock() + return f.populated && f.initialPopulationCount == 0 +} + +// Add inserts an item, and puts it in the queue. The item is only enqueued +// if it doesn't already exist in the set. +func (f *DeltaFIFO) Add(obj interface{}) error { + f.lock.Lock() + defer f.lock.Unlock() + f.populated = true + return f.queueActionLocked(Added, obj) +} + +// Update is just like Add, but makes an Updated Delta. +func (f *DeltaFIFO) Update(obj interface{}) error { + f.lock.Lock() + defer f.lock.Unlock() + f.populated = true + return f.queueActionLocked(Updated, obj) +} + +// Delete is just like Add, but makes an Deleted Delta. If the item does not +// already exist, it will be ignored. (It may have already been deleted by a +// Replace (re-list), for example. +func (f *DeltaFIFO) Delete(obj interface{}) error { + id, err := f.KeyOf(obj) + if err != nil { + return KeyError{obj, err} + } + f.lock.Lock() + defer f.lock.Unlock() + f.populated = true + if f.knownObjects == nil { + if _, exists := f.items[id]; !exists { + // Presumably, this was deleted when a relist happened. + // Don't provide a second report of the same deletion. + return nil + } + } else { + // We only want to skip the "deletion" action if the object doesn't + // exist in knownObjects and it doesn't have corresponding item in items. + // Note that even if there is a "deletion" action in items, we can ignore it, + // because it will be deduped automatically in "queueActionLocked" + _, exists, err := f.knownObjects.GetByKey(id) + _, itemsExist := f.items[id] + if err == nil && !exists && !itemsExist { + // Presumably, this was deleted when a relist happened. + // Don't provide a second report of the same deletion. + // TODO(lavalamp): This may be racy-- we aren't properly locked + // with knownObjects. + return nil + } + } + + return f.queueActionLocked(Deleted, obj) +} + +// AddIfNotPresent inserts an item, and puts it in the queue. If the item is already +// present in the set, it is neither enqueued nor added to the set. +// +// This is useful in a single producer/consumer scenario so that the consumer can +// safely retry items without contending with the producer and potentially enqueueing +// stale items. +// +// Important: obj must be a Deltas (the output of the Pop() function). Yes, this is +// different from the Add/Update/Delete functions. +func (f *DeltaFIFO) AddIfNotPresent(obj interface{}) error { + deltas, ok := obj.(Deltas) + if !ok { + return fmt.Errorf("object must be of type deltas, but got: %#v", obj) + } + id, err := f.KeyOf(deltas.Newest().Object) + if err != nil { + return KeyError{obj, err} + } + f.lock.Lock() + defer f.lock.Unlock() + f.addIfNotPresent(id, deltas) + return nil +} + +// addIfNotPresent inserts deltas under id if it does not exist, and assumes the caller +// already holds the fifo lock. +func (f *DeltaFIFO) addIfNotPresent(id string, deltas Deltas) { + f.populated = true + if _, exists := f.items[id]; exists { + return + } + + f.queue = append(f.queue, id) + f.items[id] = deltas + f.cond.Broadcast() +} + +// re-listing and watching can deliver the same update multiple times in any +// order. This will combine the most recent two deltas if they are the same. +func dedupDeltas(deltas Deltas) Deltas { + n := len(deltas) + if n < 2 { + return deltas + } + a := &deltas[n-1] + b := &deltas[n-2] + if out := isDup(a, b); out != nil { + d := append(Deltas{}, deltas[:n-2]...) + return append(d, *out) + } + return deltas +} + +// If a & b represent the same event, returns the delta that ought to be kept. +// Otherwise, returns nil. +// TODO: is there anything other than deletions that need deduping? +func isDup(a, b *Delta) *Delta { + if out := isDeletionDup(a, b); out != nil { + return out + } + // TODO: Detect other duplicate situations? Are there any? + return nil +} + +// keep the one with the most information if both are deletions. +func isDeletionDup(a, b *Delta) *Delta { + if b.Type != Deleted || a.Type != Deleted { + return nil + } + // Do more sophisticated checks, or is this sufficient? + if _, ok := b.Object.(DeletedFinalStateUnknown); ok { + return a + } + return b +} + +// willObjectBeDeletedLocked returns true only if the last delta for the +// given object is Delete. Caller must lock first. +func (f *DeltaFIFO) willObjectBeDeletedLocked(id string) bool { + deltas := f.items[id] + return len(deltas) > 0 && deltas[len(deltas)-1].Type == Deleted +} + +// queueActionLocked appends to the delta list for the object, calling +// f.deltaCompressor if needed. Caller must lock first. +func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) error { + id, err := f.KeyOf(obj) + if err != nil { + return KeyError{obj, err} + } + + // If object is supposed to be deleted (last event is Deleted), + // then we should ignore Sync events, because it would result in + // recreation of this object. + if actionType == Sync && f.willObjectBeDeletedLocked(id) { + return nil + } + + newDeltas := append(f.items[id], Delta{actionType, obj}) + newDeltas = dedupDeltas(newDeltas) + if f.deltaCompressor != nil { + newDeltas = f.deltaCompressor.Compress(newDeltas) + } + + _, exists := f.items[id] + if len(newDeltas) > 0 { + if !exists { + f.queue = append(f.queue, id) + } + f.items[id] = newDeltas + f.cond.Broadcast() + } else if exists { + // The compression step removed all deltas, so + // we need to remove this from our map (extra items + // in the queue are ignored if they are not in the + // map). + delete(f.items, id) + } + return nil +} + +// List returns a list of all the items; it returns the object +// from the most recent Delta. +// You should treat the items returned inside the deltas as immutable. +func (f *DeltaFIFO) List() []interface{} { + f.lock.RLock() + defer f.lock.RUnlock() + return f.listLocked() +} + +func (f *DeltaFIFO) listLocked() []interface{} { + list := make([]interface{}, 0, len(f.items)) + for _, item := range f.items { + // Copy item's slice so operations on this slice (delta + // compression) won't interfere with the object we return. + item = copyDeltas(item) + list = append(list, item.Newest().Object) + } + return list +} + +// ListKeys returns a list of all the keys of the objects currently +// in the FIFO. +func (f *DeltaFIFO) ListKeys() []string { + f.lock.RLock() + defer f.lock.RUnlock() + list := make([]string, 0, len(f.items)) + for key := range f.items { + list = append(list, key) + } + return list +} + +// Get returns the complete list of deltas for the requested item, +// or sets exists=false. +// You should treat the items returned inside the deltas as immutable. +func (f *DeltaFIFO) Get(obj interface{}) (item interface{}, exists bool, err error) { + key, err := f.KeyOf(obj) + if err != nil { + return nil, false, KeyError{obj, err} + } + return f.GetByKey(key) +} + +// GetByKey returns the complete list of deltas for the requested item, +// setting exists=false if that list is empty. +// You should treat the items returned inside the deltas as immutable. +func (f *DeltaFIFO) GetByKey(key string) (item interface{}, exists bool, err error) { + f.lock.RLock() + defer f.lock.RUnlock() + d, exists := f.items[key] + if exists { + // Copy item's slice so operations on this slice (delta + // compression) won't interfere with the object we return. + d = copyDeltas(d) + } + return d, exists, nil +} + +// Pop blocks until an item is added to the queue, and then returns it. If +// multiple items are ready, they are returned in the order in which they were +// added/updated. The item is removed from the queue (and the store) before it +// is returned, so if you don't successfully process it, you need to add it back +// with AddIfNotPresent(). +// process function is called under lock, so it is safe update data structures +// in it that need to be in sync with the queue (e.g. knownKeys). The PopProcessFunc +// may return an instance of ErrRequeue with a nested error to indicate the current +// item should be requeued (equivalent to calling AddIfNotPresent under the lock). +// +// Pop returns a 'Deltas', which has a complete list of all the things +// that happened to the object (deltas) while it was sitting in the queue. +func (f *DeltaFIFO) Pop(process PopProcessFunc) (interface{}, error) { + f.lock.Lock() + defer f.lock.Unlock() + for { + for len(f.queue) == 0 { + f.cond.Wait() + } + id := f.queue[0] + f.queue = f.queue[1:] + item, ok := f.items[id] + if f.initialPopulationCount > 0 { + f.initialPopulationCount-- + } + if !ok { + // Item may have been deleted subsequently. + continue + } + delete(f.items, id) + err := process(item) + if e, ok := err.(ErrRequeue); ok { + f.addIfNotPresent(id, item) + err = e.Err + } + // Don't need to copyDeltas here, because we're transferring + // ownership to the caller. + return item, err + } +} + +// Replace will delete the contents of 'f', using instead the given map. +// 'f' takes ownership of the map, you should not reference the map again +// after calling this function. f's queue is reset, too; upon return, it +// will contain the items in the map, in no particular order. +func (f *DeltaFIFO) Replace(list []interface{}, resourceVersion string) error { + f.lock.Lock() + defer f.lock.Unlock() + keys := make(sets.String, len(list)) + + if !f.populated { + f.populated = true + f.initialPopulationCount = len(list) + } + + for _, item := range list { + key, err := f.KeyOf(item) + if err != nil { + return KeyError{item, err} + } + keys.Insert(key) + if err := f.queueActionLocked(Sync, item); err != nil { + return fmt.Errorf("couldn't enqueue object: %v", err) + } + } + + if f.knownObjects == nil { + // Do deletion detection against our own list. + for k, oldItem := range f.items { + if keys.Has(k) { + continue + } + var deletedObj interface{} + if n := oldItem.Newest(); n != nil { + deletedObj = n.Object + } + if err := f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}); err != nil { + return err + } + } + return nil + } + + // Detect deletions not already in the queue. + // TODO(lavalamp): This may be racy-- we aren't properly locked + // with knownObjects. Unproven. + knownKeys := f.knownObjects.ListKeys() + for _, k := range knownKeys { + if keys.Has(k) { + continue + } + + deletedObj, exists, err := f.knownObjects.GetByKey(k) + if err != nil { + deletedObj = nil + glog.Errorf("Unexpected error %v during lookup of key %v, placing DeleteFinalStateUnknown marker without object", err, k) + } else if !exists { + deletedObj = nil + glog.Infof("Key %v does not exist in known objects store, placing DeleteFinalStateUnknown marker without object", k) + } + if err := f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}); err != nil { + return err + } + } + return nil +} + +// Resync will send a sync event for each item +func (f *DeltaFIFO) Resync() error { + f.lock.RLock() + defer f.lock.RUnlock() + for _, k := range f.knownObjects.ListKeys() { + obj, exists, err := f.knownObjects.GetByKey(k) + if err != nil { + glog.Errorf("Unexpected error %v during lookup of key %v, unable to queue object for sync", err, k) + continue + } else if !exists { + glog.Infof("Key %v does not exist in known objects store, unable to queue object for sync", k) + continue + } + + if err := f.queueActionLocked(Sync, obj); err != nil { + return fmt.Errorf("couldn't queue object: %v", err) + } + } + return nil +} + +// A KeyListerGetter is anything that knows how to list its keys and look up by key. +type KeyListerGetter interface { + KeyLister + KeyGetter +} + +// A KeyLister is anything that knows how to list its keys. +type KeyLister interface { + ListKeys() []string +} + +// A KeyGetter is anything that knows how to get the value stored under a given key. +type KeyGetter interface { + GetByKey(key string) (interface{}, bool, error) +} + +// DeltaCompressor is an algorithm that removes redundant changes. +type DeltaCompressor interface { + Compress(Deltas) Deltas +} + +// DeltaCompressorFunc should remove redundant changes; but changes that +// are redundant depend on one's desired semantics, so this is an +// injectable function. +// +// DeltaCompressorFunc adapts a raw function to be a DeltaCompressor. +type DeltaCompressorFunc func(Deltas) Deltas + +// Compress just calls dc. +func (dc DeltaCompressorFunc) Compress(d Deltas) Deltas { + return dc(d) +} + +// DeltaType is the type of a change (addition, deletion, etc) +type DeltaType string + +const ( + Added DeltaType = "Added" + Updated DeltaType = "Updated" + Deleted DeltaType = "Deleted" + // The other types are obvious. You'll get Sync deltas when: + // * A watch expires/errors out and a new list/watch cycle is started. + // * You've turned on periodic syncs. + // (Anything that trigger's DeltaFIFO's Replace() method.) + Sync DeltaType = "Sync" +) + +// Delta is the type stored by a DeltaFIFO. It tells you what change +// happened, and the object's state after* that change. +// +// [*] Unless the change is a deletion, and then you'll get the final +// state of the object before it was deleted. +type Delta struct { + Type DeltaType + Object interface{} +} + +// Deltas is a list of one or more 'Delta's to an individual object. +// The oldest delta is at index 0, the newest delta is the last one. +type Deltas []Delta + +// Oldest is a convenience function that returns the oldest delta, or +// nil if there are no deltas. +func (d Deltas) Oldest() *Delta { + if len(d) > 0 { + return &d[0] + } + return nil +} + +// Newest is a convenience function that returns the newest delta, or +// nil if there are no deltas. +func (d Deltas) Newest() *Delta { + if n := len(d); n > 0 { + return &d[n-1] + } + return nil +} + +// copyDeltas returns a shallow copy of d; that is, it copies the slice but not +// the objects in the slice. This allows Get/List to return an object that we +// know won't be clobbered by a subsequent call to a delta compressor. +func copyDeltas(d Deltas) Deltas { + d2 := make(Deltas, len(d)) + copy(d2, d) + return d2 +} + +// DeletedFinalStateUnknown is placed into a DeltaFIFO in the case where +// an object was deleted but the watch deletion event was missed. In this +// case we don't know the final "resting" state of the object, so there's +// a chance the included `Obj` is stale. +type DeletedFinalStateUnknown struct { + Key string + Obj interface{} +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/doc.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/doc.go new file mode 100644 index 0000000..4f593f0 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/doc.go @@ -0,0 +1,24 @@ +/* +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 cache is a client-side caching mechanism. It is useful for +// reducing the number of server calls you'd otherwise need to make. +// Reflector watches a server and updates a Store. Two stores are provided; +// one that simply caches objects (for example, to allow a scheduler to +// list currently available nodes), and one that additionally acts as +// a FIFO queue (for example, to allow a scheduler to process incoming +// pods). +package cache diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache.go new file mode 100644 index 0000000..8c5c470 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache.go @@ -0,0 +1,208 @@ +/* +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 cache + +import ( + "sync" + "time" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/util" +) + +// ExpirationCache implements the store interface +// 1. All entries are automatically time stamped on insert +// a. The key is computed based off the original item/keyFunc +// b. The value inserted under that key is the timestamped item +// 2. Expiration happens lazily on read based on the expiration policy +// a. No item can be inserted into the store while we're expiring +// *any* item in the cache. +// 3. Time-stamps are stripped off unexpired entries before return +// Note that the ExpirationCache is inherently slower than a normal +// threadSafeStore because it takes a write lock every time it checks if +// an item has expired. +type ExpirationCache struct { + cacheStorage ThreadSafeStore + keyFunc KeyFunc + clock util.Clock + expirationPolicy ExpirationPolicy + // expirationLock is a write lock used to guarantee that we don't clobber + // newly inserted objects because of a stale expiration timestamp comparison + expirationLock sync.Mutex +} + +// ExpirationPolicy dictates when an object expires. Currently only abstracted out +// so unittests don't rely on the system clock. +type ExpirationPolicy interface { + IsExpired(obj *timestampedEntry) bool +} + +// TTLPolicy implements a ttl based ExpirationPolicy. +type TTLPolicy struct { + // >0: Expire entries with an age > ttl + // <=0: Don't expire any entry + Ttl time.Duration + + // Clock used to calculate ttl expiration + Clock util.Clock +} + +// IsExpired returns true if the given object is older than the ttl, or it can't +// determine its age. +func (p *TTLPolicy) IsExpired(obj *timestampedEntry) bool { + return p.Ttl > 0 && p.Clock.Since(obj.timestamp) > p.Ttl +} + +// timestampedEntry is the only type allowed in a ExpirationCache. +type timestampedEntry struct { + obj interface{} + timestamp time.Time +} + +// getTimestampedEntry returnes the timestampedEntry stored under the given key. +func (c *ExpirationCache) getTimestampedEntry(key string) (*timestampedEntry, bool) { + item, _ := c.cacheStorage.Get(key) + if tsEntry, ok := item.(*timestampedEntry); ok { + return tsEntry, true + } + return nil, false +} + +// getOrExpire retrieves the object from the timestampedEntry if and only if it hasn't +// already expired. It holds a write lock across deletion. +func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) { + // Prevent all inserts from the time we deem an item as "expired" to when we + // delete it, so an un-expired item doesn't sneak in under the same key, just + // before the Delete. + c.expirationLock.Lock() + defer c.expirationLock.Unlock() + timestampedItem, exists := c.getTimestampedEntry(key) + if !exists { + return nil, false + } + if c.expirationPolicy.IsExpired(timestampedItem) { + glog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj) + c.cacheStorage.Delete(key) + return nil, false + } + return timestampedItem.obj, true +} + +// GetByKey returns the item stored under the key, or sets exists=false. +func (c *ExpirationCache) GetByKey(key string) (interface{}, bool, error) { + obj, exists := c.getOrExpire(key) + return obj, exists, nil +} + +// Get returns unexpired items. It purges the cache of expired items in the +// process. +func (c *ExpirationCache) Get(obj interface{}) (interface{}, bool, error) { + key, err := c.keyFunc(obj) + if err != nil { + return nil, false, KeyError{obj, err} + } + obj, exists := c.getOrExpire(key) + return obj, exists, nil +} + +// List retrieves a list of unexpired items. It purges the cache of expired +// items in the process. +func (c *ExpirationCache) List() []interface{} { + items := c.cacheStorage.List() + + list := make([]interface{}, 0, len(items)) + for _, item := range items { + obj := item.(*timestampedEntry).obj + if key, err := c.keyFunc(obj); err != nil { + list = append(list, obj) + } else if obj, exists := c.getOrExpire(key); exists { + list = append(list, obj) + } + } + return list +} + +// ListKeys returns a list of all keys in the expiration cache. +func (c *ExpirationCache) ListKeys() []string { + return c.cacheStorage.ListKeys() +} + +// Add timestamps an item and inserts it into the cache, overwriting entries +// that might exist under the same key. +func (c *ExpirationCache) Add(obj interface{}) error { + c.expirationLock.Lock() + defer c.expirationLock.Unlock() + + key, err := c.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + c.cacheStorage.Add(key, ×tampedEntry{obj, c.clock.Now()}) + return nil +} + +// Update has not been implemented yet for lack of a use case, so this method +// simply calls `Add`. This effectively refreshes the timestamp. +func (c *ExpirationCache) Update(obj interface{}) error { + return c.Add(obj) +} + +// Delete removes an item from the cache. +func (c *ExpirationCache) Delete(obj interface{}) error { + c.expirationLock.Lock() + defer c.expirationLock.Unlock() + key, err := c.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + c.cacheStorage.Delete(key) + return nil +} + +// Replace will convert all items in the given list to TimestampedEntries +// before attempting the replace operation. The replace operation will +// delete the contents of the ExpirationCache `c`. +func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) error { + c.expirationLock.Lock() + defer c.expirationLock.Unlock() + items := map[string]interface{}{} + ts := c.clock.Now() + for _, item := range list { + key, err := c.keyFunc(item) + if err != nil { + return KeyError{item, err} + } + items[key] = ×tampedEntry{item, ts} + } + c.cacheStorage.Replace(items, resourceVersion) + return nil +} + +// Resync will touch all objects to put them into the processing queue +func (c *ExpirationCache) Resync() error { + return c.cacheStorage.Resync() +} + +// NewTTLStore creates and returns a ExpirationCache with a TTLPolicy +func NewTTLStore(keyFunc KeyFunc, ttl time.Duration) Store { + return &ExpirationCache{ + cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}), + keyFunc: keyFunc, + clock: util.RealClock{}, + expirationPolicy: &TTLPolicy{ttl, util.RealClock{}}, + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache_fakes.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache_fakes.go new file mode 100644 index 0000000..eb1d535 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/expiration_cache_fakes.go @@ -0,0 +1,54 @@ +/* +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 cache + +import ( + "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/sets" +) + +type fakeThreadSafeMap struct { + ThreadSafeStore + deletedKeys chan<- string +} + +func (c *fakeThreadSafeMap) Delete(key string) { + if c.deletedKeys != nil { + c.ThreadSafeStore.Delete(key) + c.deletedKeys <- key + } +} + +type FakeExpirationPolicy struct { + NeverExpire sets.String + RetrieveKeyFunc KeyFunc +} + +func (p *FakeExpirationPolicy) IsExpired(obj *timestampedEntry) bool { + key, _ := p.RetrieveKeyFunc(obj) + return !p.NeverExpire.Has(key) +} + +func NewFakeExpirationStore(keyFunc KeyFunc, deletedKeys chan<- string, expirationPolicy ExpirationPolicy, cacheClock util.Clock) Store { + cacheStorage := NewThreadSafeStore(Indexers{}, Indices{}) + return &ExpirationCache{ + cacheStorage: &fakeThreadSafeMap{cacheStorage, deletedKeys}, + keyFunc: keyFunc, + clock: cacheClock, + expirationPolicy: expirationPolicy, + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fake_custom_store.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fake_custom_store.go new file mode 100644 index 0000000..8d71c24 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fake_custom_store.go @@ -0,0 +1,102 @@ +/* +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 cache + +// FakeStore lets you define custom functions for store operations +type FakeCustomStore struct { + AddFunc func(obj interface{}) error + UpdateFunc func(obj interface{}) error + DeleteFunc func(obj interface{}) error + ListFunc func() []interface{} + ListKeysFunc func() []string + GetFunc func(obj interface{}) (item interface{}, exists bool, err error) + GetByKeyFunc func(key string) (item interface{}, exists bool, err error) + ReplaceFunc func(list []interface{}, resourceVerion string) error + ResyncFunc func() error +} + +// Add calls the custom Add function if defined +func (f *FakeCustomStore) Add(obj interface{}) error { + if f.AddFunc != nil { + return f.AddFunc(obj) + } + return nil +} + +// Update calls the custom Update function if defined +func (f *FakeCustomStore) Update(obj interface{}) error { + if f.UpdateFunc != nil { + return f.Update(obj) + } + return nil +} + +// Delete calls the custom Delete function if defined +func (f *FakeCustomStore) Delete(obj interface{}) error { + if f.DeleteFunc != nil { + return f.DeleteFunc(obj) + } + return nil +} + +// List calls the custom List function if defined +func (f *FakeCustomStore) List() []interface{} { + if f.ListFunc != nil { + return f.ListFunc() + } + return nil +} + +// ListKeys calls the custom ListKeys function if defined +func (f *FakeCustomStore) ListKeys() []string { + if f.ListKeysFunc != nil { + return f.ListKeysFunc() + } + return nil +} + +// Get calls the custom Get function if defined +func (f *FakeCustomStore) Get(obj interface{}) (item interface{}, exists bool, err error) { + if f.GetFunc != nil { + return f.GetFunc(obj) + } + return nil, false, nil +} + +// GetByKey calls the custom GetByKey function if defined +func (f *FakeCustomStore) GetByKey(key string) (item interface{}, exists bool, err error) { + if f.GetByKeyFunc != nil { + return f.GetByKeyFunc(key) + } + return nil, false, nil +} + +// Replace calls the custom Replace function if defined +func (f *FakeCustomStore) Replace(list []interface{}, resourceVersion string) error { + if f.ReplaceFunc != nil { + return f.ReplaceFunc(list, resourceVersion) + } + return nil +} + +// Resync calls the custom Resync function if defined +func (f *FakeCustomStore) Resync() error { + if f.ResyncFunc != nil { + return f.ResyncFunc() + } + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fifo.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fifo.go new file mode 100644 index 0000000..a6d5e0a --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/fifo.go @@ -0,0 +1,321 @@ +/* +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 cache + +import ( + "sync" + + "k8s.io/kubernetes/pkg/util/sets" +) + +// PopProcessFunc is passed to Pop() method of Queue interface. +// It is supposed to process the element popped from the queue. +type PopProcessFunc func(interface{}) error + +// ErrRequeue may be returned by a PopProcessFunc to safely requeue +// the current item. The value of Err will be returned from Pop. +type ErrRequeue struct { + // Err is returned by the Pop function + Err error +} + +func (e ErrRequeue) Error() string { + if e.Err == nil { + return "the popped item should be requeued without returning an error" + } + return e.Err.Error() +} + +// Queue is exactly like a Store, but has a Pop() method too. +type Queue interface { + Store + + // Pop blocks until it has something to process. + // It returns the object that was process and the result of processing. + // The PopProcessFunc may return an ErrRequeue{...} to indicate the item + // should be requeued before releasing the lock on the queue. + Pop(PopProcessFunc) (interface{}, error) + + // AddIfNotPresent adds a value previously + // returned by Pop back into the queue as long + // as nothing else (presumably more recent) + // has since been added. + AddIfNotPresent(interface{}) error + + // Return true if the first batch of items has been popped + HasSynced() bool +} + +// Helper function for popping from Queue. +// WARNING: Do NOT use this function in non-test code to avoid races +// unless you really really really really know what you are doing. +func Pop(queue Queue) interface{} { + var result interface{} + queue.Pop(func(obj interface{}) error { + result = obj + return nil + }) + return result +} + +// FIFO receives adds and updates from a Reflector, and puts them in a queue for +// FIFO order processing. If multiple adds/updates of a single item happen while +// an item is in the queue before it has been processed, it will only be +// processed once, and when it is processed, the most recent version will be +// processed. This can't be done with a channel. +// +// FIFO solves this use case: +// * You want to process every object (exactly) once. +// * You want to process the most recent version of the object when you process it. +// * You do not want to process deleted objects, they should be removed from the queue. +// * You do not want to periodically reprocess objects. +// Compare with DeltaFIFO for other use cases. +type FIFO struct { + lock sync.RWMutex + cond sync.Cond + // We depend on the property that items in the set are in the queue and vice versa. + items map[string]interface{} + queue []string + + // populated is true if the first batch of items inserted by Replace() has been populated + // or Delete/Add/Update was called first. + populated bool + // initialPopulationCount is the number of items inserted by the first call of Replace() + initialPopulationCount int + + // keyFunc is used to make the key used for queued item insertion and retrieval, and + // should be deterministic. + keyFunc KeyFunc +} + +var ( + _ = Queue(&FIFO{}) // FIFO is a Queue +) + +// Return true if an Add/Update/Delete/AddIfNotPresent are called first, +// or an Update called first but the first batch of items inserted by Replace() has been popped +func (f *FIFO) HasSynced() bool { + f.lock.Lock() + defer f.lock.Unlock() + return f.populated && f.initialPopulationCount == 0 +} + +// Add inserts an item, and puts it in the queue. The item is only enqueued +// if it doesn't already exist in the set. +func (f *FIFO) Add(obj interface{}) error { + id, err := f.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + f.lock.Lock() + defer f.lock.Unlock() + f.populated = true + if _, exists := f.items[id]; !exists { + f.queue = append(f.queue, id) + } + f.items[id] = obj + f.cond.Broadcast() + return nil +} + +// AddIfNotPresent inserts an item, and puts it in the queue. If the item is already +// present in the set, it is neither enqueued nor added to the set. +// +// This is useful in a single producer/consumer scenario so that the consumer can +// safely retry items without contending with the producer and potentially enqueueing +// stale items. +func (f *FIFO) AddIfNotPresent(obj interface{}) error { + id, err := f.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + f.lock.Lock() + defer f.lock.Unlock() + f.addIfNotPresent(id, obj) + return nil +} + +// addIfNotPresent assumes the fifo lock is already held and adds the the provided +// item to the queue under id if it does not already exist. +func (f *FIFO) addIfNotPresent(id string, obj interface{}) { + f.populated = true + if _, exists := f.items[id]; exists { + return + } + + f.queue = append(f.queue, id) + f.items[id] = obj + f.cond.Broadcast() +} + +// Update is the same as Add in this implementation. +func (f *FIFO) Update(obj interface{}) error { + return f.Add(obj) +} + +// Delete removes an item. It doesn't add it to the queue, because +// this implementation assumes the consumer only cares about the objects, +// not the order in which they were created/added. +func (f *FIFO) Delete(obj interface{}) error { + id, err := f.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + f.lock.Lock() + defer f.lock.Unlock() + f.populated = true + delete(f.items, id) + return err +} + +// List returns a list of all the items. +func (f *FIFO) List() []interface{} { + f.lock.RLock() + defer f.lock.RUnlock() + list := make([]interface{}, 0, len(f.items)) + for _, item := range f.items { + list = append(list, item) + } + return list +} + +// ListKeys returns a list of all the keys of the objects currently +// in the FIFO. +func (f *FIFO) ListKeys() []string { + f.lock.RLock() + defer f.lock.RUnlock() + list := make([]string, 0, len(f.items)) + for key := range f.items { + list = append(list, key) + } + return list +} + +// Get returns the requested item, or sets exists=false. +func (f *FIFO) Get(obj interface{}) (item interface{}, exists bool, err error) { + key, err := f.keyFunc(obj) + if err != nil { + return nil, false, KeyError{obj, err} + } + return f.GetByKey(key) +} + +// GetByKey returns the requested item, or sets exists=false. +func (f *FIFO) GetByKey(key string) (item interface{}, exists bool, err error) { + f.lock.RLock() + defer f.lock.RUnlock() + item, exists = f.items[key] + return item, exists, nil +} + +// Pop waits until an item is ready and processes it. If multiple items are +// ready, they are returned in the order in which they were added/updated. +// The item is removed from the queue (and the store) before it is processed, +// so if you don't successfully process it, it should be added back with +// AddIfNotPresent(). process function is called under lock, so it is safe +// update data structures in it that need to be in sync with the queue. +func (f *FIFO) Pop(process PopProcessFunc) (interface{}, error) { + f.lock.Lock() + defer f.lock.Unlock() + for { + for len(f.queue) == 0 { + f.cond.Wait() + } + id := f.queue[0] + f.queue = f.queue[1:] + if f.initialPopulationCount > 0 { + f.initialPopulationCount-- + } + item, ok := f.items[id] + if !ok { + // Item may have been deleted subsequently. + continue + } + delete(f.items, id) + err := process(item) + if e, ok := err.(ErrRequeue); ok { + f.addIfNotPresent(id, item) + err = e.Err + } + return item, err + } +} + +// Replace will delete the contents of 'f', using instead the given map. +// 'f' takes ownership of the map, you should not reference the map again +// after calling this function. f's queue is reset, too; upon return, it +// will contain the items in the map, in no particular order. +func (f *FIFO) Replace(list []interface{}, resourceVersion string) error { + items := map[string]interface{}{} + for _, item := range list { + key, err := f.keyFunc(item) + if err != nil { + return KeyError{item, err} + } + items[key] = item + } + + f.lock.Lock() + defer f.lock.Unlock() + + if !f.populated { + f.populated = true + f.initialPopulationCount = len(items) + } + + f.items = items + f.queue = f.queue[:0] + for id := range items { + f.queue = append(f.queue, id) + } + if len(f.queue) > 0 { + f.cond.Broadcast() + } + return nil +} + +// Resync will touch all objects to put them into the processing queue +func (f *FIFO) Resync() error { + f.lock.Lock() + defer f.lock.Unlock() + + inQueue := sets.NewString() + for _, id := range f.queue { + inQueue.Insert(id) + } + for id := range f.items { + if !inQueue.Has(id) { + f.queue = append(f.queue, id) + } + } + if len(f.queue) > 0 { + f.cond.Broadcast() + } + return nil +} + +// NewFIFO returns a Store which can be used to queue up items to +// process. +func NewFIFO(keyFunc KeyFunc) *FIFO { + f := &FIFO{ + items: map[string]interface{}{}, + queue: []string{}, + keyFunc: keyFunc, + } + f.cond.L = &f.lock + return f +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/index.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/index.go new file mode 100644 index 0000000..4379880 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/index.go @@ -0,0 +1,82 @@ +/* +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 cache + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/util/sets" +) + +// Indexer is a storage interface that lets you list objects using multiple indexing functions +type Indexer interface { + Store + // Retrieve list of objects that match on the named indexing function + Index(indexName string, obj interface{}) ([]interface{}, error) + // ListIndexFuncValues returns the list of generated values of an Index func + ListIndexFuncValues(indexName string) []string + // ByIndex lists object that match on the named indexing function with the exact key + ByIndex(indexName, indexKey string) ([]interface{}, error) + // GetIndexer return the indexers + GetIndexers() Indexers + + // AddIndexers adds more indexers to this store. If you call this after you already have data + // in the store, the results are undefined. + AddIndexers(newIndexers Indexers) error +} + +// IndexFunc knows how to provide an indexed value for an object. +type IndexFunc func(obj interface{}) ([]string, error) + +// IndexFuncToKeyFuncAdapter adapts an indexFunc to a keyFunc. This is only useful if your index function returns +// unique values for every object. This is conversion can create errors when more than one key is found. You +// should prefer to make proper key and index functions. +func IndexFuncToKeyFuncAdapter(indexFunc IndexFunc) KeyFunc { + return func(obj interface{}) (string, error) { + indexKeys, err := indexFunc(obj) + if err != nil { + return "", err + } + if len(indexKeys) > 1 { + return "", fmt.Errorf("too many keys: %v", indexKeys) + } + return indexKeys[0], nil + } +} + +const ( + NamespaceIndex string = "namespace" +) + +// MetaNamespaceIndexFunc is a default index function that indexes based on an object's namespace +func MetaNamespaceIndexFunc(obj interface{}) ([]string, error) { + meta, err := meta.Accessor(obj) + if err != nil { + return []string{""}, fmt.Errorf("object has no meta: %v", err) + } + return []string{meta.GetNamespace()}, nil +} + +// Index maps the indexed value to a set of keys in the store that match on that value +type Index map[string]sets.String + +// Indexers maps a name to a IndexFunc +type Indexers map[string]IndexFunc + +// Indices maps a name to an Index +type Indices map[string]Index diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listers.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listers.go new file mode 100644 index 0000000..29e5859 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listers.go @@ -0,0 +1,672 @@ +/* +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 cache + +import ( + "fmt" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/labels" +) + +// TODO: generate these classes and methods for all resources of interest using +// a script. Can use "go generate" once 1.4 is supported by all users. + +// StoreToPodLister makes a Store have the List method of the client.PodInterface +// The Store must contain (only) Pods. +// +// Example: +// s := cache.NewStore() +// lw := cache.ListWatch{Client: c, FieldSelector: sel, Resource: "pods"} +// r := cache.NewReflector(lw, &api.Pod{}, s).Run() +// l := StoreToPodLister{s} +// l.List() +type StoreToPodLister struct { + Indexer +} + +// Please note that selector is filtering among the pods that have gotten into +// the store; there may have been some filtering that already happened before +// that. +// +// TODO: converge on the interface in pkg/client. +func (s *StoreToPodLister) List(selector labels.Selector) (pods []*api.Pod, err error) { + // TODO: it'd be great to just call + // s.Pods(api.NamespaceAll).List(selector), however then we'd have to + // remake the list.Items as a []*api.Pod. So leave this separate for + // now. + for _, m := range s.Indexer.List() { + pod := m.(*api.Pod) + if selector.Matches(labels.Set(pod.Labels)) { + pods = append(pods, pod) + } + } + return pods, nil +} + +// Pods is taking baby steps to be more like the api in pkg/client +func (s *StoreToPodLister) Pods(namespace string) storePodsNamespacer { + return storePodsNamespacer{s.Indexer, namespace} +} + +type storePodsNamespacer struct { + indexer Indexer + namespace string +} + +// Please note that selector is filtering among the pods that have gotten into +// the store; there may have been some filtering that already happened before +// that. +func (s storePodsNamespacer) List(selector labels.Selector) (api.PodList, error) { + pods := api.PodList{} + + if s.namespace == api.NamespaceAll { + for _, m := range s.indexer.List() { + pod := m.(*api.Pod) + if selector.Matches(labels.Set(pod.Labels)) { + pods.Items = append(pods.Items, *pod) + } + } + return pods, nil + } + + key := &api.Pod{ObjectMeta: api.ObjectMeta{Namespace: s.namespace}} + items, err := s.indexer.Index(NamespaceIndex, key) + if err != nil { + // Ignore error; do slow search without index. + glog.Warningf("can not retrieve list of objects using index : %v", err) + for _, m := range s.indexer.List() { + pod := m.(*api.Pod) + if s.namespace == pod.Namespace && selector.Matches(labels.Set(pod.Labels)) { + pods.Items = append(pods.Items, *pod) + } + } + return pods, nil + } + for _, m := range items { + pod := m.(*api.Pod) + if selector.Matches(labels.Set(pod.Labels)) { + pods.Items = append(pods.Items, *pod) + } + } + return pods, nil +} + +// Exists returns true if a pod matching the namespace/name of the given pod exists in the store. +func (s *StoreToPodLister) Exists(pod *api.Pod) (bool, error) { + _, exists, err := s.Indexer.Get(pod) + if err != nil { + return false, err + } + return exists, nil +} + +// NodeConditionPredicate is a function that indicates whether the given node's conditions meet +// some set of criteria defined by the function. +type NodeConditionPredicate func(node *api.Node) bool + +// StoreToNodeLister makes a Store have the List method of the client.NodeInterface +// The Store must contain (only) Nodes. +type StoreToNodeLister struct { + Store +} + +func (s *StoreToNodeLister) List() (machines api.NodeList, err error) { + for _, m := range s.Store.List() { + machines.Items = append(machines.Items, *(m.(*api.Node))) + } + return machines, nil +} + +// NodeCondition returns a storeToNodeConditionLister +func (s *StoreToNodeLister) NodeCondition(predicate NodeConditionPredicate) storeToNodeConditionLister { + // TODO: Move this filtering server side. Currently our selectors don't facilitate searching through a list so we + // have the reflector filter out the Unschedulable field and sift through node conditions in the lister. + return storeToNodeConditionLister{s.Store, predicate} +} + +// storeToNodeConditionLister filters and returns nodes matching the given type and status from the store. +type storeToNodeConditionLister struct { + store Store + predicate NodeConditionPredicate +} + +// List returns a list of nodes that match the conditions defined by the predicate functions in the storeToNodeConditionLister. +func (s storeToNodeConditionLister) List() (nodes api.NodeList, err error) { + for _, m := range s.store.List() { + node := m.(*api.Node) + if s.predicate(node) { + nodes.Items = append(nodes.Items, *node) + } else { + glog.V(5).Infof("Node %s matches none of the conditions", node.Name) + } + } + return +} + +// StoreToReplicationControllerLister gives a store List and Exists methods. The store must contain only ReplicationControllers. +type StoreToReplicationControllerLister struct { + Indexer +} + +// Exists checks if the given rc exists in the store. +func (s *StoreToReplicationControllerLister) Exists(controller *api.ReplicationController) (bool, error) { + _, exists, err := s.Indexer.Get(controller) + if err != nil { + return false, err + } + return exists, nil +} + +// StoreToReplicationControllerLister lists all controllers in the store. +// TODO: converge on the interface in pkg/client +func (s *StoreToReplicationControllerLister) List() (controllers []api.ReplicationController, err error) { + for _, c := range s.Indexer.List() { + controllers = append(controllers, *(c.(*api.ReplicationController))) + } + return controllers, nil +} + +func (s *StoreToReplicationControllerLister) ReplicationControllers(namespace string) storeReplicationControllersNamespacer { + return storeReplicationControllersNamespacer{s.Indexer, namespace} +} + +type storeReplicationControllersNamespacer struct { + indexer Indexer + namespace string +} + +func (s storeReplicationControllersNamespacer) List(selector labels.Selector) ([]api.ReplicationController, error) { + controllers := []api.ReplicationController{} + + if s.namespace == api.NamespaceAll { + for _, m := range s.indexer.List() { + rc := *(m.(*api.ReplicationController)) + if selector.Matches(labels.Set(rc.Labels)) { + controllers = append(controllers, rc) + } + } + return controllers, nil + } + + key := &api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: s.namespace}} + items, err := s.indexer.Index(NamespaceIndex, key) + if err != nil { + // Ignore error; do slow search without index. + glog.Warningf("can not retrieve list of objects using index : %v", err) + for _, m := range s.indexer.List() { + rc := *(m.(*api.ReplicationController)) + if s.namespace == rc.Namespace && selector.Matches(labels.Set(rc.Labels)) { + controllers = append(controllers, rc) + } + } + return controllers, nil + } + for _, m := range items { + rc := *(m.(*api.ReplicationController)) + if selector.Matches(labels.Set(rc.Labels)) { + controllers = append(controllers, rc) + } + } + return controllers, nil +} + +// GetPodControllers returns a list of replication controllers managing a pod. Returns an error only if no matching controllers are found. +func (s *StoreToReplicationControllerLister) GetPodControllers(pod *api.Pod) (controllers []api.ReplicationController, err error) { + var selector labels.Selector + var rc api.ReplicationController + + if len(pod.Labels) == 0 { + err = fmt.Errorf("no controllers found for pod %v because it has no labels", pod.Name) + return + } + + key := &api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace}} + items, err := s.Indexer.Index(NamespaceIndex, key) + if err != nil { + return + } + + for _, m := range items { + rc = *m.(*api.ReplicationController) + labelSet := labels.Set(rc.Spec.Selector) + selector = labels.Set(rc.Spec.Selector).AsSelector() + + // If an rc with a nil or empty selector creeps in, it should match nothing, not everything. + if labelSet.AsSelector().Empty() || !selector.Matches(labels.Set(pod.Labels)) { + continue + } + controllers = append(controllers, rc) + } + if len(controllers) == 0 { + err = fmt.Errorf("could not find controller for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + return +} + +// StoreToDeploymentLister gives a store List and Exists methods. The store must contain only Deployments. +type StoreToDeploymentLister struct { + Store +} + +// Exists checks if the given deployment exists in the store. +func (s *StoreToDeploymentLister) Exists(deployment *extensions.Deployment) (bool, error) { + _, exists, err := s.Store.Get(deployment) + if err != nil { + return false, err + } + return exists, nil +} + +// StoreToDeploymentLister lists all deployments in the store. +// TODO: converge on the interface in pkg/client +func (s *StoreToDeploymentLister) List() (deployments []extensions.Deployment, err error) { + for _, c := range s.Store.List() { + deployments = append(deployments, *(c.(*extensions.Deployment))) + } + return deployments, nil +} + +// GetDeploymentsForReplicaSet returns a list of deployments managing a replica set. Returns an error only if no matching deployments are found. +func (s *StoreToDeploymentLister) GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) (deployments []extensions.Deployment, err error) { + var d extensions.Deployment + + if len(rs.Labels) == 0 { + err = fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) + return + } + + // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label + for _, m := range s.Store.List() { + d = *m.(*extensions.Deployment) + if d.Namespace != rs.Namespace { + continue + } + + selector, err := unversioned.LabelSelectorAsSelector(d.Spec.Selector) + if err != nil { + return nil, fmt.Errorf("invalid label selector: %v", err) + } + // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. + if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { + continue + } + deployments = append(deployments, d) + } + if len(deployments) == 0 { + err = fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) + } + return +} + +// StoreToReplicaSetLister gives a store List and Exists methods. The store must contain only ReplicaSets. +type StoreToReplicaSetLister struct { + Store +} + +// Exists checks if the given ReplicaSet exists in the store. +func (s *StoreToReplicaSetLister) Exists(rs *extensions.ReplicaSet) (bool, error) { + _, exists, err := s.Store.Get(rs) + if err != nil { + return false, err + } + return exists, nil +} + +// List lists all ReplicaSets in the store. +// TODO: converge on the interface in pkg/client +func (s *StoreToReplicaSetLister) List() (rss []extensions.ReplicaSet, err error) { + for _, rs := range s.Store.List() { + rss = append(rss, *(rs.(*extensions.ReplicaSet))) + } + return rss, nil +} + +type storeReplicaSetsNamespacer struct { + store Store + namespace string +} + +func (s storeReplicaSetsNamespacer) List(selector labels.Selector) (rss []extensions.ReplicaSet, err error) { + for _, c := range s.store.List() { + rs := *(c.(*extensions.ReplicaSet)) + if s.namespace == api.NamespaceAll || s.namespace == rs.Namespace { + if selector.Matches(labels.Set(rs.Labels)) { + rss = append(rss, rs) + } + } + } + return +} + +func (s *StoreToReplicaSetLister) ReplicaSets(namespace string) storeReplicaSetsNamespacer { + return storeReplicaSetsNamespacer{s.Store, namespace} +} + +// GetPodReplicaSets returns a list of ReplicaSets managing a pod. Returns an error only if no matching ReplicaSets are found. +func (s *StoreToReplicaSetLister) GetPodReplicaSets(pod *api.Pod) (rss []extensions.ReplicaSet, err error) { + var selector labels.Selector + var rs extensions.ReplicaSet + + if len(pod.Labels) == 0 { + err = fmt.Errorf("no ReplicaSets found for pod %v because it has no labels", pod.Name) + return + } + + for _, m := range s.Store.List() { + rs = *m.(*extensions.ReplicaSet) + if rs.Namespace != pod.Namespace { + continue + } + selector, err = unversioned.LabelSelectorAsSelector(rs.Spec.Selector) + if err != nil { + err = fmt.Errorf("invalid selector: %v", err) + return + } + + // If a ReplicaSet with a nil or empty selector creeps in, it should match nothing, not everything. + if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { + continue + } + rss = append(rss, rs) + } + if len(rss) == 0 { + err = fmt.Errorf("could not find ReplicaSet for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + return +} + +// StoreToDaemonSetLister gives a store List and Exists methods. The store must contain only DaemonSets. +type StoreToDaemonSetLister struct { + Store +} + +// Exists checks if the given daemon set exists in the store. +func (s *StoreToDaemonSetLister) Exists(ds *extensions.DaemonSet) (bool, error) { + _, exists, err := s.Store.Get(ds) + if err != nil { + return false, err + } + return exists, nil +} + +// List lists all daemon sets in the store. +// TODO: converge on the interface in pkg/client +func (s *StoreToDaemonSetLister) List() (dss extensions.DaemonSetList, err error) { + for _, c := range s.Store.List() { + dss.Items = append(dss.Items, *(c.(*extensions.DaemonSet))) + } + return dss, nil +} + +// GetPodDaemonSets returns a list of daemon sets managing a pod. +// Returns an error if and only if no matching daemon sets are found. +func (s *StoreToDaemonSetLister) GetPodDaemonSets(pod *api.Pod) (daemonSets []extensions.DaemonSet, err error) { + var selector labels.Selector + var daemonSet extensions.DaemonSet + + if len(pod.Labels) == 0 { + err = fmt.Errorf("no daemon sets found for pod %v because it has no labels", pod.Name) + return + } + + for _, m := range s.Store.List() { + daemonSet = *m.(*extensions.DaemonSet) + if daemonSet.Namespace != pod.Namespace { + continue + } + selector, err = unversioned.LabelSelectorAsSelector(daemonSet.Spec.Selector) + if err != nil { + // this should not happen if the DaemonSet passed validation + return nil, err + } + + // If a daemonSet with a nil or empty selector creeps in, it should match nothing, not everything. + if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { + continue + } + daemonSets = append(daemonSets, daemonSet) + } + if len(daemonSets) == 0 { + err = fmt.Errorf("could not find daemon set for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + return +} + +// StoreToServiceLister makes a Store that has the List method of the client.ServiceInterface +// The Store must contain (only) Services. +type StoreToServiceLister struct { + Store +} + +func (s *StoreToServiceLister) List() (services api.ServiceList, err error) { + for _, m := range s.Store.List() { + services.Items = append(services.Items, *(m.(*api.Service))) + } + return services, nil +} + +// TODO: Move this back to scheduler as a helper function that takes a Store, +// rather than a method of StoreToServiceLister. +func (s *StoreToServiceLister) GetPodServices(pod *api.Pod) (services []api.Service, err error) { + var selector labels.Selector + var service api.Service + + for _, m := range s.Store.List() { + service = *m.(*api.Service) + // consider only services that are in the same namespace as the pod + if service.Namespace != pod.Namespace { + continue + } + if service.Spec.Selector == nil { + // services with nil selectors match nothing, not everything. + continue + } + selector = labels.Set(service.Spec.Selector).AsSelector() + if selector.Matches(labels.Set(pod.Labels)) { + services = append(services, service) + } + } + if len(services) == 0 { + err = fmt.Errorf("could not find service for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + + return +} + +// StoreToEndpointsLister makes a Store that lists endpoints. +type StoreToEndpointsLister struct { + Store +} + +// List lists all endpoints in the store. +func (s *StoreToEndpointsLister) List() (services api.EndpointsList, err error) { + for _, m := range s.Store.List() { + services.Items = append(services.Items, *(m.(*api.Endpoints))) + } + return services, nil +} + +// GetServiceEndpoints returns the endpoints of a service, matched on service name. +func (s *StoreToEndpointsLister) GetServiceEndpoints(svc *api.Service) (ep api.Endpoints, err error) { + for _, m := range s.Store.List() { + ep = *m.(*api.Endpoints) + if svc.Name == ep.Name && svc.Namespace == ep.Namespace { + return ep, nil + } + } + err = fmt.Errorf("could not find endpoints for service: %v", svc.Name) + return +} + +// StoreToJobLister gives a store List and Exists methods. The store must contain only Jobs. +type StoreToJobLister struct { + Store +} + +// Exists checks if the given job exists in the store. +func (s *StoreToJobLister) Exists(job *batch.Job) (bool, error) { + _, exists, err := s.Store.Get(job) + if err != nil { + return false, err + } + return exists, nil +} + +// StoreToJobLister lists all jobs in the store. +func (s *StoreToJobLister) List() (jobs batch.JobList, err error) { + for _, c := range s.Store.List() { + jobs.Items = append(jobs.Items, *(c.(*batch.Job))) + } + return jobs, nil +} + +// GetPodJobs returns a list of jobs managing a pod. Returns an error only if no matching jobs are found. +func (s *StoreToJobLister) GetPodJobs(pod *api.Pod) (jobs []batch.Job, err error) { + var selector labels.Selector + var job batch.Job + + if len(pod.Labels) == 0 { + err = fmt.Errorf("no jobs found for pod %v because it has no labels", pod.Name) + return + } + + for _, m := range s.Store.List() { + job = *m.(*batch.Job) + if job.Namespace != pod.Namespace { + continue + } + + selector, _ = unversioned.LabelSelectorAsSelector(job.Spec.Selector) + if !selector.Matches(labels.Set(pod.Labels)) { + continue + } + jobs = append(jobs, job) + } + if len(jobs) == 0 { + err = fmt.Errorf("could not find jobs for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + return +} + +// Typed wrapper around a store of PersistentVolumes +type StoreToPVFetcher struct { + Store +} + +// GetPersistentVolumeInfo returns cached data for the PersistentVolume 'id'. +func (s *StoreToPVFetcher) GetPersistentVolumeInfo(id string) (*api.PersistentVolume, error) { + o, exists, err := s.Get(&api.PersistentVolume{ObjectMeta: api.ObjectMeta{Name: id}}) + + if err != nil { + return nil, fmt.Errorf("error retrieving PersistentVolume '%v' from cache: %v", id, err) + } + + if !exists { + return nil, fmt.Errorf("PersistentVolume '%v' not found", id) + } + + return o.(*api.PersistentVolume), nil +} + +// Typed wrapper around a store of PersistentVolumeClaims +type StoreToPVCFetcher struct { + Store +} + +// GetPersistentVolumeClaimInfo returns cached data for the PersistentVolumeClaim 'id'. +func (s *StoreToPVCFetcher) GetPersistentVolumeClaimInfo(namespace string, id string) (*api.PersistentVolumeClaim, error) { + o, exists, err := s.Get(&api.PersistentVolumeClaim{ObjectMeta: api.ObjectMeta{Namespace: namespace, Name: id}}) + if err != nil { + return nil, fmt.Errorf("error retrieving PersistentVolumeClaim '%s/%s' from cache: %v", namespace, id, err) + } + + if !exists { + return nil, fmt.Errorf("PersistentVolumeClaim '%s/%s' not found", namespace, id) + } + + return o.(*api.PersistentVolumeClaim), nil +} + +// StoreToPetSetLister gives a store List and Exists methods. The store must contain only PetSets. +type StoreToPetSetLister struct { + Store +} + +// Exists checks if the given PetSet exists in the store. +func (s *StoreToPetSetLister) Exists(ps *apps.PetSet) (bool, error) { + _, exists, err := s.Store.Get(ps) + if err != nil { + return false, err + } + return exists, nil +} + +// List lists all PetSets in the store. +func (s *StoreToPetSetLister) List() (psList []apps.PetSet, err error) { + for _, ps := range s.Store.List() { + psList = append(psList, *(ps.(*apps.PetSet))) + } + return psList, nil +} + +type storePetSetsNamespacer struct { + store Store + namespace string +} + +func (s *StoreToPetSetLister) PetSets(namespace string) storePetSetsNamespacer { + return storePetSetsNamespacer{s.Store, namespace} +} + +// GetPodPetSets returns a list of PetSets managing a pod. Returns an error only if no matching PetSets are found. +func (s *StoreToPetSetLister) GetPodPetSets(pod *api.Pod) (psList []apps.PetSet, err error) { + var selector labels.Selector + var ps apps.PetSet + + if len(pod.Labels) == 0 { + err = fmt.Errorf("no PetSets found for pod %v because it has no labels", pod.Name) + return + } + + for _, m := range s.Store.List() { + ps = *m.(*apps.PetSet) + if ps.Namespace != pod.Namespace { + continue + } + selector, err = unversioned.LabelSelectorAsSelector(ps.Spec.Selector) + if err != nil { + err = fmt.Errorf("invalid selector: %v", err) + return + } + + // If a PetSet with a nil or empty selector creeps in, it should match nothing, not everything. + if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { + continue + } + psList = append(psList, ps) + } + if len(psList) == 0 { + err = fmt.Errorf("could not find PetSet for pod %s in namespace %s with labels: %v", pod.Name, pod.Namespace, pod.Labels) + } + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listwatch.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listwatch.go new file mode 100644 index 0000000..ff56c0b --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/listwatch.go @@ -0,0 +1,86 @@ +/* +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 cache + +import ( + "time" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/watch" +) + +// ListFunc knows how to list resources +type ListFunc func(options api.ListOptions) (runtime.Object, error) + +// WatchFunc knows how to watch resources +type WatchFunc func(options api.ListOptions) (watch.Interface, error) + +// ListWatch knows how to list and watch a set of apiserver resources. It satisfies the ListerWatcher interface. +// It is a convenience function for users of NewReflector, etc. +// ListFunc and WatchFunc must not be nil +type ListWatch struct { + ListFunc ListFunc + WatchFunc WatchFunc +} + +// Getter interface knows how to access Get method from RESTClient. +type Getter interface { + Get() *restclient.Request +} + +// NewListWatchFromClient creates a new ListWatch from the specified client, resource, namespace and field selector. +func NewListWatchFromClient(c Getter, resource string, namespace string, fieldSelector fields.Selector) *ListWatch { + listFunc := func(options api.ListOptions) (runtime.Object, error) { + return c.Get(). + Namespace(namespace). + Resource(resource). + VersionedParams(&options, api.ParameterCodec). + FieldsSelectorParam(fieldSelector). + Do(). + Get() + } + watchFunc := func(options api.ListOptions) (watch.Interface, error) { + return c.Get(). + Prefix("watch"). + Namespace(namespace). + Resource(resource). + VersionedParams(&options, api.ParameterCodec). + FieldsSelectorParam(fieldSelector). + Watch() + } + return &ListWatch{ListFunc: listFunc, WatchFunc: watchFunc} +} + +func timeoutFromListOptions(options api.ListOptions) time.Duration { + if options.TimeoutSeconds != nil { + return time.Duration(*options.TimeoutSeconds) * time.Second + } + return 0 +} + +// List a set of apiserver resources +func (lw *ListWatch) List(options api.ListOptions) (runtime.Object, error) { + return lw.ListFunc(options) +} + +// Watch a set of apiserver resources +func (lw *ListWatch) Watch(options api.ListOptions) (watch.Interface, error) { + return lw.WatchFunc(options) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/reflector.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/reflector.go new file mode 100644 index 0000000..e1af63e --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/reflector.go @@ -0,0 +1,423 @@ +/* +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 cache + +import ( + "errors" + "fmt" + "io" + "math/rand" + "net" + "net/url" + "reflect" + "regexp" + goruntime "runtime" + "runtime/debug" + "strconv" + "strings" + "sync" + "syscall" + "time" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/api" + apierrs "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/runtime" + utilruntime "k8s.io/kubernetes/pkg/util/runtime" + "k8s.io/kubernetes/pkg/util/wait" + "k8s.io/kubernetes/pkg/watch" +) + +// ListerWatcher is any object that knows how to perform an initial list and start a watch on a resource. +type ListerWatcher interface { + // List should return a list type object; the Items field will be extracted, and the + // ResourceVersion field will be used to start the watch in the right place. + List(options api.ListOptions) (runtime.Object, error) + // Watch should begin a watch at the specified version. + Watch(options api.ListOptions) (watch.Interface, error) +} + +// Reflector watches a specified resource and causes all changes to be reflected in the given store. +type Reflector struct { + // name identifies this reflector. By default it will be a file:line if possible. + name string + + // The type of object we expect to place in the store. + expectedType reflect.Type + // The destination to sync up with the watch source + store Store + // listerWatcher is used to perform lists and watches. + listerWatcher ListerWatcher + // period controls timing between one watch ending and + // the beginning of the next one. + period time.Duration + resyncPeriod time.Duration + // now() returns current time - exposed for testing purposes + now func() time.Time + // nextResync is approximate time of next resync (0 if not scheduled) + nextResync time.Time + // lastSyncResourceVersion is the resource version token last + // observed when doing a sync with the underlying store + // it is thread safe, but not synchronized with the underlying store + lastSyncResourceVersion string + // lastSyncResourceVersionMutex guards read/write access to lastSyncResourceVersion + lastSyncResourceVersionMutex sync.RWMutex +} + +var ( + // We try to spread the load on apiserver by setting timeouts for + // watch requests - it is random in [minWatchTimeout, 2*minWatchTimeout]. + // However, it can be modified to avoid periodic resync to break the + // TCP connection. + minWatchTimeout = 5 * time.Minute + // If we are within 'forceResyncThreshold' from the next planned resync + // and are just before issuing Watch(), resync will be forced now. + forceResyncThreshold = 3 * time.Second + // We try to set timeouts for Watch() so that we will finish about + // than 'timeoutThreshold' from next planned periodic resync. + timeoutThreshold = 1 * time.Second +) + +// NewNamespaceKeyedIndexerAndReflector creates an Indexer and a Reflector +// The indexer is configured to key on namespace +func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interface{}, resyncPeriod time.Duration) (indexer Indexer, reflector *Reflector) { + indexer = NewIndexer(MetaNamespaceKeyFunc, Indexers{"namespace": MetaNamespaceIndexFunc}) + reflector = NewReflector(lw, expectedType, indexer, resyncPeriod) + return indexer, reflector +} + +// NewReflector creates a new Reflector object which will keep the given store up to +// date with the server's contents for the given resource. Reflector promises to +// only put things in the store that have the type of expectedType, unless expectedType +// is nil. If resyncPeriod is non-zero, then lists will be executed after every +// resyncPeriod, so that you can use reflectors to periodically process everything as +// well as incrementally processing the things that change. +func NewReflector(lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector { + return NewNamedReflector(getDefaultReflectorName(internalPackages...), lw, expectedType, store, resyncPeriod) +} + +// NewNamedReflector same as NewReflector, but with a specified name for logging +func NewNamedReflector(name string, lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector { + r := &Reflector{ + name: name, + listerWatcher: lw, + store: store, + expectedType: reflect.TypeOf(expectedType), + period: time.Second, + resyncPeriod: resyncPeriod, + now: time.Now, + } + return r +} + +// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common +// call chains to NewReflector, so they'd be low entropy names for reflectors +var internalPackages = []string{"kubernetes/pkg/client/cache/", "kubernetes/pkg/controller/framework/", "/runtime/asm_"} + +// getDefaultReflectorName walks back through the call stack until we find a caller from outside of the ignoredPackages +// it returns back a shortpath/filename:line to aid in identification of this reflector when it starts logging +func getDefaultReflectorName(ignoredPackages ...string) string { + name := "????" + const maxStack = 10 + for i := 1; i < maxStack; i++ { + _, file, line, ok := goruntime.Caller(i) + if !ok { + file, line, ok = extractStackCreator() + if !ok { + break + } + i += maxStack + } + if hasPackage(file, ignoredPackages) { + continue + } + + file = trimPackagePrefix(file) + name = fmt.Sprintf("%s:%d", file, line) + break + } + return name +} + +// hasPackage returns true if the file is in one of the ignored packages. +func hasPackage(file string, ignoredPackages []string) bool { + for _, ignoredPackage := range ignoredPackages { + if strings.Contains(file, ignoredPackage) { + return true + } + } + return false +} + +// trimPackagePrefix reduces dulpicate values off the front of a package name. +func trimPackagePrefix(file string) string { + if l := strings.LastIndex(file, "k8s.io/kubernetes/pkg/"); l >= 0 { + return file[l+len("k8s.io/kubernetes/"):] + } + if l := strings.LastIndex(file, "/src/"); l >= 0 { + return file[l+5:] + } + if l := strings.LastIndex(file, "/pkg/"); l >= 0 { + return file[l+1:] + } + return file +} + +var stackCreator = regexp.MustCompile(`(?m)^created by (.*)\n\s+(.*):(\d+) \+0x[[:xdigit:]]+$`) + +// extractStackCreator retrieves the goroutine file and line that launched this stack. Returns false +// if the creator cannot be located. +// TODO: Go does not expose this via runtime https://github.com/golang/go/issues/11440 +func extractStackCreator() (string, int, bool) { + stack := debug.Stack() + matches := stackCreator.FindStringSubmatch(string(stack)) + if matches == nil || len(matches) != 4 { + return "", 0, false + } + line, err := strconv.Atoi(matches[3]) + if err != nil { + return "", 0, false + } + return matches[2], line, true +} + +// Run starts a watch and handles watch events. Will restart the watch if it is closed. +// Run starts a goroutine and returns immediately. +func (r *Reflector) Run() { + glog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name) + go wait.Until(func() { + if err := r.ListAndWatch(wait.NeverStop); err != nil { + utilruntime.HandleError(err) + } + }, r.period, wait.NeverStop) +} + +// RunUntil starts a watch and handles watch events. Will restart the watch if it is closed. +// RunUntil starts a goroutine and returns immediately. It will exit when stopCh is closed. +func (r *Reflector) RunUntil(stopCh <-chan struct{}) { + glog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name) + go wait.Until(func() { + if err := r.ListAndWatch(stopCh); err != nil { + utilruntime.HandleError(err) + } + }, r.period, stopCh) +} + +var ( + // nothing will ever be sent down this channel + neverExitWatch <-chan time.Time = make(chan time.Time) + + // Used to indicate that watching stopped so that a resync could happen. + errorResyncRequested = errors.New("resync channel fired") + + // Used to indicate that watching stopped because of a signal from the stop + // channel passed in from a client of the reflector. + errorStopRequested = errors.New("Stop requested") +) + +// resyncChan returns a channel which will receive something when a resync is +// required, and a cleanup function. +func (r *Reflector) resyncChan() (<-chan time.Time, func() bool) { + if r.resyncPeriod == 0 { + r.nextResync = time.Time{} + return neverExitWatch, func() bool { return false } + } + // The cleanup function is required: imagine the scenario where watches + // always fail so we end up listing frequently. Then, if we don't + // manually stop the timer, we could end up with many timers active + // concurrently. + r.nextResync = r.now().Add(r.resyncPeriod) + t := time.NewTimer(r.resyncPeriod) + return t.C, t.Stop +} + +// ListAndWatch first lists all items and get the resource version at the moment of call, +// and then use the resource version to watch. +// It returns error if ListAndWatch didn't even try to initialize watch. +func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error { + glog.V(3).Infof("Listing and watching %v from %s", r.expectedType, r.name) + var resourceVersion string + resyncCh, cleanup := r.resyncChan() + defer cleanup() + + // Explicitly set "0" as resource version - it's fine for the List() + // to be served from cache and potentially be delayed relative to + // etcd contents. Reflector framework will catch up via Watch() eventually. + options := api.ListOptions{ResourceVersion: "0"} + list, err := r.listerWatcher.List(options) + if err != nil { + return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err) + } + listMetaInterface, err := meta.ListAccessor(list) + if err != nil { + return fmt.Errorf("%s: Unable to understand list result %#v: %v", r.name, list, err) + } + resourceVersion = listMetaInterface.GetResourceVersion() + items, err := meta.ExtractList(list) + if err != nil { + return fmt.Errorf("%s: Unable to understand list result %#v (%v)", r.name, list, err) + } + if err := r.syncWith(items, resourceVersion); err != nil { + return fmt.Errorf("%s: Unable to sync list result: %v", r.name, err) + } + r.setLastSyncResourceVersion(resourceVersion) + + resyncerrc := make(chan error, 1) + go func() { + for { + select { + case <-resyncCh: + case <-stopCh: + return + } + glog.V(4).Infof("%s: next resync planned for %#v, forcing now", r.name, r.nextResync) + if err := r.store.Resync(); err != nil { + resyncerrc <- err + return + } + cleanup() + resyncCh, cleanup = r.resyncChan() + } + }() + + for { + timemoutseconds := int64(minWatchTimeout.Seconds() * (rand.Float64() + 1.0)) + options = api.ListOptions{ + ResourceVersion: resourceVersion, + // We want to avoid situations of hanging watchers. Stop any wachers that do not + // receive any events within the timeout window. + TimeoutSeconds: &timemoutseconds, + } + + w, err := r.listerWatcher.Watch(options) + if err != nil { + switch err { + case io.EOF: + // watch closed normally + case io.ErrUnexpectedEOF: + glog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err) + default: + utilruntime.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err)) + } + // If this is "connection refused" error, it means that most likely apiserver is not responsive. + // It doesn't make sense to re-list all objects because most likely we will be able to restart + // watch where we ended. + // If that's the case wait and resend watch request. + if urlError, ok := err.(*url.Error); ok { + if opError, ok := urlError.Err.(*net.OpError); ok { + if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { + time.Sleep(time.Second) + continue + } + } + } + return nil + } + + if err := r.watchHandler(w, &resourceVersion, resyncerrc, stopCh); err != nil { + if err != errorStopRequested { + glog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err) + } + return nil + } + } +} + +// syncWith replaces the store's items with the given list. +func (r *Reflector) syncWith(items []runtime.Object, resourceVersion string) error { + found := make([]interface{}, 0, len(items)) + for _, item := range items { + found = append(found, item) + } + return r.store.Replace(found, resourceVersion) +} + +// watchHandler watches w and keeps *resourceVersion up to date. +func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, errc chan error, stopCh <-chan struct{}) error { + start := time.Now() + eventCount := 0 + + // Stopping the watcher should be idempotent and if we return from this function there's no way + // we're coming back in with the same watch interface. + defer w.Stop() + +loop: + for { + select { + case <-stopCh: + return errorStopRequested + case err := <-errc: + return err + case event, ok := <-w.ResultChan(): + if !ok { + break loop + } + if event.Type == watch.Error { + return apierrs.FromObject(event.Object) + } + if e, a := r.expectedType, reflect.TypeOf(event.Object); e != nil && e != a { + utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a)) + continue + } + meta, err := meta.Accessor(event.Object) + if err != nil { + utilruntime.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event)) + continue + } + newResourceVersion := meta.GetResourceVersion() + switch event.Type { + case watch.Added: + r.store.Add(event.Object) + case watch.Modified: + r.store.Update(event.Object) + case watch.Deleted: + // TODO: Will any consumers need access to the "last known + // state", which is passed in event.Object? If so, may need + // to change this. + r.store.Delete(event.Object) + default: + utilruntime.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event)) + } + *resourceVersion = newResourceVersion + r.setLastSyncResourceVersion(newResourceVersion) + eventCount++ + } + } + + watchDuration := time.Now().Sub(start) + if watchDuration < 1*time.Second && eventCount == 0 { + glog.V(4).Infof("%s: Unexpected watch close - watch lasted less than a second and no items received", r.name) + return errors.New("very short watch") + } + glog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount) + return nil +} + +// LastSyncResourceVersion is the resource version observed when last sync with the underlying store +// The value returned is not synchronized with access to the underlying store and is not thread-safe +func (r *Reflector) LastSyncResourceVersion() string { + r.lastSyncResourceVersionMutex.RLock() + defer r.lastSyncResourceVersionMutex.RUnlock() + return r.lastSyncResourceVersion +} + +func (r *Reflector) setLastSyncResourceVersion(v string) { + r.lastSyncResourceVersionMutex.Lock() + defer r.lastSyncResourceVersionMutex.Unlock() + r.lastSyncResourceVersion = v +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/store.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/store.go new file mode 100644 index 0000000..4cd2479 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/store.go @@ -0,0 +1,240 @@ +/* +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 cache + +import ( + "fmt" + "strings" + + "k8s.io/kubernetes/pkg/api/meta" +) + +// Store is a generic object storage interface. Reflector knows how to watch a server +// and update a store. A generic store is provided, which allows Reflector to be used +// as a local caching system, and an LRU store, which allows Reflector to work like a +// queue of items yet to be processed. +// +// Store makes no assumptions about stored object identity; it is the responsibility +// of a Store implementation to provide a mechanism to correctly key objects and to +// define the contract for obtaining objects by some arbitrary key type. +type Store interface { + Add(obj interface{}) error + Update(obj interface{}) error + Delete(obj interface{}) error + List() []interface{} + ListKeys() []string + Get(obj interface{}) (item interface{}, exists bool, err error) + GetByKey(key string) (item interface{}, exists bool, err error) + + // Replace will delete the contents of the store, using instead the + // given list. Store takes ownership of the list, you should not reference + // it after calling this function. + Replace([]interface{}, string) error + Resync() error +} + +// KeyFunc knows how to make a key from an object. Implementations should be deterministic. +type KeyFunc func(obj interface{}) (string, error) + +// KeyError will be returned any time a KeyFunc gives an error; it includes the object +// at fault. +type KeyError struct { + Obj interface{} + Err error +} + +// Error gives a human-readable description of the error. +func (k KeyError) Error() string { + return fmt.Sprintf("couldn't create key for object %+v: %v", k.Obj, k.Err) +} + +// ExplicitKey can be passed to MetaNamespaceKeyFunc if you have the key for +// the object but not the object itself. +type ExplicitKey string + +// MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make +// keys for API objects which implement meta.Interface. +// The key uses the format / unless is empty, then +// it's just . +// +// TODO: replace key-as-string with a key-as-struct so that this +// packing/unpacking won't be necessary. +func MetaNamespaceKeyFunc(obj interface{}) (string, error) { + if key, ok := obj.(ExplicitKey); ok { + return string(key), nil + } + meta, err := meta.Accessor(obj) + if err != nil { + return "", fmt.Errorf("object has no meta: %v", err) + } + if len(meta.GetNamespace()) > 0 { + return meta.GetNamespace() + "/" + meta.GetName(), nil + } + return meta.GetName(), nil +} + +// SplitMetaNamespaceKey returns the namespace and name that +// MetaNamespaceKeyFunc encoded into key. +// +// TODO: replace key-as-string with a key-as-struct so that this +// packing/unpacking won't be necessary. +func SplitMetaNamespaceKey(key string) (namespace, name string, err error) { + parts := strings.Split(key, "/") + switch len(parts) { + case 1: + // name only, no namespace + return "", parts[0], nil + case 2: + // namespace and name + return parts[0], parts[1], nil + } + + return "", "", fmt.Errorf("unexpected key format: %q", key) +} + +// cache responsibilities are limited to: +// 1. Computing keys for objects via keyFunc +// 2. Invoking methods of a ThreadSafeStorage interface +type cache struct { + // cacheStorage bears the burden of thread safety for the cache + cacheStorage ThreadSafeStore + // keyFunc is used to make the key for objects stored in and retrieved from items, and + // should be deterministic. + keyFunc KeyFunc +} + +var _ Store = &cache{} + +// Add inserts an item into the cache. +func (c *cache) Add(obj interface{}) error { + key, err := c.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + c.cacheStorage.Add(key, obj) + return nil +} + +// Update sets an item in the cache to its updated state. +func (c *cache) Update(obj interface{}) error { + key, err := c.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + c.cacheStorage.Update(key, obj) + return nil +} + +// Delete removes an item from the cache. +func (c *cache) Delete(obj interface{}) error { + key, err := c.keyFunc(obj) + if err != nil { + return KeyError{obj, err} + } + c.cacheStorage.Delete(key) + return nil +} + +// List returns a list of all the items. +// List is completely threadsafe as long as you treat all items as immutable. +func (c *cache) List() []interface{} { + return c.cacheStorage.List() +} + +// ListKeys returns a list of all the keys of the objects currently +// in the cache. +func (c *cache) ListKeys() []string { + return c.cacheStorage.ListKeys() +} + +// GetIndexers returns the indexers of cache +func (c *cache) GetIndexers() Indexers { + return c.cacheStorage.GetIndexers() +} + +// Index returns a list of items that match on the index function +// Index is thread-safe so long as you treat all items as immutable +func (c *cache) Index(indexName string, obj interface{}) ([]interface{}, error) { + return c.cacheStorage.Index(indexName, obj) +} + +// ListIndexFuncValues returns the list of generated values of an Index func +func (c *cache) ListIndexFuncValues(indexName string) []string { + return c.cacheStorage.ListIndexFuncValues(indexName) +} + +func (c *cache) ByIndex(indexName, indexKey string) ([]interface{}, error) { + return c.cacheStorage.ByIndex(indexName, indexKey) +} + +func (c *cache) AddIndexers(newIndexers Indexers) error { + return c.cacheStorage.AddIndexers(newIndexers) +} + +// Get returns the requested item, or sets exists=false. +// Get is completely threadsafe as long as you treat all items as immutable. +func (c *cache) Get(obj interface{}) (item interface{}, exists bool, err error) { + key, err := c.keyFunc(obj) + if err != nil { + return nil, false, KeyError{obj, err} + } + return c.GetByKey(key) +} + +// GetByKey returns the request item, or exists=false. +// GetByKey is completely threadsafe as long as you treat all items as immutable. +func (c *cache) GetByKey(key string) (item interface{}, exists bool, err error) { + item, exists = c.cacheStorage.Get(key) + return item, exists, nil +} + +// Replace will delete the contents of 'c', using instead the given list. +// 'c' takes ownership of the list, you should not reference the list again +// after calling this function. +func (c *cache) Replace(list []interface{}, resourceVersion string) error { + items := map[string]interface{}{} + for _, item := range list { + key, err := c.keyFunc(item) + if err != nil { + return KeyError{item, err} + } + items[key] = item + } + c.cacheStorage.Replace(items, resourceVersion) + return nil +} + +// Resync touches all items in the store to force processing +func (c *cache) Resync() error { + return c.cacheStorage.Resync() +} + +// NewStore returns a Store implemented simply with a map and a lock. +func NewStore(keyFunc KeyFunc) Store { + return &cache{ + cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}), + keyFunc: keyFunc, + } +} + +// NewIndexer returns an Indexer implemented simply with a map and a lock. +func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer { + return &cache{ + cacheStorage: NewThreadSafeStore(indexers, Indices{}), + keyFunc: keyFunc, + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/thread_safe_store.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/thread_safe_store.go new file mode 100644 index 0000000..9d88ce3 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/thread_safe_store.go @@ -0,0 +1,288 @@ +/* +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 cache + +import ( + "fmt" + "sync" + + "k8s.io/kubernetes/pkg/util/sets" +) + +// ThreadSafeStore is an interface that allows concurrent access to a storage backend. +// TL;DR caveats: you must not modify anything returned by Get or List as it will break +// the indexing feature in addition to not being thread safe. +// +// The guarantees of thread safety provided by List/Get are only valid if the caller +// treats returned items as read-only. For example, a pointer inserted in the store +// through `Add` will be returned as is by `Get`. Multiple clients might invoke `Get` +// on the same key and modify the pointer in a non-thread-safe way. Also note that +// modifying objects stored by the indexers (if any) will *not* automatically lead +// to a re-index. So it's not a good idea to directly modify the objects returned by +// Get/List, in general. +type ThreadSafeStore interface { + Add(key string, obj interface{}) + Update(key string, obj interface{}) + Delete(key string) + Get(key string) (item interface{}, exists bool) + List() []interface{} + ListKeys() []string + Replace(map[string]interface{}, string) + Index(indexName string, obj interface{}) ([]interface{}, error) + ListIndexFuncValues(name string) []string + ByIndex(indexName, indexKey string) ([]interface{}, error) + GetIndexers() Indexers + + // AddIndexers adds more indexers to this store. If you call this after you already have data + // in the store, the results are undefined. + AddIndexers(newIndexers Indexers) error + Resync() error +} + +// threadSafeMap implements ThreadSafeStore +type threadSafeMap struct { + lock sync.RWMutex + items map[string]interface{} + + // indexers maps a name to an IndexFunc + indexers Indexers + // indices maps a name to an Index + indices Indices +} + +func (c *threadSafeMap) Add(key string, obj interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + oldObject := c.items[key] + c.items[key] = obj + c.updateIndices(oldObject, obj, key) +} + +func (c *threadSafeMap) Update(key string, obj interface{}) { + c.lock.Lock() + defer c.lock.Unlock() + oldObject := c.items[key] + c.items[key] = obj + c.updateIndices(oldObject, obj, key) +} + +func (c *threadSafeMap) Delete(key string) { + c.lock.Lock() + defer c.lock.Unlock() + if obj, exists := c.items[key]; exists { + c.deleteFromIndices(obj, key) + delete(c.items, key) + } +} + +func (c *threadSafeMap) Get(key string) (item interface{}, exists bool) { + c.lock.RLock() + defer c.lock.RUnlock() + item, exists = c.items[key] + return item, exists +} + +func (c *threadSafeMap) List() []interface{} { + c.lock.RLock() + defer c.lock.RUnlock() + list := make([]interface{}, 0, len(c.items)) + for _, item := range c.items { + list = append(list, item) + } + return list +} + +// ListKeys returns a list of all the keys of the objects currently +// in the threadSafeMap. +func (c *threadSafeMap) ListKeys() []string { + c.lock.RLock() + defer c.lock.RUnlock() + list := make([]string, 0, len(c.items)) + for key := range c.items { + list = append(list, key) + } + return list +} + +func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) { + c.lock.Lock() + defer c.lock.Unlock() + c.items = items + + // rebuild any index + c.indices = Indices{} + for key, item := range c.items { + c.updateIndices(nil, item, key) + } +} + +// Index returns a list of items that match on the index function +// Index is thread-safe so long as you treat all items as immutable +func (c *threadSafeMap) Index(indexName string, obj interface{}) ([]interface{}, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + indexFunc := c.indexers[indexName] + if indexFunc == nil { + return nil, fmt.Errorf("Index with name %s does not exist", indexName) + } + + indexKeys, err := indexFunc(obj) + if err != nil { + return nil, err + } + index := c.indices[indexName] + + // need to de-dupe the return list. Since multiple keys are allowed, this can happen. + returnKeySet := sets.String{} + for _, indexKey := range indexKeys { + set := index[indexKey] + for _, key := range set.List() { + returnKeySet.Insert(key) + } + } + + list := make([]interface{}, 0, returnKeySet.Len()) + for absoluteKey := range returnKeySet { + list = append(list, c.items[absoluteKey]) + } + return list, nil +} + +// ByIndex returns a list of items that match an exact value on the index function +func (c *threadSafeMap) ByIndex(indexName, indexKey string) ([]interface{}, error) { + c.lock.RLock() + defer c.lock.RUnlock() + + indexFunc := c.indexers[indexName] + if indexFunc == nil { + return nil, fmt.Errorf("Index with name %s does not exist", indexName) + } + + index := c.indices[indexName] + + set := index[indexKey] + list := make([]interface{}, 0, set.Len()) + for _, key := range set.List() { + list = append(list, c.items[key]) + } + + return list, nil +} + +func (c *threadSafeMap) ListIndexFuncValues(indexName string) []string { + c.lock.RLock() + defer c.lock.RUnlock() + + index := c.indices[indexName] + names := make([]string, 0, len(index)) + for key := range index { + names = append(names, key) + } + return names +} + +func (c *threadSafeMap) GetIndexers() Indexers { + return c.indexers +} + +func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error { + c.lock.Lock() + defer c.lock.Unlock() + + if len(c.items) > 0 { + return fmt.Errorf("cannot add indexers to running index") + } + + oldKeys := sets.StringKeySet(c.indexers) + newKeys := sets.StringKeySet(newIndexers) + + if oldKeys.HasAny(newKeys.List()...) { + return fmt.Errorf("indexer conflict: %v", oldKeys.Intersection(newKeys)) + } + + for k, v := range newIndexers { + c.indexers[k] = v + } + return nil +} + +// updateIndices modifies the objects location in the managed indexes, if this is an update, you must provide an oldObj +// updateIndices must be called from a function that already has a lock on the cache +func (c *threadSafeMap) updateIndices(oldObj interface{}, newObj interface{}, key string) error { + // if we got an old object, we need to remove it before we add it again + if oldObj != nil { + c.deleteFromIndices(oldObj, key) + } + for name, indexFunc := range c.indexers { + indexValues, err := indexFunc(newObj) + if err != nil { + return err + } + index := c.indices[name] + if index == nil { + index = Index{} + c.indices[name] = index + } + + for _, indexValue := range indexValues { + set := index[indexValue] + if set == nil { + set = sets.String{} + index[indexValue] = set + } + set.Insert(key) + } + } + return nil +} + +// deleteFromIndices removes the object from each of the managed indexes +// it is intended to be called from a function that already has a lock on the cache +func (c *threadSafeMap) deleteFromIndices(obj interface{}, key string) error { + for name, indexFunc := range c.indexers { + indexValues, err := indexFunc(obj) + if err != nil { + return err + } + + index := c.indices[name] + if index == nil { + continue + } + for _, indexValue := range indexValues { + set := index[indexValue] + if set != nil { + set.Delete(key) + } + } + } + return nil +} + +func (c *threadSafeMap) Resync() error { + // Nothing to do + return nil +} + +func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore { + return &threadSafeMap{ + items: map[string]interface{}{}, + indexers: indexers, + indices: indices, + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/undelta_store.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/undelta_store.go new file mode 100644 index 0000000..117df46 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/cache/undelta_store.go @@ -0,0 +1,83 @@ +/* +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 cache + +// UndeltaStore listens to incremental updates and sends complete state on every change. +// It implements the Store interface so that it can receive a stream of mirrored objects +// from Reflector. Whenever it receives any complete (Store.Replace) or incremental change +// (Store.Add, Store.Update, Store.Delete), it sends the complete state by calling PushFunc. +// It is thread-safe. It guarantees that every change (Add, Update, Replace, Delete) results +// in one call to PushFunc, but sometimes PushFunc may be called twice with the same values. +// PushFunc should be thread safe. +type UndeltaStore struct { + Store + PushFunc func([]interface{}) +} + +// Assert that it implements the Store interface. +var _ Store = &UndeltaStore{} + +// Note about thread safety. The Store implementation (cache.cache) uses a lock for all methods. +// In the functions below, the lock gets released and reacquired betweend the {Add,Delete,etc} +// and the List. So, the following can happen, resulting in two identical calls to PushFunc. +// time thread 1 thread 2 +// 0 UndeltaStore.Add(a) +// 1 UndeltaStore.Add(b) +// 2 Store.Add(a) +// 3 Store.Add(b) +// 4 Store.List() -> [a,b] +// 5 Store.List() -> [a,b] + +func (u *UndeltaStore) Add(obj interface{}) error { + if err := u.Store.Add(obj); err != nil { + return err + } + u.PushFunc(u.Store.List()) + return nil +} + +func (u *UndeltaStore) Update(obj interface{}) error { + if err := u.Store.Update(obj); err != nil { + return err + } + u.PushFunc(u.Store.List()) + return nil +} + +func (u *UndeltaStore) Delete(obj interface{}) error { + if err := u.Store.Delete(obj); err != nil { + return err + } + u.PushFunc(u.Store.List()) + return nil +} + +func (u *UndeltaStore) Replace(list []interface{}, resourceVersion string) error { + if err := u.Store.Replace(list, resourceVersion); err != nil { + return err + } + u.PushFunc(u.Store.List()) + return nil +} + +// NewUndeltaStore returns an UndeltaStore implemented with a Store. +func NewUndeltaStore(pushFunc func([]interface{}), keyFunc KeyFunc) *UndeltaStore { + return &UndeltaStore{ + Store: NewStore(keyFunc), + PushFunc: pushFunc, + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/metrics/metrics.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/metrics/metrics.go new file mode 100644 index 0000000..53029b5 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/metrics/metrics.go @@ -0,0 +1,67 @@ +/* +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 metrics provides utilities for registering client metrics to Prometheus. +package metrics + +import ( + "sync" + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +const restClientSubsystem = "rest_client" + +var ( + // RequestLatency is a Prometheus Summary metric type partitioned by + // "verb" and "url" labels. It is used for the rest client latency metrics. + RequestLatency = prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Subsystem: restClientSubsystem, + Name: "request_latency_microseconds", + Help: "Request latency in microseconds. Broken down by verb and URL", + MaxAge: time.Hour, + }, + []string{"verb", "url"}, + ) + + RequestResult = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: restClientSubsystem, + Name: "request_status_codes", + Help: "Number of http requests, partitioned by metadata", + }, + []string{"code", "method", "host"}, + ) +) + +var registerMetrics sync.Once + +// Register registers all metrics to Prometheus with +// respect to the RequestLatency. +func Register() { + // Register the metrics. + registerMetrics.Do(func() { + prometheus.MustRegister(RequestLatency) + prometheus.MustRegister(RequestResult) + }) +} + +// Calculates the time since the specified start in microseconds. +func SinceInMicroseconds(start time.Time) float64 { + return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds()) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/client.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/client.go new file mode 100644 index 0000000..24ad191 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/client.go @@ -0,0 +1,224 @@ +/* +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 restclient + +import ( + "fmt" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "time" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/flowcontrol" +) + +const ( + // Environment variables: Note that the duration should be long enough that the backoff + // persists for some reasonable time (i.e. 120 seconds). The typical base might be "1". + envBackoffBase = "KUBE_CLIENT_BACKOFF_BASE" + envBackoffDuration = "KUBE_CLIENT_BACKOFF_DURATION" +) + +// RESTClient imposes common Kubernetes API conventions on a set of resource paths. +// The baseURL is expected to point to an HTTP or HTTPS path that is the parent +// of one or more resources. The server should return a decodable API resource +// object, or an api.Status object which contains information about the reason for +// any failure. +// +// Most consumers should use client.New() to get a Kubernetes API client. +type RESTClient struct { + // base is the root URL for all invocations of the client + base *url.URL + // versionedAPIPath is a path segment connecting the base URL to the resource root + versionedAPIPath string + + // contentConfig is the information used to communicate with the server. + contentConfig ContentConfig + + // serializers contain all serializers for undelying content type. + serializers Serializers + + // creates BackoffManager that is passed to requests. + createBackoffMgr func() BackoffManager + + // TODO extract this into a wrapper interface via the RESTClient interface in kubectl. + Throttle flowcontrol.RateLimiter + + // Set specific behavior of the client. If not set http.DefaultClient will be used. + Client *http.Client +} + +type Serializers struct { + Encoder runtime.Encoder + Decoder runtime.Decoder + StreamingSerializer runtime.Serializer + Framer runtime.Framer + RenegotiatedDecoder func(contentType string, params map[string]string) (runtime.Decoder, error) +} + +// NewRESTClient creates a new RESTClient. This client performs generic REST functions +// such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and +// decoding of responses from the server. +func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ContentConfig, maxQPS float32, maxBurst int, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) { + base := *baseURL + if !strings.HasSuffix(base.Path, "/") { + base.Path += "/" + } + base.RawQuery = "" + base.Fragment = "" + + if config.GroupVersion == nil { + config.GroupVersion = &unversioned.GroupVersion{} + } + if len(config.ContentType) == 0 { + config.ContentType = "application/json" + } + serializers, err := createSerializers(config) + if err != nil { + return nil, err + } + + var throttle flowcontrol.RateLimiter + if maxQPS > 0 && rateLimiter == nil { + throttle = flowcontrol.NewTokenBucketRateLimiter(maxQPS, maxBurst) + } else if rateLimiter != nil { + throttle = rateLimiter + } + return &RESTClient{ + base: &base, + versionedAPIPath: versionedAPIPath, + contentConfig: config, + serializers: *serializers, + createBackoffMgr: readExpBackoffConfig, + Throttle: throttle, + Client: client, + }, nil +} + +// GetRateLimiter returns rate limier for a given client, or nil if it's called on a nil client +func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { + if c == nil { + return nil + } + return c.Throttle +} + +// readExpBackoffConfig handles the internal logic of determining what the +// backoff policy is. By default if no information is available, NoBackoff. +// TODO Generalize this see #17727 . +func readExpBackoffConfig() BackoffManager { + backoffBase := os.Getenv(envBackoffBase) + backoffDuration := os.Getenv(envBackoffDuration) + + backoffBaseInt, errBase := strconv.ParseInt(backoffBase, 10, 64) + backoffDurationInt, errDuration := strconv.ParseInt(backoffDuration, 10, 64) + if errBase != nil || errDuration != nil { + return &NoBackoff{} + } + return &URLBackoff{ + Backoff: flowcontrol.NewBackOff( + time.Duration(backoffBaseInt)*time.Second, + time.Duration(backoffDurationInt)*time.Second)} +} + +// createSerializers creates all necessary serializers for given contentType. +func createSerializers(config ContentConfig) (*Serializers, error) { + negotiated := config.NegotiatedSerializer + contentType := config.ContentType + info, ok := negotiated.SerializerForMediaType(contentType, nil) + if !ok { + return nil, fmt.Errorf("serializer for %s not registered", contentType) + } + streamInfo, ok := negotiated.StreamingSerializerForMediaType(contentType, nil) + if !ok { + return nil, fmt.Errorf("streaming serializer for %s not registered", contentType) + } + internalGV := unversioned.GroupVersion{ + Group: config.GroupVersion.Group, + Version: runtime.APIVersionInternal, + } + return &Serializers{ + Encoder: negotiated.EncoderForVersion(info.Serializer, *config.GroupVersion), + Decoder: negotiated.DecoderToVersion(info.Serializer, internalGV), + StreamingSerializer: streamInfo.Serializer, + Framer: streamInfo.Framer, + RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) { + renegotiated, ok := negotiated.SerializerForMediaType(contentType, params) + if !ok { + return nil, fmt.Errorf("serializer for %s not registered", contentType) + } + return negotiated.DecoderToVersion(renegotiated.Serializer, internalGV), nil + }, + }, nil +} + +// Verb begins a request with a verb (GET, POST, PUT, DELETE). +// +// Example usage of RESTClient's request building interface: +// c, err := NewRESTClient(...) +// if err != nil { ... } +// resp, err := c.Verb("GET"). +// Path("pods"). +// SelectorParam("labels", "area=staging"). +// Timeout(10*time.Second). +// Do() +// if err != nil { ... } +// list, ok := resp.(*api.PodList) +// +func (c *RESTClient) Verb(verb string) *Request { + backoff := c.createBackoffMgr() + + if c.Client == nil { + return NewRequest(nil, verb, c.base, c.versionedAPIPath, c.contentConfig, c.serializers, backoff, c.Throttle) + } + return NewRequest(c.Client, verb, c.base, c.versionedAPIPath, c.contentConfig, c.serializers, backoff, c.Throttle) +} + +// Post begins a POST request. Short for c.Verb("POST"). +func (c *RESTClient) Post() *Request { + return c.Verb("POST") +} + +// Put begins a PUT request. Short for c.Verb("PUT"). +func (c *RESTClient) Put() *Request { + return c.Verb("PUT") +} + +// Patch begins a PATCH request. Short for c.Verb("Patch"). +func (c *RESTClient) Patch(pt api.PatchType) *Request { + return c.Verb("PATCH").SetHeader("Content-Type", string(pt)) +} + +// Get begins a GET request. Short for c.Verb("GET"). +func (c *RESTClient) Get() *Request { + return c.Verb("GET") +} + +// Delete begins a DELETE request. Short for c.Verb("DELETE"). +func (c *RESTClient) Delete() *Request { + return c.Verb("DELETE") +} + +// APIVersion returns the APIVersion this RESTClient is expected to use. +func (c *RESTClient) APIVersion() unversioned.GroupVersion { + return *c.contentConfig.GroupVersion +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/config.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/config.go new file mode 100644 index 0000000..fec5f49 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/config.go @@ -0,0 +1,328 @@ +/* +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 restclient + +import ( + "fmt" + "io/ioutil" + "net" + "net/http" + "os" + "path" + gruntime "runtime" + "strings" + + "github.com/golang/glog" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/crypto" + "k8s.io/kubernetes/pkg/util/flowcontrol" + "k8s.io/kubernetes/pkg/version" +) + +const ( + DefaultQPS float32 = 5.0 + DefaultBurst int = 10 +) + +// Config holds the common attributes that can be passed to a Kubernetes client on +// initialization. +type Config struct { + // Host must be a host string, a host:port pair, or a URL to the base of the apiserver. + // If a URL is given then the (optional) Path of that URL represents a prefix that must + // be appended to all request URIs used to access the apiserver. This allows a frontend + // proxy to easily relocate all of the apiserver endpoints. + Host string + // APIPath is a sub-path that points to an API root. + APIPath string + // Prefix is the sub path of the server. If not specified, the client will set + // a default value. Use "/" to indicate the server root should be used + Prefix string + + // ContentConfig contains settings that affect how objects are transformed when + // sent to the server. + ContentConfig + + // Server requires Basic authentication + Username string + Password string + + // Server requires Bearer authentication. This client will not attempt to use + // refresh tokens for an OAuth2 flow. + // TODO: demonstrate an OAuth2 compatible client. + BearerToken string + + // Impersonate is the username that this RESTClient will impersonate + Impersonate string + + // Server requires plugin-specified authentication. + AuthProvider *clientcmdapi.AuthProviderConfig + + // Callback to persist config for AuthProvider. + AuthConfigPersister AuthProviderConfigPersister + + // TLSClientConfig contains settings to enable transport layer security + TLSClientConfig + + // Server should be accessed without verifying the TLS + // certificate. For testing only. + Insecure bool + + // UserAgent is an optional field that specifies the caller of this request. + UserAgent string + + // Transport may be used for custom HTTP behavior. This attribute may not + // be specified with the TLS client certificate options. Use WrapTransport + // for most client level operations. + Transport http.RoundTripper + // WrapTransport will be invoked for custom HTTP behavior after the underlying + // transport is initialized (either the transport created from TLSClientConfig, + // Transport, or http.DefaultTransport). The config may layer other RoundTrippers + // on top of the returned RoundTripper. + WrapTransport func(rt http.RoundTripper) http.RoundTripper + + // QPS indicates the maximum QPS to the master from this client. + // If it's zero, the created RESTClient will use DefaultQPS: 5 + QPS float32 + + // Maximum burst for throttle. + // If it's zero, the created RESTClient will use DefaultBurst: 10. + Burst int + + // Rate limiter for limiting connections to the master from this client. If present overwrites QPS/Burst + RateLimiter flowcontrol.RateLimiter +} + +// TLSClientConfig contains settings to enable transport layer security +type TLSClientConfig struct { + // Server requires TLS client certificate authentication + CertFile string + // Server requires TLS client certificate authentication + KeyFile string + // Trusted root certificates for server + CAFile string + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + CertData []byte + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + KeyData []byte + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + CAData []byte +} + +type ContentConfig struct { + // ContentType specifies the wire format used to communicate with the server. + // This value will be set as the Accept header on requests made to the server, and + // as the default content type on any object sent to the server. If not set, + // "application/json" is used. + ContentType string + // GroupVersion is the API version to talk to. Must be provided when initializing + // a RESTClient directly. When initializing a Client, will be set with the default + // code version. + GroupVersion *unversioned.GroupVersion + // NegotiatedSerializer is used for obtaining encoders and decoders for multiple + // supported media types. + NegotiatedSerializer runtime.NegotiatedSerializer +} + +// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config +// object. Note that a RESTClient may require fields that are optional when initializing a Client. +// A RESTClient created by this method is generic - it expects to operate on an API that follows +// the Kubernetes conventions, but may not be the Kubernetes API. +func RESTClientFor(config *Config) (*RESTClient, error) { + if config.GroupVersion == nil { + return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient") + } + if config.NegotiatedSerializer == nil { + return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient") + } + qps := config.QPS + if config.QPS == 0.0 { + qps = DefaultQPS + } + burst := config.Burst + if config.Burst == 0 { + burst = DefaultBurst + } + + baseURL, versionedAPIPath, err := defaultServerUrlFor(config) + if err != nil { + return nil, err + } + + transport, err := TransportFor(config) + if err != nil { + return nil, err + } + + var httpClient *http.Client + if transport != http.DefaultTransport { + httpClient = &http.Client{Transport: transport} + } + + return NewRESTClient(baseURL, versionedAPIPath, config.ContentConfig, qps, burst, config.RateLimiter, httpClient) +} + +// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows +// the config.Version to be empty. +func UnversionedRESTClientFor(config *Config) (*RESTClient, error) { + if config.NegotiatedSerializer == nil { + return nil, fmt.Errorf("NeogitatedSerializer is required when initializing a RESTClient") + } + + baseURL, versionedAPIPath, err := defaultServerUrlFor(config) + if err != nil { + return nil, err + } + + transport, err := TransportFor(config) + if err != nil { + return nil, err + } + + var httpClient *http.Client + if transport != http.DefaultTransport { + httpClient = &http.Client{Transport: transport} + } + + versionConfig := config.ContentConfig + if versionConfig.GroupVersion == nil { + v := unversioned.SchemeGroupVersion + versionConfig.GroupVersion = &v + } + + return NewRESTClient(baseURL, versionedAPIPath, versionConfig, config.QPS, config.Burst, config.RateLimiter, httpClient) +} + +// SetKubernetesDefaults sets default values on the provided client config for accessing the +// Kubernetes API or returns an error if any of the defaults are impossible or invalid. +func SetKubernetesDefaults(config *Config) error { + if len(config.UserAgent) == 0 { + config.UserAgent = DefaultKubernetesUserAgent() + } + return nil +} + +// DefaultKubernetesUserAgent returns the default user agent that clients can use. +func DefaultKubernetesUserAgent() string { + commit := version.Get().GitCommit + if len(commit) > 7 { + commit = commit[:7] + } + if len(commit) == 0 { + commit = "unknown" + } + version := version.Get().GitVersion + seg := strings.SplitN(version, "-", 2) + version = seg[0] + return fmt.Sprintf("%s/%s (%s/%s) kubernetes/%s", path.Base(os.Args[0]), version, gruntime.GOOS, gruntime.GOARCH, commit) +} + +// InClusterConfig returns a config object which uses the service account +// kubernetes gives to pods. It's intended for clients that expect to be +// running inside a pod running on kuberenetes. It will return an error if +// called from a process not running in a kubernetes environment. +func InClusterConfig() (*Config, error) { + host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT") + if len(host) == 0 || len(port) == 0 { + return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined") + } + + token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey) + if err != nil { + return nil, err + } + tlsClientConfig := TLSClientConfig{} + rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey + if _, err := crypto.CertPoolFromFile(rootCAFile); err != nil { + glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err) + } else { + tlsClientConfig.CAFile = rootCAFile + } + + return &Config{ + // TODO: switch to using cluster DNS. + Host: "https://" + net.JoinHostPort(host, port), + BearerToken: string(token), + TLSClientConfig: tlsClientConfig, + }, nil +} + +// IsConfigTransportTLS returns true if and only if the provided +// config will result in a protected connection to the server when it +// is passed to restclient.RESTClientFor(). Use to determine when to +// send credentials over the wire. +// +// Note: the Insecure flag is ignored when testing for this value, so MITM attacks are +// still possible. +func IsConfigTransportTLS(config Config) bool { + baseURL, _, err := defaultServerUrlFor(&config) + if err != nil { + return false + } + return baseURL.Scheme == "https" +} + +// LoadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData, +// KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are +// either populated or were empty to start. +func LoadTLSFiles(c *Config) error { + var err error + c.CAData, err = dataFromSliceOrFile(c.CAData, c.CAFile) + if err != nil { + return err + } + + c.CertData, err = dataFromSliceOrFile(c.CertData, c.CertFile) + if err != nil { + return err + } + + c.KeyData, err = dataFromSliceOrFile(c.KeyData, c.KeyFile) + if err != nil { + return err + } + return nil +} + +// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file, +// or an error if an error occurred reading the file +func dataFromSliceOrFile(data []byte, file string) ([]byte, error) { + if len(data) > 0 { + return data, nil + } + if len(file) > 0 { + fileData, err := ioutil.ReadFile(file) + if err != nil { + return []byte{}, err + } + return fileData, nil + } + return nil, nil +} + +func AddUserAgent(config *Config, userAgent string) *Config { + fullUserAgent := DefaultKubernetesUserAgent() + "/" + userAgent + config.UserAgent = fullUserAgent + return config +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/plugin.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/plugin.go new file mode 100644 index 0000000..06ac3cc --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/plugin.go @@ -0,0 +1,73 @@ +/* +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 restclient + +import ( + "fmt" + "net/http" + "sync" + + "github.com/golang/glog" + + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +type AuthProvider interface { + // WrapTransport allows the plugin to create a modified RoundTripper that + // attaches authorization headers (or other info) to requests. + WrapTransport(http.RoundTripper) http.RoundTripper + // Login allows the plugin to initialize its configuration. It must not + // require direct user interaction. + Login() error +} + +// Factory generates an AuthProvider plugin. +// clusterAddress is the address of the current cluster. +// config is the initial configuration for this plugin. +// persister allows the plugin to save updated configuration. +type Factory func(clusterAddress string, config map[string]string, persister AuthProviderConfigPersister) (AuthProvider, error) + +// AuthProviderConfigPersister allows a plugin to persist configuration info +// for just itself. +type AuthProviderConfigPersister interface { + Persist(map[string]string) error +} + +// All registered auth provider plugins. +var pluginsLock sync.Mutex +var plugins = make(map[string]Factory) + +func RegisterAuthProviderPlugin(name string, plugin Factory) error { + pluginsLock.Lock() + defer pluginsLock.Unlock() + if _, found := plugins[name]; found { + return fmt.Errorf("Auth Provider Plugin %q was registered twice", name) + } + glog.V(4).Infof("Registered Auth Provider Plugin %q", name) + plugins[name] = plugin + return nil +} + +func GetAuthProvider(clusterAddress string, apc *clientcmdapi.AuthProviderConfig, persister AuthProviderConfigPersister) (AuthProvider, error) { + pluginsLock.Lock() + defer pluginsLock.Unlock() + p, ok := plugins[apc.Name] + if !ok { + return nil, fmt.Errorf("No Auth Provider found for name %q", apc.Name) + } + return p(clusterAddress, apc.Config, persister) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/request.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/request.go new file mode 100644 index 0000000..51fac6b --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/request.go @@ -0,0 +1,1086 @@ +/* +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 restclient + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "mime" + "net/http" + "net/url" + "path" + "reflect" + "strconv" + "strings" + "time" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/api/validation" + "k8s.io/kubernetes/pkg/client/metrics" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/runtime/serializer/streaming" + "k8s.io/kubernetes/pkg/util/flowcontrol" + "k8s.io/kubernetes/pkg/util/net" + "k8s.io/kubernetes/pkg/util/sets" + "k8s.io/kubernetes/pkg/watch" + "k8s.io/kubernetes/pkg/watch/versioned" +) + +var ( + // specialParams lists parameters that are handled specially and which users of Request + // are therefore not allowed to set manually. + specialParams = sets.NewString("timeout") + + // longThrottleLatency defines threshold for logging requests. All requests being + // throttle for more than longThrottleLatency will be logged. + longThrottleLatency = 50 * time.Millisecond +) + +func init() { + metrics.Register() +} + +// HTTPClient is an interface for testing a request object. +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// ResponseWrapper is an interface for getting a response. +// The response may be either accessed as a raw data (the whole output is put into memory) or as a stream. +type ResponseWrapper interface { + DoRaw() ([]byte, error) + Stream() (io.ReadCloser, error) +} + +// RequestConstructionError is returned when there's an error assembling a request. +type RequestConstructionError struct { + Err error +} + +// Error returns a textual description of 'r'. +func (r *RequestConstructionError) Error() string { + return fmt.Sprintf("request construction error: '%v'", r.Err) +} + +// Request allows for building up a request to a server in a chained fashion. +// Any errors are stored until the end of your call, so you only have to +// check once. +type Request struct { + // required + client HTTPClient + verb string + + baseURL *url.URL + content ContentConfig + serializers Serializers + + // generic components accessible via method setters + pathPrefix string + subpath string + params url.Values + headers http.Header + + // structural elements of the request that are part of the Kubernetes API conventions + namespace string + namespaceSet bool + resource string + resourceName string + subresource string + selector labels.Selector + timeout time.Duration + + // output + err error + body io.Reader + + // The constructed request and the response + req *http.Request + resp *http.Response + + backoffMgr BackoffManager + throttle flowcontrol.RateLimiter +} + +// NewRequest creates a new request helper object for accessing runtime.Objects on a server. +func NewRequest(client HTTPClient, verb string, baseURL *url.URL, versionedAPIPath string, content ContentConfig, serializers Serializers, backoff BackoffManager, throttle flowcontrol.RateLimiter) *Request { + if backoff == nil { + glog.V(2).Infof("Not implementing request backoff strategy.") + backoff = &NoBackoff{} + } + + pathPrefix := "/" + if baseURL != nil { + pathPrefix = path.Join(pathPrefix, baseURL.Path) + } + r := &Request{ + client: client, + verb: verb, + baseURL: baseURL, + pathPrefix: path.Join(pathPrefix, versionedAPIPath), + content: content, + serializers: serializers, + backoffMgr: backoff, + throttle: throttle, + } + if len(content.ContentType) > 0 { + r.SetHeader("Accept", content.ContentType+", */*") + } + return r +} + +// Prefix adds segments to the relative beginning to the request path. These +// items will be placed before the optional Namespace, Resource, or Name sections. +// Setting AbsPath will clear any previously set Prefix segments +func (r *Request) Prefix(segments ...string) *Request { + if r.err != nil { + return r + } + r.pathPrefix = path.Join(r.pathPrefix, path.Join(segments...)) + return r +} + +// Suffix appends segments to the end of the path. These items will be placed after the prefix and optional +// Namespace, Resource, or Name sections. +func (r *Request) Suffix(segments ...string) *Request { + if r.err != nil { + return r + } + r.subpath = path.Join(r.subpath, path.Join(segments...)) + return r +} + +// Resource sets the resource to access (/[ns//]) +func (r *Request) Resource(resource string) *Request { + if r.err != nil { + return r + } + if len(r.resource) != 0 { + r.err = fmt.Errorf("resource already set to %q, cannot change to %q", r.resource, resource) + return r + } + if msgs := validation.IsValidPathSegmentName(resource); len(msgs) != 0 { + r.err = fmt.Errorf("invalid resource %q: %v", resource, msgs) + return r + } + r.resource = resource + return r +} + +// SubResource sets a sub-resource path which can be multiple segments segment after the resource +// name but before the suffix. +func (r *Request) SubResource(subresources ...string) *Request { + if r.err != nil { + return r + } + subresource := path.Join(subresources...) + if len(r.subresource) != 0 { + r.err = fmt.Errorf("subresource already set to %q, cannot change to %q", r.resource, subresource) + return r + } + for _, s := range subresources { + if msgs := validation.IsValidPathSegmentName(s); len(msgs) != 0 { + r.err = fmt.Errorf("invalid subresource %q: %v", s, msgs) + return r + } + } + r.subresource = subresource + return r +} + +// Name sets the name of a resource to access (/[ns//]) +func (r *Request) Name(resourceName string) *Request { + if r.err != nil { + return r + } + if len(resourceName) == 0 { + r.err = fmt.Errorf("resource name may not be empty") + return r + } + if len(r.resourceName) != 0 { + r.err = fmt.Errorf("resource name already set to %q, cannot change to %q", r.resourceName, resourceName) + return r + } + if msgs := validation.IsValidPathSegmentName(resourceName); len(msgs) != 0 { + r.err = fmt.Errorf("invalid resource name %q: %v", resourceName, msgs) + return r + } + r.resourceName = resourceName + return r +} + +// Namespace applies the namespace scope to a request (/[ns//]) +func (r *Request) Namespace(namespace string) *Request { + if r.err != nil { + return r + } + if r.namespaceSet { + r.err = fmt.Errorf("namespace already set to %q, cannot change to %q", r.namespace, namespace) + return r + } + if msgs := validation.IsValidPathSegmentName(namespace); len(msgs) != 0 { + r.err = fmt.Errorf("invalid namespace %q: %v", namespace, msgs) + return r + } + r.namespaceSet = true + r.namespace = namespace + return r +} + +// NamespaceIfScoped is a convenience function to set a namespace if scoped is true +func (r *Request) NamespaceIfScoped(namespace string, scoped bool) *Request { + if scoped { + return r.Namespace(namespace) + } + return r +} + +// AbsPath overwrites an existing path with the segments provided. Trailing slashes are preserved +// when a single segment is passed. +func (r *Request) AbsPath(segments ...string) *Request { + if r.err != nil { + return r + } + r.pathPrefix = path.Join(r.baseURL.Path, path.Join(segments...)) + if len(segments) == 1 && (len(r.baseURL.Path) > 1 || len(segments[0]) > 1) && strings.HasSuffix(segments[0], "/") { + // preserve any trailing slashes for legacy behavior + r.pathPrefix += "/" + } + return r +} + +// RequestURI overwrites existing path and parameters with the value of the provided server relative +// URI. Some parameters (those in specialParameters) cannot be overwritten. +func (r *Request) RequestURI(uri string) *Request { + if r.err != nil { + return r + } + locator, err := url.Parse(uri) + if err != nil { + r.err = err + return r + } + r.pathPrefix = locator.Path + if len(locator.Query()) > 0 { + if r.params == nil { + r.params = make(url.Values) + } + for k, v := range locator.Query() { + r.params[k] = v + } + } + return r +} + +const ( + // A constant that clients can use to refer in a field selector to the object name field. + // Will be automatically emitted as the correct name for the API version. + nodeUnschedulable = "spec.unschedulable" + objectNameField = "metadata.name" + podHost = "spec.nodeName" + podStatus = "status.phase" + secretType = "type" + + eventReason = "reason" + eventSource = "source" + eventType = "type" + eventInvolvedKind = "involvedObject.kind" + eventInvolvedNamespace = "involvedObject.namespace" + eventInvolvedName = "involvedObject.name" + eventInvolvedUID = "involvedObject.uid" + eventInvolvedAPIVersion = "involvedObject.apiVersion" + eventInvolvedResourceVersion = "involvedObject.resourceVersion" + eventInvolvedFieldPath = "involvedObject.fieldPath" +) + +type clientFieldNameToAPIVersionFieldName map[string]string + +func (c clientFieldNameToAPIVersionFieldName) filterField(field, value string) (newField, newValue string, err error) { + newFieldName, ok := c[field] + if !ok { + return "", "", fmt.Errorf("%v - %v - no field mapping defined", field, value) + } + return newFieldName, value, nil +} + +type resourceTypeToFieldMapping map[string]clientFieldNameToAPIVersionFieldName + +func (r resourceTypeToFieldMapping) filterField(resourceType, field, value string) (newField, newValue string, err error) { + fMapping, ok := r[resourceType] + if !ok { + return "", "", fmt.Errorf("%v - %v - %v - no field mapping defined", resourceType, field, value) + } + return fMapping.filterField(field, value) +} + +type versionToResourceToFieldMapping map[unversioned.GroupVersion]resourceTypeToFieldMapping + +func (v versionToResourceToFieldMapping) filterField(groupVersion *unversioned.GroupVersion, resourceType, field, value string) (newField, newValue string, err error) { + rMapping, ok := v[*groupVersion] + if !ok { + glog.Warningf("Field selector: %v - %v - %v - %v: need to check if this is versioned correctly.", groupVersion, resourceType, field, value) + return field, value, nil + } + newField, newValue, err = rMapping.filterField(resourceType, field, value) + if err != nil { + // This is only a warning until we find and fix all of the client's usages. + glog.Warningf("Field selector: %v - %v - %v - %v: need to check if this is versioned correctly.", groupVersion, resourceType, field, value) + return field, value, nil + } + return newField, newValue, nil +} + +var fieldMappings = versionToResourceToFieldMapping{ + v1.SchemeGroupVersion: resourceTypeToFieldMapping{ + "nodes": clientFieldNameToAPIVersionFieldName{ + objectNameField: objectNameField, + nodeUnschedulable: nodeUnschedulable, + }, + "pods": clientFieldNameToAPIVersionFieldName{ + podHost: podHost, + podStatus: podStatus, + }, + "secrets": clientFieldNameToAPIVersionFieldName{ + secretType: secretType, + }, + "serviceAccounts": clientFieldNameToAPIVersionFieldName{ + objectNameField: objectNameField, + }, + "endpoints": clientFieldNameToAPIVersionFieldName{ + objectNameField: objectNameField, + }, + "events": clientFieldNameToAPIVersionFieldName{ + objectNameField: objectNameField, + eventReason: eventReason, + eventSource: eventSource, + eventType: eventType, + eventInvolvedKind: eventInvolvedKind, + eventInvolvedNamespace: eventInvolvedNamespace, + eventInvolvedName: eventInvolvedName, + eventInvolvedUID: eventInvolvedUID, + eventInvolvedAPIVersion: eventInvolvedAPIVersion, + eventInvolvedResourceVersion: eventInvolvedResourceVersion, + eventInvolvedFieldPath: eventInvolvedFieldPath, + }, + }, +} + +// FieldsSelectorParam adds the given selector as a query parameter with the name paramName. +func (r *Request) FieldsSelectorParam(s fields.Selector) *Request { + if r.err != nil { + return r + } + if s == nil { + return r + } + if s.Empty() { + return r + } + s2, err := s.Transform(func(field, value string) (newField, newValue string, err error) { + return fieldMappings.filterField(r.content.GroupVersion, r.resource, field, value) + }) + if err != nil { + r.err = err + return r + } + return r.setParam(unversioned.FieldSelectorQueryParam(r.content.GroupVersion.String()), s2.String()) +} + +// LabelsSelectorParam adds the given selector as a query parameter +func (r *Request) LabelsSelectorParam(s labels.Selector) *Request { + if r.err != nil { + return r + } + if s == nil { + return r + } + if s.Empty() { + return r + } + return r.setParam(unversioned.LabelSelectorQueryParam(r.content.GroupVersion.String()), s.String()) +} + +// UintParam creates a query parameter with the given value. +func (r *Request) UintParam(paramName string, u uint64) *Request { + if r.err != nil { + return r + } + return r.setParam(paramName, strconv.FormatUint(u, 10)) +} + +// Param creates a query parameter with the given string value. +func (r *Request) Param(paramName, s string) *Request { + if r.err != nil { + return r + } + return r.setParam(paramName, s) +} + +// VersionedParams will take the provided object, serialize it to a map[string][]string using the +// implicit RESTClient API version and the default parameter codec, and then add those as parameters +// to the request. Use this to provide versioned query parameters from client libraries. +func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request { + if r.err != nil { + return r + } + params, err := codec.EncodeParameters(obj, *r.content.GroupVersion) + if err != nil { + r.err = err + return r + } + for k, v := range params { + for _, value := range v { + // TODO: Move it to setParam method, once we get rid of + // FieldSelectorParam & LabelSelectorParam methods. + if k == unversioned.LabelSelectorQueryParam(r.content.GroupVersion.String()) && value == "" { + // Don't set an empty selector for backward compatibility. + // Since there is no way to get the difference between empty + // and unspecified string, we don't set it to avoid having + // labelSelector= param in every request. + continue + } + if k == unversioned.FieldSelectorQueryParam(r.content.GroupVersion.String()) { + if len(value) == 0 { + // Don't set an empty selector for backward compatibility. + // Since there is no way to get the difference between empty + // and unspecified string, we don't set it to avoid having + // fieldSelector= param in every request. + continue + } + // TODO: Filtering should be handled somewhere else. + selector, err := fields.ParseSelector(value) + if err != nil { + r.err = fmt.Errorf("unparsable field selector: %v", err) + return r + } + filteredSelector, err := selector.Transform( + func(field, value string) (newField, newValue string, err error) { + return fieldMappings.filterField(r.content.GroupVersion, r.resource, field, value) + }) + if err != nil { + r.err = fmt.Errorf("untransformable field selector: %v", err) + return r + } + value = filteredSelector.String() + } + + r.setParam(k, value) + } + } + return r +} + +func (r *Request) setParam(paramName, value string) *Request { + if specialParams.Has(paramName) { + r.err = fmt.Errorf("must set %v through the corresponding function, not directly.", paramName) + return r + } + if r.params == nil { + r.params = make(url.Values) + } + r.params[paramName] = append(r.params[paramName], value) + return r +} + +func (r *Request) SetHeader(key, value string) *Request { + if r.headers == nil { + r.headers = http.Header{} + } + r.headers.Set(key, value) + return r +} + +// Timeout makes the request use the given duration as a timeout. Sets the "timeout" +// parameter. +func (r *Request) Timeout(d time.Duration) *Request { + if r.err != nil { + return r + } + r.timeout = d + return r +} + +// Body makes the request use obj as the body. Optional. +// If obj is a string, try to read a file of that name. +// If obj is a []byte, send it directly. +// If obj is an io.Reader, use it directly. +// If obj is a runtime.Object, marshal it correctly, and set Content-Type header. +// If obj is a runtime.Object and nil, do nothing. +// Otherwise, set an error. +func (r *Request) Body(obj interface{}) *Request { + if r.err != nil { + return r + } + switch t := obj.(type) { + case string: + data, err := ioutil.ReadFile(t) + if err != nil { + r.err = err + return r + } + glog.V(8).Infof("Request Body: %s", string(data)) + r.body = bytes.NewReader(data) + case []byte: + glog.V(8).Infof("Request Body: %s", string(t)) + r.body = bytes.NewReader(t) + case io.Reader: + r.body = t + case runtime.Object: + // callers may pass typed interface pointers, therefore we must check nil with reflection + if reflect.ValueOf(t).IsNil() { + return r + } + data, err := runtime.Encode(r.serializers.Encoder, t) + if err != nil { + r.err = err + return r + } + glog.V(8).Infof("Request Body: %s", string(data)) + r.body = bytes.NewReader(data) + r.SetHeader("Content-Type", r.content.ContentType) + default: + r.err = fmt.Errorf("unknown type used for body: %+v", obj) + } + return r +} + +// URL returns the current working URL. +func (r *Request) URL() *url.URL { + p := r.pathPrefix + if r.namespaceSet && len(r.namespace) > 0 { + p = path.Join(p, "namespaces", r.namespace) + } + if len(r.resource) != 0 { + p = path.Join(p, strings.ToLower(r.resource)) + } + // Join trims trailing slashes, so preserve r.pathPrefix's trailing slash for backwards compatibility if nothing was changed + if len(r.resourceName) != 0 || len(r.subpath) != 0 || len(r.subresource) != 0 { + p = path.Join(p, r.resourceName, r.subresource, r.subpath) + } + + finalURL := &url.URL{} + if r.baseURL != nil { + *finalURL = *r.baseURL + } + finalURL.Path = p + + query := url.Values{} + for key, values := range r.params { + for _, value := range values { + query.Add(key, value) + } + } + + // timeout is handled specially here. + if r.timeout != 0 { + query.Set("timeout", r.timeout.String()) + } + finalURL.RawQuery = query.Encode() + return finalURL +} + +// finalURLTemplate is similar to URL(), but will make all specific parameter values equal +// - instead of name or namespace, "{name}" and "{namespace}" will be used, and all query +// parameters will be reset. This creates a copy of the request so as not to change the +// underyling object. This means some useful request info (like the types of field +// selectors in use) will be lost. +// TODO: preserve field selector keys +func (r Request) finalURLTemplate() string { + if len(r.resourceName) != 0 { + r.resourceName = "{name}" + } + if r.namespaceSet && len(r.namespace) != 0 { + r.namespace = "{namespace}" + } + newParams := url.Values{} + v := []string{"{value}"} + for k := range r.params { + newParams[k] = v + } + r.params = newParams + return r.URL().String() +} + +func (r *Request) tryThrottle() { + now := time.Now() + if r.throttle != nil { + r.throttle.Accept() + } + if latency := time.Since(now); latency > longThrottleLatency { + glog.V(4).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String()) + } +} + +// Watch attempts to begin watching the requested location. +// Returns a watch.Interface, or an error. +func (r *Request) Watch() (watch.Interface, error) { + // We specifically don't want to rate limit watches, so we + // don't use r.throttle here. + if r.err != nil { + return nil, r.err + } + if r.serializers.Framer == nil { + return nil, fmt.Errorf("watching resources is not possible with this client (content-type: %s)", r.content.ContentType) + } + + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, r.body) + if err != nil { + return nil, err + } + req.Header = r.headers + client := r.client + if client == nil { + client = http.DefaultClient + } + r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL())) + resp, err := client.Do(req) + updateURLMetrics(r, resp, err) + if r.baseURL != nil { + if err != nil { + r.backoffMgr.UpdateBackoff(r.baseURL, err, 0) + } else { + r.backoffMgr.UpdateBackoff(r.baseURL, err, resp.StatusCode) + } + } + if err != nil { + // The watch stream mechanism handles many common partial data errors, so closed + // connections can be retried in many cases. + if net.IsProbableEOF(err) { + return watch.NewEmptyWatch(), nil + } + return nil, err + } + if resp.StatusCode != http.StatusOK { + defer resp.Body.Close() + if result := r.transformResponse(resp, req); result.err != nil { + return nil, result.err + } + return nil, fmt.Errorf("for request '%+v', got status: %v", url, resp.StatusCode) + } + framer := r.serializers.Framer.NewFrameReader(resp.Body) + decoder := streaming.NewDecoder(framer, r.serializers.StreamingSerializer) + return watch.NewStreamWatcher(versioned.NewDecoder(decoder, r.serializers.Decoder)), nil +} + +// updateURLMetrics is a convenience function for pushing metrics. +// It also handles corner cases for incomplete/invalid request data. +func updateURLMetrics(req *Request, resp *http.Response, err error) { + url := "none" + if req.baseURL != nil { + url = req.baseURL.Host + } + + // If we have an error (i.e. apiserver down) we report that as a metric label. + if err != nil { + metrics.RequestResult.WithLabelValues(err.Error(), req.verb, url).Inc() + } else { + //Metrics for failure codes + metrics.RequestResult.WithLabelValues(strconv.Itoa(resp.StatusCode), req.verb, url).Inc() + } +} + +// Stream formats and executes the request, and offers streaming of the response. +// Returns io.ReadCloser which could be used for streaming of the response, or an error +// Any non-2xx http status code causes an error. If we get a non-2xx code, we try to convert the body into an APIStatus object. +// If we can, we return that as an error. Otherwise, we create an error that lists the http status and the content of the response. +func (r *Request) Stream() (io.ReadCloser, error) { + if r.err != nil { + return nil, r.err + } + + r.tryThrottle() + + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, nil) + if err != nil { + return nil, err + } + req.Header = r.headers + client := r.client + if client == nil { + client = http.DefaultClient + } + r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL())) + resp, err := client.Do(req) + updateURLMetrics(r, resp, err) + if r.baseURL != nil { + if err != nil { + r.backoffMgr.UpdateBackoff(r.URL(), err, 0) + } else { + r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode) + } + } + if err != nil { + return nil, err + } + + switch { + case (resp.StatusCode >= 200) && (resp.StatusCode < 300): + return resp.Body, nil + + default: + // ensure we close the body before returning the error + defer resp.Body.Close() + + // we have a decent shot at taking the object returned, parsing it as a status object and returning a more normal error + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("%v while accessing %v", resp.Status, url) + } + + // TODO: Check ContentType. + if runtimeObject, err := runtime.Decode(r.serializers.Decoder, bodyBytes); err == nil { + statusError := errors.FromObject(runtimeObject) + + if _, ok := statusError.(errors.APIStatus); ok { + return nil, statusError + } + } + + bodyText := string(bodyBytes) + return nil, fmt.Errorf("%s while accessing %v: %s", resp.Status, url, bodyText) + } +} + +// request connects to the server and invokes the provided function when a server response is +// received. It handles retry behavior and up front validation of requests. It will invoke +// fn at most once. It will return an error if a problem occurred prior to connecting to the +// server - the provided function is responsible for handling server errors. +func (r *Request) request(fn func(*http.Request, *http.Response)) error { + //Metrics for total request latency + start := time.Now() + defer func() { + metrics.RequestLatency.WithLabelValues(r.verb, r.finalURLTemplate()).Observe(metrics.SinceInMicroseconds(start)) + }() + + if r.err != nil { + glog.V(4).Infof("Error in request: %v", r.err) + return r.err + } + + // TODO: added to catch programmer errors (invoking operations with an object with an empty namespace) + if (r.verb == "GET" || r.verb == "PUT" || r.verb == "DELETE") && r.namespaceSet && len(r.resourceName) > 0 && len(r.namespace) == 0 { + return fmt.Errorf("an empty namespace may not be set when a resource name is provided") + } + if (r.verb == "POST") && r.namespaceSet && len(r.namespace) == 0 { + return fmt.Errorf("an empty namespace may not be set during creation") + } + + client := r.client + if client == nil { + client = http.DefaultClient + } + + // Right now we make about ten retry attempts if we get a Retry-After response. + // TODO: Change to a timeout based approach. + maxRetries := 10 + retries := 0 + for { + url := r.URL().String() + req, err := http.NewRequest(r.verb, url, r.body) + if err != nil { + return err + } + req.Header = r.headers + + r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL())) + resp, err := client.Do(req) + updateURLMetrics(r, resp, err) + if err != nil { + r.backoffMgr.UpdateBackoff(r.URL(), err, 0) + } else { + r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode) + } + if err != nil { + return err + } + + done := func() bool { + // ensure the response body is closed before we reconnect, so that we reuse the same + // TCP connection + defer resp.Body.Close() + + retries++ + if seconds, wait := checkWait(resp); wait && retries < maxRetries { + if seeker, ok := r.body.(io.Seeker); ok && r.body != nil { + _, err := seeker.Seek(0, 0) + if err != nil { + glog.V(4).Infof("Could not retry request, can't Seek() back to beginning of body for %T", r.body) + fn(req, resp) + return true + } + } + + glog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", seconds, retries, url) + r.backoffMgr.Sleep(time.Duration(seconds) * time.Second) + return false + } + fn(req, resp) + return true + }() + if done { + return nil + } + } +} + +// Do formats and executes the request. Returns a Result object for easy response +// processing. +// +// Error type: +// * If the request can't be constructed, or an error happened earlier while building its +// arguments: *RequestConstructionError +// * If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError +// * http.Client.Do errors are returned directly. +func (r *Request) Do() Result { + r.tryThrottle() + + var result Result + err := r.request(func(req *http.Request, resp *http.Response) { + result = r.transformResponse(resp, req) + }) + if err != nil { + return Result{err: err} + } + return result +} + +// DoRaw executes the request but does not process the response body. +func (r *Request) DoRaw() ([]byte, error) { + r.tryThrottle() + + var result Result + err := r.request(func(req *http.Request, resp *http.Response) { + result.body, result.err = ioutil.ReadAll(resp.Body) + }) + if err != nil { + return nil, err + } + return result.body, result.err +} + +// transformResponse converts an API response into a structured API object +func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result { + var body []byte + if resp.Body != nil { + if data, err := ioutil.ReadAll(resp.Body); err == nil { + body = data + } + } + glog.V(8).Infof("Response Body: %s", string(body)) + + // Did the server give us a status response? + isStatusResponse := false + // Because release-1.1 server returns Status with empty APIVersion at paths + // to the Extensions resources, we need to use DecodeInto here to provide + // default groupVersion, otherwise a status response won't be correctly + // decoded. + status := &unversioned.Status{} + err := runtime.DecodeInto(r.serializers.Decoder, body, status) + if err == nil && len(status.Status) > 0 { + isStatusResponse = true + } + + switch { + case resp.StatusCode == http.StatusSwitchingProtocols: + // no-op, we've been upgraded + case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent: + if !isStatusResponse { + return Result{err: r.transformUnstructuredResponseError(resp, req, body)} + } + return Result{err: errors.FromObject(status)} + } + + // If the server gave us a status back, look at what it was. + success := resp.StatusCode >= http.StatusOK && resp.StatusCode <= http.StatusPartialContent + if isStatusResponse && (status.Status != unversioned.StatusSuccess && !success) { + // "Failed" requests are clearly just an error and it makes sense to return them as such. + return Result{err: errors.FromObject(status)} + } + + contentType := resp.Header.Get("Content-Type") + var decoder runtime.Decoder + if contentType == r.content.ContentType { + decoder = r.serializers.Decoder + } else { + mediaType, params, err := mime.ParseMediaType(contentType) + if err != nil { + return Result{err: errors.NewInternalError(err)} + } + decoder, err = r.serializers.RenegotiatedDecoder(mediaType, params) + if err != nil { + return Result{ + body: body, + contentType: contentType, + statusCode: resp.StatusCode, + } + } + } + + return Result{ + body: body, + contentType: contentType, + statusCode: resp.StatusCode, + decoder: decoder, + } +} + +// transformUnstructuredResponseError handles an error from the server that is not in a structured form. +// It is expected to transform any response that is not recognizable as a clear server sent error from the +// K8S API using the information provided with the request. In practice, HTTP proxies and client libraries +// introduce a level of uncertainty to the responses returned by servers that in common use result in +// unexpected responses. The rough structure is: +// +// 1. Assume the server sends you something sane - JSON + well defined error objects + proper codes +// - this is the happy path +// - when you get this output, trust what the server sends +// 2. Guard against empty fields / bodies in received JSON and attempt to cull sufficient info from them to +// generate a reasonable facsimile of the original failure. +// - Be sure to use a distinct error type or flag that allows a client to distinguish between this and error 1 above +// 3. Handle true disconnect failures / completely malformed data by moving up to a more generic client error +// 4. Distinguish between various connection failures like SSL certificates, timeouts, proxy errors, unexpected +// initial contact, the presence of mismatched body contents from posted content types +// - Give these a separate distinct error type and capture as much as possible of the original message +// +// TODO: introduce transformation of generic http.Client.Do() errors that separates 4. +func (r *Request) transformUnstructuredResponseError(resp *http.Response, req *http.Request, body []byte) error { + if body == nil && resp.Body != nil { + if data, err := ioutil.ReadAll(resp.Body); err == nil { + body = data + } + } + glog.V(8).Infof("Response Body: %s", string(body)) + + message := "unknown" + if isTextResponse(resp) { + message = strings.TrimSpace(string(body)) + } + retryAfter, _ := retryAfterSeconds(resp) + return errors.NewGenericServerResponse( + resp.StatusCode, + req.Method, + unversioned.GroupResource{ + Group: r.content.GroupVersion.Group, + Resource: r.resource, + }, + r.resourceName, + message, + retryAfter, + true, + ) +} + +// isTextResponse returns true if the response appears to be a textual media type. +func isTextResponse(resp *http.Response) bool { + contentType := resp.Header.Get("Content-Type") + if len(contentType) == 0 { + return true + } + media, _, err := mime.ParseMediaType(contentType) + if err != nil { + return false + } + return strings.HasPrefix(media, "text/") +} + +// checkWait returns true along with a number of seconds if the server instructed us to wait +// before retrying. +func checkWait(resp *http.Response) (int, bool) { + switch r := resp.StatusCode; { + // any 500 error code and 429 can trigger a wait + case r == errors.StatusTooManyRequests, r >= 500: + default: + return 0, false + } + i, ok := retryAfterSeconds(resp) + return i, ok +} + +// retryAfterSeconds returns the value of the Retry-After header and true, or 0 and false if +// the header was missing or not a valid number. +func retryAfterSeconds(resp *http.Response) (int, bool) { + if h := resp.Header.Get("Retry-After"); len(h) > 0 { + if i, err := strconv.Atoi(h); err == nil { + return i, true + } + } + return 0, false +} + +// Result contains the result of calling Request.Do(). +type Result struct { + body []byte + contentType string + err error + statusCode int + + decoder runtime.Decoder +} + +// Raw returns the raw result. +func (r Result) Raw() ([]byte, error) { + return r.body, r.err +} + +// Get returns the result as an object. +func (r Result) Get() (runtime.Object, error) { + if r.err != nil { + return nil, r.err + } + if r.decoder == nil { + return nil, fmt.Errorf("serializer for %s doesn't exist", r.contentType) + } + return runtime.Decode(r.decoder, r.body) +} + +// StatusCode returns the HTTP status code of the request. (Only valid if no +// error was returned.) +func (r Result) StatusCode(statusCode *int) Result { + *statusCode = r.statusCode + return r +} + +// Into stores the result into obj, if possible. If obj is nil it is ignored. +func (r Result) Into(obj runtime.Object) error { + if r.err != nil { + return r.err + } + if r.decoder == nil { + return fmt.Errorf("serializer for %s doesn't exist", r.contentType) + } + return runtime.DecodeInto(r.decoder, r.body, obj) +} + +// WasCreated updates the provided bool pointer to whether the server returned +// 201 created or a different response. +func (r Result) WasCreated(wasCreated *bool) Result { + *wasCreated = r.statusCode == http.StatusCreated + return r +} + +// Error returns the error executing the request, nil if no error occurred. +// See the Request.Do() comment for what errors you might get. +func (r Result) Error() error { + return r.err +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/transport.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/transport.go new file mode 100644 index 0000000..c385914 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/transport.go @@ -0,0 +1,94 @@ +/* +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 restclient + +import ( + "crypto/tls" + "net/http" + + "k8s.io/kubernetes/pkg/client/transport" +) + +// TLSConfigFor returns a tls.Config that will provide the transport level security defined +// by the provided Config. Will return nil if no transport level security is requested. +func TLSConfigFor(config *Config) (*tls.Config, error) { + cfg, err := config.transportConfig() + if err != nil { + return nil, err + } + return transport.TLSConfigFor(cfg) +} + +// TransportFor returns an http.RoundTripper that will provide the authentication +// or transport level security defined by the provided Config. Will return the +// default http.DefaultTransport if no special case behavior is needed. +func TransportFor(config *Config) (http.RoundTripper, error) { + cfg, err := config.transportConfig() + if err != nil { + return nil, err + } + return transport.New(cfg) +} + +// HTTPWrappersForConfig wraps a round tripper with any relevant layered behavior from the +// config. Exposed to allow more clients that need HTTP-like behavior but then must hijack +// the underlying connection (like WebSocket or HTTP2 clients). Pure HTTP clients should use +// the higher level TransportFor or RESTClientFor methods. +func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) { + cfg, err := config.transportConfig() + if err != nil { + return nil, err + } + return transport.HTTPWrappersForConfig(cfg, rt) +} + +// transportConfig converts a client config to an appropriate transport config. +func (c *Config) transportConfig() (*transport.Config, error) { + wt := c.WrapTransport + if c.AuthProvider != nil { + provider, err := GetAuthProvider(c.Host, c.AuthProvider, c.AuthConfigPersister) + if err != nil { + return nil, err + } + if wt != nil { + previousWT := wt + wt = func(rt http.RoundTripper) http.RoundTripper { + return provider.WrapTransport(previousWT(rt)) + } + } else { + wt = provider.WrapTransport + } + } + return &transport.Config{ + UserAgent: c.UserAgent, + Transport: c.Transport, + WrapTransport: wt, + TLS: transport.TLSConfig{ + CAFile: c.CAFile, + CAData: c.CAData, + CertFile: c.CertFile, + CertData: c.CertData, + KeyFile: c.KeyFile, + KeyData: c.KeyData, + Insecure: c.Insecure, + }, + Username: c.Username, + Password: c.Password, + BearerToken: c.BearerToken, + Impersonate: c.Impersonate, + }, nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/url_utils.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/url_utils.go new file mode 100644 index 0000000..81f16d6 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/url_utils.go @@ -0,0 +1,93 @@ +/* +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 restclient + +import ( + "fmt" + "net/url" + "path" + + "k8s.io/kubernetes/pkg/api/unversioned" +) + +// DefaultServerURL converts a host, host:port, or URL string to the default base server API path +// to use with a Client at a given API version following the standard conventions for a +// Kubernetes API. +func DefaultServerURL(host, apiPath string, groupVersion unversioned.GroupVersion, defaultTLS bool) (*url.URL, string, error) { + if host == "" { + return nil, "", fmt.Errorf("host must be a URL or a host:port pair") + } + base := host + hostURL, err := url.Parse(base) + if err != nil { + return nil, "", err + } + if hostURL.Scheme == "" || hostURL.Host == "" { + scheme := "http://" + if defaultTLS { + scheme = "https://" + } + hostURL, err = url.Parse(scheme + base) + if err != nil { + return nil, "", err + } + if hostURL.Path != "" && hostURL.Path != "/" { + return nil, "", fmt.Errorf("host must be a URL or a host:port pair: %q", base) + } + } + + // hostURL.Path is optional; a non-empty Path is treated as a prefix that is to be applied to + // all URIs used to access the host. this is useful when there's a proxy in front of the + // apiserver that has relocated the apiserver endpoints, forwarding all requests from, for + // example, /a/b/c to the apiserver. in this case the Path should be /a/b/c. + // + // if running without a frontend proxy (that changes the location of the apiserver), then + // hostURL.Path should be blank. + // + // versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base + versionedAPIPath := path.Join("/", apiPath) + + // Add the version to the end of the path + if len(groupVersion.Group) > 0 { + versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Group, groupVersion.Version) + + } else { + versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version) + + } + + return hostURL, versionedAPIPath, nil +} + +// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It +// requires Host and Version to be set prior to being called. +func defaultServerUrlFor(config *Config) (*url.URL, string, error) { + // TODO: move the default to secure when the apiserver supports TLS by default + // config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA." + hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0 + hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0 + defaultTLS := hasCA || hasCert || config.Insecure + host := config.Host + if host == "" { + host = "localhost" + } + + if config.GroupVersion != nil { + return DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS) + } + return DefaultServerURL(host, config.APIPath, unversioned.GroupVersion{}, defaultTLS) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/urlbackoff.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/urlbackoff.go new file mode 100644 index 0000000..24a89ed --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/urlbackoff.go @@ -0,0 +1,107 @@ +/* +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 restclient + +import ( + "net/url" + "time" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/util/flowcontrol" + "k8s.io/kubernetes/pkg/util/sets" +) + +// Set of resp. Codes that we backoff for. +// In general these should be errors that indicate a server is overloaded. +// These shouldn't be configured by any user, we set them based on conventions +// described in +var serverIsOverloadedSet = sets.NewInt(429) +var maxResponseCode = 499 + +type BackoffManager interface { + UpdateBackoff(actualUrl *url.URL, err error, responseCode int) + CalculateBackoff(actualUrl *url.URL) time.Duration + Sleep(d time.Duration) +} + +// URLBackoff struct implements the semantics on top of Backoff which +// we need for URL specific exponential backoff. +type URLBackoff struct { + // Uses backoff as underlying implementation. + Backoff *flowcontrol.Backoff +} + +// NoBackoff is a stub implementation, can be used for mocking or else as a default. +type NoBackoff struct { +} + +func (n *NoBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) { + // do nothing. +} + +func (n *NoBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration { + return 0 * time.Second +} + +func (n *NoBackoff) Sleep(d time.Duration) { + time.Sleep(d) +} + +// Disable makes the backoff trivial, i.e., sets it to zero. This might be used +// by tests which want to run 1000s of mock requests without slowing down. +func (b *URLBackoff) Disable() { + glog.V(4).Infof("Disabling backoff strategy") + b.Backoff = flowcontrol.NewBackOff(0*time.Second, 0*time.Second) +} + +// baseUrlKey returns the key which urls will be mapped to. +// For example, 127.0.0.1:8080/api/v2/abcde -> 127.0.0.1:8080. +func (b *URLBackoff) baseUrlKey(rawurl *url.URL) string { + // Simple implementation for now, just the host. + // We may backoff specific paths (i.e. "pods") differentially + // in the future. + host, err := url.Parse(rawurl.String()) + if err != nil { + glog.V(4).Infof("Error extracting url: %v", rawurl) + panic("bad url!") + } + return host.Host +} + +// UpdateBackoff updates backoff metadata +func (b *URLBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) { + // range for retry counts that we store is [0,13] + if responseCode > maxResponseCode || serverIsOverloadedSet.Has(responseCode) { + b.Backoff.Next(b.baseUrlKey(actualUrl), b.Backoff.Clock.Now()) + return + } else if responseCode >= 300 || err != nil { + glog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err) + } + + //If we got this far, there is no backoff required for this URL anymore. + b.Backoff.Reset(b.baseUrlKey(actualUrl)) +} + +// CalculateBackoff takes a url and back's off exponentially, +// based on its knowledge of existing failures. +func (b *URLBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration { + return b.Backoff.Get(b.baseUrlKey(actualUrl)) +} + +func (b *URLBackoff) Sleep(d time.Duration) { + b.Backoff.Clock.Sleep(d) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/versions.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/versions.go new file mode 100644 index 0000000..3376434 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/restclient/versions.go @@ -0,0 +1,88 @@ +/* +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 restclient + +import ( + "encoding/json" + "fmt" + "net/http" + "path" + + "k8s.io/kubernetes/pkg/api/unversioned" +) + +const ( + legacyAPIPath = "/api" + defaultAPIPath = "/apis" +) + +// TODO: Is this obsoleted by the discovery client? + +// ServerAPIVersions returns the GroupVersions supported by the API server. +// It creates a RESTClient based on the passed in config, but it doesn't rely +// on the Version and Codec of the config, because it uses AbsPath and +// takes the raw response. +func ServerAPIVersions(c *Config) (groupVersions []string, err error) { + transport, err := TransportFor(c) + if err != nil { + return nil, err + } + client := http.Client{Transport: transport} + + configCopy := *c + configCopy.GroupVersion = nil + configCopy.APIPath = "" + baseURL, _, err := defaultServerUrlFor(&configCopy) + if err != nil { + return nil, err + } + // Get the groupVersions exposed at /api + originalPath := baseURL.Path + baseURL.Path = path.Join(originalPath, legacyAPIPath) + resp, err := client.Get(baseURL.String()) + if err != nil { + return nil, err + } + var v unversioned.APIVersions + defer resp.Body.Close() + err = json.NewDecoder(resp.Body).Decode(&v) + if err != nil { + return nil, fmt.Errorf("unexpected error: %v", err) + } + + groupVersions = append(groupVersions, v.Versions...) + // Get the groupVersions exposed at /apis + baseURL.Path = path.Join(originalPath, defaultAPIPath) + resp2, err := client.Get(baseURL.String()) + if err != nil { + return nil, err + } + var apiGroupList unversioned.APIGroupList + defer resp2.Body.Close() + err = json.NewDecoder(resp2.Body).Decode(&apiGroupList) + if err != nil { + return nil, fmt.Errorf("unexpected error: %v", err) + } + + for _, g := range apiGroupList.Groups { + for _, gv := range g.Versions { + groupVersions = append(groupVersions, gv.GroupVersion) + } + } + + return groupVersions, nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/cache.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/cache.go new file mode 100644 index 0000000..eedfd3d --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/cache.go @@ -0,0 +1,88 @@ +/* +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 transport + +import ( + "fmt" + "net" + "net/http" + "sync" + "time" + + utilnet "k8s.io/kubernetes/pkg/util/net" +) + +// TlsTransportCache caches TLS http.RoundTrippers different configurations. The +// same RoundTripper will be returned for configs with identical TLS options If +// the config has no custom TLS options, http.DefaultTransport is returned. +type tlsTransportCache struct { + mu sync.Mutex + transports map[string]*http.Transport +} + +const idleConnsPerHost = 25 + +var tlsCache = &tlsTransportCache{transports: make(map[string]*http.Transport)} + +func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { + key, err := tlsConfigKey(config) + if err != nil { + return nil, err + } + + // Ensure we only create a single transport for the given TLS options + c.mu.Lock() + defer c.mu.Unlock() + + // See if we already have a custom transport for this config + if t, ok := c.transports[key]; ok { + return t, nil + } + + // Get the TLS options for this client config + tlsConfig, err := TLSConfigFor(config) + if err != nil { + return nil, err + } + // The options didn't require a custom TLS config + if tlsConfig == nil { + return http.DefaultTransport, nil + } + + // Cache a single transport for these options + c.transports[key] = utilnet.SetTransportDefaults(&http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSHandshakeTimeout: 10 * time.Second, + TLSClientConfig: tlsConfig, + MaxIdleConnsPerHost: idleConnsPerHost, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + }) + return c.transports[key], nil +} + +// tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor +func tlsConfigKey(c *Config) (string, error) { + // Make sure ca/key/cert content is loaded + if err := loadTLSFiles(c); err != nil { + return "", err + } + // Only include the things that actually affect the tls.Config + return fmt.Sprintf("%v/%x/%x/%x", c.TLS.Insecure, c.TLS.CAData, c.TLS.CertData, c.TLS.KeyData), nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/config.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/config.go new file mode 100644 index 0000000..6e5c68a --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/config.go @@ -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 transport + +import "net/http" + +// Config holds various options for establishing a transport. +type Config struct { + // UserAgent is an optional field that specifies the caller of this + // request. + UserAgent string + + // The base TLS configuration for this transport. + TLS TLSConfig + + // Username and password for basic authentication + Username string + Password string + + // Bearer token for authentication + BearerToken string + + // Impersonate is the username that this Config will impersonate + Impersonate string + + // Transport may be used for custom HTTP behavior. This attribute may + // not be specified with the TLS client certificate options. Use + // WrapTransport for most client level operations. + Transport http.RoundTripper + + // WrapTransport will be invoked for custom HTTP behavior after the + // underlying transport is initialized (either the transport created + // from TLSClientConfig, Transport, or http.DefaultTransport). The + // config may layer other RoundTrippers on top of the returned + // RoundTripper. + WrapTransport func(rt http.RoundTripper) http.RoundTripper +} + +// HasCA returns whether the configuration has a certificate authority or not. +func (c *Config) HasCA() bool { + return len(c.TLS.CAData) > 0 || len(c.TLS.CAFile) > 0 +} + +// HasBasicAuth returns whether the configuration has basic authentication or not. +func (c *Config) HasBasicAuth() bool { + return len(c.Username) != 0 +} + +// HasTokenAuth returns whether the configuration has token authentication or not. +func (c *Config) HasTokenAuth() bool { + return len(c.BearerToken) != 0 +} + +// HasCertAuth returns whether the configuration has certificate authentication or not. +func (c *Config) HasCertAuth() bool { + return len(c.TLS.CertData) != 0 || len(c.TLS.CertFile) != 0 +} + +// TLSConfig holds the information needed to set up a TLS transport. +type TLSConfig struct { + CAFile string // Path of the PEM-encoded server trusted root certificates. + CertFile string // Path of the PEM-encoded client certificate. + KeyFile string // Path of the PEM-encoded client key. + + Insecure bool // Server should be accessed without verifying the certificate. For testing only. + + CAData []byte // Bytes of the PEM-encoded server trusted root certificates. Supercedes CAFile. + CertData []byte // Bytes of the PEM-encoded client certificate. Supercedes CertFile. + KeyData []byte // Bytes of the PEM-encoded client key. Supercedes KeyFile. +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/round_trippers.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/round_trippers.go new file mode 100644 index 0000000..aadf0cb --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/round_trippers.go @@ -0,0 +1,337 @@ +/* +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 transport + +import ( + "fmt" + "net/http" + "time" + + "github.com/golang/glog" +) + +// HTTPWrappersForConfig wraps a round tripper with any relevant layered +// behavior from the config. Exposed to allow more clients that need HTTP-like +// behavior but then must hijack the underlying connection (like WebSocket or +// HTTP2 clients). Pure HTTP clients should use the RoundTripper returned from +// New. +func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) { + if config.WrapTransport != nil { + rt = config.WrapTransport(rt) + } + + rt = DebugWrappers(rt) + + // Set authentication wrappers + switch { + case config.HasBasicAuth() && config.HasTokenAuth(): + return nil, fmt.Errorf("username/password or bearer token may be set, but not both") + case config.HasTokenAuth(): + rt = NewBearerAuthRoundTripper(config.BearerToken, rt) + case config.HasBasicAuth(): + rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt) + } + if len(config.UserAgent) > 0 { + rt = NewUserAgentRoundTripper(config.UserAgent, rt) + } + if len(config.Impersonate) > 0 { + rt = NewImpersonatingRoundTripper(config.Impersonate, rt) + } + return rt, nil +} + +// DebugWrappers wraps a round tripper and logs based on the current log level. +func DebugWrappers(rt http.RoundTripper) http.RoundTripper { + switch { + case bool(glog.V(9)): + rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders) + case bool(glog.V(8)): + rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders) + case bool(glog.V(7)): + rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus) + case bool(glog.V(6)): + rt = newDebuggingRoundTripper(rt, debugURLTiming) + } + + return rt +} + +type requestCanceler interface { + CancelRequest(*http.Request) +} + +type userAgentRoundTripper struct { + agent string + rt http.RoundTripper +} + +func NewUserAgentRoundTripper(agent string, rt http.RoundTripper) http.RoundTripper { + return &userAgentRoundTripper{agent, rt} +} + +func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("User-Agent")) != 0 { + return rt.rt.RoundTrip(req) + } + req = cloneRequest(req) + req.Header.Set("User-Agent", rt.agent) + return rt.rt.RoundTrip(req) +} + +func (rt *userAgentRoundTripper) CancelRequest(req *http.Request) { + if canceler, ok := rt.rt.(requestCanceler); ok { + canceler.CancelRequest(req) + } else { + glog.Errorf("CancelRequest not implemented") + } +} + +func (rt *userAgentRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } + +type basicAuthRoundTripper struct { + username string + password string + rt http.RoundTripper +} + +// NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a +// request unless it has already been set. +func NewBasicAuthRoundTripper(username, password string, rt http.RoundTripper) http.RoundTripper { + return &basicAuthRoundTripper{username, password, rt} +} + +func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Authorization")) != 0 { + return rt.rt.RoundTrip(req) + } + req = cloneRequest(req) + req.SetBasicAuth(rt.username, rt.password) + return rt.rt.RoundTrip(req) +} + +func (rt *basicAuthRoundTripper) CancelRequest(req *http.Request) { + if canceler, ok := rt.rt.(requestCanceler); ok { + canceler.CancelRequest(req) + } else { + glog.Errorf("CancelRequest not implemented") + } +} + +func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } + +type impersonatingRoundTripper struct { + impersonate string + delegate http.RoundTripper +} + +// NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set. +func NewImpersonatingRoundTripper(impersonate string, delegate http.RoundTripper) http.RoundTripper { + return &impersonatingRoundTripper{impersonate, delegate} +} + +func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Impersonate-User")) != 0 { + return rt.delegate.RoundTrip(req) + } + req = cloneRequest(req) + req.Header.Set("Impersonate-User", rt.impersonate) + return rt.delegate.RoundTrip(req) +} + +func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) { + if canceler, ok := rt.delegate.(requestCanceler); ok { + canceler.CancelRequest(req) + } else { + glog.Errorf("CancelRequest not implemented") + } +} + +func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.delegate } + +type bearerAuthRoundTripper struct { + bearer string + rt http.RoundTripper +} + +// NewBearerAuthRoundTripper adds the provided bearer token to a request +// unless the authorization header has already been set. +func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper { + return &bearerAuthRoundTripper{bearer, rt} +} + +func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if len(req.Header.Get("Authorization")) != 0 { + return rt.rt.RoundTrip(req) + } + + req = cloneRequest(req) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rt.bearer)) + return rt.rt.RoundTrip(req) +} + +func (rt *bearerAuthRoundTripper) CancelRequest(req *http.Request) { + if canceler, ok := rt.rt.(requestCanceler); ok { + canceler.CancelRequest(req) + } else { + glog.Errorf("CancelRequest not implemented") + } +} + +func (rt *bearerAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } + +// cloneRequest returns a clone of the provided *http.Request. +// The clone is a shallow copy of the struct and its Header map. +func cloneRequest(r *http.Request) *http.Request { + // shallow copy of the struct + r2 := new(http.Request) + *r2 = *r + // deep copy of the Header + r2.Header = make(http.Header) + for k, s := range r.Header { + r2.Header[k] = s + } + return r2 +} + +// requestInfo keeps track of information about a request/response combination +type requestInfo struct { + RequestHeaders http.Header + RequestVerb string + RequestURL string + + ResponseStatus string + ResponseHeaders http.Header + ResponseErr error + + Duration time.Duration +} + +// newRequestInfo creates a new RequestInfo based on an http request +func newRequestInfo(req *http.Request) *requestInfo { + return &requestInfo{ + RequestURL: req.URL.String(), + RequestVerb: req.Method, + RequestHeaders: req.Header, + } +} + +// complete adds information about the response to the requestInfo +func (r *requestInfo) complete(response *http.Response, err error) { + if err != nil { + r.ResponseErr = err + return + } + r.ResponseStatus = response.Status + r.ResponseHeaders = response.Header +} + +// toCurl returns a string that can be run as a command in a terminal (minus the body) +func (r *requestInfo) toCurl() string { + headers := "" + for key, values := range r.RequestHeaders { + for _, value := range values { + headers += fmt.Sprintf(` -H %q`, fmt.Sprintf("%s: %s", key, value)) + } + } + + return fmt.Sprintf("curl -k -v -X%s %s %s", r.RequestVerb, headers, r.RequestURL) +} + +// debuggingRoundTripper will display information about the requests passing +// through it based on what is configured +type debuggingRoundTripper struct { + delegatedRoundTripper http.RoundTripper + + levels map[debugLevel]bool +} + +type debugLevel int + +const ( + debugJustURL debugLevel = iota + debugURLTiming + debugCurlCommand + debugRequestHeaders + debugResponseStatus + debugResponseHeaders +) + +func newDebuggingRoundTripper(rt http.RoundTripper, levels ...debugLevel) *debuggingRoundTripper { + drt := &debuggingRoundTripper{ + delegatedRoundTripper: rt, + levels: make(map[debugLevel]bool, len(levels)), + } + for _, v := range levels { + drt.levels[v] = true + } + return drt +} + +func (rt *debuggingRoundTripper) CancelRequest(req *http.Request) { + if canceler, ok := rt.delegatedRoundTripper.(requestCanceler); ok { + canceler.CancelRequest(req) + } else { + glog.Errorf("CancelRequest not implemented") + } +} + +func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + reqInfo := newRequestInfo(req) + + if rt.levels[debugJustURL] { + glog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL) + } + if rt.levels[debugCurlCommand] { + glog.Infof("%s", reqInfo.toCurl()) + + } + if rt.levels[debugRequestHeaders] { + glog.Infof("Request Headers:") + for key, values := range reqInfo.RequestHeaders { + for _, value := range values { + glog.Infof(" %s: %s", key, value) + } + } + } + + startTime := time.Now() + response, err := rt.delegatedRoundTripper.RoundTrip(req) + reqInfo.Duration = time.Since(startTime) + + reqInfo.complete(response, err) + + if rt.levels[debugURLTiming] { + glog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond)) + } + if rt.levels[debugResponseStatus] { + glog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond)) + } + if rt.levels[debugResponseHeaders] { + glog.Infof("Response Headers:") + for key, values := range reqInfo.ResponseHeaders { + for _, value := range values { + glog.Infof(" %s: %s", key, value) + } + } + } + + return response, err +} + +func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper { + return rt.delegatedRoundTripper +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/transport.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/transport.go new file mode 100644 index 0000000..9c5b9ef --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/transport/transport.go @@ -0,0 +1,140 @@ +/* +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 transport + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "io/ioutil" + "net/http" +) + +// New returns an http.RoundTripper that will provide the authentication +// or transport level security defined by the provided Config. +func New(config *Config) (http.RoundTripper, error) { + // Set transport level security + if config.Transport != nil && (config.HasCA() || config.HasCertAuth() || config.TLS.Insecure) { + return nil, fmt.Errorf("using a custom transport with TLS certificate options or the insecure flag is not allowed") + } + + var ( + rt http.RoundTripper + err error + ) + + if config.Transport != nil { + rt = config.Transport + } else { + rt, err = tlsCache.get(config) + if err != nil { + return nil, err + } + } + + return HTTPWrappersForConfig(config, rt) +} + +// TLSConfigFor returns a tls.Config that will provide the transport level security defined +// by the provided Config. Will return nil if no transport level security is requested. +func TLSConfigFor(c *Config) (*tls.Config, error) { + if !(c.HasCA() || c.HasCertAuth() || c.TLS.Insecure) { + return nil, nil + } + if c.HasCA() && c.TLS.Insecure { + return nil, fmt.Errorf("specifying a root certificates file with the insecure flag is not allowed") + } + if err := loadTLSFiles(c); err != nil { + return nil, err + } + + tlsConfig := &tls.Config{ + // Can't use SSLv3 because of POODLE and BEAST + // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher + // Can't use TLSv1.1 because of RC4 cipher usage + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: c.TLS.Insecure, + } + + if c.HasCA() { + tlsConfig.RootCAs = rootCertPool(c.TLS.CAData) + } + + if c.HasCertAuth() { + cert, err := tls.X509KeyPair(c.TLS.CertData, c.TLS.KeyData) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + + return tlsConfig, nil +} + +// loadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData, +// KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are +// either populated or were empty to start. +func loadTLSFiles(c *Config) error { + var err error + c.TLS.CAData, err = dataFromSliceOrFile(c.TLS.CAData, c.TLS.CAFile) + if err != nil { + return err + } + + c.TLS.CertData, err = dataFromSliceOrFile(c.TLS.CertData, c.TLS.CertFile) + if err != nil { + return err + } + + c.TLS.KeyData, err = dataFromSliceOrFile(c.TLS.KeyData, c.TLS.KeyFile) + if err != nil { + return err + } + return nil +} + +// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file, +// or an error if an error occurred reading the file +func dataFromSliceOrFile(data []byte, file string) ([]byte, error) { + if len(data) > 0 { + return data, nil + } + if len(file) > 0 { + fileData, err := ioutil.ReadFile(file) + if err != nil { + return []byte{}, err + } + return fileData, nil + } + return nil, nil +} + +// rootCertPool returns nil if caData is empty. When passed along, this will mean "use system CAs". +// When caData is not empty, it will be the ONLY information used in the CertPool. +func rootCertPool(caData []byte) *x509.CertPool { + // What we really want is a copy of x509.systemRootsPool, but that isn't exposed. It's difficult to build (see the go + // code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values + // It doesn't allow trusting either/or, but hopefully that won't be an issue + if len(caData) == 0 { + return nil + } + + // if we have caData, use it + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(caData) + return certPool +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/typed/discovery/discovery_client.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/typed/discovery/discovery_client.go new file mode 100644 index 0000000..1bd18b9 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/typed/discovery/discovery_client.go @@ -0,0 +1,317 @@ +/* +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 discovery + +import ( + "encoding/json" + "fmt" + "net/url" + "strings" + + "github.com/emicklei/go-restful/swagger" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/runtime/serializer" + utilerrors "k8s.io/kubernetes/pkg/util/errors" + "k8s.io/kubernetes/pkg/version" +) + +// DiscoveryInterface holds the methods that discover server-supported API groups, +// versions and resources. +type DiscoveryInterface interface { + ServerGroupsInterface + ServerResourcesInterface + ServerVersionInterface + SwaggerSchemaInterface +} + +// ServerGroupsInterface has methods for obtaining supported groups on the API server +type ServerGroupsInterface interface { + // ServerGroups returns the supported groups, with information like supported versions and the + // preferred version. + ServerGroups() (*unversioned.APIGroupList, error) +} + +// ServerResourcesInterface has methods for obtaining supported resources on the API server +type ServerResourcesInterface interface { + // ServerResourcesForGroupVersion returns the supported resources for a group and version. + ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) + // ServerResources returns the supported resources for all groups and versions. + ServerResources() (map[string]*unversioned.APIResourceList, error) + // ServerPreferredResources returns the supported resources with the version preferred by the + // server. + ServerPreferredResources() ([]unversioned.GroupVersionResource, error) + // ServerPreferredNamespacedResources returns the supported namespaced resources with the + // version preferred by the server. + ServerPreferredNamespacedResources() ([]unversioned.GroupVersionResource, error) +} + +// ServerVersionInterface has a method for retrieving the server's version. +type ServerVersionInterface interface { + // ServerVersion retrieves and parses the server's version (git version). + ServerVersion() (*version.Info, error) +} + +// SwaggerSchemaInterface has a method to retrieve the swagger schema. +type SwaggerSchemaInterface interface { + // SwaggerSchema retrieves and parses the swagger API schema the server supports. + SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) +} + +// DiscoveryClient implements the functions that discover server-supported API groups, +// versions and resources. +type DiscoveryClient struct { + *restclient.RESTClient + + LegacyPrefix string +} + +// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so +// group would be "". +func apiVersionsToAPIGroup(apiVersions *unversioned.APIVersions) (apiGroup unversioned.APIGroup) { + groupVersions := []unversioned.GroupVersionForDiscovery{} + for _, version := range apiVersions.Versions { + groupVersion := unversioned.GroupVersionForDiscovery{ + GroupVersion: version, + Version: version, + } + groupVersions = append(groupVersions, groupVersion) + } + apiGroup.Versions = groupVersions + // There should be only one groupVersion returned at /api + apiGroup.PreferredVersion = groupVersions[0] + return +} + +// ServerGroups returns the supported groups, with information like supported versions and the +// preferred version. +func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList, err error) { + // Get the groupVersions exposed at /api + v := &unversioned.APIVersions{} + err = d.Get().AbsPath(d.LegacyPrefix).Do().Into(v) + apiGroup := unversioned.APIGroup{} + if err == nil { + apiGroup = apiVersionsToAPIGroup(v) + } + if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) { + return nil, err + } + + // Get the groupVersions exposed at /apis + apiGroupList = &unversioned.APIGroupList{} + err = d.Get().AbsPath("/apis").Do().Into(apiGroupList) + if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) { + return nil, err + } + // to be compatible with a v1.0 server, if it's a 403 or 404, ignore and return whatever we got from /api + if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) { + apiGroupList = &unversioned.APIGroupList{} + } + + // append the group retrieved from /api to the list + apiGroupList.Groups = append(apiGroupList.Groups, apiGroup) + return apiGroupList, nil +} + +// ServerResourcesForGroupVersion returns the supported resources for a group and version. +func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) { + url := url.URL{} + if len(groupVersion) == 0 { + return nil, fmt.Errorf("groupVersion shouldn't be empty") + } + if len(d.LegacyPrefix) > 0 && groupVersion == "v1" { + url.Path = d.LegacyPrefix + "/" + groupVersion + } else { + url.Path = "/apis/" + groupVersion + } + resources = &unversioned.APIResourceList{} + err = d.Get().AbsPath(url.String()).Do().Into(resources) + if err != nil { + // ignore 403 or 404 error to be compatible with an v1.0 server. + if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) { + return resources, nil + } else { + return nil, err + } + } + return resources, nil +} + +// ServerResources returns the supported resources for all groups and versions. +func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) { + apiGroups, err := d.ServerGroups() + if err != nil { + return nil, err + } + groupVersions := unversioned.ExtractGroupVersions(apiGroups) + result := map[string]*unversioned.APIResourceList{} + for _, groupVersion := range groupVersions { + resources, err := d.ServerResourcesForGroupVersion(groupVersion) + if err != nil { + return nil, err + } + result[groupVersion] = resources + } + return result, nil +} + +// serverPreferredResources returns the supported resources with the version preferred by the +// server. If namespaced is true, only namespaced resources will be returned. +func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) { + results := []unversioned.GroupVersionResource{} + serverGroupList, err := d.ServerGroups() + if err != nil { + return results, err + } + + allErrs := []error{} + for _, apiGroup := range serverGroupList.Groups { + preferredVersion := apiGroup.PreferredVersion + apiResourceList, err := d.ServerResourcesForGroupVersion(preferredVersion.GroupVersion) + if err != nil { + allErrs = append(allErrs, err) + continue + } + groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: preferredVersion.Version} + for _, apiResource := range apiResourceList.APIResources { + // ignore the root scoped resources if "namespaced" is true. + if namespaced && !apiResource.Namespaced { + continue + } + if strings.Contains(apiResource.Name, "/") { + continue + } + results = append(results, groupVersion.WithResource(apiResource.Name)) + } + } + return results, utilerrors.NewAggregate(allErrs) +} + +// ServerPreferredResources returns the supported resources with the version preferred by the +// server. +func (d *DiscoveryClient) ServerPreferredResources() ([]unversioned.GroupVersionResource, error) { + return d.serverPreferredResources(false) +} + +// ServerPreferredNamespacedResources returns the supported namespaced resources with the +// version preferred by the server. +func (d *DiscoveryClient) ServerPreferredNamespacedResources() ([]unversioned.GroupVersionResource, error) { + return d.serverPreferredResources(true) +} + +// ServerVersion retrieves and parses the server's version (git version). +func (d *DiscoveryClient) ServerVersion() (*version.Info, error) { + body, err := d.Get().AbsPath("/version").Do().Raw() + if err != nil { + return nil, err + } + var info version.Info + err = json.Unmarshal(body, &info) + if err != nil { + return nil, fmt.Errorf("got '%s': %v", string(body), err) + } + return &info, nil +} + +// SwaggerSchema retrieves and parses the swagger API schema the server supports. +func (d *DiscoveryClient) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) { + if version.IsEmpty() { + return nil, fmt.Errorf("groupVersion cannot be empty") + } + + groupList, err := d.ServerGroups() + if err != nil { + return nil, err + } + groupVersions := unversioned.ExtractGroupVersions(groupList) + // This check also takes care the case that kubectl is newer than the running endpoint + if stringDoesntExistIn(version.String(), groupVersions) { + return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions) + } + var path string + if len(d.LegacyPrefix) > 0 && version == v1.SchemeGroupVersion { + path = "/swaggerapi" + d.LegacyPrefix + "/" + version.Version + } else { + path = "/swaggerapi/apis/" + version.Group + "/" + version.Version + } + + body, err := d.Get().AbsPath(path).Do().Raw() + if err != nil { + return nil, err + } + var schema swagger.ApiDeclaration + err = json.Unmarshal(body, &schema) + if err != nil { + return nil, fmt.Errorf("got '%s': %v", string(body), err) + } + return &schema, nil +} + +func setDiscoveryDefaults(config *restclient.Config) error { + config.APIPath = "" + config.GroupVersion = nil + codec := runtime.NoopEncoder{Decoder: api.Codecs.UniversalDecoder()} + config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper( + runtime.SerializerInfo{Serializer: codec}, + runtime.StreamSerializerInfo{}, + ) + if len(config.UserAgent) == 0 { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + return nil +} + +// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. This client +// can be used to discover supported resources in the API server. +func NewDiscoveryClientForConfig(c *restclient.Config) (*DiscoveryClient, error) { + config := *c + if err := setDiscoveryDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.UnversionedRESTClientFor(&config) + return &DiscoveryClient{RESTClient: client, LegacyPrefix: "/api"}, err +} + +// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If +// there is an error, it panics. +func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient { + client, err := NewDiscoveryClientForConfig(c) + if err != nil { + panic(err) + } + return client + +} + +// New creates a new DiscoveryClient for the given RESTClient. +func NewDiscoveryClient(c *restclient.RESTClient) *DiscoveryClient { + return &DiscoveryClient{RESTClient: c, LegacyPrefix: "/api"} +} + +func stringDoesntExistIn(str string, slice []string) bool { + for _, s := range slice { + if s == str { + return false + } + } + return true +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/apps.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/apps.go new file mode 100644 index 0000000..f2498cb --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/apps.go @@ -0,0 +1,76 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type AppsInterface interface { + PetSetNamespacer +} + +// AppsClient is used to interact with Kubernetes batch features. +type AppsClient struct { + *restclient.RESTClient +} + +func (c *AppsClient) PetSets(namespace string) PetSetInterface { + return newPetSet(c, namespace) +} + +func NewApps(c *restclient.Config) (*AppsClient, error) { + config := *c + if err := setAppsDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &AppsClient{client}, nil +} + +func NewAppsOrDie(c *restclient.Config) *AppsClient { + client, err := NewApps(c) + if err != nil { + panic(err) + } + return client +} + +func setAppsDefaults(config *restclient.Config) error { + g, err := registered.Group(apps.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/auth/clientauth.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/auth/clientauth.go new file mode 100644 index 0000000..128597f --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/auth/clientauth.go @@ -0,0 +1,125 @@ +/* +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 auth defines a file format for holding authentication +information needed by clients of Kubernetes. Typically, +a Kubernetes cluster will put auth info for the admin in a known +location when it is created, and will (soon) put it in a known +location within a Container's file tree for Containers that +need access to the Kubernetes API. + +Having a defined format allows: + - clients to be implmented in multiple languages + - applications which link clients to be portable across + clusters with different authentication styles (e.g. + some may use SSL Client certs, others may not, etc) + - when the format changes, applications only + need to update this code. + +The file format is json, marshalled from a struct authcfg.Info. + +Clinet libraries in other languages should use the same format. + +It is not intended to store general preferences, such as default +namespace, output options, etc. CLIs (such as kubectl) and UIs should +develop their own format and may wish to inline the authcfg.Info type. + +The authcfg.Info is just a file format. It is distinct from +client.Config which holds options for creating a client.Client. +Helper functions are provided in this package to fill in a +client.Client from an authcfg.Info. + +Example: + + import ( + "pkg/client" + "pkg/client/auth" + ) + + info, err := auth.LoadFromFile(filename) + if err != nil { + // handle error + } + clientConfig = client.Config{} + clientConfig.Host = "example.com:4901" + clientConfig = info.MergeWithConfig() + client := client.New(clientConfig) + client.Pods(ns).List() +*/ +package auth + +// TODO: need a way to rotate Tokens. Therefore, need a way for client object to be reset when the authcfg is updated. +import ( + "encoding/json" + "io/ioutil" + "os" + + "k8s.io/kubernetes/pkg/client/restclient" +) + +// Info holds Kubernetes API authorization config. It is intended +// to be read/written from a file as a JSON object. +type Info struct { + User string + Password string + CAFile string + CertFile string + KeyFile string + BearerToken string + Insecure *bool +} + +// LoadFromFile parses an Info object from a file path. +// If the file does not exist, then os.IsNotExist(err) == true +func LoadFromFile(path string) (*Info, error) { + var info Info + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil, err + } + data, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + err = json.Unmarshal(data, &info) + if err != nil { + return nil, err + } + return &info, err +} + +// MergeWithConfig returns a copy of a client.Config with values from the Info. +// The fields of client.Config with a corresponding field in the Info are set +// with the value from the Info. +func (info Info) MergeWithConfig(c restclient.Config) (restclient.Config, error) { + var config restclient.Config = c + config.Username = info.User + config.Password = info.Password + config.CAFile = info.CAFile + config.CertFile = info.CertFile + config.KeyFile = info.KeyFile + config.BearerToken = info.BearerToken + if info.Insecure != nil { + config.Insecure = *info.Insecure + } + return config, nil +} + +func (info Info) Complete() bool { + return len(info.User) > 0 || + len(info.CertFile) > 0 || + len(info.BearerToken) > 0 +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/autoscaling.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/autoscaling.go new file mode 100644 index 0000000..188a5ea --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/autoscaling.go @@ -0,0 +1,77 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type AutoscalingInterface interface { + HorizontalPodAutoscalersNamespacer +} + +// AutoscalingClient is used to interact with Kubernetes autoscaling features. +type AutoscalingClient struct { + *restclient.RESTClient +} + +func (c *AutoscalingClient) HorizontalPodAutoscalers(namespace string) HorizontalPodAutoscalerInterface { + return newHorizontalPodAutoscalers(c, namespace) +} + +func NewAutoscaling(c *restclient.Config) (*AutoscalingClient, error) { + config := *c + if err := setAutoscalingDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &AutoscalingClient{client}, nil +} + +func NewAutoscalingOrDie(c *restclient.Config) *AutoscalingClient { + client, err := NewAutoscaling(c) + if err != nil { + panic(err) + } + return client +} + +func setAutoscalingDefaults(config *restclient.Config) error { + // if autoscaling group is not registered, return an error + g, err := registered.Group(autoscaling.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/batch.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/batch.go new file mode 100644 index 0000000..c31652f --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/batch.go @@ -0,0 +1,107 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/batch/v2alpha1" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type BatchInterface interface { + JobsNamespacer + ScheduledJobsNamespacer +} + +// BatchClient is used to interact with Kubernetes batch features. +type BatchClient struct { + *restclient.RESTClient +} + +func (c *BatchClient) Jobs(namespace string) JobInterface { + return newJobsV1(c, namespace) +} + +func (c *BatchClient) ScheduledJobs(namespace string) ScheduledJobInterface { + return newScheduledJobs(c, namespace) +} + +func NewBatch(c *restclient.Config) (*BatchClient, error) { + config := *c + if err := setBatchDefaults(&config, nil); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &BatchClient{client}, nil +} + +func NewBatchV2Alpha1(c *restclient.Config) (*BatchClient, error) { + config := *c + if err := setBatchDefaults(&config, &v2alpha1.SchemeGroupVersion); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &BatchClient{client}, nil +} + +func NewBatchOrDie(c *restclient.Config) *BatchClient { + var ( + client *BatchClient + err error + ) + if c.ContentConfig.GroupVersion != nil && *c.ContentConfig.GroupVersion == v2alpha1.SchemeGroupVersion { + client, err = NewBatchV2Alpha1(c) + } else { + client, err = NewBatch(c) + } + if err != nil { + panic(err) + } + return client +} + +func setBatchDefaults(config *restclient.Config, gv *unversioned.GroupVersion) error { + // if batch group is not registered, return an error + g, err := registered.Group(batch.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + if gv != nil { + copyGroupVersion = *gv + } + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificates.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificates.go new file mode 100644 index 0000000..29b15c4 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificates.go @@ -0,0 +1,86 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/certificates" + "k8s.io/kubernetes/pkg/client/restclient" +) + +// Interface holds the methods for clients of Kubernetes to allow mock testing. +type CertificatesInterface interface { + CertificateSigningRequests() CertificateSigningRequestInterface +} + +type CertificatesClient struct { + *restclient.RESTClient +} + +func (c *CertificatesClient) CertificateSigningRequests() CertificateSigningRequestInterface { + return newCertificateSigningRequests(c) +} + +// NewCertificates creates a new CertificatesClient for the given config. +func NewCertificates(c *restclient.Config) (*CertificatesClient, error) { + config := *c + if err := setCertificatesDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &CertificatesClient{client}, nil +} + +// NewCertificatesOrDie creates a new CertificatesClient for the given config and +// panics if there is an error in the config. +func NewCertificatesOrDie(c *restclient.Config) *CertificatesClient { + client, err := NewCertificates(c) + if err != nil { + panic(err) + } + return client +} + +func setCertificatesDefaults(config *restclient.Config) error { + // if certificates group is not registered, return an error + g, err := registered.Group(certificates.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificatesigningrequests.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificatesigningrequests.go new file mode 100644 index 0000000..f3ce09f --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/certificatesigningrequests.go @@ -0,0 +1,104 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/certificates" + "k8s.io/kubernetes/pkg/watch" +) + +// CertificateSigningRequestInterface has methods to work with CertificateSigningRequest resources. +type CertificateSigningRequestInterface interface { + List(opts api.ListOptions) (*certificates.CertificateSigningRequestList, error) + Get(name string) (*certificates.CertificateSigningRequest, error) + Delete(name string, options *api.DeleteOptions) error + Create(certificateSigningRequest *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) + Update(certificateSigningRequest *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) + UpdateStatus(certificateSigningRequest *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) + UpdateApproval(certificateSigningRequest *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// certificateSigningRequests implements CertificateSigningRequestsNamespacer interface +type certificateSigningRequests struct { + client *CertificatesClient +} + +// newCertificateSigningRequests returns a certificateSigningRequests +func newCertificateSigningRequests(c *CertificatesClient) *certificateSigningRequests { + return &certificateSigningRequests{ + client: c, + } +} + +// List takes label and field selectors, and returns the list of certificateSigningRequests that match those selectors. +func (c *certificateSigningRequests) List(opts api.ListOptions) (result *certificates.CertificateSigningRequestList, err error) { + result = &certificates.CertificateSigningRequestList{} + err = c.client.Get().Resource("certificatesigningrequests").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the certificateSigningRequest, and returns the corresponding CertificateSigningRequest object, and an error if it occurs +func (c *certificateSigningRequests) Get(name string) (result *certificates.CertificateSigningRequest, err error) { + result = &certificates.CertificateSigningRequest{} + err = c.client.Get().Resource("certificatesigningrequests").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the certificateSigningRequest and deletes it. Returns an error if one occurs. +func (c *certificateSigningRequests) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Resource("certificatesigningrequests").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a certificateSigningRequest and creates it. Returns the server's representation of the certificateSigningRequest, and an error, if it occurs. +func (c *certificateSigningRequests) Create(certificateSigningRequest *certificates.CertificateSigningRequest) (result *certificates.CertificateSigningRequest, err error) { + result = &certificates.CertificateSigningRequest{} + err = c.client.Post().Resource("certificatesigningrequests").Body(certificateSigningRequest).Do().Into(result) + return +} + +// Update takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if it occurs. +func (c *certificateSigningRequests) Update(certificateSigningRequest *certificates.CertificateSigningRequest) (result *certificates.CertificateSigningRequest, err error) { + result = &certificates.CertificateSigningRequest{} + err = c.client.Put().Resource("certificatesigningrequests").Name(certificateSigningRequest.Name).Body(certificateSigningRequest).Do().Into(result) + return +} + +// UpdateStatus takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if it occurs. +func (c *certificateSigningRequests) UpdateStatus(certificateSigningRequest *certificates.CertificateSigningRequest) (result *certificates.CertificateSigningRequest, err error) { + result = &certificates.CertificateSigningRequest{} + err = c.client.Put().Resource("certificatesigningrequests").Name(certificateSigningRequest.Name).SubResource("status").Body(certificateSigningRequest).Do().Into(result) + return +} + +// UpdateApproval takes the representation of a certificateSigningRequest and updates it. Returns the server's representation of the certificateSigningRequest, and an error, if it occurs. +func (c *certificateSigningRequests) UpdateApproval(certificateSigningRequest *certificates.CertificateSigningRequest) (result *certificates.CertificateSigningRequest, err error) { + result = &certificates.CertificateSigningRequest{} + err = c.client.Put().Resource("certificatesigningrequests").Name(certificateSigningRequest.Name).SubResource("approval").Body(certificateSigningRequest).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested certificateSigningRequests. +func (c *certificateSigningRequests) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(api.NamespaceAll). + Resource("certificatesigningrequests"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/client.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/client.go new file mode 100644 index 0000000..5474e96 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/client.go @@ -0,0 +1,179 @@ +/* +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 unversioned + +import ( + "net" + "net/url" + "strings" + + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/client/typed/discovery" +) + +// Interface holds the methods for clients of Kubernetes, +// an interface to allow mock testing. +type Interface interface { + PodsNamespacer + PodTemplatesNamespacer + ReplicationControllersNamespacer + ServicesNamespacer + EndpointsNamespacer + NodesInterface + EventNamespacer + LimitRangesNamespacer + ResourceQuotasNamespacer + ServiceAccountsNamespacer + SecretsNamespacer + NamespacesInterface + PersistentVolumesInterface + PersistentVolumeClaimsNamespacer + ComponentStatusesInterface + ConfigMapsNamespacer + Autoscaling() AutoscalingInterface + Batch() BatchInterface + Extensions() ExtensionsInterface + Rbac() RbacInterface + Discovery() discovery.DiscoveryInterface + Certificates() CertificatesInterface +} + +func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface { + return newReplicationControllers(c, namespace) +} + +func (c *Client) Nodes() NodeInterface { + return newNodes(c) +} + +func (c *Client) Events(namespace string) EventInterface { + return newEvents(c, namespace) +} + +func (c *Client) Endpoints(namespace string) EndpointsInterface { + return newEndpoints(c, namespace) +} + +func (c *Client) Pods(namespace string) PodInterface { + return newPods(c, namespace) +} + +func (c *Client) PodTemplates(namespace string) PodTemplateInterface { + return newPodTemplates(c, namespace) +} + +func (c *Client) Services(namespace string) ServiceInterface { + return newServices(c, namespace) +} +func (c *Client) LimitRanges(namespace string) LimitRangeInterface { + return newLimitRanges(c, namespace) +} + +func (c *Client) ResourceQuotas(namespace string) ResourceQuotaInterface { + return newResourceQuotas(c, namespace) +} + +func (c *Client) ServiceAccounts(namespace string) ServiceAccountsInterface { + return newServiceAccounts(c, namespace) +} + +func (c *Client) Secrets(namespace string) SecretsInterface { + return newSecrets(c, namespace) +} + +func (c *Client) Namespaces() NamespaceInterface { + return newNamespaces(c) +} + +func (c *Client) PersistentVolumes() PersistentVolumeInterface { + return newPersistentVolumes(c) +} + +func (c *Client) PersistentVolumeClaims(namespace string) PersistentVolumeClaimInterface { + return newPersistentVolumeClaims(c, namespace) +} + +func (c *Client) ComponentStatuses() ComponentStatusInterface { + return newComponentStatuses(c) +} + +func (c *Client) ConfigMaps(namespace string) ConfigMapsInterface { + return newConfigMaps(c, namespace) +} + +// Client is the implementation of a Kubernetes client. +type Client struct { + *restclient.RESTClient + *AutoscalingClient + *BatchClient + *ExtensionsClient + *AppsClient + *PolicyClient + *RbacClient + *discovery.DiscoveryClient + *CertificatesClient +} + +// IsTimeout tests if this is a timeout error in the underlying transport. +// This is unbelievably ugly. +// See: http://stackoverflow.com/questions/23494950/specifically-check-for-timeout-error for details +func IsTimeout(err error) bool { + if err == nil { + return false + } + switch err := err.(type) { + case *url.Error: + if err, ok := err.Err.(net.Error); ok { + return err.Timeout() + } + case net.Error: + return err.Timeout() + } + + if strings.Contains(err.Error(), "use of closed network connection") { + return true + } + return false +} + +func (c *Client) Autoscaling() AutoscalingInterface { + return c.AutoscalingClient +} + +func (c *Client) Batch() BatchInterface { + return c.BatchClient +} + +func (c *Client) Extensions() ExtensionsInterface { + return c.ExtensionsClient +} + +func (c *Client) Apps() AppsInterface { + return c.AppsClient +} + +func (c *Client) Rbac() RbacInterface { + return c.RbacClient +} + +func (c *Client) Discovery() discovery.DiscoveryInterface { + return c.DiscoveryClient +} + +func (c *Client) Certificates() CertificatesInterface { + return c.CertificatesClient +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/helpers.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/helpers.go new file mode 100644 index 0000000..43e2648 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/helpers.go @@ -0,0 +1,183 @@ +/* +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 api + +import ( + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" +) + +func init() { + sDec, _ := base64.StdEncoding.DecodeString("REDACTED+") + redactedBytes = []byte(string(sDec)) +} + +// IsConfigEmpty returns true if the config is empty. +func IsConfigEmpty(config *Config) bool { + return len(config.AuthInfos) == 0 && len(config.Clusters) == 0 && len(config.Contexts) == 0 && + len(config.CurrentContext) == 0 && + len(config.Preferences.Extensions) == 0 && !config.Preferences.Colors && + len(config.Extensions) == 0 +} + +// MinifyConfig read the current context and uses that to keep only the relevant pieces of config +// This is useful for making secrets based on kubeconfig files +func MinifyConfig(config *Config) error { + if len(config.CurrentContext) == 0 { + return errors.New("current-context must exist in order to minify") + } + + currContext, exists := config.Contexts[config.CurrentContext] + if !exists { + return fmt.Errorf("cannot locate context %v", config.CurrentContext) + } + + newContexts := map[string]*Context{} + newContexts[config.CurrentContext] = currContext + + newClusters := map[string]*Cluster{} + if len(currContext.Cluster) > 0 { + if _, exists := config.Clusters[currContext.Cluster]; !exists { + return fmt.Errorf("cannot locate cluster %v", currContext.Cluster) + } + + newClusters[currContext.Cluster] = config.Clusters[currContext.Cluster] + } + + newAuthInfos := map[string]*AuthInfo{} + if len(currContext.AuthInfo) > 0 { + if _, exists := config.AuthInfos[currContext.AuthInfo]; !exists { + return fmt.Errorf("cannot locate user %v", currContext.AuthInfo) + } + + newAuthInfos[currContext.AuthInfo] = config.AuthInfos[currContext.AuthInfo] + } + + config.AuthInfos = newAuthInfos + config.Clusters = newClusters + config.Contexts = newContexts + + return nil +} + +var redactedBytes []byte + +// Flatten redacts raw data entries from the config object for a human-readable view. +func ShortenConfig(config *Config) { + // trick json encoder into printing a human readable string in the raw data + // by base64 decoding what we want to print. Relies on implementation of + // http://golang.org/pkg/encoding/json/#Marshal using base64 to encode []byte + for key, authInfo := range config.AuthInfos { + if len(authInfo.ClientKeyData) > 0 { + authInfo.ClientKeyData = redactedBytes + } + if len(authInfo.ClientCertificateData) > 0 { + authInfo.ClientCertificateData = redactedBytes + } + config.AuthInfos[key] = authInfo + } + for key, cluster := range config.Clusters { + if len(cluster.CertificateAuthorityData) > 0 { + cluster.CertificateAuthorityData = redactedBytes + } + config.Clusters[key] = cluster + } +} + +// Flatten changes the config object into a self contained config (useful for making secrets) +func FlattenConfig(config *Config) error { + for key, authInfo := range config.AuthInfos { + baseDir, err := MakeAbs(path.Dir(authInfo.LocationOfOrigin), "") + if err != nil { + return err + } + + if err := FlattenContent(&authInfo.ClientCertificate, &authInfo.ClientCertificateData, baseDir); err != nil { + return err + } + if err := FlattenContent(&authInfo.ClientKey, &authInfo.ClientKeyData, baseDir); err != nil { + return err + } + + config.AuthInfos[key] = authInfo + } + for key, cluster := range config.Clusters { + baseDir, err := MakeAbs(path.Dir(cluster.LocationOfOrigin), "") + if err != nil { + return err + } + + if err := FlattenContent(&cluster.CertificateAuthority, &cluster.CertificateAuthorityData, baseDir); err != nil { + return err + } + + config.Clusters[key] = cluster + } + + return nil +} + +func FlattenContent(path *string, contents *[]byte, baseDir string) error { + if len(*path) != 0 { + if len(*contents) > 0 { + return errors.New("cannot have values for both path and contents") + } + + var err error + absPath := ResolvePath(*path, baseDir) + *contents, err = ioutil.ReadFile(absPath) + if err != nil { + return err + } + + *path = "" + } + + return nil +} + +// ResolvePath returns the path as an absolute paths, relative to the given base directory +func ResolvePath(path string, base string) string { + // Don't resolve empty paths + if len(path) > 0 { + // Don't resolve absolute paths + if !filepath.IsAbs(path) { + return filepath.Join(base, path) + } + } + + return path +} + +func MakeAbs(path, base string) (string, error) { + if filepath.IsAbs(path) { + return path, nil + } + if len(base) == 0 { + cwd, err := os.Getwd() + if err != nil { + return "", err + } + base = cwd + } + return filepath.Join(base, path), nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest/latest.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest/latest.go new file mode 100644 index 0000000..0b9a427 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest/latest.go @@ -0,0 +1,54 @@ +/* +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 latest + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" + _ "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/runtime/serializer/json" + "k8s.io/kubernetes/pkg/runtime/serializer/versioning" +) + +// Version is the string that represents the current external default version. +const Version = "v1" + +var ExternalVersion = unversioned.GroupVersion{Group: "", Version: "v1"} + +// OldestVersion is the string that represents the oldest server version supported, +// for client code that wants to hardcode the lowest common denominator. +const OldestVersion = "v1" + +// Versions is the list of versions that are recognized in code. The order provided +// may be assumed to be least feature rich to most feature rich, and clients may +// choose to prefer the latter items in the list over the former items when presented +// with a set of versions to choose. +var Versions = []string{"v1"} + +var Codec runtime.Codec + +func init() { + yamlSerializer := json.NewYAMLSerializer(json.DefaultMetaFactory, api.Scheme, api.Scheme) + Codec = versioning.NewCodecForScheme( + api.Scheme, + yamlSerializer, + yamlSerializer, + []unversioned.GroupVersion{{Version: Version}}, + []unversioned.GroupVersion{{Version: runtime.APIVersionInternal}}, + ) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/register.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/register.go new file mode 100644 index 0000000..5426e7f --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/register.go @@ -0,0 +1,43 @@ +/* +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 api + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" +) + +// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered. +var Scheme = runtime.NewScheme() + +// SchemeGroupVersion is group version used to register these objects +// TODO this should be in the "kubeconfig" group +var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: runtime.APIVersionInternal} + +func init() { + Scheme.AddKnownTypes(SchemeGroupVersion, + &Config{}, + ) +} + +func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj } +func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { + obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() +} +func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind { + return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/types.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/types.go new file mode 100644 index 0000000..95b5289 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/types.go @@ -0,0 +1,152 @@ +/* +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 api + +import ( + "k8s.io/kubernetes/pkg/runtime" +) + +// Where possible, json tags match the cli argument names. +// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. + +// Config holds the information needed to build connect to remote kubernetes clusters as a given user +// IMPORTANT if you add fields to this struct, please update IsConfigEmpty() +type Config struct { + // Legacy field from pkg/api/types.go TypeMeta. + // TODO(jlowdermilk): remove this after eliminating downstream dependencies. + Kind string `json:"kind,omitempty"` + // DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc). + // Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify + // a single value for the cluster version. + // This field isn't really needed anyway, so we are deprecating it without replacement. + // It will be ignored if it is present. + APIVersion string `json:"apiVersion,omitempty"` + // Preferences holds general information to be use for cli interactions + Preferences Preferences `json:"preferences"` + // Clusters is a map of referencable names to cluster configs + Clusters map[string]*Cluster `json:"clusters"` + // AuthInfos is a map of referencable names to user configs + AuthInfos map[string]*AuthInfo `json:"users"` + // Contexts is a map of referencable names to context configs + Contexts map[string]*Context `json:"contexts"` + // CurrentContext is the name of the context that you would like to use by default + CurrentContext string `json:"current-context"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions map[string]runtime.Object `json:"extensions,omitempty"` +} + +// IMPORTANT if you add fields to this struct, please update IsConfigEmpty() +type Preferences struct { + Colors bool `json:"colors,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions map[string]runtime.Object `json:"extensions,omitempty"` +} + +// Cluster contains information about how to communicate with a kubernetes cluster +type Cluster struct { + // LocationOfOrigin indicates where this object came from. It is used for round tripping config post-merge, but never serialized. + LocationOfOrigin string + // Server is the address of the kubernetes cluster (https://hostname:port). + Server string `json:"server"` + // APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc). + APIVersion string `json:"api-version,omitempty"` + // InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure. + InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"` + // CertificateAuthority is the path to a cert file for the certificate authority. + CertificateAuthority string `json:"certificate-authority,omitempty"` + // CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority + CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions map[string]runtime.Object `json:"extensions,omitempty"` +} + +// AuthInfo contains information that describes identity information. This is use to tell the kubernetes cluster who you are. +type AuthInfo struct { + // LocationOfOrigin indicates where this object came from. It is used for round tripping config post-merge, but never serialized. + LocationOfOrigin string + // ClientCertificate is the path to a client cert file for TLS. + ClientCertificate string `json:"client-certificate,omitempty"` + // ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate + ClientCertificateData []byte `json:"client-certificate-data,omitempty"` + // ClientKey is the path to a client key file for TLS. + ClientKey string `json:"client-key,omitempty"` + // ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey + ClientKeyData []byte `json:"client-key-data,omitempty"` + // Token is the bearer token for authentication to the kubernetes cluster. + Token string `json:"token,omitempty"` + // Impersonate is the username to act-as. + Impersonate string `json:"act-as,omitempty"` + // Username is the username for basic authentication to the kubernetes cluster. + Username string `json:"username,omitempty"` + // Password is the password for basic authentication to the kubernetes cluster. + Password string `json:"password,omitempty"` + // AuthProvider specifies a custom authentication plugin for the kubernetes cluster. + AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions map[string]runtime.Object `json:"extensions,omitempty"` +} + +// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with) +type Context struct { + // LocationOfOrigin indicates where this object came from. It is used for round tripping config post-merge, but never serialized. + LocationOfOrigin string + // Cluster is the name of the cluster for this context + Cluster string `json:"cluster"` + // AuthInfo is the name of the authInfo for this context + AuthInfo string `json:"user"` + // Namespace is the default namespace to use on unspecified requests + Namespace string `json:"namespace,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions map[string]runtime.Object `json:"extensions,omitempty"` +} + +// AuthProviderConfig holds the configuration for a specified auth provider. +type AuthProviderConfig struct { + Name string `json:"name"` + Config map[string]string `json:"config,omitempty"` +} + +// NewConfig is a convenience function that returns a new Config object with non-nil maps +func NewConfig() *Config { + return &Config{ + Preferences: *NewPreferences(), + Clusters: make(map[string]*Cluster), + AuthInfos: make(map[string]*AuthInfo), + Contexts: make(map[string]*Context), + Extensions: make(map[string]runtime.Object), + } +} + +// NewConfig is a convenience function that returns a new Config object with non-nil maps +func NewContext() *Context { + return &Context{Extensions: make(map[string]runtime.Object)} +} + +// NewConfig is a convenience function that returns a new Config object with non-nil maps +func NewCluster() *Cluster { + return &Cluster{Extensions: make(map[string]runtime.Object)} +} + +// NewConfig is a convenience function that returns a new Config object with non-nil maps +func NewAuthInfo() *AuthInfo { + return &AuthInfo{Extensions: make(map[string]runtime.Object)} +} + +// NewConfig is a convenience function that returns a new Config object with non-nil maps +func NewPreferences() *Preferences { + return &Preferences{Extensions: make(map[string]runtime.Object)} +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/conversion.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/conversion.go new file mode 100644 index 0000000..e22e5f8 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/conversion.go @@ -0,0 +1,231 @@ +/* +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 v1 + +import ( + "sort" + + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" + "k8s.io/kubernetes/pkg/conversion" + "k8s.io/kubernetes/pkg/runtime" +) + +func init() { + err := api.Scheme.AddConversionFuncs( + func(in *Cluster, out *api.Cluster, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *api.Cluster, out *Cluster, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *Preferences, out *api.Preferences, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *api.Preferences, out *Preferences, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *AuthInfo, out *api.AuthInfo, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *api.AuthInfo, out *AuthInfo, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *Context, out *api.Context, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + func(in *api.Context, out *Context, s conversion.Scope) error { + return s.DefaultConvert(in, out, conversion.IgnoreMissingFields) + }, + + func(in *Config, out *api.Config, s conversion.Scope) error { + out.CurrentContext = in.CurrentContext + if err := s.Convert(&in.Preferences, &out.Preferences, 0); err != nil { + return err + } + + out.Clusters = make(map[string]*api.Cluster) + if err := s.Convert(&in.Clusters, &out.Clusters, 0); err != nil { + return err + } + out.AuthInfos = make(map[string]*api.AuthInfo) + if err := s.Convert(&in.AuthInfos, &out.AuthInfos, 0); err != nil { + return err + } + out.Contexts = make(map[string]*api.Context) + if err := s.Convert(&in.Contexts, &out.Contexts, 0); err != nil { + return err + } + out.Extensions = make(map[string]runtime.Object) + if err := s.Convert(&in.Extensions, &out.Extensions, 0); err != nil { + return err + } + return nil + }, + func(in *api.Config, out *Config, s conversion.Scope) error { + out.CurrentContext = in.CurrentContext + if err := s.Convert(&in.Preferences, &out.Preferences, 0); err != nil { + return err + } + + out.Clusters = make([]NamedCluster, 0, 0) + if err := s.Convert(&in.Clusters, &out.Clusters, 0); err != nil { + return err + } + out.AuthInfos = make([]NamedAuthInfo, 0, 0) + if err := s.Convert(&in.AuthInfos, &out.AuthInfos, 0); err != nil { + return err + } + out.Contexts = make([]NamedContext, 0, 0) + if err := s.Convert(&in.Contexts, &out.Contexts, 0); err != nil { + return err + } + out.Extensions = make([]NamedExtension, 0, 0) + if err := s.Convert(&in.Extensions, &out.Extensions, 0); err != nil { + return err + } + return nil + }, + func(in *[]NamedCluster, out *map[string]*api.Cluster, s conversion.Scope) error { + for _, curr := range *in { + newCluster := api.NewCluster() + if err := s.Convert(&curr.Cluster, newCluster, 0); err != nil { + return err + } + (*out)[curr.Name] = newCluster + } + + return nil + }, + func(in *map[string]*api.Cluster, out *[]NamedCluster, s conversion.Scope) error { + allKeys := make([]string, 0, len(*in)) + for key := range *in { + allKeys = append(allKeys, key) + } + sort.Strings(allKeys) + + for _, key := range allKeys { + newCluster := (*in)[key] + oldCluster := &Cluster{} + if err := s.Convert(newCluster, oldCluster, 0); err != nil { + return err + } + + namedCluster := NamedCluster{key, *oldCluster} + *out = append(*out, namedCluster) + } + + return nil + }, + func(in *[]NamedAuthInfo, out *map[string]*api.AuthInfo, s conversion.Scope) error { + for _, curr := range *in { + newAuthInfo := api.NewAuthInfo() + if err := s.Convert(&curr.AuthInfo, newAuthInfo, 0); err != nil { + return err + } + (*out)[curr.Name] = newAuthInfo + } + + return nil + }, + func(in *map[string]*api.AuthInfo, out *[]NamedAuthInfo, s conversion.Scope) error { + allKeys := make([]string, 0, len(*in)) + for key := range *in { + allKeys = append(allKeys, key) + } + sort.Strings(allKeys) + + for _, key := range allKeys { + newAuthInfo := (*in)[key] + oldAuthInfo := &AuthInfo{} + if err := s.Convert(newAuthInfo, oldAuthInfo, 0); err != nil { + return err + } + + namedAuthInfo := NamedAuthInfo{key, *oldAuthInfo} + *out = append(*out, namedAuthInfo) + } + + return nil + }, + func(in *[]NamedContext, out *map[string]*api.Context, s conversion.Scope) error { + for _, curr := range *in { + newContext := api.NewContext() + if err := s.Convert(&curr.Context, newContext, 0); err != nil { + return err + } + (*out)[curr.Name] = newContext + } + + return nil + }, + func(in *map[string]*api.Context, out *[]NamedContext, s conversion.Scope) error { + allKeys := make([]string, 0, len(*in)) + for key := range *in { + allKeys = append(allKeys, key) + } + sort.Strings(allKeys) + + for _, key := range allKeys { + newContext := (*in)[key] + oldContext := &Context{} + if err := s.Convert(newContext, oldContext, 0); err != nil { + return err + } + + namedContext := NamedContext{key, *oldContext} + *out = append(*out, namedContext) + } + + return nil + }, + func(in *[]NamedExtension, out *map[string]runtime.Object, s conversion.Scope) error { + for _, curr := range *in { + var newExtension runtime.Object + if err := s.Convert(&curr.Extension, &newExtension, 0); err != nil { + return err + } + (*out)[curr.Name] = newExtension + } + + return nil + }, + func(in *map[string]runtime.Object, out *[]NamedExtension, s conversion.Scope) error { + allKeys := make([]string, 0, len(*in)) + for key := range *in { + allKeys = append(allKeys, key) + } + sort.Strings(allKeys) + + for _, key := range allKeys { + newExtension := (*in)[key] + oldExtension := &runtime.RawExtension{} + if err := s.Convert(newExtension, oldExtension, 0); err != nil { + return err + } + + namedExtension := NamedExtension{key, *oldExtension} + *out = append(*out, namedExtension) + } + + return nil + }, + ) + if err != nil { + // If one of the conversion functions is malformed, detect it immediately. + panic(err) + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/register.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/register.go new file mode 100644 index 0000000..dcdb533 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/register.go @@ -0,0 +1,40 @@ +/* +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 v1 + +import ( + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +// SchemeGroupVersion is group version used to register these objects +// TODO this should be in the "kubeconfig" group +var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: "v1"} + +func init() { + api.Scheme.AddKnownTypes(SchemeGroupVersion, + &Config{}, + ) +} + +func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj } +func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { + obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() +} +func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind { + return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/types.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/types.go new file mode 100644 index 0000000..77bce80 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1/types.go @@ -0,0 +1,145 @@ +/* +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 v1 + +import ( + "k8s.io/kubernetes/pkg/runtime" +) + +// Where possible, json tags match the cli argument names. +// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. + +// Config holds the information needed to build connect to remote kubernetes clusters as a given user +type Config struct { + // Legacy field from pkg/api/types.go TypeMeta. + // TODO(jlowdermilk): remove this after eliminating downstream dependencies. + Kind string `json:"kind,omitempty"` + // DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc). + // Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify + // a single value for the cluster version. + // This field isn't really needed anyway, so we are deprecating it without replacement. + // It will be ignored if it is present. + APIVersion string `json:"apiVersion,omitempty"` + // Preferences holds general information to be use for cli interactions + Preferences Preferences `json:"preferences"` + // Clusters is a map of referencable names to cluster configs + Clusters []NamedCluster `json:"clusters"` + // AuthInfos is a map of referencable names to user configs + AuthInfos []NamedAuthInfo `json:"users"` + // Contexts is a map of referencable names to context configs + Contexts []NamedContext `json:"contexts"` + // CurrentContext is the name of the context that you would like to use by default + CurrentContext string `json:"current-context"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions []NamedExtension `json:"extensions,omitempty"` +} + +type Preferences struct { + Colors bool `json:"colors,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions []NamedExtension `json:"extensions,omitempty"` +} + +// Cluster contains information about how to communicate with a kubernetes cluster +type Cluster struct { + // Server is the address of the kubernetes cluster (https://hostname:port). + Server string `json:"server"` + // APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc). + APIVersion string `json:"api-version,omitempty"` + // InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure. + InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"` + // CertificateAuthority is the path to a cert file for the certificate authority. + CertificateAuthority string `json:"certificate-authority,omitempty"` + // CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority + CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions []NamedExtension `json:"extensions,omitempty"` +} + +// AuthInfo contains information that describes identity information. This is use to tell the kubernetes cluster who you are. +type AuthInfo struct { + // ClientCertificate is the path to a client cert file for TLS. + ClientCertificate string `json:"client-certificate,omitempty"` + // ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate + ClientCertificateData []byte `json:"client-certificate-data,omitempty"` + // ClientKey is the path to a client key file for TLS. + ClientKey string `json:"client-key,omitempty"` + // ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey + ClientKeyData []byte `json:"client-key-data,omitempty"` + // Token is the bearer token for authentication to the kubernetes cluster. + Token string `json:"token,omitempty"` + // Impersonate is the username to imperonate. The name matches the flag. + Impersonate string `json:"as,omitempty"` + // Username is the username for basic authentication to the kubernetes cluster. + Username string `json:"username,omitempty"` + // Password is the password for basic authentication to the kubernetes cluster. + Password string `json:"password,omitempty"` + // AuthProvider specifies a custom authentication plugin for the kubernetes cluster. + AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions []NamedExtension `json:"extensions,omitempty"` +} + +// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with) +type Context struct { + // Cluster is the name of the cluster for this context + Cluster string `json:"cluster"` + // AuthInfo is the name of the authInfo for this context + AuthInfo string `json:"user"` + // Namespace is the default namespace to use on unspecified requests + Namespace string `json:"namespace,omitempty"` + // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields + Extensions []NamedExtension `json:"extensions,omitempty"` +} + +// NamedCluster relates nicknames to cluster information +type NamedCluster struct { + // Name is the nickname for this Cluster + Name string `json:"name"` + // Cluster holds the cluster information + Cluster Cluster `json:"cluster"` +} + +// NamedContext relates nicknames to context information +type NamedContext struct { + // Name is the nickname for this Context + Name string `json:"name"` + // Context holds the context information + Context Context `json:"context"` +} + +// NamedAuthInfo relates nicknames to auth information +type NamedAuthInfo struct { + // Name is the nickname for this AuthInfo + Name string `json:"name"` + // AuthInfo holds the auth information + AuthInfo AuthInfo `json:"user"` +} + +// NamedExtension relates nicknames to extension information +type NamedExtension struct { + // Name is the nickname for this Extension + Name string `json:"name"` + // Extension holds the extension information + Extension runtime.RawExtension `json:"extension"` +} + +// AuthProviderConfig holds the configuration for a specified auth provider. +type AuthProviderConfig struct { + Name string `json:"name"` + Config map[string]string `json:"config"` +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/auth_loaders.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/auth_loaders.go new file mode 100644 index 0000000..0abc425 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/auth_loaders.go @@ -0,0 +1,91 @@ +/* +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 clientcmd + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + + clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth" +) + +// AuthLoaders are used to build clientauth.Info objects. +type AuthLoader interface { + // LoadAuth takes a path to a config file and can then do anything it needs in order to return a valid clientauth.Info + LoadAuth(path string) (*clientauth.Info, error) +} + +// default implementation of an AuthLoader +type defaultAuthLoader struct{} + +// LoadAuth for defaultAuthLoader simply delegates to clientauth.LoadFromFile +func (*defaultAuthLoader) LoadAuth(path string) (*clientauth.Info, error) { + return clientauth.LoadFromFile(path) +} + +type PromptingAuthLoader struct { + reader io.Reader +} + +// LoadAuth parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist. +func (a *PromptingAuthLoader) LoadAuth(path string) (*clientauth.Info, error) { + var auth clientauth.Info + // Prompt for user/pass and write a file if none exists. + if _, err := os.Stat(path); os.IsNotExist(err) { + auth = *a.Prompt() + data, err := json.Marshal(auth) + if err != nil { + return &auth, err + } + err = ioutil.WriteFile(path, data, 0600) + return &auth, err + } + authPtr, err := clientauth.LoadFromFile(path) + if err != nil { + return nil, err + } + return authPtr, nil +} + +// Prompt pulls the user and password from a reader +func (a *PromptingAuthLoader) Prompt() *clientauth.Info { + auth := &clientauth.Info{} + auth.User = promptForString("Username", a.reader) + auth.Password = promptForString("Password", a.reader) + + return auth +} + +func promptForString(field string, r io.Reader) string { + fmt.Printf("Please enter %s: ", field) + var result string + fmt.Fscan(r, &result) + return result +} + +// NewPromptingAuthLoader is an AuthLoader that parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist. +func NewPromptingAuthLoader(reader io.Reader) *PromptingAuthLoader { + return &PromptingAuthLoader{reader} +} + +// NewDefaultAuthLoader returns a default implementation of an AuthLoader that only reads from a config file +func NewDefaultAuthLoader() AuthLoader { + return &defaultAuthLoader{} +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/client_config.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/client_config.go new file mode 100644 index 0000000..47b14e2 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/client_config.go @@ -0,0 +1,411 @@ +/* +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 clientcmd + +import ( + "fmt" + "io" + "io/ioutil" + "net/url" + "os" + "strings" + + "github.com/golang/glog" + "github.com/imdario/mergo" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/restclient" + clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +var ( + // DefaultCluster is the cluster config used when no other config is specified + // TODO: eventually apiserver should start on 443 and be secure by default + DefaultCluster = clientcmdapi.Cluster{Server: "http://localhost:8080"} + + // EnvVarCluster allows overriding the DefaultCluster using an envvar for the server name + EnvVarCluster = clientcmdapi.Cluster{Server: os.Getenv("KUBERNETES_MASTER")} + + DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{}, nil, NewDefaultClientConfigLoadingRules()} +) + +// ClientConfig is used to make it easy to get an api server client +type ClientConfig interface { + // RawConfig returns the merged result of all overrides + RawConfig() (clientcmdapi.Config, error) + // ClientConfig returns a complete client config + ClientConfig() (*restclient.Config, error) + // Namespace returns the namespace resulting from the merged + // result of all overrides and a boolean indicating if it was + // overridden + Namespace() (string, bool, error) + // ConfigAccess returns the rules for loading/persisting the config. + ConfigAccess() ConfigAccess +} + +type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister + +// DirectClientConfig is a ClientConfig interface that is backed by a clientcmdapi.Config, options overrides, and an optional fallbackReader for auth information +type DirectClientConfig struct { + config clientcmdapi.Config + contextName string + overrides *ConfigOverrides + fallbackReader io.Reader + configAccess ConfigAccess +} + +// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name +func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig { + return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules()} +} + +// NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information +func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig { + return &DirectClientConfig{config, contextName, overrides, nil, configAccess} +} + +// NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags +func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig { + return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess} +} + +func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) { + return config.config, nil +} + +// ClientConfig implements ClientConfig +func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) { + if err := config.ConfirmUsable(); err != nil { + return nil, err + } + + configAuthInfo := config.getAuthInfo() + configClusterInfo := config.getCluster() + + clientConfig := &restclient.Config{} + clientConfig.Host = configClusterInfo.Server + if u, err := url.ParseRequestURI(clientConfig.Host); err == nil && u.Opaque == "" && len(u.Path) > 1 { + u.RawQuery = "" + u.Fragment = "" + clientConfig.Host = u.String() + } + if len(configAuthInfo.Impersonate) > 0 { + clientConfig.Impersonate = configAuthInfo.Impersonate + } + + // only try to read the auth information if we are secure + if restclient.IsConfigTransportTLS(*clientConfig) { + var err error + + // mergo is a first write wins for map value and a last writing wins for interface values + // NOTE: This behavior changed with https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a. + // Our mergo.Merge version is older than this change. + var persister restclient.AuthProviderConfigPersister + if config.configAccess != nil { + persister = PersisterForUser(config.configAccess, config.getAuthInfoName()) + } + userAuthPartialConfig, err := getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader, persister) + if err != nil { + return nil, err + } + mergo.Merge(clientConfig, userAuthPartialConfig) + + serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo) + if err != nil { + return nil, err + } + mergo.Merge(clientConfig, serverAuthPartialConfig) + } + + return clientConfig, nil +} + +// clientauth.Info object contain both user identification and server identification. We want different precedence orders for +// both, so we have to split the objects and merge them separately +// we want this order of precedence for the server identification +// 1. configClusterInfo (the final result of command line flags and merged .kubeconfig files) +// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority) +// 3. load the ~/.kubernetes_auth file as a default +func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) { + mergedConfig := &restclient.Config{} + + // configClusterInfo holds the information identify the server provided by .kubeconfig + configClientConfig := &restclient.Config{} + configClientConfig.CAFile = configClusterInfo.CertificateAuthority + configClientConfig.CAData = configClusterInfo.CertificateAuthorityData + configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify + mergo.Merge(mergedConfig, configClientConfig) + + return mergedConfig, nil +} + +// clientauth.Info object contain both user identification and server identification. We want different precedence orders for +// both, so we have to split the objects and merge them separately +// we want this order of precedence for user identifcation +// 1. configAuthInfo minus auth-path (the final result of command line flags and merged .kubeconfig files) +// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority) +// 3. if there is not enough information to idenfity the user, load try the ~/.kubernetes_auth file +// 4. if there is not enough information to identify the user, prompt if possible +func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig restclient.AuthProviderConfigPersister) (*restclient.Config, error) { + mergedConfig := &restclient.Config{} + + // blindly overwrite existing values based on precedence + if len(configAuthInfo.Token) > 0 { + mergedConfig.BearerToken = configAuthInfo.Token + } + if len(configAuthInfo.Impersonate) > 0 { + mergedConfig.Impersonate = configAuthInfo.Impersonate + } + if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 { + mergedConfig.CertFile = configAuthInfo.ClientCertificate + mergedConfig.CertData = configAuthInfo.ClientCertificateData + mergedConfig.KeyFile = configAuthInfo.ClientKey + mergedConfig.KeyData = configAuthInfo.ClientKeyData + } + if len(configAuthInfo.Username) > 0 || len(configAuthInfo.Password) > 0 { + mergedConfig.Username = configAuthInfo.Username + mergedConfig.Password = configAuthInfo.Password + } + if configAuthInfo.AuthProvider != nil { + mergedConfig.AuthProvider = configAuthInfo.AuthProvider + mergedConfig.AuthConfigPersister = persistAuthConfig + } + + // if there still isn't enough information to authenticate the user, try prompting + if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) { + prompter := NewPromptingAuthLoader(fallbackReader) + promptedAuthInfo := prompter.Prompt() + + promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo) + previouslyMergedConfig := mergedConfig + mergedConfig = &restclient.Config{} + mergo.Merge(mergedConfig, promptedConfig) + mergo.Merge(mergedConfig, previouslyMergedConfig) + } + + return mergedConfig, nil +} + +// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information +func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config { + config := &restclient.Config{} + config.Username = info.User + config.Password = info.Password + config.CertFile = info.CertFile + config.KeyFile = info.KeyFile + config.BearerToken = info.BearerToken + return config +} + +// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information +func makeServerIdentificationConfig(info clientauth.Info) restclient.Config { + config := restclient.Config{} + config.CAFile = info.CAFile + if info.Insecure != nil { + config.Insecure = *info.Insecure + } + return config +} + +func canIdentifyUser(config restclient.Config) bool { + return len(config.Username) > 0 || + (len(config.CertFile) > 0 || len(config.CertData) > 0) || + len(config.BearerToken) > 0 || + config.AuthProvider != nil +} + +// Namespace implements ClientConfig +func (config *DirectClientConfig) Namespace() (string, bool, error) { + if err := config.ConfirmUsable(); err != nil { + return "", false, err + } + + configContext := config.getContext() + + if len(configContext.Namespace) == 0 { + return api.NamespaceDefault, false, nil + } + + overridden := false + if config.overrides != nil && config.overrides.Context.Namespace != "" { + overridden = true + } + return configContext.Namespace, overridden, nil +} + +// ConfigAccess implements ClientConfig +func (config *DirectClientConfig) ConfigAccess() ConfigAccess { + return config.configAccess +} + +// ConfirmUsable looks a particular context and determines if that particular part of the config is useable. There might still be errors in the config, +// but no errors in the sections requested or referenced. It does not return early so that it can find as many errors as possible. +func (config *DirectClientConfig) ConfirmUsable() error { + validationErrors := make([]error, 0) + validationErrors = append(validationErrors, validateAuthInfo(config.getAuthInfoName(), config.getAuthInfo())...) + validationErrors = append(validationErrors, validateClusterInfo(config.getClusterName(), config.getCluster())...) + // when direct client config is specified, and our only error is that no server is defined, we should + // return a standard "no config" error + if len(validationErrors) == 1 && validationErrors[0] == ErrEmptyCluster { + return newErrConfigurationInvalid([]error{ErrEmptyConfig}) + } + return newErrConfigurationInvalid(validationErrors) +} + +func (config *DirectClientConfig) getContextName() string { + if len(config.overrides.CurrentContext) != 0 { + return config.overrides.CurrentContext + } + if len(config.contextName) != 0 { + return config.contextName + } + + return config.config.CurrentContext +} + +func (config *DirectClientConfig) getAuthInfoName() string { + if len(config.overrides.Context.AuthInfo) != 0 { + return config.overrides.Context.AuthInfo + } + return config.getContext().AuthInfo +} + +func (config *DirectClientConfig) getClusterName() string { + if len(config.overrides.Context.Cluster) != 0 { + return config.overrides.Context.Cluster + } + return config.getContext().Cluster +} + +func (config *DirectClientConfig) getContext() clientcmdapi.Context { + contexts := config.config.Contexts + contextName := config.getContextName() + + var mergedContext clientcmdapi.Context + if configContext, exists := contexts[contextName]; exists { + mergo.Merge(&mergedContext, configContext) + } + mergo.Merge(&mergedContext, config.overrides.Context) + + return mergedContext +} + +func (config *DirectClientConfig) getAuthInfo() clientcmdapi.AuthInfo { + authInfos := config.config.AuthInfos + authInfoName := config.getAuthInfoName() + + var mergedAuthInfo clientcmdapi.AuthInfo + if configAuthInfo, exists := authInfos[authInfoName]; exists { + mergo.Merge(&mergedAuthInfo, configAuthInfo) + } + mergo.Merge(&mergedAuthInfo, config.overrides.AuthInfo) + + return mergedAuthInfo +} + +func (config *DirectClientConfig) getCluster() clientcmdapi.Cluster { + clusterInfos := config.config.Clusters + clusterInfoName := config.getClusterName() + + var mergedClusterInfo clientcmdapi.Cluster + mergo.Merge(&mergedClusterInfo, DefaultCluster) + mergo.Merge(&mergedClusterInfo, EnvVarCluster) + if configClusterInfo, exists := clusterInfos[clusterInfoName]; exists { + mergo.Merge(&mergedClusterInfo, configClusterInfo) + } + mergo.Merge(&mergedClusterInfo, config.overrides.ClusterInfo) + // An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data + // otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set" + caLen := len(config.overrides.ClusterInfo.CertificateAuthority) + caDataLen := len(config.overrides.ClusterInfo.CertificateAuthorityData) + if config.overrides.ClusterInfo.InsecureSkipTLSVerify && caLen == 0 && caDataLen == 0 { + mergedClusterInfo.CertificateAuthority = "" + mergedClusterInfo.CertificateAuthorityData = nil + } + + return mergedClusterInfo +} + +// inClusterClientConfig makes a config that will work from within a kubernetes cluster container environment. +type inClusterClientConfig struct{} + +func (inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) { + return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters") +} + +func (inClusterClientConfig) ClientConfig() (*restclient.Config, error) { + return restclient.InClusterConfig() +} + +func (inClusterClientConfig) Namespace() (string, error) { + // This way assumes you've set the POD_NAMESPACE environment variable using the downward API. + // This check has to be done first for backwards compatibility with the way InClusterConfig was originally set up + if ns := os.Getenv("POD_NAMESPACE"); ns != "" { + return ns, nil + } + + // Fall back to the namespace associated with the service account token, if available + if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if ns := strings.TrimSpace(string(data)); len(ns) > 0 { + return ns, nil + } + } + + return "default", nil +} + +func (inClusterClientConfig) ConfigAccess() ConfigAccess { + return NewDefaultClientConfigLoadingRules() +} + +// Possible returns true if loading an inside-kubernetes-cluster is possible. +func (inClusterClientConfig) Possible() bool { + fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token") + return os.Getenv("KUBERNETES_SERVICE_HOST") != "" && + os.Getenv("KUBERNETES_SERVICE_PORT") != "" && + err == nil && !fi.IsDir() +} + +// BuildConfigFromFlags is a helper function that builds configs from a master +// url or a kubeconfig filepath. These are passed in as command line flags for cluster +// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath +// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback +// to the default config. +func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) { + if kubeconfigPath == "" && masterUrl == "" { + glog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.") + kubeconfig, err := restclient.InClusterConfig() + if err == nil { + return kubeconfig, nil + } + glog.Warning("error creating inClusterConfig, falling back to default config: ", err) + } + return NewNonInteractiveDeferredLoadingClientConfig( + &ClientConfigLoadingRules{ExplicitPath: kubeconfigPath}, + &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig() +} + +// BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master +// url and a kubeconfigGetter. +func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) { + // TODO: We do not need a DeferredLoader here. Refactor code and see if we can use DirectClientConfig here. + cc := NewNonInteractiveDeferredLoadingClientConfig( + &ClientConfigGetter{kubeconfigGetter: kubeconfigGetter}, + &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}) + return cc.ClientConfig() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/config.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/config.go new file mode 100644 index 0000000..9df69a7 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/config.go @@ -0,0 +1,472 @@ +/* +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 clientcmd + +import ( + "errors" + "os" + "path" + "path/filepath" + "reflect" + "sort" + + "github.com/golang/glog" + + "k8s.io/kubernetes/pkg/client/restclient" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +// ConfigAccess is used by subcommands and methods in this package to load and modify the appropriate config files +type ConfigAccess interface { + // GetLoadingPrecedence returns the slice of files that should be used for loading and inspecting the config + GetLoadingPrecedence() []string + // GetStartingConfig returns the config that subcommands should being operating against. It may or may not be merged depending on loading rules + GetStartingConfig() (*clientcmdapi.Config, error) + // GetDefaultFilename returns the name of the file you should write into (create if necessary), if you're trying to create a new stanza as opposed to updating an existing one. + GetDefaultFilename() string + // IsExplicitFile indicates whether or not this command is interested in exactly one file. This implementation only ever does that via a flag, but implementations that handle local, global, and flags may have more + IsExplicitFile() bool + // GetExplicitFile returns the particular file this command is operating against. This implementation only ever has one, but implementations that handle local, global, and flags may have more + GetExplicitFile() string +} + +type PathOptions struct { + // GlobalFile is the full path to the file to load as the global (final) option + GlobalFile string + // EnvVar is the env var name that points to the list of kubeconfig files to load + EnvVar string + // ExplicitFileFlag is the name of the flag to use for prompting for the kubeconfig file + ExplicitFileFlag string + + // GlobalFileSubpath is an optional value used for displaying help + GlobalFileSubpath string + + LoadingRules *ClientConfigLoadingRules +} + +func (o *PathOptions) GetEnvVarFiles() []string { + if len(o.EnvVar) == 0 { + return []string{} + } + + envVarValue := os.Getenv(o.EnvVar) + if len(envVarValue) == 0 { + return []string{} + } + + return filepath.SplitList(envVarValue) +} + +func (o *PathOptions) GetLoadingPrecedence() []string { + if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 { + return envVarFiles + } + + return []string{o.GlobalFile} +} + +func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) { + // don't mutate the original + loadingRules := *o.LoadingRules + loadingRules.Precedence = o.GetLoadingPrecedence() + + clientConfig := NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &ConfigOverrides{}) + rawConfig, err := clientConfig.RawConfig() + if os.IsNotExist(err) { + return clientcmdapi.NewConfig(), nil + } + if err != nil { + return nil, err + } + + return &rawConfig, nil +} + +func (o *PathOptions) GetDefaultFilename() string { + if o.IsExplicitFile() { + return o.GetExplicitFile() + } + + if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 { + if len(envVarFiles) == 1 { + return envVarFiles[0] + } + + // if any of the envvar files already exists, return it + for _, envVarFile := range envVarFiles { + if _, err := os.Stat(envVarFile); err == nil { + return envVarFile + } + } + + // otherwise, return the last one in the list + return envVarFiles[len(envVarFiles)-1] + } + + return o.GlobalFile +} + +func (o *PathOptions) IsExplicitFile() bool { + if len(o.LoadingRules.ExplicitPath) > 0 { + return true + } + + return false +} + +func (o *PathOptions) GetExplicitFile() string { + return o.LoadingRules.ExplicitPath +} + +func NewDefaultPathOptions() *PathOptions { + ret := &PathOptions{ + GlobalFile: RecommendedHomeFile, + EnvVar: RecommendedConfigPathEnvVar, + ExplicitFileFlag: RecommendedConfigPathFlag, + + GlobalFileSubpath: path.Join(RecommendedHomeDir, RecommendedFileName), + + LoadingRules: NewDefaultClientConfigLoadingRules(), + } + ret.LoadingRules.DoNotResolvePaths = true + + return ret +} + +// ModifyConfig takes a Config object, iterates through Clusters, AuthInfos, and Contexts, uses the LocationOfOrigin if specified or +// uses the default destination file to write the results into. This results in multiple file reads, but it's very easy to follow. +// Preferences and CurrentContext should always be set in the default destination file. Since we can't distinguish between empty and missing values +// (no nil strings), we're forced have separate handling for them. In the kubeconfig cases, newConfig should have at most one difference, +// that means that this code will only write into a single file. If you want to relativizePaths, you must provide a fully qualified path in any +// modified element. +func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error { + possibleSources := configAccess.GetLoadingPrecedence() + // sort the possible kubeconfig files so we always "lock" in the same order + // to avoid deadlock (note: this can fail w/ symlinks, but... come on). + sort.Strings(possibleSources) + for _, filename := range possibleSources { + if err := lockFile(filename); err != nil { + return err + } + defer unlockFile(filename) + } + + startingConfig, err := configAccess.GetStartingConfig() + if err != nil { + return err + } + + // We need to find all differences, locate their original files, read a partial config to modify only that stanza and write out the file. + // Special case the test for current context and preferences since those always write to the default file. + if reflect.DeepEqual(*startingConfig, newConfig) { + // nothing to do + return nil + } + + if startingConfig.CurrentContext != newConfig.CurrentContext { + if err := writeCurrentContext(configAccess, newConfig.CurrentContext); err != nil { + return err + } + } + + if !reflect.DeepEqual(startingConfig.Preferences, newConfig.Preferences) { + if err := writePreferences(configAccess, newConfig.Preferences); err != nil { + return err + } + } + + // Search every cluster, authInfo, and context. First from new to old for differences, then from old to new for deletions + for key, cluster := range newConfig.Clusters { + startingCluster, exists := startingConfig.Clusters[key] + if !reflect.DeepEqual(cluster, startingCluster) || !exists { + destinationFile := cluster.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + t := *cluster + + configToWrite.Clusters[key] = &t + configToWrite.Clusters[key].LocationOfOrigin = destinationFile + if relativizePaths { + if err := RelativizeClusterLocalPaths(configToWrite.Clusters[key]); err != nil { + return err + } + } + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + for key, context := range newConfig.Contexts { + startingContext, exists := startingConfig.Contexts[key] + if !reflect.DeepEqual(context, startingContext) || !exists { + destinationFile := context.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + configToWrite.Contexts[key] = context + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + for key, authInfo := range newConfig.AuthInfos { + startingAuthInfo, exists := startingConfig.AuthInfos[key] + if !reflect.DeepEqual(authInfo, startingAuthInfo) || !exists { + destinationFile := authInfo.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + t := *authInfo + configToWrite.AuthInfos[key] = &t + configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile + if relativizePaths { + if err := RelativizeAuthInfoLocalPaths(configToWrite.AuthInfos[key]); err != nil { + return err + } + } + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + for key, cluster := range startingConfig.Clusters { + if _, exists := newConfig.Clusters[key]; !exists { + destinationFile := cluster.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + delete(configToWrite.Clusters, key) + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + for key, context := range startingConfig.Contexts { + if _, exists := newConfig.Contexts[key]; !exists { + destinationFile := context.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + delete(configToWrite.Contexts, key) + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + for key, authInfo := range startingConfig.AuthInfos { + if _, exists := newConfig.AuthInfos[key]; !exists { + destinationFile := authInfo.LocationOfOrigin + if len(destinationFile) == 0 { + destinationFile = configAccess.GetDefaultFilename() + } + + configToWrite, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + delete(configToWrite.AuthInfos, key) + + if err := WriteToFile(*configToWrite, destinationFile); err != nil { + return err + } + } + } + + return nil +} + +func PersisterForUser(configAccess ConfigAccess, user string) restclient.AuthProviderConfigPersister { + return &persister{configAccess, user} +} + +type persister struct { + configAccess ConfigAccess + user string +} + +func (p *persister) Persist(config map[string]string) error { + newConfig, err := p.configAccess.GetStartingConfig() + if err != nil { + return err + } + authInfo, ok := newConfig.AuthInfos[p.user] + if ok && authInfo.AuthProvider != nil { + authInfo.AuthProvider.Config = config + ModifyConfig(p.configAccess, *newConfig, false) + } + return nil +} + +// writeCurrentContext takes three possible paths. +// If newCurrentContext is the same as the startingConfig's current context, then we exit. +// If newCurrentContext has a value, then that value is written into the default destination file. +// If newCurrentContext is empty, then we find the config file that is setting the CurrentContext and clear the value from that file +func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) error { + if startingConfig, err := configAccess.GetStartingConfig(); err != nil { + return err + } else if startingConfig.CurrentContext == newCurrentContext { + return nil + } + + if configAccess.IsExplicitFile() { + file := configAccess.GetExplicitFile() + currConfig, err := getConfigFromFile(file) + if err != nil { + return err + } + currConfig.CurrentContext = newCurrentContext + if err := WriteToFile(*currConfig, file); err != nil { + return err + } + + return nil + } + + if len(newCurrentContext) > 0 { + destinationFile := configAccess.GetDefaultFilename() + config, err := getConfigFromFile(destinationFile) + if err != nil { + return err + } + config.CurrentContext = newCurrentContext + + if err := WriteToFile(*config, destinationFile); err != nil { + return err + } + + return nil + } + + // we're supposed to be clearing the current context. We need to find the first spot in the chain that is setting it and clear it + for _, file := range configAccess.GetLoadingPrecedence() { + if _, err := os.Stat(file); err == nil { + currConfig, err := getConfigFromFile(file) + if err != nil { + return err + } + + if len(currConfig.CurrentContext) > 0 { + currConfig.CurrentContext = newCurrentContext + if err := WriteToFile(*currConfig, file); err != nil { + return err + } + + return nil + } + } + } + + return errors.New("no config found to write context") +} + +func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferences) error { + if startingConfig, err := configAccess.GetStartingConfig(); err != nil { + return err + } else if reflect.DeepEqual(startingConfig.Preferences, newPrefs) { + return nil + } + + if configAccess.IsExplicitFile() { + file := configAccess.GetExplicitFile() + currConfig, err := getConfigFromFile(file) + if err != nil { + return err + } + currConfig.Preferences = newPrefs + if err := WriteToFile(*currConfig, file); err != nil { + return err + } + + return nil + } + + for _, file := range configAccess.GetLoadingPrecedence() { + currConfig, err := getConfigFromFile(file) + if err != nil { + return err + } + + if !reflect.DeepEqual(currConfig.Preferences, newPrefs) { + currConfig.Preferences = newPrefs + if err := WriteToFile(*currConfig, file); err != nil { + return err + } + + return nil + } + } + + return errors.New("no config found to write preferences") +} + +// getConfigFromFile tries to read a kubeconfig file and if it can't, returns an error. One exception, missing files result in empty configs, not an error. +func getConfigFromFile(filename string) (*clientcmdapi.Config, error) { + config, err := LoadFromFile(filename) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if config == nil { + config = clientcmdapi.NewConfig() + } + return config, nil +} + +// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit. One exception, missing files result in empty configs, not an exit +func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config { + config, err := getConfigFromFile(filename) + if err != nil { + glog.FatalDepth(1, err) + } + + return config +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/doc.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/doc.go new file mode 100644 index 0000000..30ef6f3 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/doc.go @@ -0,0 +1,37 @@ +/* +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 clientcmd provides one stop shopping for building a working client from a fixed config, +from a .kubeconfig file, from command line flags, or from any merged combination. + +Sample usage from merged .kubeconfig files (local directory, home directory) + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + // if you want to change the loading rules (which files in which order), you can do so here + + configOverrides := &clientcmd.ConfigOverrides{} + // if you want to change override values or bind them to flags, there are methods to help you + + kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) + config, err := kubeConfig.ClientConfig() + if err != nil { + // Do something + } + client, err := unversioned.New(config) + // ... +*/ +package clientcmd diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/loader.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/loader.go new file mode 100644 index 0000000..1009406 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/loader.go @@ -0,0 +1,585 @@ +/* +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 clientcmd + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + goruntime "runtime" + "strings" + + "github.com/golang/glog" + "github.com/imdario/mergo" + + "k8s.io/kubernetes/pkg/api/unversioned" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" + clientcmdlatest "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest" + "k8s.io/kubernetes/pkg/runtime" + utilerrors "k8s.io/kubernetes/pkg/util/errors" + "k8s.io/kubernetes/pkg/util/homedir" +) + +const ( + RecommendedConfigPathFlag = "kubeconfig" + RecommendedConfigPathEnvVar = "KUBECONFIG" + RecommendedHomeDir = ".kube" + RecommendedFileName = "config" + RecommendedSchemaName = "schema" +) + +var RecommendedHomeFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedFileName) +var RecommendedSchemaFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedSchemaName) + +// currentMigrationRules returns a map that holds the history of recommended home directories used in previous versions. +// Any future changes to RecommendedHomeFile and related are expected to add a migration rule here, in order to make +// sure existing config files are migrated to their new locations properly. +func currentMigrationRules() map[string]string { + oldRecommendedHomeFile := path.Join(os.Getenv("HOME"), "/.kube/.kubeconfig") + oldRecommendedWindowsHomeFile := path.Join(os.Getenv("HOME"), RecommendedHomeDir, RecommendedFileName) + + migrationRules := map[string]string{} + migrationRules[RecommendedHomeFile] = oldRecommendedHomeFile + if goruntime.GOOS == "windows" { + migrationRules[RecommendedHomeFile] = oldRecommendedWindowsHomeFile + } + return migrationRules +} + +type ClientConfigLoader interface { + ConfigAccess + Load() (*clientcmdapi.Config, error) +} + +type KubeconfigGetter func() (*clientcmdapi.Config, error) + +type ClientConfigGetter struct { + kubeconfigGetter KubeconfigGetter +} + +// ClientConfigGetter implements the ClientConfigLoader interface. +var _ ClientConfigLoader = &ClientConfigGetter{} + +func (g *ClientConfigGetter) Load() (*clientcmdapi.Config, error) { + return g.kubeconfigGetter() +} + +func (g *ClientConfigGetter) GetLoadingPrecedence() []string { + return nil +} +func (g *ClientConfigGetter) GetStartingConfig() (*clientcmdapi.Config, error) { + return nil, nil +} +func (g *ClientConfigGetter) GetDefaultFilename() string { + return "" +} +func (g *ClientConfigGetter) IsExplicitFile() bool { + return false +} +func (g *ClientConfigGetter) GetExplicitFile() string { + return "" +} + +// ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config +// Callers can put the chain together however they want, but we'd recommend: +// EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath +// ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if thie file is not present +type ClientConfigLoadingRules struct { + ExplicitPath string + Precedence []string + + // MigrationRules is a map of destination files to source files. If a destination file is not present, then the source file is checked. + // If the source file is present, then it is copied to the destination file BEFORE any further loading happens. + MigrationRules map[string]string + + // DoNotResolvePaths indicates whether or not to resolve paths with respect to the originating files. This is phrased as a negative so + // that a default object that doesn't set this will usually get the behavior it wants. + DoNotResolvePaths bool +} + +// ClientConfigLoadingRules implements the ClientConfigLoader interface. +var _ ClientConfigLoader = &ClientConfigLoadingRules{} + +// NewDefaultClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to +// use this constructor +func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules { + chain := []string{} + + envVarFiles := os.Getenv(RecommendedConfigPathEnvVar) + if len(envVarFiles) != 0 { + chain = append(chain, filepath.SplitList(envVarFiles)...) + + } else { + chain = append(chain, RecommendedHomeFile) + } + + return &ClientConfigLoadingRules{ + Precedence: chain, + MigrationRules: currentMigrationRules(), + } +} + +// Load starts by running the MigrationRules and then +// takes the loading rules and returns a Config object based on following rules. +// if the ExplicitPath, return the unmerged explicit file +// Otherwise, return a merged config based on the Precedence slice +// A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored. +// Read errors or files with non-deserializable content produce errors. +// The first file to set a particular map key wins and map key's value is never changed. +// BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed. +// This results in some odd looking logic to merge in one direction, merge in the other, and then merge the two. +// It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even +// non-conflicting entries from the second file's "red-user" are discarded. +// Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder +// and only absolute file paths are returned. +func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) { + if err := rules.Migrate(); err != nil { + return nil, err + } + + errlist := []error{} + + kubeConfigFiles := []string{} + + // Make sure a file we were explicitly told to use exists + if len(rules.ExplicitPath) > 0 { + if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) { + return nil, err + } + kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath) + + } else { + kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...) + } + + kubeconfigs := []*clientcmdapi.Config{} + // read and cache the config files so that we only look at them once + for _, filename := range kubeConfigFiles { + if len(filename) == 0 { + // no work to do + continue + } + + config, err := LoadFromFile(filename) + if os.IsNotExist(err) { + // skip missing files + continue + } + if err != nil { + errlist = append(errlist, fmt.Errorf("Error loading config file \"%s\": %v", filename, err)) + continue + } + + kubeconfigs = append(kubeconfigs, config) + } + + // first merge all of our maps + mapConfig := clientcmdapi.NewConfig() + for _, kubeconfig := range kubeconfigs { + mergo.Merge(mapConfig, kubeconfig) + } + + // merge all of the struct values in the reverse order so that priority is given correctly + // errors are not added to the list the second time + nonMapConfig := clientcmdapi.NewConfig() + for i := len(kubeconfigs) - 1; i >= 0; i-- { + kubeconfig := kubeconfigs[i] + mergo.Merge(nonMapConfig, kubeconfig) + } + + // since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and + // get the values we expect. + config := clientcmdapi.NewConfig() + mergo.Merge(config, mapConfig) + mergo.Merge(config, nonMapConfig) + + if rules.ResolvePaths() { + if err := ResolveLocalPaths(config); err != nil { + errlist = append(errlist, err) + } + } + + return config, utilerrors.NewAggregate(errlist) +} + +// Migrate uses the MigrationRules map. If a destination file is not present, then the source file is checked. +// If the source file is present, then it is copied to the destination file BEFORE any further loading happens. +func (rules *ClientConfigLoadingRules) Migrate() error { + if rules.MigrationRules == nil { + return nil + } + + for destination, source := range rules.MigrationRules { + if _, err := os.Stat(destination); err == nil { + // if the destination already exists, do nothing + continue + } else if os.IsPermission(err) { + // if we can't access the file, skip it + continue + } else if !os.IsNotExist(err) { + // if we had an error other than non-existence, fail + return err + } + + if sourceInfo, err := os.Stat(source); err != nil { + if os.IsNotExist(err) || os.IsPermission(err) { + // if the source file doesn't exist or we can't access it, there's no work to do. + continue + } + + // if we had an error other than non-existence, fail + return err + } else if sourceInfo.IsDir() { + return fmt.Errorf("cannot migrate %v to %v because it is a directory", source, destination) + } + + in, err := os.Open(source) + if err != nil { + return err + } + defer in.Close() + out, err := os.Create(destination) + if err != nil { + return err + } + defer out.Close() + + if _, err = io.Copy(out, in); err != nil { + return err + } + } + + return nil +} + +// GetLoadingPrecedence implements ConfigAccess +func (rules *ClientConfigLoadingRules) GetLoadingPrecedence() []string { + return rules.Precedence +} + +// GetStartingConfig implements ConfigAccess +func (rules *ClientConfigLoadingRules) GetStartingConfig() (*clientcmdapi.Config, error) { + clientConfig := NewNonInteractiveDeferredLoadingClientConfig(rules, &ConfigOverrides{}) + rawConfig, err := clientConfig.RawConfig() + if os.IsNotExist(err) { + return clientcmdapi.NewConfig(), nil + } + if err != nil { + return nil, err + } + + return &rawConfig, nil +} + +// GetDefaultFilename implements ConfigAccess +func (rules *ClientConfigLoadingRules) GetDefaultFilename() string { + // Explicit file if we have one. + if rules.IsExplicitFile() { + return rules.GetExplicitFile() + } + // Otherwise, first existing file from precedence. + for _, filename := range rules.GetLoadingPrecedence() { + if _, err := os.Stat(filename); err == nil { + return filename + } + } + // If none exists, use the first from precedence. + if len(rules.Precedence) > 0 { + return rules.Precedence[0] + } + return "" +} + +// IsExplicitFile implements ConfigAccess +func (rules *ClientConfigLoadingRules) IsExplicitFile() bool { + return len(rules.ExplicitPath) > 0 +} + +// GetExplicitFile implements ConfigAccess +func (rules *ClientConfigLoadingRules) GetExplicitFile() string { + return rules.ExplicitPath +} + +// LoadFromFile takes a filename and deserializes the contents into Config object +func LoadFromFile(filename string) (*clientcmdapi.Config, error) { + kubeconfigBytes, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + config, err := Load(kubeconfigBytes) + if err != nil { + return nil, err + } + glog.V(6).Infoln("Config loaded from file", filename) + + // set LocationOfOrigin on every Cluster, User, and Context + for key, obj := range config.AuthInfos { + obj.LocationOfOrigin = filename + config.AuthInfos[key] = obj + } + for key, obj := range config.Clusters { + obj.LocationOfOrigin = filename + config.Clusters[key] = obj + } + for key, obj := range config.Contexts { + obj.LocationOfOrigin = filename + config.Contexts[key] = obj + } + + if config.AuthInfos == nil { + config.AuthInfos = map[string]*clientcmdapi.AuthInfo{} + } + if config.Clusters == nil { + config.Clusters = map[string]*clientcmdapi.Cluster{} + } + if config.Contexts == nil { + config.Contexts = map[string]*clientcmdapi.Context{} + } + + return config, nil +} + +// Load takes a byte slice and deserializes the contents into Config object. +// Encapsulates deserialization without assuming the source is a file. +func Load(data []byte) (*clientcmdapi.Config, error) { + config := clientcmdapi.NewConfig() + // if there's no data in a file, return the default object instead of failing (DecodeInto reject empty input) + if len(data) == 0 { + return config, nil + } + decoded, _, err := clientcmdlatest.Codec.Decode(data, &unversioned.GroupVersionKind{Version: clientcmdlatest.Version, Kind: "Config"}, config) + if err != nil { + return nil, err + } + return decoded.(*clientcmdapi.Config), nil +} + +// WriteToFile serializes the config to yaml and writes it out to a file. If not present, it creates the file with the mode 0600. If it is present +// it stomps the contents +func WriteToFile(config clientcmdapi.Config, filename string) error { + content, err := Write(config) + if err != nil { + return err + } + dir := filepath.Dir(filename) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err = os.MkdirAll(dir, 0755); err != nil { + return err + } + } + + if err := ioutil.WriteFile(filename, content, 0600); err != nil { + return err + } + return nil +} + +func lockFile(filename string) error { + // TODO: find a way to do this with actual file locks. Will + // probably need seperate solution for windows and linux. + + // Make sure the dir exists before we try to create a lock file. + dir := filepath.Dir(filename) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err = os.MkdirAll(dir, 0755); err != nil { + return err + } + } + f, err := os.OpenFile(lockName(filename), os.O_CREATE|os.O_EXCL, 0) + if err != nil { + return err + } + f.Close() + return nil +} + +func unlockFile(filename string) error { + return os.Remove(lockName(filename)) +} + +func lockName(filename string) string { + return filename + ".lock" +} + +// Write serializes the config to yaml. +// Encapsulates serialization without assuming the destination is a file. +func Write(config clientcmdapi.Config) ([]byte, error) { + return runtime.Encode(clientcmdlatest.Codec, &config) +} + +func (rules ClientConfigLoadingRules) ResolvePaths() bool { + return !rules.DoNotResolvePaths +} + +// ResolveLocalPaths resolves all relative paths in the config object with respect to the stanza's LocationOfOrigin +// this cannot be done directly inside of LoadFromFile because doing so there would make it impossible to load a file without +// modification of its contents. +func ResolveLocalPaths(config *clientcmdapi.Config) error { + for _, cluster := range config.Clusters { + if len(cluster.LocationOfOrigin) == 0 { + continue + } + base, err := filepath.Abs(filepath.Dir(cluster.LocationOfOrigin)) + if err != nil { + return fmt.Errorf("Could not determine the absolute path of config file %s: %v", cluster.LocationOfOrigin, err) + } + + if err := ResolvePaths(GetClusterFileReferences(cluster), base); err != nil { + return err + } + } + for _, authInfo := range config.AuthInfos { + if len(authInfo.LocationOfOrigin) == 0 { + continue + } + base, err := filepath.Abs(filepath.Dir(authInfo.LocationOfOrigin)) + if err != nil { + return fmt.Errorf("Could not determine the absolute path of config file %s: %v", authInfo.LocationOfOrigin, err) + } + + if err := ResolvePaths(GetAuthInfoFileReferences(authInfo), base); err != nil { + return err + } + } + + return nil +} + +// RelativizeClusterLocalPaths first absolutizes the paths by calling ResolveLocalPaths. This assumes that any NEW path is already +// absolute, but any existing path will be resolved relative to LocationOfOrigin +func RelativizeClusterLocalPaths(cluster *clientcmdapi.Cluster) error { + if len(cluster.LocationOfOrigin) == 0 { + return fmt.Errorf("no location of origin for %s", cluster.Server) + } + base, err := filepath.Abs(filepath.Dir(cluster.LocationOfOrigin)) + if err != nil { + return fmt.Errorf("could not determine the absolute path of config file %s: %v", cluster.LocationOfOrigin, err) + } + + if err := ResolvePaths(GetClusterFileReferences(cluster), base); err != nil { + return err + } + if err := RelativizePathWithNoBacksteps(GetClusterFileReferences(cluster), base); err != nil { + return err + } + + return nil +} + +// RelativizeAuthInfoLocalPaths first absolutizes the paths by calling ResolveLocalPaths. This assumes that any NEW path is already +// absolute, but any existing path will be resolved relative to LocationOfOrigin +func RelativizeAuthInfoLocalPaths(authInfo *clientcmdapi.AuthInfo) error { + if len(authInfo.LocationOfOrigin) == 0 { + return fmt.Errorf("no location of origin for %v", authInfo) + } + base, err := filepath.Abs(filepath.Dir(authInfo.LocationOfOrigin)) + if err != nil { + return fmt.Errorf("could not determine the absolute path of config file %s: %v", authInfo.LocationOfOrigin, err) + } + + if err := ResolvePaths(GetAuthInfoFileReferences(authInfo), base); err != nil { + return err + } + if err := RelativizePathWithNoBacksteps(GetAuthInfoFileReferences(authInfo), base); err != nil { + return err + } + + return nil +} + +func RelativizeConfigPaths(config *clientcmdapi.Config, base string) error { + return RelativizePathWithNoBacksteps(GetConfigFileReferences(config), base) +} + +func ResolveConfigPaths(config *clientcmdapi.Config, base string) error { + return ResolvePaths(GetConfigFileReferences(config), base) +} + +func GetConfigFileReferences(config *clientcmdapi.Config) []*string { + refs := []*string{} + + for _, cluster := range config.Clusters { + refs = append(refs, GetClusterFileReferences(cluster)...) + } + for _, authInfo := range config.AuthInfos { + refs = append(refs, GetAuthInfoFileReferences(authInfo)...) + } + + return refs +} + +func GetClusterFileReferences(cluster *clientcmdapi.Cluster) []*string { + return []*string{&cluster.CertificateAuthority} +} + +func GetAuthInfoFileReferences(authInfo *clientcmdapi.AuthInfo) []*string { + return []*string{&authInfo.ClientCertificate, &authInfo.ClientKey} +} + +// ResolvePaths updates the given refs to be absolute paths, relative to the given base directory +func ResolvePaths(refs []*string, base string) error { + for _, ref := range refs { + // Don't resolve empty paths + if len(*ref) > 0 { + // Don't resolve absolute paths + if !filepath.IsAbs(*ref) { + *ref = filepath.Join(base, *ref) + } + } + } + return nil +} + +// RelativizePathWithNoBacksteps updates the given refs to be relative paths, relative to the given base directory as long as they do not require backsteps. +// Any path requiring a backstep is left as-is as long it is absolute. Any non-absolute path that can't be relativized produces an error +func RelativizePathWithNoBacksteps(refs []*string, base string) error { + for _, ref := range refs { + // Don't relativize empty paths + if len(*ref) > 0 { + rel, err := MakeRelative(*ref, base) + if err != nil { + return err + } + + // if we have a backstep, don't mess with the path + if strings.HasPrefix(rel, "../") { + if filepath.IsAbs(*ref) { + continue + } + + return fmt.Errorf("%v requires backsteps and is not absolute", *ref) + } + + *ref = rel + } + } + return nil +} + +func MakeRelative(path, base string) (string, error) { + if len(path) > 0 { + rel, err := filepath.Rel(base, path) + if err != nil { + return path, err + } + return rel, nil + } + return path, nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/merged_client_builder.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/merged_client_builder.go new file mode 100644 index 0000000..0180469 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/merged_client_builder.go @@ -0,0 +1,122 @@ +/* +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 clientcmd + +import ( + "io" + "reflect" + "sync" + + "github.com/golang/glog" + + "k8s.io/kubernetes/pkg/client/restclient" + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +// DeferredLoadingClientConfig is a ClientConfig interface that is backed by a client config loader. +// It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that +// the most recent rules are used. This is useful in cases where you bind flags to loading rule parameters before +// the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid +// passing extraneous information down a call stack +type DeferredLoadingClientConfig struct { + loader ClientConfigLoader + overrides *ConfigOverrides + fallbackReader io.Reader + + clientConfig ClientConfig + loadingLock sync.Mutex +} + +// NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name +func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig { + return &DeferredLoadingClientConfig{loader: loader, overrides: overrides} +} + +// NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name and the fallback auth reader +func NewInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig { + return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, fallbackReader: fallbackReader} +} + +func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) { + if config.clientConfig == nil { + config.loadingLock.Lock() + defer config.loadingLock.Unlock() + + if config.clientConfig == nil { + mergedConfig, err := config.loader.Load() + if err != nil { + return nil, err + } + + var mergedClientConfig ClientConfig + if config.fallbackReader != nil { + mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader) + } else { + mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader) + } + + config.clientConfig = mergedClientConfig + } + } + + return config.clientConfig, nil +} + +func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) { + mergedConfig, err := config.createClientConfig() + if err != nil { + return clientcmdapi.Config{}, err + } + + return mergedConfig.RawConfig() +} + +// ClientConfig implements ClientConfig +func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) { + mergedClientConfig, err := config.createClientConfig() + if err != nil { + return nil, err + } + + mergedConfig, err := mergedClientConfig.ClientConfig() + if err != nil { + return nil, err + } + // Are we running in a cluster and were no other configs found? If so, use the in-cluster-config. + icc := inClusterClientConfig{} + defaultConfig, err := DefaultClientConfig.ClientConfig() + if icc.Possible() && err == nil && reflect.DeepEqual(mergedConfig, defaultConfig) { + glog.V(2).Info("No kubeconfig could be created, falling back to service account.") + return icc.ClientConfig() + } + return mergedConfig, nil +} + +// Namespace implements KubeConfig +func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) { + mergedKubeConfig, err := config.createClientConfig() + if err != nil { + return "", false, err + } + + return mergedKubeConfig.Namespace() +} + +// ConfigAccess implements ClientConfig +func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess { + return config.loader +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/overrides.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/overrides.go new file mode 100644 index 0000000..40a35e6 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/overrides.go @@ -0,0 +1,198 @@ +/* +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 clientcmd + +import ( + "strconv" + + "github.com/spf13/pflag" + + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" +) + +// ConfigOverrides holds values that should override whatever information is pulled from the actual Config object. You can't +// simply use an actual Config object, because Configs hold maps, but overrides are restricted to "at most one" +type ConfigOverrides struct { + AuthInfo clientcmdapi.AuthInfo + ClusterInfo clientcmdapi.Cluster + Context clientcmdapi.Context + CurrentContext string +} + +// ConfigOverrideFlags holds the flag names to be used for binding command line flags. Notice that this structure tightly +// corresponds to ConfigOverrides +type ConfigOverrideFlags struct { + AuthOverrideFlags AuthOverrideFlags + ClusterOverrideFlags ClusterOverrideFlags + ContextOverrideFlags ContextOverrideFlags + CurrentContext FlagInfo +} + +// AuthOverrideFlags holds the flag names to be used for binding command line flags for AuthInfo objects +type AuthOverrideFlags struct { + ClientCertificate FlagInfo + ClientKey FlagInfo + Token FlagInfo + Impersonate FlagInfo + Username FlagInfo + Password FlagInfo +} + +// ContextOverrideFlags holds the flag names to be used for binding command line flags for Cluster objects +type ContextOverrideFlags struct { + ClusterName FlagInfo + AuthInfoName FlagInfo + Namespace FlagInfo +} + +// ClusterOverride holds the flag names to be used for binding command line flags for Cluster objects +type ClusterOverrideFlags struct { + APIServer FlagInfo + APIVersion FlagInfo + CertificateAuthority FlagInfo + InsecureSkipTLSVerify FlagInfo +} + +// FlagInfo contains information about how to register a flag. This struct is useful if you want to provide a way for an extender to +// get back a set of recommended flag names, descriptions, and defaults, but allow for customization by an extender. This makes for +// coherent extension, without full prescription +type FlagInfo struct { + // LongName is the long string for a flag. If this is empty, then the flag will not be bound + LongName string + // ShortName is the single character for a flag. If this is empty, then there will be no short flag + ShortName string + // Default is the default value for the flag + Default string + // Description is the description for the flag + Description string +} + +// BindStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered +func (f FlagInfo) BindStringFlag(flags *pflag.FlagSet, target *string) { + // you can't register a flag without a long name + if len(f.LongName) > 0 { + flags.StringVarP(target, f.LongName, f.ShortName, f.Default, f.Description) + } +} + +// BindBoolFlag binds the flag based on the provided info. If LongName == "", nothing is registered +func (f FlagInfo) BindBoolFlag(flags *pflag.FlagSet, target *bool) { + // you can't register a flag without a long name + if len(f.LongName) > 0 { + // try to parse Default as a bool. If it fails, assume false + boolVal, err := strconv.ParseBool(f.Default) + if err != nil { + boolVal = false + } + + flags.BoolVarP(target, f.LongName, f.ShortName, boolVal, f.Description) + } +} + +const ( + FlagClusterName = "cluster" + FlagAuthInfoName = "user" + FlagContext = "context" + FlagNamespace = "namespace" + FlagAPIServer = "server" + FlagAPIVersion = "api-version" + FlagInsecure = "insecure-skip-tls-verify" + FlagCertFile = "client-certificate" + FlagKeyFile = "client-key" + FlagCAFile = "certificate-authority" + FlagEmbedCerts = "embed-certs" + FlagBearerToken = "token" + FlagImpersonate = "as" + FlagUsername = "username" + FlagPassword = "password" +) + +// RecommendedAuthOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing +func RecommendedAuthOverrideFlags(prefix string) AuthOverrideFlags { + return AuthOverrideFlags{ + ClientCertificate: FlagInfo{prefix + FlagCertFile, "", "", "Path to a client certificate file for TLS"}, + ClientKey: FlagInfo{prefix + FlagKeyFile, "", "", "Path to a client key file for TLS"}, + Token: FlagInfo{prefix + FlagBearerToken, "", "", "Bearer token for authentication to the API server"}, + Impersonate: FlagInfo{prefix + FlagImpersonate, "", "", "Username to impersonate for the operation"}, + Username: FlagInfo{prefix + FlagUsername, "", "", "Username for basic authentication to the API server"}, + Password: FlagInfo{prefix + FlagPassword, "", "", "Password for basic authentication to the API server"}, + } +} + +// RecommendedClusterOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing +func RecommendedClusterOverrideFlags(prefix string) ClusterOverrideFlags { + return ClusterOverrideFlags{ + APIServer: FlagInfo{prefix + FlagAPIServer, "", "", "The address and port of the Kubernetes API server"}, + APIVersion: FlagInfo{prefix + FlagAPIVersion, "", "", "DEPRECATED: The API version to use when talking to the server"}, + CertificateAuthority: FlagInfo{prefix + FlagCAFile, "", "", "Path to a cert. file for the certificate authority"}, + InsecureSkipTLSVerify: FlagInfo{prefix + FlagInsecure, "", "false", "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure"}, + } +} + +// RecommendedConfigOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing +func RecommendedConfigOverrideFlags(prefix string) ConfigOverrideFlags { + return ConfigOverrideFlags{ + AuthOverrideFlags: RecommendedAuthOverrideFlags(prefix), + ClusterOverrideFlags: RecommendedClusterOverrideFlags(prefix), + ContextOverrideFlags: RecommendedContextOverrideFlags(prefix), + CurrentContext: FlagInfo{prefix + FlagContext, "", "", "The name of the kubeconfig context to use"}, + } +} + +// RecommendedContextOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing +func RecommendedContextOverrideFlags(prefix string) ContextOverrideFlags { + return ContextOverrideFlags{ + ClusterName: FlagInfo{prefix + FlagClusterName, "", "", "The name of the kubeconfig cluster to use"}, + AuthInfoName: FlagInfo{prefix + FlagAuthInfoName, "", "", "The name of the kubeconfig user to use"}, + Namespace: FlagInfo{prefix + FlagNamespace, "", "", "If present, the namespace scope for this CLI request"}, + } +} + +// BindAuthInfoFlags is a convenience method to bind the specified flags to their associated variables +func BindAuthInfoFlags(authInfo *clientcmdapi.AuthInfo, flags *pflag.FlagSet, flagNames AuthOverrideFlags) { + flagNames.ClientCertificate.BindStringFlag(flags, &authInfo.ClientCertificate) + flagNames.ClientKey.BindStringFlag(flags, &authInfo.ClientKey) + flagNames.Token.BindStringFlag(flags, &authInfo.Token) + flagNames.Impersonate.BindStringFlag(flags, &authInfo.Impersonate) + flagNames.Username.BindStringFlag(flags, &authInfo.Username) + flagNames.Password.BindStringFlag(flags, &authInfo.Password) +} + +// BindClusterFlags is a convenience method to bind the specified flags to their associated variables +func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, flagNames ClusterOverrideFlags) { + flagNames.APIServer.BindStringFlag(flags, &clusterInfo.Server) + // TODO: remove --api-version flag in 1.3. + flagNames.APIVersion.BindStringFlag(flags, &clusterInfo.APIVersion) + flags.MarkDeprecated(FlagAPIVersion, "flag is no longer respected and will be deleted in the next release") + flagNames.CertificateAuthority.BindStringFlag(flags, &clusterInfo.CertificateAuthority) + flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify) +} + +// BindOverrideFlags is a convenience method to bind the specified flags to their associated variables +func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) { + BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags) + BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags) + BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags) + flagNames.CurrentContext.BindStringFlag(flags, &overrides.CurrentContext) +} + +// BindFlags is a convenience method to bind the specified flags to their associated variables +func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) { + flagNames.ClusterName.BindStringFlag(flags, &contextInfo.Cluster) + flagNames.AuthInfoName.BindStringFlag(flags, &contextInfo.AuthInfo) + flagNames.Namespace.BindStringFlag(flags, &contextInfo.Namespace) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/validation.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/validation.go new file mode 100644 index 0000000..63f8ade --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clientcmd/validation.go @@ -0,0 +1,270 @@ +/* +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 clientcmd + +import ( + "errors" + "fmt" + "os" + "reflect" + "strings" + + clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" + utilerrors "k8s.io/kubernetes/pkg/util/errors" + "k8s.io/kubernetes/pkg/util/validation" +) + +var ( + ErrNoContext = errors.New("no context chosen") + ErrEmptyConfig = errors.New("no configuration has been provided") + // message is for consistency with old behavior + ErrEmptyCluster = errors.New("cluster has no server defined") +) + +type errContextNotFound struct { + ContextName string +} + +func (e *errContextNotFound) Error() string { + return fmt.Sprintf("context was not found for specified context: %v", e.ContextName) +} + +// IsContextNotFound returns a boolean indicating whether the error is known to +// report that a context was not found +func IsContextNotFound(err error) bool { + if err == nil { + return false + } + if _, ok := err.(*errContextNotFound); ok || err == ErrNoContext { + return true + } + return strings.Contains(err.Error(), "context was not found for specified context") +} + +// IsEmptyConfig returns true if the provided error indicates the provided configuration +// is empty. +func IsEmptyConfig(err error) bool { + switch t := err.(type) { + case errConfigurationInvalid: + return len(t) == 1 && t[0] == ErrEmptyConfig + } + return err == ErrEmptyConfig +} + +// errConfigurationInvalid is a set of errors indicating the configuration is invalid. +type errConfigurationInvalid []error + +// errConfigurationInvalid implements error and Aggregate +var _ error = errConfigurationInvalid{} +var _ utilerrors.Aggregate = errConfigurationInvalid{} + +func newErrConfigurationInvalid(errs []error) error { + switch len(errs) { + case 0: + return nil + default: + return errConfigurationInvalid(errs) + } +} + +// Error implements the error interface +func (e errConfigurationInvalid) Error() string { + return fmt.Sprintf("invalid configuration: %v", utilerrors.NewAggregate(e).Error()) +} + +// Errors implements the AggregateError interface +func (e errConfigurationInvalid) Errors() []error { + return e +} + +// IsConfigurationInvalid returns true if the provided error indicates the configuration is invalid. +func IsConfigurationInvalid(err error) bool { + switch err.(type) { + case *errContextNotFound, errConfigurationInvalid: + return true + } + return IsContextNotFound(err) +} + +// Validate checks for errors in the Config. It does not return early so that it can find as many errors as possible. +func Validate(config clientcmdapi.Config) error { + validationErrors := make([]error, 0) + + if clientcmdapi.IsConfigEmpty(&config) { + return newErrConfigurationInvalid([]error{ErrEmptyConfig}) + } + + if len(config.CurrentContext) != 0 { + if _, exists := config.Contexts[config.CurrentContext]; !exists { + validationErrors = append(validationErrors, &errContextNotFound{config.CurrentContext}) + } + } + + for contextName, context := range config.Contexts { + validationErrors = append(validationErrors, validateContext(contextName, *context, config)...) + } + + for authInfoName, authInfo := range config.AuthInfos { + validationErrors = append(validationErrors, validateAuthInfo(authInfoName, *authInfo)...) + } + + for clusterName, clusterInfo := range config.Clusters { + validationErrors = append(validationErrors, validateClusterInfo(clusterName, *clusterInfo)...) + } + + return newErrConfigurationInvalid(validationErrors) +} + +// ConfirmUsable looks a particular context and determines if that particular part of the config is useable. There might still be errors in the config, +// but no errors in the sections requested or referenced. It does not return early so that it can find as many errors as possible. +func ConfirmUsable(config clientcmdapi.Config, passedContextName string) error { + validationErrors := make([]error, 0) + + if clientcmdapi.IsConfigEmpty(&config) { + return newErrConfigurationInvalid([]error{ErrEmptyConfig}) + } + + var contextName string + if len(passedContextName) != 0 { + contextName = passedContextName + } else { + contextName = config.CurrentContext + } + + if len(contextName) == 0 { + return ErrNoContext + } + + context, exists := config.Contexts[contextName] + if !exists { + validationErrors = append(validationErrors, &errContextNotFound{contextName}) + } + + if exists { + validationErrors = append(validationErrors, validateContext(contextName, *context, config)...) + validationErrors = append(validationErrors, validateAuthInfo(context.AuthInfo, *config.AuthInfos[context.AuthInfo])...) + validationErrors = append(validationErrors, validateClusterInfo(context.Cluster, *config.Clusters[context.Cluster])...) + } + + return newErrConfigurationInvalid(validationErrors) +} + +// validateClusterInfo looks for conflicts and errors in the cluster info +func validateClusterInfo(clusterName string, clusterInfo clientcmdapi.Cluster) []error { + validationErrors := make([]error, 0) + + if reflect.DeepEqual(clientcmdapi.Cluster{}, clusterInfo) { + return []error{ErrEmptyCluster} + } + + if len(clusterInfo.Server) == 0 { + if len(clusterName) == 0 { + validationErrors = append(validationErrors, fmt.Errorf("default cluster has no server defined")) + } else { + validationErrors = append(validationErrors, fmt.Errorf("no server found for cluster %q", clusterName)) + } + } + // Make sure CA data and CA file aren't both specified + if len(clusterInfo.CertificateAuthority) != 0 && len(clusterInfo.CertificateAuthorityData) != 0 { + validationErrors = append(validationErrors, fmt.Errorf("certificate-authority-data and certificate-authority are both specified for %v. certificate-authority-data will override.", clusterName)) + } + if len(clusterInfo.CertificateAuthority) != 0 { + clientCertCA, err := os.Open(clusterInfo.CertificateAuthority) + defer clientCertCA.Close() + if err != nil { + validationErrors = append(validationErrors, fmt.Errorf("unable to read certificate-authority %v for %v due to %v", clusterInfo.CertificateAuthority, clusterName, err)) + } + } + + return validationErrors +} + +// validateAuthInfo looks for conflicts and errors in the auth info +func validateAuthInfo(authInfoName string, authInfo clientcmdapi.AuthInfo) []error { + validationErrors := make([]error, 0) + + usingAuthPath := false + methods := make([]string, 0, 3) + if len(authInfo.Token) != 0 { + methods = append(methods, "token") + } + if len(authInfo.Username) != 0 || len(authInfo.Password) != 0 { + methods = append(methods, "basicAuth") + } + + if len(authInfo.ClientCertificate) != 0 || len(authInfo.ClientCertificateData) != 0 { + // Make sure cert data and file aren't both specified + if len(authInfo.ClientCertificate) != 0 && len(authInfo.ClientCertificateData) != 0 { + validationErrors = append(validationErrors, fmt.Errorf("client-cert-data and client-cert are both specified for %v. client-cert-data will override.", authInfoName)) + } + // Make sure key data and file aren't both specified + if len(authInfo.ClientKey) != 0 && len(authInfo.ClientKeyData) != 0 { + validationErrors = append(validationErrors, fmt.Errorf("client-key-data and client-key are both specified for %v; client-key-data will override", authInfoName)) + } + // Make sure a key is specified + if len(authInfo.ClientKey) == 0 && len(authInfo.ClientKeyData) == 0 { + validationErrors = append(validationErrors, fmt.Errorf("client-key-data or client-key must be specified for %v to use the clientCert authentication method.", authInfoName)) + } + + if len(authInfo.ClientCertificate) != 0 { + clientCertFile, err := os.Open(authInfo.ClientCertificate) + defer clientCertFile.Close() + if err != nil { + validationErrors = append(validationErrors, fmt.Errorf("unable to read client-cert %v for %v due to %v", authInfo.ClientCertificate, authInfoName, err)) + } + } + if len(authInfo.ClientKey) != 0 { + clientKeyFile, err := os.Open(authInfo.ClientKey) + defer clientKeyFile.Close() + if err != nil { + validationErrors = append(validationErrors, fmt.Errorf("unable to read client-key %v for %v due to %v", authInfo.ClientKey, authInfoName, err)) + } + } + } + + // authPath also provides information for the client to identify the server, so allow multiple auth methods in that case + if (len(methods) > 1) && (!usingAuthPath) { + validationErrors = append(validationErrors, fmt.Errorf("more than one authentication method found for %v; found %v, only one is allowed", authInfoName, methods)) + } + + return validationErrors +} + +// validateContext looks for errors in the context. It is not transitive, so errors in the reference authInfo or cluster configs are not included in this return +func validateContext(contextName string, context clientcmdapi.Context, config clientcmdapi.Config) []error { + validationErrors := make([]error, 0) + + if len(context.AuthInfo) == 0 { + validationErrors = append(validationErrors, fmt.Errorf("user was not specified for context %q", contextName)) + } else if _, exists := config.AuthInfos[context.AuthInfo]; !exists { + validationErrors = append(validationErrors, fmt.Errorf("user %q was not found for context %q", context.AuthInfo, contextName)) + } + + if len(context.Cluster) == 0 { + validationErrors = append(validationErrors, fmt.Errorf("cluster was not specified for context %q", contextName)) + } else if _, exists := config.Clusters[context.Cluster]; !exists { + validationErrors = append(validationErrors, fmt.Errorf("cluster %q was not found for context %q", context.Cluster, contextName)) + } + + if len(context.Namespace) != 0 { + if len(validation.IsDNS1123Label(context.Namespace)) != 0 { + validationErrors = append(validationErrors, fmt.Errorf("namespace %q for context %q does not conform to the kubernetes DNS_LABEL rules", context.Namespace, contextName)) + } + } + + return validationErrors +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterrolebindings.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterrolebindings.go new file mode 100644 index 0000000..fa9cad9 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterrolebindings.go @@ -0,0 +1,92 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/watch" +) + +// ClusterRoleBindings has methods to work with ClusterRoleBinding resources in a namespace +type ClusterRoleBindings interface { + ClusterRoleBindings() ClusterRoleBindingInterface +} + +// ClusterRoleBindingInterface has methods to work with ClusterRoleBinding resources. +type ClusterRoleBindingInterface interface { + List(opts api.ListOptions) (*rbac.ClusterRoleBindingList, error) + Get(name string) (*rbac.ClusterRoleBinding, error) + Delete(name string, options *api.DeleteOptions) error + Create(clusterRoleBinding *rbac.ClusterRoleBinding) (*rbac.ClusterRoleBinding, error) + Update(clusterRoleBinding *rbac.ClusterRoleBinding) (*rbac.ClusterRoleBinding, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// clusterRoleBindings implements ClusterRoleBindingsNamespacer interface +type clusterRoleBindings struct { + client *RbacClient +} + +// newClusterRoleBindings returns a clusterRoleBindings +func newClusterRoleBindings(c *RbacClient) *clusterRoleBindings { + return &clusterRoleBindings{ + client: c, + } +} + +// List takes label and field selectors, and returns the list of clusterRoleBindings that match those selectors. +func (c *clusterRoleBindings) List(opts api.ListOptions) (result *rbac.ClusterRoleBindingList, err error) { + result = &rbac.ClusterRoleBindingList{} + err = c.client.Get().Resource("clusterrolebindings").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the clusterRoleBinding, and returns the corresponding ClusterRoleBinding object, and an error if it occurs +func (c *clusterRoleBindings) Get(name string) (result *rbac.ClusterRoleBinding, err error) { + result = &rbac.ClusterRoleBinding{} + err = c.client.Get().Resource("clusterrolebindings").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the clusterRoleBinding and deletes it. Returns an error if one occurs. +func (c *clusterRoleBindings) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Resource("clusterrolebindings").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a clusterRoleBinding and creates it. Returns the server's representation of the clusterRoleBinding, and an error, if it occurs. +func (c *clusterRoleBindings) Create(clusterRoleBinding *rbac.ClusterRoleBinding) (result *rbac.ClusterRoleBinding, err error) { + result = &rbac.ClusterRoleBinding{} + err = c.client.Post().Resource("clusterrolebindings").Body(clusterRoleBinding).Do().Into(result) + return +} + +// Update takes the representation of a clusterRoleBinding and updates it. Returns the server's representation of the clusterRoleBinding, and an error, if it occurs. +func (c *clusterRoleBindings) Update(clusterRoleBinding *rbac.ClusterRoleBinding) (result *rbac.ClusterRoleBinding, err error) { + result = &rbac.ClusterRoleBinding{} + err = c.client.Put().Resource("clusterrolebindings").Name(clusterRoleBinding.Name).Body(clusterRoleBinding).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterRoleBindings. +func (c *clusterRoleBindings) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Resource("clusterrolebindings"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterroles.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterroles.go new file mode 100644 index 0000000..165271a --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/clusterroles.go @@ -0,0 +1,92 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/watch" +) + +// ClusterRoles has methods to work with ClusterRole resources in a namespace +type ClusterRoles interface { + ClusterRoles() ClusterRoleInterface +} + +// ClusterRoleInterface has methods to work with ClusterRole resources. +type ClusterRoleInterface interface { + List(opts api.ListOptions) (*rbac.ClusterRoleList, error) + Get(name string) (*rbac.ClusterRole, error) + Delete(name string, options *api.DeleteOptions) error + Create(clusterRole *rbac.ClusterRole) (*rbac.ClusterRole, error) + Update(clusterRole *rbac.ClusterRole) (*rbac.ClusterRole, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// clusterRoles implements ClusterRolesNamespacer interface +type clusterRoles struct { + client *RbacClient +} + +// newClusterRoles returns a clusterRoles +func newClusterRoles(c *RbacClient) *clusterRoles { + return &clusterRoles{ + client: c, + } +} + +// List takes label and field selectors, and returns the list of clusterRoles that match those selectors. +func (c *clusterRoles) List(opts api.ListOptions) (result *rbac.ClusterRoleList, err error) { + result = &rbac.ClusterRoleList{} + err = c.client.Get().Resource("clusterroles").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the clusterRole, and returns the corresponding ClusterRole object, and an error if it occurs +func (c *clusterRoles) Get(name string) (result *rbac.ClusterRole, err error) { + result = &rbac.ClusterRole{} + err = c.client.Get().Resource("clusterroles").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the clusterRole and deletes it. Returns an error if one occurs. +func (c *clusterRoles) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Resource("clusterroles").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a clusterRole and creates it. Returns the server's representation of the clusterRole, and an error, if it occurs. +func (c *clusterRoles) Create(clusterRole *rbac.ClusterRole) (result *rbac.ClusterRole, err error) { + result = &rbac.ClusterRole{} + err = c.client.Post().Resource("clusterroles").Body(clusterRole).Do().Into(result) + return +} + +// Update takes the representation of a clusterRole and updates it. Returns the server's representation of the clusterRole, and an error, if it occurs. +func (c *clusterRoles) Update(clusterRole *rbac.ClusterRole) (result *rbac.ClusterRole, err error) { + result = &rbac.ClusterRole{} + err = c.client.Put().Resource("clusterroles").Name(clusterRole.Name).Body(clusterRole).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterRoles. +func (c *clusterRoles) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Resource("clusterroles"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/componentstatuses.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/componentstatuses.go new file mode 100644 index 0000000..aca996b --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/componentstatuses.go @@ -0,0 +1,60 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" +) + +type ComponentStatusesInterface interface { + ComponentStatuses() ComponentStatusInterface +} + +// ComponentStatusInterface contains methods to retrieve ComponentStatus +type ComponentStatusInterface interface { + List(opts api.ListOptions) (*api.ComponentStatusList, error) + Get(name string) (*api.ComponentStatus, error) + + // TODO: It'd be nice to have watch support at some point + //Watch(opts api.ListOptions) (watch.Interface, error) +} + +// componentStatuses implements ComponentStatusesInterface +type componentStatuses struct { + client *Client +} + +func newComponentStatuses(c *Client) *componentStatuses { + return &componentStatuses{c} +} + +func (c *componentStatuses) List(opts api.ListOptions) (result *api.ComponentStatusList, err error) { + result = &api.ComponentStatusList{} + err = c.client.Get(). + Resource("componentStatuses"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +func (c *componentStatuses) Get(name string) (result *api.ComponentStatus, err error) { + result = &api.ComponentStatus{} + err = c.client.Get().Resource("componentStatuses").Name(name).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/conditions.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/conditions.go new file mode 100644 index 0000000..5c28429 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/conditions.go @@ -0,0 +1,240 @@ +/* +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 unversioned + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/util/wait" + "k8s.io/kubernetes/pkg/watch" +) + +// ControllerHasDesiredReplicas returns a condition that will be true if and only if +// the desired replica count for a controller's ReplicaSelector equals the Replicas count. +func ControllerHasDesiredReplicas(c Interface, controller *api.ReplicationController) wait.ConditionFunc { + + // If we're given a controller where the status lags the spec, it either means that the controller is stale, + // or that the rc manager hasn't noticed the update yet. Polling status.Replicas is not safe in the latter case. + desiredGeneration := controller.Generation + + return func() (bool, error) { + ctrl, err := c.ReplicationControllers(controller.Namespace).Get(controller.Name) + if err != nil { + return false, err + } + // There's a chance a concurrent update modifies the Spec.Replicas causing this check to pass, + // or, after this check has passed, a modification causes the rc manager to create more pods. + // This will not be an issue once we've implemented graceful delete for rcs, but till then + // concurrent stop operations on the same rc might have unintended side effects. + return ctrl.Status.ObservedGeneration >= desiredGeneration && ctrl.Status.Replicas == ctrl.Spec.Replicas, nil + } +} + +// ReplicaSetHasDesiredReplicas returns a condition that will be true if and only if +// the desired replica count for a ReplicaSet's ReplicaSelector equals the Replicas count. +func ReplicaSetHasDesiredReplicas(c ExtensionsInterface, replicaSet *extensions.ReplicaSet) wait.ConditionFunc { + + // If we're given a ReplicaSet where the status lags the spec, it either means that the + // ReplicaSet is stale, or that the ReplicaSet manager hasn't noticed the update yet. + // Polling status.Replicas is not safe in the latter case. + desiredGeneration := replicaSet.Generation + + return func() (bool, error) { + rs, err := c.ReplicaSets(replicaSet.Namespace).Get(replicaSet.Name) + if err != nil { + return false, err + } + // There's a chance a concurrent update modifies the Spec.Replicas causing this check to + // pass, or, after this check has passed, a modification causes the ReplicaSet manager to + // create more pods. This will not be an issue once we've implemented graceful delete for + // ReplicaSets, but till then concurrent stop operations on the same ReplicaSet might have + // unintended side effects. + return rs.Status.ObservedGeneration >= desiredGeneration && rs.Status.Replicas == rs.Spec.Replicas, nil + } +} + +// JobHasDesiredParallelism returns a condition that will be true if the desired parallelism count +// for a job equals the current active counts or is less by an appropriate successful/unsuccessful count. +func JobHasDesiredParallelism(c BatchInterface, job *batch.Job) wait.ConditionFunc { + + return func() (bool, error) { + job, err := c.Jobs(job.Namespace).Get(job.Name) + if err != nil { + return false, err + } + + // desired parallelism can be either the exact number, in which case return immediately + if job.Status.Active == *job.Spec.Parallelism { + return true, nil + } + if job.Spec.Completions == nil { + // A job without specified completions needs to wait for Active to reach Parallelism. + return false, nil + } else { + // otherwise count successful + progress := *job.Spec.Completions - job.Status.Active - job.Status.Succeeded + return progress == 0, nil + } + } +} + +// DeploymentHasDesiredReplicas returns a condition that will be true if and only if +// the desired replica count for a deployment equals its updated replicas count. +// (non-terminated pods that have the desired template spec). +func DeploymentHasDesiredReplicas(c ExtensionsInterface, deployment *extensions.Deployment) wait.ConditionFunc { + // If we're given a deployment where the status lags the spec, it either + // means that the deployment is stale, or that the deployment manager hasn't + // noticed the update yet. Polling status.Replicas is not safe in the latter + // case. + desiredGeneration := deployment.Generation + + return func() (bool, error) { + deployment, err := c.Deployments(deployment.Namespace).Get(deployment.Name) + if err != nil { + return false, err + } + return deployment.Status.ObservedGeneration >= desiredGeneration && + deployment.Status.UpdatedReplicas == deployment.Spec.Replicas, nil + } +} + +// ErrPodCompleted is returned by PodRunning or PodContainerRunning to indicate that +// the pod has already reached completed state. +var ErrPodCompleted = fmt.Errorf("pod ran to completion") + +// PodRunning returns true if the pod is running, false if the pod has not yet reached running state, +// returns ErrPodCompleted if the pod has run to completion, or an error in any other case. +func PodRunning(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, "") + } + switch t := event.Object.(type) { + case *api.Pod: + switch t.Status.Phase { + case api.PodRunning: + return true, nil + case api.PodFailed, api.PodSucceeded: + return false, ErrPodCompleted + } + } + return false, nil +} + +// PodCompleted returns true if the pod has run to completion, false if the pod has not yet +// reached running state, or an error in any other case. +func PodCompleted(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, "") + } + switch t := event.Object.(type) { + case *api.Pod: + switch t.Status.Phase { + case api.PodFailed, api.PodSucceeded: + return true, nil + } + } + return false, nil +} + +// PodRunningAndReady returns true if the pod is running and ready, false if the pod has not +// yet reached those states, returns ErrPodCompleted if the pod has run to completion, or +// an error in any other case. +func PodRunningAndReady(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, "") + } + switch t := event.Object.(type) { + case *api.Pod: + switch t.Status.Phase { + case api.PodFailed, api.PodSucceeded: + return false, ErrPodCompleted + case api.PodRunning: + return api.IsPodReady(t), nil + } + } + return false, nil +} + +// PodNotPending returns true if the pod has left the pending state, false if it has not, +// or an error in any other case (such as if the pod was deleted). +func PodNotPending(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, "") + } + switch t := event.Object.(type) { + case *api.Pod: + switch t.Status.Phase { + case api.PodPending: + return false, nil + default: + return true, nil + } + } + return false, nil +} + +// PodContainerRunning returns false until the named container has ContainerStatus running (at least once), +// and will return an error if the pod is deleted, runs to completion, or the container pod is not available. +func PodContainerRunning(containerName string) watch.ConditionFunc { + return func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "pods"}, "") + } + switch t := event.Object.(type) { + case *api.Pod: + switch t.Status.Phase { + case api.PodRunning, api.PodPending: + case api.PodFailed, api.PodSucceeded: + return false, ErrPodCompleted + default: + return false, nil + } + for _, s := range t.Status.ContainerStatuses { + if s.Name != containerName { + continue + } + return s.State.Running != nil, nil + } + return false, nil + } + return false, nil + } +} + +// ServiceAccountHasSecrets returns true if the service account has at least one secret, +// false if it does not, or an error. +func ServiceAccountHasSecrets(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + return false, errors.NewNotFound(unversioned.GroupResource{Resource: "serviceaccounts"}, "") + } + switch t := event.Object.(type) { + case *api.ServiceAccount: + return len(t.Secrets) > 0, nil + } + return false, nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/configmap.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/configmap.go new file mode 100644 index 0000000..c2f2035 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/configmap.go @@ -0,0 +1,122 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +const ( + ConfigMapResourceName string = "configmaps" +) + +type ConfigMapsNamespacer interface { + ConfigMaps(namespace string) ConfigMapsInterface +} + +type ConfigMapsInterface interface { + Get(string) (*api.ConfigMap, error) + List(opts api.ListOptions) (*api.ConfigMapList, error) + Create(*api.ConfigMap) (*api.ConfigMap, error) + Delete(string) error + Update(*api.ConfigMap) (*api.ConfigMap, error) + Watch(api.ListOptions) (watch.Interface, error) +} + +type ConfigMaps struct { + client *Client + namespace string +} + +// ConfigMaps should implement ConfigMapsInterface +var _ ConfigMapsInterface = &ConfigMaps{} + +func newConfigMaps(c *Client, ns string) *ConfigMaps { + return &ConfigMaps{ + client: c, + namespace: ns, + } +} + +func (c *ConfigMaps) Get(name string) (*api.ConfigMap, error) { + result := &api.ConfigMap{} + err := c.client.Get(). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + Name(name). + Do(). + Into(result) + + return result, err +} + +func (c *ConfigMaps) List(opts api.ListOptions) (*api.ConfigMapList, error) { + result := &api.ConfigMapList{} + err := c.client.Get(). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +func (c *ConfigMaps) Create(cfg *api.ConfigMap) (*api.ConfigMap, error) { + result := &api.ConfigMap{} + err := c.client.Post(). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + Body(cfg). + Do(). + Into(result) + + return result, err +} + +func (c *ConfigMaps) Delete(name string) error { + return c.client.Delete(). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + Name(name). + Do(). + Error() +} + +func (c *ConfigMaps) Update(cfg *api.ConfigMap) (*api.ConfigMap, error) { + result := &api.ConfigMap{} + + err := c.client.Put(). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + Name(cfg.Name). + Body(cfg). + Do(). + Into(result) + + return result, err +} + +func (c *ConfigMaps) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.namespace). + Resource(ConfigMapResourceName). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/containerinfo.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/containerinfo.go new file mode 100644 index 0000000..2f9aae8 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/containerinfo.go @@ -0,0 +1,123 @@ +/* +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 unversioned + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "strconv" + + cadvisorapi "github.com/google/cadvisor/info/v1" +) + +type ContainerInfoGetter interface { + // GetContainerInfo returns information about a container. + GetContainerInfo(host, podID, containerID string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) + // GetRootInfo returns information about the root container on a machine. + GetRootInfo(host string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) + // GetMachineInfo returns the machine's information like number of cores, memory capacity. + GetMachineInfo(host string) (*cadvisorapi.MachineInfo, error) +} + +type HTTPContainerInfoGetter struct { + Client *http.Client + Port int +} + +func (self *HTTPContainerInfoGetter) GetMachineInfo(host string) (*cadvisorapi.MachineInfo, error) { + request, err := http.NewRequest( + "GET", + fmt.Sprintf("http://%v/spec", + net.JoinHostPort(host, strconv.Itoa(self.Port)), + ), + nil, + ) + if err != nil { + return nil, err + } + + response, err := self.Client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + return nil, fmt.Errorf("trying to get machine spec from %v; received status %v", + host, response.Status) + } + var minfo cadvisorapi.MachineInfo + err = json.NewDecoder(response.Body).Decode(&minfo) + if err != nil { + return nil, err + } + return &minfo, nil +} + +func (self *HTTPContainerInfoGetter) getContainerInfo(host, path string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { + var body io.Reader + if req != nil { + content, err := json.Marshal(req) + if err != nil { + return nil, err + } + body = bytes.NewBuffer(content) + } + + request, err := http.NewRequest( + "GET", + fmt.Sprintf("http://%v/stats/%v", + net.JoinHostPort(host, strconv.Itoa(self.Port)), + path, + ), + body, + ) + if err != nil { + return nil, err + } + + response, err := self.Client.Do(request) + if err != nil { + return nil, err + } + defer response.Body.Close() + if response.StatusCode != http.StatusOK { + return nil, fmt.Errorf("trying to get info for %v from %v; received status %v", + path, host, response.Status) + } + var cinfo cadvisorapi.ContainerInfo + err = json.NewDecoder(response.Body).Decode(&cinfo) + if err != nil { + return nil, err + } + return &cinfo, nil +} + +func (self *HTTPContainerInfoGetter) GetContainerInfo(host, podID, containerID string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { + return self.getContainerInfo( + host, + fmt.Sprintf("%v/%v", podID, containerID), + req, + ) +} + +func (self *HTTPContainerInfoGetter) GetRootInfo(host string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) { + return self.getContainerInfo(host, "", req) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/daemon_sets.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/daemon_sets.go new file mode 100644 index 0000000..7ec9182 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/daemon_sets.go @@ -0,0 +1,100 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// DaemonsSetsNamespacer has methods to work with DaemonSet resources in a namespace +type DaemonSetsNamespacer interface { + DaemonSets(namespace string) DaemonSetInterface +} + +type DaemonSetInterface interface { + List(opts api.ListOptions) (*extensions.DaemonSetList, error) + Get(name string) (*extensions.DaemonSet, error) + Create(ctrl *extensions.DaemonSet) (*extensions.DaemonSet, error) + Update(ctrl *extensions.DaemonSet) (*extensions.DaemonSet, error) + UpdateStatus(ctrl *extensions.DaemonSet) (*extensions.DaemonSet, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// daemonSets implements DaemonsSetsNamespacer interface +type daemonSets struct { + r *ExtensionsClient + ns string +} + +func newDaemonSets(c *ExtensionsClient, namespace string) *daemonSets { + return &daemonSets{c, namespace} +} + +// Ensure statically that daemonSets implements DaemonSetsInterface. +var _ DaemonSetInterface = &daemonSets{} + +func (c *daemonSets) List(opts api.ListOptions) (result *extensions.DaemonSetList, err error) { + result = &extensions.DaemonSetList{} + err = c.r.Get().Namespace(c.ns).Resource("daemonsets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular daemon set. +func (c *daemonSets) Get(name string) (result *extensions.DaemonSet, err error) { + result = &extensions.DaemonSet{} + err = c.r.Get().Namespace(c.ns).Resource("daemonsets").Name(name).Do().Into(result) + return +} + +// Create creates a new daemon set. +func (c *daemonSets) Create(daemon *extensions.DaemonSet) (result *extensions.DaemonSet, err error) { + result = &extensions.DaemonSet{} + err = c.r.Post().Namespace(c.ns).Resource("daemonsets").Body(daemon).Do().Into(result) + return +} + +// Update updates an existing daemon set. +func (c *daemonSets) Update(daemon *extensions.DaemonSet) (result *extensions.DaemonSet, err error) { + result = &extensions.DaemonSet{} + err = c.r.Put().Namespace(c.ns).Resource("daemonsets").Name(daemon.Name).Body(daemon).Do().Into(result) + return +} + +// UpdateStatus updates an existing daemon set status +func (c *daemonSets) UpdateStatus(daemon *extensions.DaemonSet) (result *extensions.DaemonSet, err error) { + result = &extensions.DaemonSet{} + err = c.r.Put().Namespace(c.ns).Resource("daemonsets").Name(daemon.Name).SubResource("status").Body(daemon).Do().Into(result) + return +} + +// Delete deletes an existing daemon set. +func (c *daemonSets) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("daemonsets").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested daemon sets. +func (c *daemonSets) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("daemonsets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/deployment.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/deployment.go new file mode 100644 index 0000000..a5e8afe --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/deployment.go @@ -0,0 +1,111 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// DeploymentsNamespacer has methods to work with Deployment resources in a namespace +type DeploymentsNamespacer interface { + Deployments(namespace string) DeploymentInterface +} + +// DeploymentInterface has methods to work with Deployment resources. +type DeploymentInterface interface { + List(opts api.ListOptions) (*extensions.DeploymentList, error) + Get(name string) (*extensions.Deployment, error) + Delete(name string, options *api.DeleteOptions) error + Create(*extensions.Deployment) (*extensions.Deployment, error) + Update(*extensions.Deployment) (*extensions.Deployment, error) + UpdateStatus(*extensions.Deployment) (*extensions.Deployment, error) + Watch(opts api.ListOptions) (watch.Interface, error) + Rollback(*extensions.DeploymentRollback) error +} + +// deployments implements DeploymentInterface +type deployments struct { + client *ExtensionsClient + ns string +} + +// Ensure statically that deployments implements DeploymentInterface. +var _ DeploymentInterface = &deployments{} + +// newDeployments returns a Deployments +func newDeployments(c *ExtensionsClient, namespace string) *deployments { + return &deployments{ + client: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of Deployments that match those selectors. +func (c *deployments) List(opts api.ListOptions) (result *extensions.DeploymentList, err error) { + result = &extensions.DeploymentList{} + err = c.client.Get().Namespace(c.ns).Resource("deployments").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes name of the deployment, and returns the corresponding deployment object, and an error if there is any. +func (c *deployments) Get(name string) (result *extensions.Deployment, err error) { + result = &extensions.Deployment{} + err = c.client.Get().Namespace(c.ns).Resource("deployments").Name(name).Do().Into(result) + return +} + +// Delete takes name of the deployment and deletes it. Returns an error if one occurs. +func (c *deployments) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Namespace(c.ns).Resource("deployments").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a deployment and creates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *deployments) Create(deployment *extensions.Deployment) (result *extensions.Deployment, err error) { + result = &extensions.Deployment{} + err = c.client.Post().Namespace(c.ns).Resource("deployments").Body(deployment).Do().Into(result) + return +} + +// Update takes the representation of a deployment and updates it. Returns the server's representation of the deployment, and an error, if there is any. +func (c *deployments) Update(deployment *extensions.Deployment) (result *extensions.Deployment, err error) { + result = &extensions.Deployment{} + err = c.client.Put().Namespace(c.ns).Resource("deployments").Name(deployment.Name).Body(deployment).Do().Into(result) + return +} + +func (c *deployments) UpdateStatus(deployment *extensions.Deployment) (result *extensions.Deployment, err error) { + result = &extensions.Deployment{} + err = c.client.Put().Namespace(c.ns).Resource("deployments").Name(deployment.Name).SubResource("status").Body(deployment).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested deployments. +func (c *deployments) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("deployments"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// Rollback applied the provided DeploymentRollback to the named deployment in the current namespace. +func (c *deployments) Rollback(deploymentRollback *extensions.DeploymentRollback) error { + return c.client.Post().Namespace(c.ns).Resource("deployments").Name(deploymentRollback.Name).SubResource("rollback").Body(deploymentRollback).Do().Error() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/doc.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/doc.go new file mode 100644 index 0000000..dac3925 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/doc.go @@ -0,0 +1,57 @@ +/* +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 unversioned contains the implementation of the client side communication with the +Kubernetes master. The Client class provides methods for reading, creating, updating, +and deleting pods, replication controllers, daemons, services, and nodes. + +Most consumers should use the Config object to create a Client: + + import ( + client "k8s.io/kubernetes/pkg/client/unversioned" + "k8s.io/kubernetes/pkg/api" + ) + + [...] + + config := &client.Config{ + Host: "http://localhost:8080", + Username: "test", + Password: "password", + } + client, err := client.New(config) + if err != nil { + // handle error + } + pods, err := client.Pods(api.NamespaceDefault).List(api.ListOptions{}) + if err != nil { + // handle error + } + +More advanced consumers may wish to provide their own transport via a http.RoundTripper: + + config := &client.Config{ + Host: "https://localhost:8080", + Transport: oauthclient.Transport(), + } + client, err := client.New(config) + +The RESTClient type implements the Kubernetes API conventions (see `docs/devel/api-conventions.md`) +for a given API path and is intended for use by consumers implementing their own Kubernetes +compatible APIs. +*/ +package unversioned diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/endpoints.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/endpoints.go new file mode 100644 index 0000000..6e20a34 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/endpoints.go @@ -0,0 +1,101 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// EndpointsNamespacer has methods to work with Endpoints resources in a namespace +type EndpointsNamespacer interface { + Endpoints(namespace string) EndpointsInterface +} + +// EndpointsInterface has methods to work with Endpoints resources +type EndpointsInterface interface { + Create(endpoints *api.Endpoints) (*api.Endpoints, error) + List(opts api.ListOptions) (*api.EndpointsList, error) + Get(name string) (*api.Endpoints, error) + Delete(name string) error + Update(endpoints *api.Endpoints) (*api.Endpoints, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// endpoints implements EndpointsInterface +type endpoints struct { + r *Client + ns string +} + +// newEndpoints returns a endpoints +func newEndpoints(c *Client, namespace string) *endpoints { + return &endpoints{c, namespace} +} + +// Create creates a new endpoint. +func (c *endpoints) Create(endpoints *api.Endpoints) (*api.Endpoints, error) { + result := &api.Endpoints{} + err := c.r.Post().Namespace(c.ns).Resource("endpoints").Body(endpoints).Do().Into(result) + return result, err +} + +// List takes a selector, and returns the list of endpoints that match that selector +func (c *endpoints) List(opts api.ListOptions) (result *api.EndpointsList, err error) { + result = &api.EndpointsList{} + err = c.r.Get(). + Namespace(c.ns). + Resource("endpoints"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + return +} + +// Get returns information about the endpoints for a particular service. +func (c *endpoints) Get(name string) (result *api.Endpoints, err error) { + result = &api.Endpoints{} + err = c.r.Get().Namespace(c.ns).Resource("endpoints").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the endpoint, and returns an error if one occurs +func (c *endpoints) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("endpoints").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested endpoints for a service. +func (c *endpoints) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("endpoints"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +func (c *endpoints) Update(endpoints *api.Endpoints) (*api.Endpoints, error) { + result := &api.Endpoints{} + err := c.r.Put(). + Namespace(c.ns). + Resource("endpoints"). + Name(endpoints.Name). + Body(endpoints). + Do(). + Into(result) + return result, err +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/events.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/events.go new file mode 100644 index 0000000..3421bd8 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/events.go @@ -0,0 +1,219 @@ +/* +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 unversioned + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/watch" +) + +// EventNamespacer can return an EventInterface for the given namespace. +type EventNamespacer interface { + Events(namespace string) EventInterface +} + +// EventInterface has methods to work with Event resources +type EventInterface interface { + Create(event *api.Event) (*api.Event, error) + Update(event *api.Event) (*api.Event, error) + Patch(event *api.Event, data []byte) (*api.Event, error) + List(opts api.ListOptions) (*api.EventList, error) + Get(name string) (*api.Event, error) + Watch(opts api.ListOptions) (watch.Interface, error) + // Search finds events about the specified object + Search(objOrRef runtime.Object) (*api.EventList, error) + Delete(name string) error + // DeleteCollection deletes a collection of events. + DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error + // Returns the appropriate field selector based on the API version being used to communicate with the server. + // The returned field selector can be used with List and Watch to filter desired events. + GetFieldSelector(involvedObjectName, involvedObjectNamespace, involvedObjectKind, involvedObjectUID *string) fields.Selector +} + +// events implements Events interface +type events struct { + client *Client + namespace string +} + +// newEvents returns a new events object. +func newEvents(c *Client, ns string) *events { + return &events{ + client: c, + namespace: ns, + } +} + +// Create makes a new event. Returns the copy of the event the server returns, +// or an error. The namespace to create the event within is deduced from the +// event; it must either match this event client's namespace, or this event +// client must have been created with the "" namespace. +func (e *events) Create(event *api.Event) (*api.Event, error) { + if e.namespace != "" && event.Namespace != e.namespace { + return nil, fmt.Errorf("can't create an event with namespace '%v' in namespace '%v'", event.Namespace, e.namespace) + } + result := &api.Event{} + err := e.client.Post(). + Namespace(event.Namespace). + Resource("events"). + Body(event). + Do(). + Into(result) + return result, err +} + +// Update modifies an existing event. It returns the copy of the event that the server returns, +// or an error. The namespace and key to update the event within is deduced from the event. The +// namespace must either match this event client's namespace, or this event client must have been +// created with the "" namespace. Update also requires the ResourceVersion to be set in the event +// object. +func (e *events) Update(event *api.Event) (*api.Event, error) { + result := &api.Event{} + err := e.client.Put(). + Namespace(event.Namespace). + Resource("events"). + Name(event.Name). + Body(event). + Do(). + Into(result) + return result, err +} + +// Patch modifies an existing event. It returns the copy of the event that the server returns, or an +// error. The namespace and name of the target event is deduced from the incompleteEvent. The +// namespace must either match this event client's namespace, or this event client must have been +// created with the "" namespace. +func (e *events) Patch(incompleteEvent *api.Event, data []byte) (*api.Event, error) { + result := &api.Event{} + err := e.client.Patch(api.StrategicMergePatchType). + Namespace(incompleteEvent.Namespace). + Resource("events"). + Name(incompleteEvent.Name). + Body(data). + Do(). + Into(result) + return result, err +} + +// List returns a list of events matching the selectors. +func (e *events) List(opts api.ListOptions) (*api.EventList, error) { + result := &api.EventList{} + err := e.client.Get(). + Namespace(e.namespace). + Resource("events"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + return result, err +} + +// Get returns the given event, or an error. +func (e *events) Get(name string) (*api.Event, error) { + result := &api.Event{} + err := e.client.Get(). + Namespace(e.namespace). + Resource("events"). + Name(name). + Do(). + Into(result) + return result, err +} + +// Watch starts watching for events matching the given selectors. +func (e *events) Watch(opts api.ListOptions) (watch.Interface, error) { + return e.client.Get(). + Prefix("watch"). + Namespace(e.namespace). + Resource("events"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// Search finds events about the specified object. The namespace of the +// object must match this event's client namespace unless the event client +// was made with the "" namespace. +func (e *events) Search(objOrRef runtime.Object) (*api.EventList, error) { + ref, err := api.GetReference(objOrRef) + if err != nil { + return nil, err + } + if e.namespace != "" && ref.Namespace != e.namespace { + return nil, fmt.Errorf("won't be able to find any events of namespace '%v' in namespace '%v'", ref.Namespace, e.namespace) + } + stringRefKind := string(ref.Kind) + var refKind *string + if stringRefKind != "" { + refKind = &stringRefKind + } + stringRefUID := string(ref.UID) + var refUID *string + if stringRefUID != "" { + refUID = &stringRefUID + } + fieldSelector := e.GetFieldSelector(&ref.Name, &ref.Namespace, refKind, refUID) + return e.List(api.ListOptions{FieldSelector: fieldSelector}) +} + +// Delete deletes an existing event. +func (e *events) Delete(name string) error { + return e.client.Delete(). + Namespace(e.namespace). + Resource("events"). + Name(name). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (e *events) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error { + return e.client.Delete(). + Namespace(e.namespace). + Resource("events"). + VersionedParams(&listOptions, api.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Returns the appropriate field selector based on the API version being used to communicate with the server. +// The returned field selector can be used with List and Watch to filter desired events. +func (e *events) GetFieldSelector(involvedObjectName, involvedObjectNamespace, involvedObjectKind, involvedObjectUID *string) fields.Selector { + apiVersion := e.client.APIVersion().String() + field := fields.Set{} + if involvedObjectName != nil { + field[GetInvolvedObjectNameFieldLabel(apiVersion)] = *involvedObjectName + } + if involvedObjectNamespace != nil { + field["involvedObject.namespace"] = *involvedObjectNamespace + } + if involvedObjectKind != nil { + field["involvedObject.kind"] = *involvedObjectKind + } + if involvedObjectUID != nil { + field["involvedObject.uid"] = *involvedObjectUID + } + return field.AsSelector() +} + +// Returns the appropriate field label to use for name of the involved object as per the given API version. +func GetInvolvedObjectNameFieldLabel(version string) string { + return "involvedObject.name" +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/extensions.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/extensions.go new file mode 100644 index 0000000..39b3408 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/extensions.go @@ -0,0 +1,131 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/client/restclient" +) + +// Interface holds the experimental methods for clients of Kubernetes +// to allow mock testing. +// Features of Extensions group are not supported and may be changed or removed in +// incompatible ways at any time. +type ExtensionsInterface interface { + ScaleNamespacer + DaemonSetsNamespacer + DeploymentsNamespacer + JobsNamespacer + IngressNamespacer + NetworkPolicyNamespacer + ThirdPartyResourceNamespacer + ReplicaSetsNamespacer + PodSecurityPoliciesInterface +} + +// ExtensionsClient is used to interact with experimental Kubernetes features. +// Features of Extensions group are not supported and may be changed or removed in +// incompatible ways at any time. +type ExtensionsClient struct { + *restclient.RESTClient +} + +func (c *ExtensionsClient) PodSecurityPolicies() PodSecurityPolicyInterface { + return newPodSecurityPolicy(c) +} + +func (c *ExtensionsClient) Scales(namespace string) ScaleInterface { + return newScales(c, namespace) +} + +func (c *ExtensionsClient) DaemonSets(namespace string) DaemonSetInterface { + return newDaemonSets(c, namespace) +} + +func (c *ExtensionsClient) Deployments(namespace string) DeploymentInterface { + return newDeployments(c, namespace) +} + +func (c *ExtensionsClient) Jobs(namespace string) JobInterface { + return newJobs(c, namespace) +} + +func (c *ExtensionsClient) Ingress(namespace string) IngressInterface { + return newIngress(c, namespace) +} + +func (c *ExtensionsClient) NetworkPolicies(namespace string) NetworkPolicyInterface { + return newNetworkPolicies(c, namespace) +} + +func (c *ExtensionsClient) ThirdPartyResources() ThirdPartyResourceInterface { + return newThirdPartyResources(c) +} + +func (c *ExtensionsClient) ReplicaSets(namespace string) ReplicaSetInterface { + return newReplicaSets(c, namespace) +} + +// NewExtensions creates a new ExtensionsClient for the given config. This client +// provides access to experimental Kubernetes features. +// Features of Extensions group are not supported and may be changed or removed in +// incompatible ways at any time. +func NewExtensions(c *restclient.Config) (*ExtensionsClient, error) { + config := *c + if err := setExtensionsDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ExtensionsClient{client}, nil +} + +// NewExtensionsOrDie creates a new ExtensionsClient for the given config and +// panics if there is an error in the config. +// Features of Extensions group are not supported and may be changed or removed in +// incompatible ways at any time. +func NewExtensionsOrDie(c *restclient.Config) *ExtensionsClient { + client, err := NewExtensions(c) + if err != nil { + panic(err) + } + return client +} + +func setExtensionsDefaults(config *restclient.Config) error { + // if experimental group is not registered, return an error + g, err := registered.Group(extensions.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/flags.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/flags.go new file mode 100644 index 0000000..7d32a25 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/flags.go @@ -0,0 +1,31 @@ +/* +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 unversioned + +import ( + "time" +) + +// FlagSet abstracts the flag interface for compatibility with both Golang "flag" +// and cobra pflags (Posix style). +type FlagSet interface { + StringVar(p *string, name, value, usage string) + BoolVar(p *bool, name string, value bool, usage string) + UintVar(p *uint, name string, value uint, usage string) + DurationVar(p *time.Duration, name string, value time.Duration, usage string) + IntVar(p *int, name string, value int, usage string) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/helper.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/helper.go new file mode 100644 index 0000000..8475769 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/helper.go @@ -0,0 +1,273 @@ +/* +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 unversioned + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/certificates" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/client/typed/discovery" + "k8s.io/kubernetes/pkg/util/sets" + "k8s.io/kubernetes/pkg/version" + // Import solely to initialize client auth plugins. + _ "k8s.io/kubernetes/plugin/pkg/client/auth" +) + +const ( + legacyAPIPath = "/api" + defaultAPIPath = "/apis" +) + +// New creates a Kubernetes client for the given config. This client works with pods, +// replication controllers, daemons, and services. It allows operations such as list, get, update +// and delete on these objects. An error is returned if the provided configuration +// is not valid. +func New(c *restclient.Config) (*Client, error) { + config := *c + if err := SetKubernetesDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + + discoveryConfig := *c + discoveryClient, err := discovery.NewDiscoveryClientForConfig(&discoveryConfig) + if err != nil { + return nil, err + } + + var autoscalingClient *AutoscalingClient + if registered.IsRegistered(autoscaling.GroupName) { + autoscalingConfig := *c + autoscalingClient, err = NewAutoscaling(&autoscalingConfig) + if err != nil { + return nil, err + } + } + + var batchClient *BatchClient + if registered.IsRegistered(batch.GroupName) { + batchConfig := *c + batchClient, err = NewBatch(&batchConfig) + if err != nil { + return nil, err + } + } + + var extensionsClient *ExtensionsClient + if registered.IsRegistered(extensions.GroupName) { + extensionsConfig := *c + extensionsClient, err = NewExtensions(&extensionsConfig) + if err != nil { + return nil, err + } + } + var policyClient *PolicyClient + if registered.IsRegistered(policy.GroupName) { + policyConfig := *c + policyClient, err = NewPolicy(&policyConfig) + if err != nil { + return nil, err + } + } + var certsClient *CertificatesClient + if registered.IsRegistered(certificates.GroupName) { + certsConfig := *c + certsClient, err = NewCertificates(&certsConfig) + if err != nil { + return nil, err + } + } + + var appsClient *AppsClient + if registered.IsRegistered(apps.GroupName) { + appsConfig := *c + appsClient, err = NewApps(&appsConfig) + if err != nil { + return nil, err + } + } + + var rbacClient *RbacClient + if registered.IsRegistered(rbac.GroupName) { + rbacConfig := *c + rbacClient, err = NewRbac(&rbacConfig) + if err != nil { + return nil, err + } + } + + return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, CertificatesClient: certsClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient, AppsClient: appsClient, PolicyClient: policyClient, RbacClient: rbacClient}, nil +} + +// MatchesServerVersion queries the server to compares the build version +// (git hash) of the client with the server's build version. It returns an error +// if it failed to contact the server or if the versions are not an exact match. +func MatchesServerVersion(client *Client, c *restclient.Config) error { + var err error + if client == nil { + client, err = New(c) + if err != nil { + return err + } + } + cVer := version.Get() + sVer, err := client.Discovery().ServerVersion() + if err != nil { + return fmt.Errorf("couldn't read version from server: %v\n", err) + } + // GitVersion includes GitCommit and GitTreeState, but best to be safe? + if cVer.GitVersion != sVer.GitVersion || cVer.GitCommit != sVer.GitCommit || cVer.GitTreeState != sVer.GitTreeState { + return fmt.Errorf("server version (%#v) differs from client version (%#v)!\n", sVer, cVer) + } + + return nil +} + +// NegotiateVersion queries the server's supported api versions to find +// a version that both client and server support. +// - If no version is provided, try registered client versions in order of +// preference. +// - If version is provided, but not default config (explicitly requested via +// commandline flag), and is unsupported by the server, print a warning to +// stderr and try client's registered versions in order of preference. +// - If version is config default, and the server does not support it, +// return an error. +func NegotiateVersion(client *Client, c *restclient.Config, requestedGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) { + var err error + if client == nil { + client, err = New(c) + if err != nil { + return nil, err + } + } + clientVersions := sets.String{} + for _, gv := range clientRegisteredGVs { + clientVersions.Insert(gv.String()) + } + groups, err := client.ServerGroups() + if err != nil { + // This is almost always a connection error, and higher level code should treat this as a generic error, + // not a negotiation specific error. + return nil, err + } + versions := unversioned.ExtractGroupVersions(groups) + serverVersions := sets.String{} + for _, v := range versions { + serverVersions.Insert(v) + } + + // If no version requested, use config version (may also be empty). + // make a copy of the original so we don't risk mutating input here or in the returned value + var preferredGV *unversioned.GroupVersion + switch { + case requestedGV != nil: + t := *requestedGV + preferredGV = &t + case c.GroupVersion != nil: + t := *c.GroupVersion + preferredGV = &t + } + + // If version explicitly requested verify that both client and server support it. + // If server does not support warn, but try to negotiate a lower version. + if preferredGV != nil { + if !clientVersions.Has(preferredGV.String()) { + return nil, fmt.Errorf("client does not support API version %q; client supported API versions: %v", preferredGV, clientVersions) + + } + // If the server supports no versions, then we should just use the preferredGV + // This can happen because discovery fails due to 403 Forbidden errors + if len(serverVersions) == 0 { + return preferredGV, nil + } + if serverVersions.Has(preferredGV.String()) { + return preferredGV, nil + } + // If we are using an explicit config version the server does not support, fail. + if (c.GroupVersion != nil) && (*preferredGV == *c.GroupVersion) { + return nil, fmt.Errorf("server does not support API version %q", preferredGV) + } + } + + for _, clientGV := range clientRegisteredGVs { + if serverVersions.Has(clientGV.String()) { + // Version was not explicitly requested in command config (--api-version). + // Ok to fall back to a supported version with a warning. + // TODO: caesarxuchao: enable the warning message when we have + // proper fix. Please refer to issue #14895. + // if len(version) != 0 { + // glog.Warningf("Server does not support API version '%s'. Falling back to '%s'.", version, clientVersion) + // } + t := clientGV + return &t, nil + } + } + return nil, fmt.Errorf("failed to negotiate an api version; server supports: %v, client supports: %v", + serverVersions, clientVersions) +} + +// NewOrDie creates a Kubernetes client and panics if the provided API version is not recognized. +func NewOrDie(c *restclient.Config) *Client { + client, err := New(c) + if err != nil { + panic(err) + } + return client +} + +// NewInCluster is a shortcut for calling InClusterConfig() and then New(). +func NewInCluster() (*Client, error) { + cc, err := restclient.InClusterConfig() + if err != nil { + return nil, err + } + return New(cc) +} + +// SetKubernetesDefaults sets default values on the provided client config for accessing the +// Kubernetes API or returns an error if any of the defaults are impossible or invalid. +// TODO: this method needs to be split into one that sets defaults per group, expected to be fix in PR "Refactoring clientcache.go and helper.go #14592" +func SetKubernetesDefaults(config *restclient.Config) error { + if config.APIPath == "" { + config.APIPath = legacyAPIPath + } + g, err := registered.Group(api.GroupName) + if err != nil { + return err + } + // TODO: Unconditionally set the config.Version, until we fix the config. + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + if config.NegotiatedSerializer == nil { + config.NegotiatedSerializer = api.Codecs + } + + return restclient.SetKubernetesDefaults(config) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/horizontalpodautoscaler.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/horizontalpodautoscaler.go new file mode 100644 index 0000000..76c6a9c --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/horizontalpodautoscaler.go @@ -0,0 +1,103 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/watch" +) + +// HorizontalPodAutoscalersNamespacer has methods to work with HorizontalPodAutoscaler resources in a namespace +type HorizontalPodAutoscalersNamespacer interface { + HorizontalPodAutoscalers(namespace string) HorizontalPodAutoscalerInterface +} + +// HorizontalPodAutoscalerInterface has methods to work with HorizontalPodAutoscaler resources. +type HorizontalPodAutoscalerInterface interface { + List(opts api.ListOptions) (*autoscaling.HorizontalPodAutoscalerList, error) + Get(name string) (*autoscaling.HorizontalPodAutoscaler, error) + Delete(name string, options *api.DeleteOptions) error + Create(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) + Update(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) + UpdateStatus(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// horizontalPodAutoscalers implements HorizontalPodAutoscalersNamespacer interface using AutoscalingClient internally +type horizontalPodAutoscalers struct { + client *AutoscalingClient + ns string +} + +// newHorizontalPodAutoscalers returns a horizontalPodAutoscalers +func newHorizontalPodAutoscalers(c *AutoscalingClient, namespace string) *horizontalPodAutoscalers { + return &horizontalPodAutoscalers{ + client: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of horizontalPodAutoscalers that match those selectors. +func (c *horizontalPodAutoscalers) List(opts api.ListOptions) (result *autoscaling.HorizontalPodAutoscalerList, err error) { + result = &autoscaling.HorizontalPodAutoscalerList{} + err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the horizontalPodAutoscaler, and returns the corresponding HorizontalPodAutoscaler object, and an error if it occurs +func (c *horizontalPodAutoscalers) Get(name string) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} + err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. +func (c *horizontalPodAutoscalers) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. +func (c *horizontalPodAutoscalers) Create(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} + err = c.client.Post().Namespace(c.ns).Resource("horizontalPodAutoscalers").Body(horizontalPodAutoscaler).Do().Into(result) + return +} + +// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. +func (c *horizontalPodAutoscalers) Update(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} + err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).Body(horizontalPodAutoscaler).Do().Into(result) + return +} + +// UpdateStatus takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. +func (c *horizontalPodAutoscalers) UpdateStatus(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} + err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).SubResource("status").Body(horizontalPodAutoscaler).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. +func (c *horizontalPodAutoscalers) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("horizontalPodAutoscalers"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/import_known_versions.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/import_known_versions.go new file mode 100644 index 0000000..8508573 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/import_known_versions.go @@ -0,0 +1,41 @@ +/* +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 unversioned + +// These imports are the API groups the client will support. +import ( + "fmt" + + _ "k8s.io/kubernetes/pkg/api/install" + "k8s.io/kubernetes/pkg/apimachinery/registered" + _ "k8s.io/kubernetes/pkg/apis/apps/install" + _ "k8s.io/kubernetes/pkg/apis/authentication.k8s.io/install" + _ "k8s.io/kubernetes/pkg/apis/authorization/install" + _ "k8s.io/kubernetes/pkg/apis/autoscaling/install" + _ "k8s.io/kubernetes/pkg/apis/batch/install" + _ "k8s.io/kubernetes/pkg/apis/certificates/install" + _ "k8s.io/kubernetes/pkg/apis/componentconfig/install" + _ "k8s.io/kubernetes/pkg/apis/extensions/install" + _ "k8s.io/kubernetes/pkg/apis/policy/install" + _ "k8s.io/kubernetes/pkg/apis/rbac/install" +) + +func init() { + if missingVersions := registered.ValidateEnvRequestedVersions(); len(missingVersions) != 0 { + panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions)) + } +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/ingress.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/ingress.go new file mode 100644 index 0000000..59c6a6d --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/ingress.go @@ -0,0 +1,100 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// IngressNamespacer has methods to work with Ingress resources in a namespace +type IngressNamespacer interface { + Ingress(namespace string) IngressInterface +} + +// IngressInterface exposes methods to work on Ingress resources. +type IngressInterface interface { + List(opts api.ListOptions) (*extensions.IngressList, error) + Get(name string) (*extensions.Ingress, error) + Create(ingress *extensions.Ingress) (*extensions.Ingress, error) + Update(ingress *extensions.Ingress) (*extensions.Ingress, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(ingress *extensions.Ingress) (*extensions.Ingress, error) +} + +// ingress implements IngressNamespacer interface +type ingress struct { + r *ExtensionsClient + ns string +} + +// newIngress returns a ingress +func newIngress(c *ExtensionsClient, namespace string) *ingress { + return &ingress{c, namespace} +} + +// List returns a list of ingress that match the label and field selectors. +func (c *ingress) List(opts api.ListOptions) (result *extensions.IngressList, err error) { + result = &extensions.IngressList{} + err = c.r.Get().Namespace(c.ns).Resource("ingresses").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular ingress. +func (c *ingress) Get(name string) (result *extensions.Ingress, err error) { + result = &extensions.Ingress{} + err = c.r.Get().Namespace(c.ns).Resource("ingresses").Name(name).Do().Into(result) + return +} + +// Create creates a new ingress. +func (c *ingress) Create(ingress *extensions.Ingress) (result *extensions.Ingress, err error) { + result = &extensions.Ingress{} + err = c.r.Post().Namespace(c.ns).Resource("ingresses").Body(ingress).Do().Into(result) + return +} + +// Update updates an existing ingress. +func (c *ingress) Update(ingress *extensions.Ingress) (result *extensions.Ingress, err error) { + result = &extensions.Ingress{} + err = c.r.Put().Namespace(c.ns).Resource("ingresses").Name(ingress.Name).Body(ingress).Do().Into(result) + return +} + +// Delete deletes a ingress, returns error if one occurs. +func (c *ingress) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("ingresses").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested ingress. +func (c *ingress) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("ingresses"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the ingress and the new status. Returns the server's representation of the ingress, and an error, if it occurs. +func (c *ingress) UpdateStatus(ingress *extensions.Ingress) (result *extensions.Ingress, err error) { + result = &extensions.Ingress{} + err = c.r.Put().Namespace(c.ns).Resource("ingresses").Name(ingress.Name).SubResource("status").Body(ingress).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/jobs.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/jobs.go new file mode 100644 index 0000000..14cfa3a --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/jobs.go @@ -0,0 +1,167 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/watch" +) + +// JobsNamespacer has methods to work with Job resources in a namespace +type JobsNamespacer interface { + Jobs(namespace string) JobInterface +} + +// JobInterface exposes methods to work on Job resources. +type JobInterface interface { + List(opts api.ListOptions) (*batch.JobList, error) + Get(name string) (*batch.Job, error) + Create(job *batch.Job) (*batch.Job, error) + Update(job *batch.Job) (*batch.Job, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(job *batch.Job) (*batch.Job, error) +} + +// jobs implements JobsNamespacer interface +type jobs struct { + r *ExtensionsClient + ns string +} + +// newJobs returns a jobs +func newJobs(c *ExtensionsClient, namespace string) *jobs { + return &jobs{c, namespace} +} + +// Ensure statically that jobs implements JobInterface. +var _ JobInterface = &jobs{} + +// List returns a list of jobs that match the label and field selectors. +func (c *jobs) List(opts api.ListOptions) (result *batch.JobList, err error) { + result = &batch.JobList{} + err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular job. +func (c *jobs) Get(name string) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result) + return +} + +// Create creates a new job. +func (c *jobs) Create(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result) + return +} + +// Update updates an existing job. +func (c *jobs) Update(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result) + return +} + +// Delete deletes a job, returns error if one occurs. +func (c *jobs) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("jobs").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested jobs. +func (c *jobs) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("jobs"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs. +func (c *jobs) UpdateStatus(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) + return +} + +// jobsV1 implements JobsNamespacer interface using BatchClient internally +type jobsV1 struct { + r *BatchClient + ns string +} + +// newJobsV1 returns a jobsV1 +func newJobsV1(c *BatchClient, namespace string) *jobsV1 { + return &jobsV1{c, namespace} +} + +// Ensure statically that jobsV1 implements JobInterface. +var _ JobInterface = &jobsV1{} + +// List returns a list of jobs that match the label and field selectors. +func (c *jobsV1) List(opts api.ListOptions) (result *batch.JobList, err error) { + result = &batch.JobList{} + err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular job. +func (c *jobsV1) Get(name string) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result) + return +} + +// Create creates a new job. +func (c *jobsV1) Create(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result) + return +} + +// Update updates an existing job. +func (c *jobsV1) Update(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result) + return +} + +// Delete deletes a job, returns error if one occurs. +func (c *jobsV1) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("jobs").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested jobs. +func (c *jobsV1) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("jobs"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs. +func (c *jobsV1) UpdateStatus(job *batch.Job) (result *batch.Job, err error) { + result = &batch.Job{} + err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/limit_ranges.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/limit_ranges.go new file mode 100644 index 0000000..914a049 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/limit_ranges.go @@ -0,0 +1,94 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// LimitRangesNamespacer has methods to work with LimitRange resources in a namespace +type LimitRangesNamespacer interface { + LimitRanges(namespace string) LimitRangeInterface +} + +// LimitRangeInterface has methods to work with LimitRange resources. +type LimitRangeInterface interface { + List(opts api.ListOptions) (*api.LimitRangeList, error) + Get(name string) (*api.LimitRange, error) + Delete(name string) error + Create(limitRange *api.LimitRange) (*api.LimitRange, error) + Update(limitRange *api.LimitRange) (*api.LimitRange, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// limitRanges implements LimitRangesNamespacer interface +type limitRanges struct { + r *Client + ns string +} + +// newLimitRanges returns a limitRanges +func newLimitRanges(c *Client, namespace string) *limitRanges { + return &limitRanges{ + r: c, + ns: namespace, + } +} + +// List takes a selector, and returns the list of limitRanges that match that selector. +func (c *limitRanges) List(opts api.ListOptions) (result *api.LimitRangeList, err error) { + result = &api.LimitRangeList{} + err = c.r.Get().Namespace(c.ns).Resource("limitRanges").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the limitRange, and returns the corresponding Pod object, and an error if it occurs +func (c *limitRanges) Get(name string) (result *api.LimitRange, err error) { + result = &api.LimitRange{} + err = c.r.Get().Namespace(c.ns).Resource("limitRanges").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the limitRange, and returns an error if one occurs +func (c *limitRanges) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("limitRanges").Name(name).Do().Error() +} + +// Create takes the representation of a limitRange. Returns the server's representation of the limitRange, and an error, if it occurs. +func (c *limitRanges) Create(limitRange *api.LimitRange) (result *api.LimitRange, err error) { + result = &api.LimitRange{} + err = c.r.Post().Namespace(c.ns).Resource("limitRanges").Body(limitRange).Do().Into(result) + return +} + +// Update takes the representation of a limitRange to update. Returns the server's representation of the limitRange, and an error, if it occurs. +func (c *limitRanges) Update(limitRange *api.LimitRange) (result *api.LimitRange, err error) { + result = &api.LimitRange{} + err = c.r.Put().Namespace(c.ns).Resource("limitRanges").Name(limitRange.Name).Body(limitRange).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested resource +func (c *limitRanges) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("limitRanges"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/namespaces.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/namespaces.go new file mode 100644 index 0000000..b4a3836 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/namespaces.go @@ -0,0 +1,116 @@ +/* +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 unversioned + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +type NamespacesInterface interface { + Namespaces() NamespaceInterface +} + +type NamespaceInterface interface { + Create(item *api.Namespace) (*api.Namespace, error) + Get(name string) (result *api.Namespace, err error) + List(opts api.ListOptions) (*api.NamespaceList, error) + Delete(name string) error + Update(item *api.Namespace) (*api.Namespace, error) + Watch(opts api.ListOptions) (watch.Interface, error) + Finalize(item *api.Namespace) (*api.Namespace, error) + Status(item *api.Namespace) (*api.Namespace, error) +} + +// namespaces implements NamespacesInterface +type namespaces struct { + r *Client +} + +// newNamespaces returns a namespaces object. +func newNamespaces(c *Client) *namespaces { + return &namespaces{r: c} +} + +// Create creates a new namespace. +func (c *namespaces) Create(namespace *api.Namespace) (*api.Namespace, error) { + result := &api.Namespace{} + err := c.r.Post().Resource("namespaces").Body(namespace).Do().Into(result) + return result, err +} + +// List lists all the namespaces in the cluster. +func (c *namespaces) List(opts api.ListOptions) (*api.NamespaceList, error) { + result := &api.NamespaceList{} + err := c.r.Get(). + Resource("namespaces"). + VersionedParams(&opts, api.ParameterCodec). + Do().Into(result) + return result, err +} + +// Update takes the representation of a namespace to update. Returns the server's representation of the namespace, and an error, if it occurs. +func (c *namespaces) Update(namespace *api.Namespace) (result *api.Namespace, err error) { + result = &api.Namespace{} + err = c.r.Put().Resource("namespaces").Name(namespace.Name).Body(namespace).Do().Into(result) + return +} + +// Finalize takes the representation of a namespace to update. Returns the server's representation of the namespace, and an error, if it occurs. +func (c *namespaces) Finalize(namespace *api.Namespace) (result *api.Namespace, err error) { + result = &api.Namespace{} + if len(namespace.ResourceVersion) == 0 { + err = fmt.Errorf("invalid update object, missing resource version: %v", namespace) + return + } + err = c.r.Put().Resource("namespaces").Name(namespace.Name).SubResource("finalize").Body(namespace).Do().Into(result) + return +} + +// Status takes the representation of a namespace to update. Returns the server's representation of the namespace, and an error, if it occurs. +func (c *namespaces) Status(namespace *api.Namespace) (result *api.Namespace, err error) { + result = &api.Namespace{} + if len(namespace.ResourceVersion) == 0 { + err = fmt.Errorf("invalid update object, missing resource version: %v", namespace) + return + } + err = c.r.Put().Resource("namespaces").Name(namespace.Name).SubResource("status").Body(namespace).Do().Into(result) + return +} + +// Get gets an existing namespace +func (c *namespaces) Get(name string) (*api.Namespace, error) { + result := &api.Namespace{} + err := c.r.Get().Resource("namespaces").Name(name).Do().Into(result) + return result, err +} + +// Delete deletes an existing namespace. +func (c *namespaces) Delete(name string) error { + return c.r.Delete().Resource("namespaces").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested namespaces. +func (c *namespaces) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Resource("namespaces"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/network_policys.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/network_policys.go new file mode 100644 index 0000000..3e3f610 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/network_policys.go @@ -0,0 +1,92 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// NetworkPolicyNamespacer has methods to work with NetworkPolicy resources in a namespace +type NetworkPolicyNamespacer interface { + NetworkPolicies(namespace string) NetworkPolicyInterface +} + +// NetworkPolicyInterface exposes methods to work on NetworkPolicy resources. +type NetworkPolicyInterface interface { + List(opts api.ListOptions) (*extensions.NetworkPolicyList, error) + Get(name string) (*extensions.NetworkPolicy, error) + Create(networkPolicy *extensions.NetworkPolicy) (*extensions.NetworkPolicy, error) + Update(networkPolicy *extensions.NetworkPolicy) (*extensions.NetworkPolicy, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// NetworkPolicies implements NetworkPolicyNamespacer interface +type NetworkPolicies struct { + r *ExtensionsClient + ns string +} + +// newNetworkPolicies returns a NetworkPolicies +func newNetworkPolicies(c *ExtensionsClient, namespace string) *NetworkPolicies { + return &NetworkPolicies{c, namespace} +} + +// List returns a list of networkPolicy that match the label and field selectors. +func (c *NetworkPolicies) List(opts api.ListOptions) (result *extensions.NetworkPolicyList, err error) { + result = &extensions.NetworkPolicyList{} + err = c.r.Get().Namespace(c.ns).Resource("networkpolicies").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular networkPolicy. +func (c *NetworkPolicies) Get(name string) (result *extensions.NetworkPolicy, err error) { + result = &extensions.NetworkPolicy{} + err = c.r.Get().Namespace(c.ns).Resource("networkpolicies").Name(name).Do().Into(result) + return +} + +// Create creates a new networkPolicy. +func (c *NetworkPolicies) Create(networkPolicy *extensions.NetworkPolicy) (result *extensions.NetworkPolicy, err error) { + result = &extensions.NetworkPolicy{} + err = c.r.Post().Namespace(c.ns).Resource("networkpolicies").Body(networkPolicy).Do().Into(result) + return +} + +// Update updates an existing networkPolicy. +func (c *NetworkPolicies) Update(networkPolicy *extensions.NetworkPolicy) (result *extensions.NetworkPolicy, err error) { + result = &extensions.NetworkPolicy{} + err = c.r.Put().Namespace(c.ns).Resource("networkpolicies").Name(networkPolicy.Name).Body(networkPolicy).Do().Into(result) + return +} + +// Delete deletes a networkPolicy, returns error if one occurs. +func (c *NetworkPolicies) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("networkpolicies").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested networkPolicy. +func (c *NetworkPolicies) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("networkpolicies"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/nodes.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/nodes.go new file mode 100644 index 0000000..15a7db2 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/nodes.go @@ -0,0 +1,111 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +type NodesInterface interface { + Nodes() NodeInterface +} + +type NodeInterface interface { + Get(name string) (result *api.Node, err error) + Create(node *api.Node) (*api.Node, error) + List(opts api.ListOptions) (*api.NodeList, error) + Delete(name string) error + DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error + Update(*api.Node) (*api.Node, error) + UpdateStatus(*api.Node) (*api.Node, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// nodes implements NodesInterface +type nodes struct { + r *Client +} + +// newNodes returns a nodes object. +func newNodes(c *Client) *nodes { + return &nodes{c} +} + +// resourceName returns node's URL resource name. +func (c *nodes) resourceName() string { + return "nodes" +} + +// Create creates a new node. +func (c *nodes) Create(node *api.Node) (*api.Node, error) { + result := &api.Node{} + err := c.r.Post().Resource(c.resourceName()).Body(node).Do().Into(result) + return result, err +} + +// List takes a selector, and returns the list of nodes that match that selector in the cluster. +func (c *nodes) List(opts api.ListOptions) (*api.NodeList, error) { + result := &api.NodeList{} + err := c.r.Get().Resource(c.resourceName()).VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return result, err +} + +// Get gets an existing node. +func (c *nodes) Get(name string) (*api.Node, error) { + result := &api.Node{} + err := c.r.Get().Resource(c.resourceName()).Name(name).Do().Into(result) + return result, err +} + +// Delete deletes an existing node. +func (c *nodes) Delete(name string) error { + return c.r.Delete().Resource(c.resourceName()).Name(name).Do().Error() +} + +// DeleteCollection deletes a collection of nodes. +func (c *nodes) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error { + return c.r.Delete(). + Resource(c.resourceName()). + VersionedParams(&listOptions, api.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Update updates an existing node. +func (c *nodes) Update(node *api.Node) (*api.Node, error) { + result := &api.Node{} + err := c.r.Put().Resource(c.resourceName()).Name(node.Name).Body(node).Do().Into(result) + return result, err +} + +func (c *nodes) UpdateStatus(node *api.Node) (*api.Node, error) { + result := &api.Node{} + err := c.r.Put().Resource(c.resourceName()).Name(node.Name).SubResource("status").Body(node).Do().Into(result) + return result, err +} + +// Watch returns a watch.Interface that watches the requested nodes. +func (c *nodes) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(api.NamespaceAll). + Resource(c.resourceName()). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumeclaim.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumeclaim.go new file mode 100644 index 0000000..4ea3a95 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumeclaim.go @@ -0,0 +1,99 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// PersistentVolumeClaimsNamespacer has methods to work with PersistentVolumeClaim resources in a namespace +type PersistentVolumeClaimsNamespacer interface { + PersistentVolumeClaims(namespace string) PersistentVolumeClaimInterface +} + +// PersistentVolumeClaimInterface has methods to work with PersistentVolumeClaim resources. +type PersistentVolumeClaimInterface interface { + List(opts api.ListOptions) (*api.PersistentVolumeClaimList, error) + Get(name string) (*api.PersistentVolumeClaim, error) + Create(claim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) + Update(claim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) + UpdateStatus(claim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// persistentVolumeClaims implements PersistentVolumeClaimsNamespacer interface +type persistentVolumeClaims struct { + client *Client + namespace string +} + +// newPersistentVolumeClaims returns a PodsClient +func newPersistentVolumeClaims(c *Client, namespace string) *persistentVolumeClaims { + return &persistentVolumeClaims{c, namespace} +} + +func (c *persistentVolumeClaims) List(opts api.ListOptions) (result *api.PersistentVolumeClaimList, err error) { + result = &api.PersistentVolumeClaimList{} + + err = c.client.Get(). + Namespace(c.namespace). + Resource("persistentVolumeClaims"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +func (c *persistentVolumeClaims) Get(name string) (result *api.PersistentVolumeClaim, err error) { + result = &api.PersistentVolumeClaim{} + err = c.client.Get().Namespace(c.namespace).Resource("persistentVolumeClaims").Name(name).Do().Into(result) + return +} + +func (c *persistentVolumeClaims) Create(claim *api.PersistentVolumeClaim) (result *api.PersistentVolumeClaim, err error) { + result = &api.PersistentVolumeClaim{} + err = c.client.Post().Namespace(c.namespace).Resource("persistentVolumeClaims").Body(claim).Do().Into(result) + return +} + +func (c *persistentVolumeClaims) Update(claim *api.PersistentVolumeClaim) (result *api.PersistentVolumeClaim, err error) { + result = &api.PersistentVolumeClaim{} + err = c.client.Put().Namespace(c.namespace).Resource("persistentVolumeClaims").Name(claim.Name).Body(claim).Do().Into(result) + return +} + +func (c *persistentVolumeClaims) UpdateStatus(claim *api.PersistentVolumeClaim) (result *api.PersistentVolumeClaim, err error) { + result = &api.PersistentVolumeClaim{} + err = c.client.Put().Namespace(c.namespace).Resource("persistentVolumeClaims").Name(claim.Name).SubResource("status").Body(claim).Do().Into(result) + return +} + +func (c *persistentVolumeClaims) Delete(name string) error { + return c.client.Delete().Namespace(c.namespace).Resource("persistentVolumeClaims").Name(name).Do().Error() +} + +func (c *persistentVolumeClaims) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.namespace). + Resource("persistentVolumeClaims"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumes.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumes.go new file mode 100644 index 0000000..5fce1f0 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/persistentvolumes.go @@ -0,0 +1,93 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +type PersistentVolumesInterface interface { + PersistentVolumes() PersistentVolumeInterface +} + +// PersistentVolumeInterface has methods to work with PersistentVolume resources. +type PersistentVolumeInterface interface { + List(opts api.ListOptions) (*api.PersistentVolumeList, error) + Get(name string) (*api.PersistentVolume, error) + Create(volume *api.PersistentVolume) (*api.PersistentVolume, error) + Update(volume *api.PersistentVolume) (*api.PersistentVolume, error) + UpdateStatus(persistentVolume *api.PersistentVolume) (*api.PersistentVolume, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// persistentVolumes implements PersistentVolumesInterface +type persistentVolumes struct { + client *Client +} + +func newPersistentVolumes(c *Client) *persistentVolumes { + return &persistentVolumes{c} +} + +func (c *persistentVolumes) List(opts api.ListOptions) (result *api.PersistentVolumeList, err error) { + result = &api.PersistentVolumeList{} + err = c.client.Get(). + Resource("persistentVolumes"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +func (c *persistentVolumes) Get(name string) (result *api.PersistentVolume, err error) { + result = &api.PersistentVolume{} + err = c.client.Get().Resource("persistentVolumes").Name(name).Do().Into(result) + return +} + +func (c *persistentVolumes) Create(volume *api.PersistentVolume) (result *api.PersistentVolume, err error) { + result = &api.PersistentVolume{} + err = c.client.Post().Resource("persistentVolumes").Body(volume).Do().Into(result) + return +} + +func (c *persistentVolumes) Update(volume *api.PersistentVolume) (result *api.PersistentVolume, err error) { + result = &api.PersistentVolume{} + err = c.client.Put().Resource("persistentVolumes").Name(volume.Name).Body(volume).Do().Into(result) + return +} + +func (c *persistentVolumes) UpdateStatus(volume *api.PersistentVolume) (result *api.PersistentVolume, err error) { + result = &api.PersistentVolume{} + err = c.client.Put().Resource("persistentVolumes").Name(volume.Name).SubResource("status").Body(volume).Do().Into(result) + return +} + +func (c *persistentVolumes) Delete(name string) error { + return c.client.Delete().Resource("persistentVolumes").Name(name).Do().Error() +} + +func (c *persistentVolumes) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Resource("persistentVolumes"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pet_sets.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pet_sets.go new file mode 100644 index 0000000..954efcd --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pet_sets.go @@ -0,0 +1,100 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/watch" +) + +// PetSetNamespacer has methods to work with PetSet resources in a namespace +type PetSetNamespacer interface { + PetSets(namespace string) PetSetInterface +} + +// PetSetInterface exposes methods to work on PetSet resources. +type PetSetInterface interface { + List(opts api.ListOptions) (*apps.PetSetList, error) + Get(name string) (*apps.PetSet, error) + Create(petSet *apps.PetSet) (*apps.PetSet, error) + Update(petSet *apps.PetSet) (*apps.PetSet, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(petSet *apps.PetSet) (*apps.PetSet, error) +} + +// petSet implements PetSetNamespacer interface +type petSet struct { + r *AppsClient + ns string +} + +// newPetSet returns a petSet +func newPetSet(c *AppsClient, namespace string) *petSet { + return &petSet{c, namespace} +} + +// List returns a list of petSet that match the label and field selectors. +func (c *petSet) List(opts api.ListOptions) (result *apps.PetSetList, err error) { + result = &apps.PetSetList{} + err = c.r.Get().Namespace(c.ns).Resource("petsets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular petSet. +func (c *petSet) Get(name string) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Get().Namespace(c.ns).Resource("petsets").Name(name).Do().Into(result) + return +} + +// Create creates a new petSet. +func (c *petSet) Create(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Post().Namespace(c.ns).Resource("petsets").Body(petSet).Do().Into(result) + return +} + +// Update updates an existing petSet. +func (c *petSet) Update(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).Body(petSet).Do().Into(result) + return +} + +// Delete deletes a petSet, returns error if one occurs. +func (c *petSet) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("petsets").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested petSet. +func (c *petSet) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("petsets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the petSet and the new status. Returns the server's representation of the petSet, and an error, if it occurs. +func (c *petSet) UpdateStatus(petSet *apps.PetSet) (result *apps.PetSet, err error) { + result = &apps.PetSet{} + err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).SubResource("status").Body(petSet).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_disruption_budgets.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_disruption_budgets.go new file mode 100644 index 0000000..0239623 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_disruption_budgets.go @@ -0,0 +1,100 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/watch" +) + +// PodDisruptionBudgetNamespacer has methods to work with PodDisruptionBudget resources in a namespace +type PodDisruptionBudgetNamespacer interface { + PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface +} + +// PodDisruptionBudgetInterface exposes methods to work on PodDisruptionBudget resources. +type PodDisruptionBudgetInterface interface { + List(opts api.ListOptions) (*policy.PodDisruptionBudgetList, error) + Get(name string) (*policy.PodDisruptionBudget, error) + Create(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) + Update(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(podDisruptionBudget *policy.PodDisruptionBudget) (*policy.PodDisruptionBudget, error) +} + +// podDisruptionBudget implements PodDisruptionBudgetNamespacer interface +type podDisruptionBudget struct { + r *PolicyClient + ns string +} + +// newPodDisruptionBudget returns a podDisruptionBudget +func newPodDisruptionBudget(c *PolicyClient, namespace string) *podDisruptionBudget { + return &podDisruptionBudget{c, namespace} +} + +// List returns a list of podDisruptionBudget that match the label and field selectors. +func (c *podDisruptionBudget) List(opts api.ListOptions) (result *policy.PodDisruptionBudgetList, err error) { + result = &policy.PodDisruptionBudgetList{} + err = c.r.Get().Namespace(c.ns).Resource("poddisruptionbudgets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular podDisruptionBudget. +func (c *podDisruptionBudget) Get(name string) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Get().Namespace(c.ns).Resource("poddisruptionbudgets").Name(name).Do().Into(result) + return +} + +// Create creates a new podDisruptionBudget. +func (c *podDisruptionBudget) Create(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Post().Namespace(c.ns).Resource("poddisruptionbudgets").Body(podDisruptionBudget).Do().Into(result) + return +} + +// Update updates an existing podDisruptionBudget. +func (c *podDisruptionBudget) Update(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Put().Namespace(c.ns).Resource("poddisruptionbudgets").Name(podDisruptionBudget.Name).Body(podDisruptionBudget).Do().Into(result) + return +} + +// Delete deletes a podDisruptionBudget, returns error if one occurs. +func (c *podDisruptionBudget) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("poddisruptionbudgets").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested podDisruptionBudget. +func (c *podDisruptionBudget) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("poddisruptionbudgets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the podDisruptionBudget and the new status. Returns the server's representation of the podDisruptionBudget, and an error, if it occurs. +func (c *podDisruptionBudget) UpdateStatus(podDisruptionBudget *policy.PodDisruptionBudget) (result *policy.PodDisruptionBudget, err error) { + result = &policy.PodDisruptionBudget{} + err = c.r.Put().Namespace(c.ns).Resource("poddisruptionbudgets").Name(podDisruptionBudget.Name).SubResource("status").Body(podDisruptionBudget).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_templates.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_templates.go new file mode 100644 index 0000000..7627d73 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pod_templates.go @@ -0,0 +1,94 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// PodTemplatesNamespacer has methods to work with PodTemplate resources in a namespace +type PodTemplatesNamespacer interface { + PodTemplates(namespace string) PodTemplateInterface +} + +// PodTemplateInterface has methods to work with PodTemplate resources. +type PodTemplateInterface interface { + List(opts api.ListOptions) (*api.PodTemplateList, error) + Get(name string) (*api.PodTemplate, error) + Delete(name string, options *api.DeleteOptions) error + Create(podTemplate *api.PodTemplate) (*api.PodTemplate, error) + Update(podTemplate *api.PodTemplate) (*api.PodTemplate, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// podTemplates implements PodTemplatesNamespacer interface +type podTemplates struct { + r *Client + ns string +} + +// newPodTemplates returns a podTemplates +func newPodTemplates(c *Client, namespace string) *podTemplates { + return &podTemplates{ + r: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of podTemplates that match those selectors. +func (c *podTemplates) List(opts api.ListOptions) (result *api.PodTemplateList, err error) { + result = &api.PodTemplateList{} + err = c.r.Get().Namespace(c.ns).Resource("podTemplates").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the podTemplate, and returns the corresponding PodTemplate object, and an error if it occurs +func (c *podTemplates) Get(name string) (result *api.PodTemplate, err error) { + result = &api.PodTemplate{} + err = c.r.Get().Namespace(c.ns).Resource("podTemplates").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the podTemplate, and returns an error if one occurs +func (c *podTemplates) Delete(name string, options *api.DeleteOptions) error { + return c.r.Delete().Namespace(c.ns).Resource("podTemplates").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a podTemplate. Returns the server's representation of the podTemplate, and an error, if it occurs. +func (c *podTemplates) Create(podTemplate *api.PodTemplate) (result *api.PodTemplate, err error) { + result = &api.PodTemplate{} + err = c.r.Post().Namespace(c.ns).Resource("podTemplates").Body(podTemplate).Do().Into(result) + return +} + +// Update takes the representation of a podTemplate to update. Returns the server's representation of the podTemplate, and an error, if it occurs. +func (c *podTemplates) Update(podTemplate *api.PodTemplate) (result *api.PodTemplate, err error) { + result = &api.PodTemplate{} + err = c.r.Put().Namespace(c.ns).Resource("podTemplates").Name(podTemplate.Name).Body(podTemplate).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested podTemplates. +func (c *podTemplates) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("podTemplates"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pods.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pods.go new file mode 100644 index 0000000..ea16fb8 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/pods.go @@ -0,0 +1,115 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/watch" +) + +// PodsNamespacer has methods to work with Pod resources in a namespace +type PodsNamespacer interface { + Pods(namespace string) PodInterface +} + +// PodInterface has methods to work with Pod resources. +type PodInterface interface { + List(opts api.ListOptions) (*api.PodList, error) + Get(name string) (*api.Pod, error) + Delete(name string, options *api.DeleteOptions) error + Create(pod *api.Pod) (*api.Pod, error) + Update(pod *api.Pod) (*api.Pod, error) + Watch(opts api.ListOptions) (watch.Interface, error) + Bind(binding *api.Binding) error + UpdateStatus(pod *api.Pod) (*api.Pod, error) + GetLogs(name string, opts *api.PodLogOptions) *restclient.Request +} + +// pods implements PodsNamespacer interface +type pods struct { + r *Client + ns string +} + +// newPods returns a pods +func newPods(c *Client, namespace string) *pods { + return &pods{ + r: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of pods that match those selectors. +func (c *pods) List(opts api.ListOptions) (result *api.PodList, err error) { + result = &api.PodList{} + err = c.r.Get().Namespace(c.ns).Resource("pods").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the pod, and returns the corresponding Pod object, and an error if it occurs +func (c *pods) Get(name string) (result *api.Pod, err error) { + result = &api.Pod{} + err = c.r.Get().Namespace(c.ns).Resource("pods").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the pod, and returns an error if one occurs +func (c *pods) Delete(name string, options *api.DeleteOptions) error { + return c.r.Delete().Namespace(c.ns).Resource("pods").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a pod. Returns the server's representation of the pod, and an error, if it occurs. +func (c *pods) Create(pod *api.Pod) (result *api.Pod, err error) { + result = &api.Pod{} + err = c.r.Post().Namespace(c.ns).Resource("pods").Body(pod).Do().Into(result) + return +} + +// Update takes the representation of a pod to update. Returns the server's representation of the pod, and an error, if it occurs. +func (c *pods) Update(pod *api.Pod) (result *api.Pod, err error) { + result = &api.Pod{} + err = c.r.Put().Namespace(c.ns).Resource("pods").Name(pod.Name).Body(pod).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested pods. +func (c *pods) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("pods"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// Bind applies the provided binding to the named pod in the current namespace (binding.Namespace is ignored). +func (c *pods) Bind(binding *api.Binding) error { + return c.r.Post().Namespace(c.ns).Resource("pods").Name(binding.Name).SubResource("binding").Body(binding).Do().Error() +} + +// UpdateStatus takes the name of the pod and the new status. Returns the server's representation of the pod, and an error, if it occurs. +func (c *pods) UpdateStatus(pod *api.Pod) (result *api.Pod, err error) { + result = &api.Pod{} + err = c.r.Put().Namespace(c.ns).Resource("pods").Name(pod.Name).SubResource("status").Body(pod).Do().Into(result) + return +} + +// Get constructs a request for getting the logs for a pod +func (c *pods) GetLogs(name string, opts *api.PodLogOptions) *restclient.Request { + return c.r.Get().Namespace(c.ns).Name(name).Resource("pods").SubResource("log").VersionedParams(opts, api.ParameterCodec) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/podsecuritypolicy.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/podsecuritypolicy.go new file mode 100644 index 0000000..f03e643 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/podsecuritypolicy.go @@ -0,0 +1,111 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +type PodSecurityPoliciesInterface interface { + PodSecurityPolicies() PodSecurityPolicyInterface +} + +type PodSecurityPolicyInterface interface { + Get(name string) (result *extensions.PodSecurityPolicy, err error) + Create(psp *extensions.PodSecurityPolicy) (*extensions.PodSecurityPolicy, error) + List(opts api.ListOptions) (*extensions.PodSecurityPolicyList, error) + Delete(name string) error + Update(*extensions.PodSecurityPolicy) (*extensions.PodSecurityPolicy, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// podSecurityPolicy implements PodSecurityPolicyInterface +type podSecurityPolicy struct { + client *ExtensionsClient +} + +// newPodSecurityPolicy returns a podSecurityPolicy object. +func newPodSecurityPolicy(c *ExtensionsClient) *podSecurityPolicy { + return &podSecurityPolicy{c} +} + +func (s *podSecurityPolicy) Create(psp *extensions.PodSecurityPolicy) (*extensions.PodSecurityPolicy, error) { + result := &extensions.PodSecurityPolicy{} + err := s.client.Post(). + Resource("podsecuritypolicies"). + Body(psp). + Do(). + Into(result) + + return result, err +} + +// List returns a list of PodSecurityPolicies matching the selectors. +func (s *podSecurityPolicy) List(opts api.ListOptions) (*extensions.PodSecurityPolicyList, error) { + result := &extensions.PodSecurityPolicyList{} + + err := s.client.Get(). + Resource("podsecuritypolicies"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +// Get returns the given PodSecurityPolicy, or an error. +func (s *podSecurityPolicy) Get(name string) (*extensions.PodSecurityPolicy, error) { + result := &extensions.PodSecurityPolicy{} + err := s.client.Get(). + Resource("podsecuritypolicies"). + Name(name). + Do(). + Into(result) + + return result, err +} + +// Watch starts watching for PodSecurityPolicies matching the given selectors. +func (s *podSecurityPolicy) Watch(opts api.ListOptions) (watch.Interface, error) { + return s.client.Get(). + Prefix("watch"). + Resource("podsecuritypolicies"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +func (s *podSecurityPolicy) Delete(name string) error { + return s.client.Delete(). + Resource("podsecuritypolicies"). + Name(name). + Do(). + Error() +} + +func (s *podSecurityPolicy) Update(psp *extensions.PodSecurityPolicy) (result *extensions.PodSecurityPolicy, err error) { + result = &extensions.PodSecurityPolicy{} + err = s.client.Put(). + Resource("podsecuritypolicies"). + Name(psp.Name). + Body(psp). + Do(). + Into(result) + + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/policy.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/policy.go new file mode 100644 index 0000000..9a47d79 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/policy.go @@ -0,0 +1,76 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/client/restclient" +) + +type PolicyInterface interface { + PodDisruptionBudgetNamespacer +} + +// PolicyClient is used to interact with Kubernetes batch features. +type PolicyClient struct { + *restclient.RESTClient +} + +func (c *PolicyClient) PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface { + return newPodDisruptionBudget(c, namespace) +} + +func NewPolicy(c *restclient.Config) (*PolicyClient, error) { + config := *c + if err := setPolicyDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &PolicyClient{client}, nil +} + +func NewPolicyOrDie(c *restclient.Config) *PolicyClient { + client, err := NewPolicy(c) + if err != nil { + panic(err) + } + return client +} + +func setPolicyDefaults(config *restclient.Config) error { + g, err := registered.Group(policy.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rbac.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rbac.go new file mode 100644 index 0000000..09b2b40 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rbac.go @@ -0,0 +1,96 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/client/restclient" +) + +// Interface holds the methods for clients of Kubernetes to allow mock testing. +type RbacInterface interface { + RoleBindingsNamespacer + RolesNamespacer + ClusterRoleBindings + ClusterRoles +} + +type RbacClient struct { + *restclient.RESTClient +} + +func (c *RbacClient) RoleBindings(namespace string) RoleBindingInterface { + return newRoleBindings(c, namespace) +} + +func (c *RbacClient) Roles(namespace string) RoleInterface { + return newRoles(c, namespace) +} + +func (c *RbacClient) ClusterRoleBindings() ClusterRoleBindingInterface { + return newClusterRoleBindings(c) +} + +func (c *RbacClient) ClusterRoles() ClusterRoleInterface { + return newClusterRoles(c) +} + +// NewRbac creates a new RbacClient for the given config. +func NewRbac(c *restclient.Config) (*RbacClient, error) { + config := *c + if err := setRbacDefaults(&config); err != nil { + return nil, err + } + client, err := restclient.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &RbacClient{client}, nil +} + +// NewRbacOrDie creates a new RbacClient for the given config and +// panics if there is an error in the config. +func NewRbacOrDie(c *restclient.Config) *RbacClient { + client, err := NewRbac(c) + if err != nil { + panic(err) + } + return client +} + +func setRbacDefaults(config *restclient.Config) error { + // if rbac group is not registered, return an error + g, err := registered.Group(rbac.GroupName) + if err != nil { + return err + } + config.APIPath = defaultAPIPath + if config.UserAgent == "" { + config.UserAgent = restclient.DefaultKubernetesUserAgent() + } + + // TODO: Unconditionally set the config.Version, until we fix the config. + //if config.Version == "" { + copyGroupVersion := g.GroupVersion + config.GroupVersion = ©GroupVersion + //} + + config.NegotiatedSerializer = api.Codecs + return nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replica_sets.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replica_sets.go new file mode 100644 index 0000000..191a006 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replica_sets.go @@ -0,0 +1,100 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// ReplicaSetsNamespacer has methods to work with ReplicaSet resources in a namespace +type ReplicaSetsNamespacer interface { + ReplicaSets(namespace string) ReplicaSetInterface +} + +// ReplicaSetInterface has methods to work with ReplicaSet resources. +type ReplicaSetInterface interface { + List(opts api.ListOptions) (*extensions.ReplicaSetList, error) + Get(name string) (*extensions.ReplicaSet, error) + Create(ctrl *extensions.ReplicaSet) (*extensions.ReplicaSet, error) + Update(ctrl *extensions.ReplicaSet) (*extensions.ReplicaSet, error) + UpdateStatus(ctrl *extensions.ReplicaSet) (*extensions.ReplicaSet, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// replicaSets implements ReplicaSetsNamespacer interface +type replicaSets struct { + client *ExtensionsClient + ns string +} + +// newReplicaSets returns a ReplicaSetClient +func newReplicaSets(c *ExtensionsClient, namespace string) *replicaSets { + return &replicaSets{c, namespace} +} + +// List takes a selector, and returns the list of ReplicaSets that match that selector. +func (c *replicaSets) List(opts api.ListOptions) (result *extensions.ReplicaSetList, err error) { + result = &extensions.ReplicaSetList{} + err = c.client.Get().Namespace(c.ns).Resource("replicasets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular ReplicaSet. +func (c *replicaSets) Get(name string) (result *extensions.ReplicaSet, err error) { + result = &extensions.ReplicaSet{} + err = c.client.Get().Namespace(c.ns).Resource("replicasets").Name(name).Do().Into(result) + return +} + +// Create creates a new ReplicaSet. +func (c *replicaSets) Create(rs *extensions.ReplicaSet) (result *extensions.ReplicaSet, err error) { + result = &extensions.ReplicaSet{} + err = c.client.Post().Namespace(c.ns).Resource("replicasets").Body(rs).Do().Into(result) + return +} + +// Update updates an existing ReplicaSet. +func (c *replicaSets) Update(rs *extensions.ReplicaSet) (result *extensions.ReplicaSet, err error) { + result = &extensions.ReplicaSet{} + err = c.client.Put().Namespace(c.ns).Resource("replicasets").Name(rs.Name).Body(rs).Do().Into(result) + return +} + +// UpdateStatus updates an existing ReplicaSet status +func (c *replicaSets) UpdateStatus(rs *extensions.ReplicaSet) (result *extensions.ReplicaSet, err error) { + result = &extensions.ReplicaSet{} + err = c.client.Put().Namespace(c.ns).Resource("replicasets").Name(rs.Name).SubResource("status").Body(rs).Do().Into(result) + return +} + +// Delete deletes an existing ReplicaSet. +func (c *replicaSets) Delete(name string, options *api.DeleteOptions) (err error) { + return c.client.Delete().Namespace(c.ns).Resource("replicasets").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested ReplicaSets. +func (c *replicaSets) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("replicasets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replication_controllers.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replication_controllers.go new file mode 100644 index 0000000..e4b9e2d --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/replication_controllers.go @@ -0,0 +1,99 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// ReplicationControllersNamespacer has methods to work with ReplicationController resources in a namespace +type ReplicationControllersNamespacer interface { + ReplicationControllers(namespace string) ReplicationControllerInterface +} + +// ReplicationControllerInterface has methods to work with ReplicationController resources. +type ReplicationControllerInterface interface { + List(opts api.ListOptions) (*api.ReplicationControllerList, error) + Get(name string) (*api.ReplicationController, error) + Create(ctrl *api.ReplicationController) (*api.ReplicationController, error) + Update(ctrl *api.ReplicationController) (*api.ReplicationController, error) + UpdateStatus(ctrl *api.ReplicationController) (*api.ReplicationController, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// replicationControllers implements ReplicationControllersNamespacer interface +type replicationControllers struct { + r *Client + ns string +} + +// newReplicationControllers returns a PodsClient +func newReplicationControllers(c *Client, namespace string) *replicationControllers { + return &replicationControllers{c, namespace} +} + +// List takes a selector, and returns the list of replication controllers that match that selector. +func (c *replicationControllers) List(opts api.ListOptions) (result *api.ReplicationControllerList, err error) { + result = &api.ReplicationControllerList{} + err = c.r.Get().Namespace(c.ns).Resource("replicationControllers").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular replication controller. +func (c *replicationControllers) Get(name string) (result *api.ReplicationController, err error) { + result = &api.ReplicationController{} + err = c.r.Get().Namespace(c.ns).Resource("replicationControllers").Name(name).Do().Into(result) + return +} + +// Create creates a new replication controller. +func (c *replicationControllers) Create(controller *api.ReplicationController) (result *api.ReplicationController, err error) { + result = &api.ReplicationController{} + err = c.r.Post().Namespace(c.ns).Resource("replicationControllers").Body(controller).Do().Into(result) + return +} + +// Update updates an existing replication controller. +func (c *replicationControllers) Update(controller *api.ReplicationController) (result *api.ReplicationController, err error) { + result = &api.ReplicationController{} + err = c.r.Put().Namespace(c.ns).Resource("replicationControllers").Name(controller.Name).Body(controller).Do().Into(result) + return +} + +// UpdateStatus updates an existing replication controller status +func (c *replicationControllers) UpdateStatus(controller *api.ReplicationController) (result *api.ReplicationController, err error) { + result = &api.ReplicationController{} + err = c.r.Put().Namespace(c.ns).Resource("replicationControllers").Name(controller.Name).SubResource("status").Body(controller).Do().Into(result) + return +} + +// Delete deletes an existing replication controller. +func (c *replicationControllers) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("replicationControllers").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested controllers. +func (c *replicationControllers) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("replicationControllers"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/resource_quotas.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/resource_quotas.go new file mode 100644 index 0000000..9944cef --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/resource_quotas.go @@ -0,0 +1,102 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +// ResourceQuotasNamespacer has methods to work with ResourceQuota resources in a namespace +type ResourceQuotasNamespacer interface { + ResourceQuotas(namespace string) ResourceQuotaInterface +} + +// ResourceQuotaInterface has methods to work with ResourceQuota resources. +type ResourceQuotaInterface interface { + List(opts api.ListOptions) (*api.ResourceQuotaList, error) + Get(name string) (*api.ResourceQuota, error) + Delete(name string) error + Create(resourceQuota *api.ResourceQuota) (*api.ResourceQuota, error) + Update(resourceQuota *api.ResourceQuota) (*api.ResourceQuota, error) + UpdateStatus(resourceQuota *api.ResourceQuota) (*api.ResourceQuota, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// resourceQuotas implements ResourceQuotasNamespacer interface +type resourceQuotas struct { + r *Client + ns string +} + +// newResourceQuotas returns a resourceQuotas +func newResourceQuotas(c *Client, namespace string) *resourceQuotas { + return &resourceQuotas{ + r: c, + ns: namespace, + } +} + +// List takes a selector, and returns the list of resourceQuotas that match that selector. +func (c *resourceQuotas) List(opts api.ListOptions) (result *api.ResourceQuotaList, err error) { + result = &api.ResourceQuotaList{} + err = c.r.Get().Namespace(c.ns).Resource("resourceQuotas").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the resourceQuota, and returns the corresponding ResourceQuota object, and an error if it occurs +func (c *resourceQuotas) Get(name string) (result *api.ResourceQuota, err error) { + result = &api.ResourceQuota{} + err = c.r.Get().Namespace(c.ns).Resource("resourceQuotas").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the resourceQuota, and returns an error if one occurs +func (c *resourceQuotas) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("resourceQuotas").Name(name).Do().Error() +} + +// Create takes the representation of a resourceQuota. Returns the server's representation of the resourceQuota, and an error, if it occurs. +func (c *resourceQuotas) Create(resourceQuota *api.ResourceQuota) (result *api.ResourceQuota, err error) { + result = &api.ResourceQuota{} + err = c.r.Post().Namespace(c.ns).Resource("resourceQuotas").Body(resourceQuota).Do().Into(result) + return +} + +// Update takes the representation of a resourceQuota to update spec. Returns the server's representation of the resourceQuota, and an error, if it occurs. +func (c *resourceQuotas) Update(resourceQuota *api.ResourceQuota) (result *api.ResourceQuota, err error) { + result = &api.ResourceQuota{} + err = c.r.Put().Namespace(c.ns).Resource("resourceQuotas").Name(resourceQuota.Name).Body(resourceQuota).Do().Into(result) + return +} + +// Status takes the representation of a resourceQuota to update status. Returns the server's representation of the resourceQuota, and an error, if it occurs. +func (c *resourceQuotas) UpdateStatus(resourceQuota *api.ResourceQuota) (result *api.ResourceQuota, err error) { + result = &api.ResourceQuota{} + err = c.r.Put().Namespace(c.ns).Resource("resourceQuotas").Name(resourceQuota.Name).SubResource("status").Body(resourceQuota).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested resource +func (c *resourceQuotas) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("resourceQuotas"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rolebindings.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rolebindings.go new file mode 100644 index 0000000..b798380 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/rolebindings.go @@ -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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/watch" +) + +// RoleBindingsNamespacer has methods to work with RoleBinding resources in a namespace +type RoleBindingsNamespacer interface { + RoleBindings(namespace string) RoleBindingInterface +} + +// RoleBindingInterface has methods to work with RoleBinding resources. +type RoleBindingInterface interface { + List(opts api.ListOptions) (*rbac.RoleBindingList, error) + Get(name string) (*rbac.RoleBinding, error) + Delete(name string, options *api.DeleteOptions) error + Create(roleBinding *rbac.RoleBinding) (*rbac.RoleBinding, error) + Update(roleBinding *rbac.RoleBinding) (*rbac.RoleBinding, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// roleBindings implements RoleBindingsNamespacer interface +type roleBindings struct { + client *RbacClient + ns string +} + +// newRoleBindings returns a roleBindings +func newRoleBindings(c *RbacClient, namespace string) *roleBindings { + return &roleBindings{ + client: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of roleBindings that match those selectors. +func (c *roleBindings) List(opts api.ListOptions) (result *rbac.RoleBindingList, err error) { + result = &rbac.RoleBindingList{} + err = c.client.Get().Namespace(c.ns).Resource("rolebindings").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the roleBinding, and returns the corresponding RoleBinding object, and an error if it occurs +func (c *roleBindings) Get(name string) (result *rbac.RoleBinding, err error) { + result = &rbac.RoleBinding{} + err = c.client.Get().Namespace(c.ns).Resource("rolebindings").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the roleBinding and deletes it. Returns an error if one occurs. +func (c *roleBindings) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Namespace(c.ns).Resource("rolebindings").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a roleBinding and creates it. Returns the server's representation of the roleBinding, and an error, if it occurs. +func (c *roleBindings) Create(roleBinding *rbac.RoleBinding) (result *rbac.RoleBinding, err error) { + result = &rbac.RoleBinding{} + err = c.client.Post().Namespace(c.ns).Resource("rolebindings").Body(roleBinding).Do().Into(result) + return +} + +// Update takes the representation of a roleBinding and updates it. Returns the server's representation of the roleBinding, and an error, if it occurs. +func (c *roleBindings) Update(roleBinding *rbac.RoleBinding) (result *rbac.RoleBinding, err error) { + result = &rbac.RoleBinding{} + err = c.client.Put().Namespace(c.ns).Resource("rolebindings").Name(roleBinding.Name).Body(roleBinding).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested roleBindings. +func (c *roleBindings) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("rolebindings"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/roles.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/roles.go new file mode 100644 index 0000000..b265e78 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/roles.go @@ -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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/rbac" + "k8s.io/kubernetes/pkg/watch" +) + +// RolesNamespacer has methods to work with Role resources in a namespace +type RolesNamespacer interface { + Roles(namespace string) RoleInterface +} + +// RoleInterface has methods to work with Role resources. +type RoleInterface interface { + List(opts api.ListOptions) (*rbac.RoleList, error) + Get(name string) (*rbac.Role, error) + Delete(name string, options *api.DeleteOptions) error + Create(role *rbac.Role) (*rbac.Role, error) + Update(role *rbac.Role) (*rbac.Role, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// roles implements RolesNamespacer interface +type roles struct { + client *RbacClient + ns string +} + +// newRoles returns a roles +func newRoles(c *RbacClient, namespace string) *roles { + return &roles{ + client: c, + ns: namespace, + } +} + +// List takes label and field selectors, and returns the list of roles that match those selectors. +func (c *roles) List(opts api.ListOptions) (result *rbac.RoleList, err error) { + result = &rbac.RoleList{} + err = c.client.Get().Namespace(c.ns).Resource("roles").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get takes the name of the role, and returns the corresponding Role object, and an error if it occurs +func (c *roles) Get(name string) (result *rbac.Role, err error) { + result = &rbac.Role{} + err = c.client.Get().Namespace(c.ns).Resource("roles").Name(name).Do().Into(result) + return +} + +// Delete takes the name of the role and deletes it. Returns an error if one occurs. +func (c *roles) Delete(name string, options *api.DeleteOptions) error { + return c.client.Delete().Namespace(c.ns).Resource("roles").Name(name).Body(options).Do().Error() +} + +// Create takes the representation of a role and creates it. Returns the server's representation of the role, and an error, if it occurs. +func (c *roles) Create(role *rbac.Role) (result *rbac.Role, err error) { + result = &rbac.Role{} + err = c.client.Post().Namespace(c.ns).Resource("roles").Body(role).Do().Into(result) + return +} + +// Update takes the representation of a role and updates it. Returns the server's representation of the role, and an error, if it occurs. +func (c *roles) Update(role *rbac.Role) (result *rbac.Role, err error) { + result = &rbac.Role{} + err = c.client.Put().Namespace(c.ns).Resource("roles").Name(role.Name).Body(role).Do().Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested roles. +func (c *roles) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.client.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("roles"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scale.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scale.go new file mode 100644 index 0000000..a55b077 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scale.go @@ -0,0 +1,77 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api/meta" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/extensions" +) + +type ScaleNamespacer interface { + Scales(namespace string) ScaleInterface +} + +// ScaleInterface has methods to work with Scale (sub)resources. +type ScaleInterface interface { + Get(string, string) (*extensions.Scale, error) + Update(string, *extensions.Scale) (*extensions.Scale, error) +} + +// horizontalPodAutoscalers implements HorizontalPodAutoscalersNamespacer interface +type scales struct { + client *ExtensionsClient + ns string +} + +// newHorizontalPodAutoscalers returns a horizontalPodAutoscalers +func newScales(c *ExtensionsClient, namespace string) *scales { + return &scales{ + client: c, + ns: namespace, + } +} + +// Get takes the reference to scale subresource and returns the subresource or error, if one occurs. +func (c *scales) Get(kind string, name string) (result *extensions.Scale, err error) { + result = &extensions.Scale{} + + // TODO this method needs to take a proper unambiguous kind + fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind} + resource, _ := meta.KindToResource(fullyQualifiedKind) + + err = c.client.Get().Namespace(c.ns).Resource(resource.Resource).Name(name).SubResource("scale").Do().Into(result) + return +} + +func (c *scales) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) { + result = &extensions.Scale{} + + // TODO this method needs to take a proper unambiguous kind + fullyQualifiedKind := unversioned.GroupVersionKind{Kind: kind} + resource, _ := meta.KindToResource(fullyQualifiedKind) + + err = c.client.Put(). + Namespace(scale.Namespace). + Resource(resource.Resource). + Name(scale.Name). + SubResource("scale"). + Body(scale). + Do(). + Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scheduledjobs.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scheduledjobs.go new file mode 100644 index 0000000..de07a7e --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/scheduledjobs.go @@ -0,0 +1,103 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/watch" +) + +// ScheduledJobsNamespacer has methods to work with ScheduledJob resources in a namespace +type ScheduledJobsNamespacer interface { + ScheduledJobs(namespace string) ScheduledJobInterface +} + +// ScheduledJobInterface exposes methods to work on ScheduledJob resources. +type ScheduledJobInterface interface { + List(opts api.ListOptions) (*batch.ScheduledJobList, error) + Get(name string) (*batch.ScheduledJob, error) + Create(scheduledJob *batch.ScheduledJob) (*batch.ScheduledJob, error) + Update(scheduledJob *batch.ScheduledJob) (*batch.ScheduledJob, error) + Delete(name string, options *api.DeleteOptions) error + Watch(opts api.ListOptions) (watch.Interface, error) + UpdateStatus(scheduledJob *batch.ScheduledJob) (*batch.ScheduledJob, error) +} + +// scheduledJobs implements ScheduledJobsNamespacer interface +type scheduledJobs struct { + r *BatchClient + ns string +} + +// newScheduledJobs returns a scheduledJobs +func newScheduledJobs(c *BatchClient, namespace string) *scheduledJobs { + return &scheduledJobs{c, namespace} +} + +// Ensure statically that scheduledJobs implements ScheduledJobInterface. +var _ ScheduledJobInterface = &scheduledJobs{} + +// List returns a list of scheduled jobs that match the label and field selectors. +func (c *scheduledJobs) List(opts api.ListOptions) (result *batch.ScheduledJobList, err error) { + result = &batch.ScheduledJobList{} + err = c.r.Get().Namespace(c.ns).Resource("scheduledJobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular scheduled job. +func (c *scheduledJobs) Get(name string) (result *batch.ScheduledJob, err error) { + result = &batch.ScheduledJob{} + err = c.r.Get().Namespace(c.ns).Resource("scheduledJobs").Name(name).Do().Into(result) + return +} + +// Create creates a new scheduled job. +func (c *scheduledJobs) Create(job *batch.ScheduledJob) (result *batch.ScheduledJob, err error) { + result = &batch.ScheduledJob{} + err = c.r.Post().Namespace(c.ns).Resource("scheduledJobs").Body(job).Do().Into(result) + return +} + +// Update updates an existing scheduled job. +func (c *scheduledJobs) Update(job *batch.ScheduledJob) (result *batch.ScheduledJob, err error) { + result = &batch.ScheduledJob{} + err = c.r.Put().Namespace(c.ns).Resource("scheduledJobs").Name(job.Name).Body(job).Do().Into(result) + return +} + +// Delete deletes a scheduled job, returns error if one occurs. +func (c *scheduledJobs) Delete(name string, options *api.DeleteOptions) (err error) { + return c.r.Delete().Namespace(c.ns).Resource("scheduledJobs").Name(name).Body(options).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested scheduled jobs. +func (c *scheduledJobs) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("scheduledJobs"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// UpdateStatus takes the name of the scheduled job and the new status. Returns the server's representation of the scheduled job, and an error, if it occurs. +func (c *scheduledJobs) UpdateStatus(job *batch.ScheduledJob) (result *batch.ScheduledJob, err error) { + result = &batch.ScheduledJob{} + err = c.r.Put().Namespace(c.ns).Resource("scheduledJobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/secrets.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/secrets.go new file mode 100644 index 0000000..bba3fd9 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/secrets.go @@ -0,0 +1,120 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +type SecretsNamespacer interface { + Secrets(namespace string) SecretsInterface +} + +type SecretsInterface interface { + Create(secret *api.Secret) (*api.Secret, error) + Update(secret *api.Secret) (*api.Secret, error) + Delete(name string) error + List(opts api.ListOptions) (*api.SecretList, error) + Get(name string) (*api.Secret, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// events implements Secrets interface +type secrets struct { + client *Client + namespace string +} + +// newSecrets returns a new secrets object. +func newSecrets(c *Client, ns string) *secrets { + return &secrets{ + client: c, + namespace: ns, + } +} + +func (s *secrets) Create(secret *api.Secret) (*api.Secret, error) { + result := &api.Secret{} + err := s.client.Post(). + Namespace(s.namespace). + Resource("secrets"). + Body(secret). + Do(). + Into(result) + + return result, err +} + +// List returns a list of secrets matching the selectors. +func (s *secrets) List(opts api.ListOptions) (*api.SecretList, error) { + result := &api.SecretList{} + + err := s.client.Get(). + Namespace(s.namespace). + Resource("secrets"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +// Get returns the given secret, or an error. +func (s *secrets) Get(name string) (*api.Secret, error) { + result := &api.Secret{} + err := s.client.Get(). + Namespace(s.namespace). + Resource("secrets"). + Name(name). + Do(). + Into(result) + + return result, err +} + +// Watch starts watching for secrets matching the given selectors. +func (s *secrets) Watch(opts api.ListOptions) (watch.Interface, error) { + return s.client.Get(). + Prefix("watch"). + Namespace(s.namespace). + Resource("secrets"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +func (s *secrets) Delete(name string) error { + return s.client.Delete(). + Namespace(s.namespace). + Resource("secrets"). + Name(name). + Do(). + Error() +} + +func (s *secrets) Update(secret *api.Secret) (result *api.Secret, err error) { + result = &api.Secret{} + err = s.client.Put(). + Namespace(s.namespace). + Resource("secrets"). + Name(secret.Name). + Body(secret). + Do(). + Into(result) + + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/service_accounts.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/service_accounts.go new file mode 100644 index 0000000..68d1b21 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/service_accounts.go @@ -0,0 +1,120 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/watch" +) + +type ServiceAccountsNamespacer interface { + ServiceAccounts(namespace string) ServiceAccountsInterface +} + +type ServiceAccountsInterface interface { + Create(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) + Update(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) + Delete(name string) error + List(opts api.ListOptions) (*api.ServiceAccountList, error) + Get(name string) (*api.ServiceAccount, error) + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// serviceAccounts implements ServiceAccounts interface +type serviceAccounts struct { + client *Client + namespace string +} + +// newServiceAccounts returns a new serviceAccounts object. +func newServiceAccounts(c *Client, ns string) ServiceAccountsInterface { + return &serviceAccounts{ + client: c, + namespace: ns, + } +} + +func (s *serviceAccounts) Create(serviceAccount *api.ServiceAccount) (*api.ServiceAccount, error) { + result := &api.ServiceAccount{} + err := s.client.Post(). + Namespace(s.namespace). + Resource("serviceAccounts"). + Body(serviceAccount). + Do(). + Into(result) + + return result, err +} + +// List returns a list of serviceAccounts matching the selectors. +func (s *serviceAccounts) List(opts api.ListOptions) (*api.ServiceAccountList, error) { + result := &api.ServiceAccountList{} + + err := s.client.Get(). + Namespace(s.namespace). + Resource("serviceAccounts"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + + return result, err +} + +// Get returns the given serviceAccount, or an error. +func (s *serviceAccounts) Get(name string) (*api.ServiceAccount, error) { + result := &api.ServiceAccount{} + err := s.client.Get(). + Namespace(s.namespace). + Resource("serviceAccounts"). + Name(name). + Do(). + Into(result) + + return result, err +} + +// Watch starts watching for serviceAccounts matching the given selectors. +func (s *serviceAccounts) Watch(opts api.ListOptions) (watch.Interface, error) { + return s.client.Get(). + Prefix("watch"). + Namespace(s.namespace). + Resource("serviceAccounts"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +func (s *serviceAccounts) Delete(name string) error { + return s.client.Delete(). + Namespace(s.namespace). + Resource("serviceAccounts"). + Name(name). + Do(). + Error() +} + +func (s *serviceAccounts) Update(serviceAccount *api.ServiceAccount) (result *api.ServiceAccount, err error) { + result = &api.ServiceAccount{} + err = s.client.Put(). + Namespace(s.namespace). + Resource("serviceAccounts"). + Name(serviceAccount.Name). + Body(serviceAccount). + Do(). + Into(result) + + return +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/services.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/services.go new file mode 100644 index 0000000..aada5c1 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/services.go @@ -0,0 +1,121 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/util/net" + "k8s.io/kubernetes/pkg/watch" +) + +// ServicesNamespacer has methods to work with Service resources in a namespace +type ServicesNamespacer interface { + Services(namespace string) ServiceInterface +} + +// ServiceInterface has methods to work with Service resources. +type ServiceInterface interface { + List(opts api.ListOptions) (*api.ServiceList, error) + Get(name string) (*api.Service, error) + Create(srv *api.Service) (*api.Service, error) + Update(srv *api.Service) (*api.Service, error) + UpdateStatus(srv *api.Service) (*api.Service, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) + ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper +} + +// services implements ServicesNamespacer interface +type services struct { + r *Client + ns string +} + +// newServices returns a services +func newServices(c *Client, namespace string) *services { + return &services{c, namespace} +} + +// List takes a selector, and returns the list of services that match that selector +func (c *services) List(opts api.ListOptions) (result *api.ServiceList, err error) { + result = &api.ServiceList{} + err = c.r.Get(). + Namespace(c.ns). + Resource("services"). + VersionedParams(&opts, api.ParameterCodec). + Do(). + Into(result) + return +} + +// Get returns information about a particular service. +func (c *services) Get(name string) (result *api.Service, err error) { + result = &api.Service{} + err = c.r.Get().Namespace(c.ns).Resource("services").Name(name).Do().Into(result) + return +} + +// Create creates a new service. +func (c *services) Create(svc *api.Service) (result *api.Service, err error) { + result = &api.Service{} + err = c.r.Post().Namespace(c.ns).Resource("services").Body(svc).Do().Into(result) + return +} + +// Update updates an existing service. +func (c *services) Update(svc *api.Service) (result *api.Service, err error) { + result = &api.Service{} + err = c.r.Put().Namespace(c.ns).Resource("services").Name(svc.Name).Body(svc).Do().Into(result) + return +} + +// UpdateStatus takes a Service object with the new status and applies it as an update to the existing Service. +func (c *services) UpdateStatus(service *api.Service) (result *api.Service, err error) { + result = &api.Service{} + err = c.r.Put().Namespace(c.ns).Resource("services").Name(service.Name).SubResource("status").Body(service).Do().Into(result) + return +} + +// Delete deletes an existing service. +func (c *services) Delete(name string) error { + return c.r.Delete().Namespace(c.ns).Resource("services").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested services. +func (c *services) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("services"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} + +// ProxyGet returns a response of the service by calling it through the proxy. +func (c *services) ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper { + request := c.r.Get(). + Namespace(c.ns). + Resource("services"). + SubResource("proxy"). + Name(net.JoinSchemeNamePort(scheme, name, port)). + Suffix(path) + for k, v := range params { + request = request.Param(k, v) + } + return request +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/thirdpartyresources.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/thirdpartyresources.go new file mode 100644 index 0000000..68adddb --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/thirdpartyresources.go @@ -0,0 +1,98 @@ +/* +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 unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/watch" +) + +// ThirdPartyResourceNamespacer has methods to work with ThirdPartyResource resources in a namespace +type ThirdPartyResourceNamespacer interface { + ThirdPartyResources() ThirdPartyResourceInterface +} + +type ThirdPartyResourceInterface interface { + List(opts api.ListOptions) (*extensions.ThirdPartyResourceList, error) + Get(name string) (*extensions.ThirdPartyResource, error) + Create(ctrl *extensions.ThirdPartyResource) (*extensions.ThirdPartyResource, error) + Update(ctrl *extensions.ThirdPartyResource) (*extensions.ThirdPartyResource, error) + UpdateStatus(ctrl *extensions.ThirdPartyResource) (*extensions.ThirdPartyResource, error) + Delete(name string) error + Watch(opts api.ListOptions) (watch.Interface, error) +} + +// thirdPartyResources implements DaemonsSetsNamespacer interface +type thirdPartyResources struct { + r *ExtensionsClient +} + +func newThirdPartyResources(c *ExtensionsClient) *thirdPartyResources { + return &thirdPartyResources{c} +} + +// Ensure statically that thirdPartyResources implements ThirdPartyResourcesInterface. +var _ ThirdPartyResourceInterface = &thirdPartyResources{} + +func (c *thirdPartyResources) List(opts api.ListOptions) (result *extensions.ThirdPartyResourceList, err error) { + result = &extensions.ThirdPartyResourceList{} + err = c.r.Get().Resource("thirdpartyresources").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) + return +} + +// Get returns information about a particular third party resource. +func (c *thirdPartyResources) Get(name string) (result *extensions.ThirdPartyResource, err error) { + result = &extensions.ThirdPartyResource{} + err = c.r.Get().Resource("thirdpartyresources").Name(name).Do().Into(result) + return +} + +// Create creates a new third party resource. +func (c *thirdPartyResources) Create(resource *extensions.ThirdPartyResource) (result *extensions.ThirdPartyResource, err error) { + result = &extensions.ThirdPartyResource{} + err = c.r.Post().Resource("thirdpartyresources").Body(resource).Do().Into(result) + return +} + +// Update updates an existing third party resource. +func (c *thirdPartyResources) Update(resource *extensions.ThirdPartyResource) (result *extensions.ThirdPartyResource, err error) { + result = &extensions.ThirdPartyResource{} + err = c.r.Put().Resource("thirdpartyresources").Name(resource.Name).Body(resource).Do().Into(result) + return +} + +// UpdateStatus updates an existing third party resource status +func (c *thirdPartyResources) UpdateStatus(resource *extensions.ThirdPartyResource) (result *extensions.ThirdPartyResource, err error) { + result = &extensions.ThirdPartyResource{} + err = c.r.Put().Resource("thirdpartyresources").Name(resource.Name).SubResource("status").Body(resource).Do().Into(result) + return +} + +// Delete deletes an existing third party resource. +func (c *thirdPartyResources) Delete(name string) error { + return c.r.Delete().Resource("thirdpartyresources").Name(name).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested third party resources. +func (c *thirdPartyResources) Watch(opts api.ListOptions) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Resource("thirdpartyresources"). + VersionedParams(&opts, api.ParameterCodec). + Watch() +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/util.go b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/util.go new file mode 100644 index 0000000..9657ff2 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/pkg/client/unversioned/util.go @@ -0,0 +1,79 @@ +/* +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 unversioned + +import ( + "time" + + "k8s.io/kubernetes/pkg/api/errors" + "k8s.io/kubernetes/pkg/util/wait" +) + +// DefaultRetry is the recommended retry for a conflict where multiple clients +// are making changes to the same resource. +var DefaultRetry = wait.Backoff{ + Steps: 5, + Duration: 10 * time.Millisecond, + Factor: 1.0, + Jitter: 0.1, +} + +// DefaultBackoff is the recommended backoff for a conflict where a client +// may be attempting to make an unrelated modification to a resource under +// active management by one or more controllers. +var DefaultBackoff = wait.Backoff{ + Steps: 4, + Duration: 10 * time.Millisecond, + Factor: 5.0, + Jitter: 0.1, +} + +// RetryConflict executes the provided function repeatedly, retrying if the server returns a conflicting +// write. Callers should preserve previous executions if they wish to retry changes. It performs an +// exponential backoff. +// +// var pod *api.Pod +// err := RetryOnConflict(DefaultBackoff, func() (err error) { +// pod, err = c.Pods("mynamespace").UpdateStatus(podStatus) +// return +// }) +// if err != nil { +// // may be conflict if max retries were hit +// return err +// } +// ... +// +// TODO: Make Backoff an interface? +func RetryOnConflict(backoff wait.Backoff, fn func() error) error { + var lastConflictErr error + err := wait.ExponentialBackoff(backoff, func() (bool, error) { + err := fn() + switch { + case err == nil: + return true, nil + case errors.IsConflict(err): + lastConflictErr = err + return false, nil + default: + return false, err + } + }) + if err == wait.ErrWaitTimeout { + err = lastConflictErr + } + return err +} -- cgit 1.2.3-korg