use istio client-go library instead of knative (#1661)
use istio client-go library instead of knative bump kubernetes dependency version change code coverage to codecov
This commit is contained in:
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/OWNERS
generated
vendored
2
vendor/k8s.io/apiserver/pkg/storage/etcd3/OWNERS
generated
vendored
@@ -1,3 +1,5 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
reviewers:
|
||||
- wojtek-t
|
||||
- timothysc
|
||||
|
||||
130
vendor/k8s.io/apiserver/pkg/storage/etcd3/api_object_versioner.go
generated
vendored
Normal file
130
vendor/k8s.io/apiserver/pkg/storage/etcd3/api_object_versioner.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
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 etcd3
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
)
|
||||
|
||||
// APIObjectVersioner implements versioning and extracting etcd node information
|
||||
// for objects that have an embedded ObjectMeta or ListMeta field.
|
||||
type APIObjectVersioner struct{}
|
||||
|
||||
// UpdateObject implements Versioner
|
||||
func (a APIObjectVersioner) UpdateObject(obj runtime.Object, resourceVersion uint64) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
versionString := ""
|
||||
if resourceVersion != 0 {
|
||||
versionString = strconv.FormatUint(resourceVersion, 10)
|
||||
}
|
||||
accessor.SetResourceVersion(versionString)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateList implements Versioner
|
||||
func (a APIObjectVersioner) UpdateList(obj runtime.Object, resourceVersion uint64, nextKey string, count *int64) error {
|
||||
listAccessor, err := meta.ListAccessor(obj)
|
||||
if err != nil || listAccessor == nil {
|
||||
return err
|
||||
}
|
||||
versionString := ""
|
||||
if resourceVersion != 0 {
|
||||
versionString = strconv.FormatUint(resourceVersion, 10)
|
||||
}
|
||||
listAccessor.SetResourceVersion(versionString)
|
||||
listAccessor.SetContinue(nextKey)
|
||||
listAccessor.SetRemainingItemCount(count)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrepareObjectForStorage clears resource version and self link prior to writing to etcd.
|
||||
func (a APIObjectVersioner) PrepareObjectForStorage(obj runtime.Object) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetResourceVersion("")
|
||||
accessor.SetSelfLink("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ObjectResourceVersion implements Versioner
|
||||
func (a APIObjectVersioner) ObjectResourceVersion(obj runtime.Object) (uint64, error) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
version := accessor.GetResourceVersion()
|
||||
if len(version) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return strconv.ParseUint(version, 10, 64)
|
||||
}
|
||||
|
||||
// ParseResourceVersion takes a resource version argument and converts it to
|
||||
// the etcd version. For watch we should pass to helper.Watch(). Because resourceVersion is
|
||||
// an opaque value, the default watch behavior for non-zero watch is to watch
|
||||
// the next value (if you pass "1", you will see updates from "2" onwards).
|
||||
func (a APIObjectVersioner) ParseResourceVersion(resourceVersion string) (uint64, error) {
|
||||
if resourceVersion == "" || resourceVersion == "0" {
|
||||
return 0, nil
|
||||
}
|
||||
version, err := strconv.ParseUint(resourceVersion, 10, 64)
|
||||
if err != nil {
|
||||
return 0, storage.NewInvalidError(field.ErrorList{
|
||||
// Validation errors are supposed to return version-specific field
|
||||
// paths, but this is probably close enough.
|
||||
field.Invalid(field.NewPath("resourceVersion"), resourceVersion, err.Error()),
|
||||
})
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// Versioner implements Versioner
|
||||
var Versioner storage.Versioner = APIObjectVersioner{}
|
||||
|
||||
// CompareResourceVersion compares etcd resource versions. Outside this API they are all strings,
|
||||
// but etcd resource versions are special, they're actually ints, so we can easily compare them.
|
||||
func (a APIObjectVersioner) CompareResourceVersion(lhs, rhs runtime.Object) int {
|
||||
lhsVersion, err := Versioner.ObjectResourceVersion(lhs)
|
||||
if err != nil {
|
||||
// coder error
|
||||
panic(err)
|
||||
}
|
||||
rhsVersion, err := Versioner.ObjectResourceVersion(rhs)
|
||||
if err != nil {
|
||||
// coder error
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if lhsVersion == rhsVersion {
|
||||
return 0
|
||||
}
|
||||
if lhsVersion < rhsVersion {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
40
vendor/k8s.io/apiserver/pkg/storage/etcd3/healthcheck.go
generated
vendored
Normal file
40
vendor/k8s.io/apiserver/pkg/storage/etcd3/healthcheck.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
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 etcd3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// etcdHealth encodes data returned from etcd /healthz handler.
|
||||
type etcdHealth struct {
|
||||
// Note this has to be public so the json library can modify it.
|
||||
Health string `json:"health"`
|
||||
}
|
||||
|
||||
// EtcdHealthCheck decodes data returned from etcd /healthz handler.
|
||||
func EtcdHealthCheck(data []byte) error {
|
||||
obj := etcdHealth{}
|
||||
if err := json.Unmarshal(data, &obj); err != nil {
|
||||
return err
|
||||
}
|
||||
if obj.Health != "true" {
|
||||
return fmt.Errorf("Unhealthy status: %s", obj.Health)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
84
vendor/k8s.io/apiserver/pkg/storage/etcd3/logger.go
generated
vendored
Normal file
84
vendor/k8s.io/apiserver/pkg/storage/etcd3/logger.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package etcd3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
clientv3.SetLogger(klogWrapper{})
|
||||
}
|
||||
|
||||
type klogWrapper struct{}
|
||||
|
||||
const klogWrapperDepth = 4
|
||||
|
||||
func (klogWrapper) Info(args ...interface{}) {
|
||||
klog.InfoDepth(klogWrapperDepth, args...)
|
||||
}
|
||||
|
||||
func (klogWrapper) Infoln(args ...interface{}) {
|
||||
klog.InfoDepth(klogWrapperDepth, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Infof(format string, args ...interface{}) {
|
||||
klog.InfoDepth(klogWrapperDepth, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Warning(args ...interface{}) {
|
||||
klog.WarningDepth(klogWrapperDepth, args...)
|
||||
}
|
||||
|
||||
func (klogWrapper) Warningln(args ...interface{}) {
|
||||
klog.WarningDepth(klogWrapperDepth, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Warningf(format string, args ...interface{}) {
|
||||
klog.WarningDepth(klogWrapperDepth, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Error(args ...interface{}) {
|
||||
klog.ErrorDepth(klogWrapperDepth, args...)
|
||||
}
|
||||
|
||||
func (klogWrapper) Errorln(args ...interface{}) {
|
||||
klog.ErrorDepth(klogWrapperDepth, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Errorf(format string, args ...interface{}) {
|
||||
klog.ErrorDepth(klogWrapperDepth, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Fatal(args ...interface{}) {
|
||||
klog.FatalDepth(klogWrapperDepth, args...)
|
||||
}
|
||||
|
||||
func (klogWrapper) Fatalln(args ...interface{}) {
|
||||
klog.FatalDepth(klogWrapperDepth, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) Fatalf(format string, args ...interface{}) {
|
||||
klog.FatalDepth(klogWrapperDepth, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (klogWrapper) V(l int) bool {
|
||||
return bool(klog.V(klog.Level(l)))
|
||||
}
|
||||
103
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
Normal file
103
vendor/k8s.io/apiserver/pkg/storage/etcd3/metrics/metrics.go
generated
vendored
Normal file
@@ -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 metrics
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
/*
|
||||
* By default, all the following metrics are defined as falling under
|
||||
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
|
||||
*
|
||||
* Promoting the stability level of the metric is a responsibility of the component owner, since it
|
||||
* involves explicitly acknowledging support for the metric across multiple releases, in accordance with
|
||||
* the metric stability policy.
|
||||
*/
|
||||
var (
|
||||
etcdRequestLatency = compbasemetrics.NewHistogramVec(
|
||||
&compbasemetrics.HistogramOpts{
|
||||
Name: "etcd_request_duration_seconds",
|
||||
Help: "Etcd request latency in seconds for each operation and object type.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
},
|
||||
[]string{"operation", "type"},
|
||||
)
|
||||
objectCounts = compbasemetrics.NewGaugeVec(
|
||||
&compbasemetrics.GaugeOpts{
|
||||
Name: "etcd_object_counts",
|
||||
Help: "Number of stored objects at the time of last check split by kind.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
},
|
||||
[]string{"resource"},
|
||||
)
|
||||
|
||||
deprecatedEtcdRequestLatenciesSummary = compbasemetrics.NewSummaryVec(
|
||||
&compbasemetrics.SummaryOpts{
|
||||
Name: "etcd_request_latencies_summary",
|
||||
Help: "(Deprecated) Etcd request latency summary in microseconds for each operation and object type.",
|
||||
StabilityLevel: compbasemetrics.ALPHA,
|
||||
},
|
||||
[]string{"operation", "type"},
|
||||
)
|
||||
)
|
||||
|
||||
var registerMetrics sync.Once
|
||||
|
||||
// Register all metrics.
|
||||
func Register() {
|
||||
// Register the metrics.
|
||||
registerMetrics.Do(func() {
|
||||
legacyregistry.MustRegister(etcdRequestLatency)
|
||||
legacyregistry.MustRegister(objectCounts)
|
||||
|
||||
// TODO(danielqsj): Remove the following metrics, they are deprecated
|
||||
legacyregistry.MustRegister(deprecatedEtcdRequestLatenciesSummary)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateObjectCount sets the etcd_object_counts metric.
|
||||
func UpdateObjectCount(resourcePrefix string, count int64) {
|
||||
objectCounts.WithLabelValues(resourcePrefix).Set(float64(count))
|
||||
}
|
||||
|
||||
// RecordEtcdRequestLatency sets the etcd_request_duration_seconds metrics.
|
||||
func RecordEtcdRequestLatency(verb, resource string, startTime time.Time) {
|
||||
etcdRequestLatency.WithLabelValues(verb, resource).Observe(sinceInSeconds(startTime))
|
||||
deprecatedEtcdRequestLatenciesSummary.WithLabelValues(verb, resource).Observe(sinceInMicroseconds(startTime))
|
||||
}
|
||||
|
||||
// Reset resets the etcd_request_duration_seconds metric.
|
||||
func Reset() {
|
||||
etcdRequestLatency.Reset()
|
||||
|
||||
deprecatedEtcdRequestLatenciesSummary.Reset()
|
||||
}
|
||||
|
||||
// sinceInMicroseconds gets the time since the specified start in microseconds.
|
||||
func sinceInMicroseconds(start time.Time) float64 {
|
||||
return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds())
|
||||
}
|
||||
|
||||
// sinceInSeconds gets the time since the specified start in seconds.
|
||||
func sinceInSeconds(start time.Time) float64 {
|
||||
return time.Since(start).Seconds()
|
||||
}
|
||||
171
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
171
vendor/k8s.io/apiserver/pkg/storage/etcd3/store.go
generated
vendored
@@ -36,10 +36,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/etcd"
|
||||
"k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utiltrace "k8s.io/apiserver/pkg/util/trace"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
// authenticatedDataString satisfies the value.Context interface. It uses the key to
|
||||
@@ -86,7 +88,7 @@ func New(c *clientv3.Client, codec runtime.Codec, prefix string, transformer val
|
||||
}
|
||||
|
||||
func newStore(c *clientv3.Client, pagingEnabled bool, codec runtime.Codec, prefix string, transformer value.Transformer) *store {
|
||||
versioner := etcd.APIObjectVersioner{}
|
||||
versioner := APIObjectVersioner{}
|
||||
result := &store{
|
||||
client: c,
|
||||
codec: codec,
|
||||
@@ -111,7 +113,9 @@ func (s *store) Versioner() storage.Versioner {
|
||||
// Get implements storage.Interface.Get.
|
||||
func (s *store) Get(ctx context.Context, key string, resourceVersion string, out runtime.Object, ignoreNotFound bool) error {
|
||||
key = path.Join(s.pathPrefix, key)
|
||||
startTime := time.Now()
|
||||
getResp, err := s.client.KV.Get(ctx, key, s.getOps...)
|
||||
metrics.RecordEtcdRequestLatency("get", getTypeName(out), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -156,11 +160,13 @@ func (s *store) Create(ctx context.Context, key string, obj, out runtime.Object,
|
||||
return storage.NewInternalError(err.Error())
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
txnResp, err := s.client.KV.Txn(ctx).If(
|
||||
notFound(key),
|
||||
).Then(
|
||||
clientv3.OpPut(key, string(newData), opts...),
|
||||
).Commit()
|
||||
metrics.RecordEtcdRequestLatency("create", getTypeName(obj), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -176,43 +182,19 @@ func (s *store) Create(ctx context.Context, key string, obj, out runtime.Object,
|
||||
}
|
||||
|
||||
// Delete implements storage.Interface.Delete.
|
||||
func (s *store) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions) error {
|
||||
func (s *store) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions, validateDeletion storage.ValidateObjectFunc) error {
|
||||
v, err := conversion.EnforcePtr(out)
|
||||
if err != nil {
|
||||
panic("unable to convert output object to pointer")
|
||||
return fmt.Errorf("unable to convert output object to pointer: %v", err)
|
||||
}
|
||||
key = path.Join(s.pathPrefix, key)
|
||||
if preconditions == nil {
|
||||
return s.unconditionalDelete(ctx, key, out)
|
||||
}
|
||||
return s.conditionalDelete(ctx, key, out, v, preconditions)
|
||||
return s.conditionalDelete(ctx, key, out, v, preconditions, validateDeletion)
|
||||
}
|
||||
|
||||
func (s *store) unconditionalDelete(ctx context.Context, key string, out runtime.Object) error {
|
||||
// We need to do get and delete in single transaction in order to
|
||||
// know the value and revision before deleting it.
|
||||
txnResp, err := s.client.KV.Txn(ctx).If().Then(
|
||||
clientv3.OpGet(key),
|
||||
clientv3.OpDelete(key),
|
||||
).Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
getResp := txnResp.Responses[0].GetResponseRange()
|
||||
if len(getResp.Kvs) == 0 {
|
||||
return storage.NewKeyNotFoundError(key, 0)
|
||||
}
|
||||
|
||||
kv := getResp.Kvs[0]
|
||||
data, _, err := s.transformer.TransformFromStorage(kv.Value, authenticatedDataString(key))
|
||||
if err != nil {
|
||||
return storage.NewInternalError(err.Error())
|
||||
}
|
||||
return decode(s.codec, s.versioner, data, out, kv.ModRevision)
|
||||
}
|
||||
|
||||
func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.Object, v reflect.Value, preconditions *storage.Preconditions) error {
|
||||
func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.Object, v reflect.Value, preconditions *storage.Preconditions, validateDeletion storage.ValidateObjectFunc) error {
|
||||
startTime := time.Now()
|
||||
getResp, err := s.client.KV.Get(ctx, key)
|
||||
metrics.RecordEtcdRequestLatency("get", getTypeName(out), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -221,9 +203,15 @@ func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.O
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := preconditions.Check(key, origState.obj); err != nil {
|
||||
if preconditions != nil {
|
||||
if err := preconditions.Check(key, origState.obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := validateDeletion(ctx, origState.obj); err != nil {
|
||||
return err
|
||||
}
|
||||
startTime := time.Now()
|
||||
txnResp, err := s.client.KV.Txn(ctx).If(
|
||||
clientv3.Compare(clientv3.ModRevision(key), "=", origState.rev),
|
||||
).Then(
|
||||
@@ -231,6 +219,7 @@ func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.O
|
||||
).Else(
|
||||
clientv3.OpGet(key),
|
||||
).Commit()
|
||||
metrics.RecordEtcdRequestLatency("delete", getTypeName(out), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -247,17 +236,19 @@ func (s *store) conditionalDelete(ctx context.Context, key string, out runtime.O
|
||||
func (s *store) GuaranteedUpdate(
|
||||
ctx context.Context, key string, out runtime.Object, ignoreNotFound bool,
|
||||
preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, suggestion ...runtime.Object) error {
|
||||
trace := utiltrace.New(fmt.Sprintf("GuaranteedUpdate etcd3: %s", reflect.TypeOf(out).String()))
|
||||
trace := utiltrace.New("GuaranteedUpdate etcd3", utiltrace.Field{"type", getTypeName(out)})
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
|
||||
v, err := conversion.EnforcePtr(out)
|
||||
if err != nil {
|
||||
panic("unable to convert output object to pointer")
|
||||
return fmt.Errorf("unable to convert output object to pointer: %v", err)
|
||||
}
|
||||
key = path.Join(s.pathPrefix, key)
|
||||
|
||||
getCurrentState := func() (*objState, error) {
|
||||
startTime := time.Now()
|
||||
getResp, err := s.client.KV.Get(ctx, key, s.getOps...)
|
||||
metrics.RecordEtcdRequestLatency("get", getTypeName(out), startTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -283,24 +274,38 @@ func (s *store) GuaranteedUpdate(
|
||||
transformContext := authenticatedDataString(key)
|
||||
for {
|
||||
if err := preconditions.Check(key, origState.obj); err != nil {
|
||||
return err
|
||||
// If our data is already up to date, return the error
|
||||
if !mustCheckData {
|
||||
return err
|
||||
}
|
||||
|
||||
// It's possible we were working with stale data
|
||||
// Actually fetch
|
||||
origState, err = getCurrentState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mustCheckData = false
|
||||
// Retry
|
||||
continue
|
||||
}
|
||||
|
||||
ret, ttl, err := s.updateState(origState, tryUpdate)
|
||||
if err != nil {
|
||||
// It's possible we were working with stale data
|
||||
if mustCheckData && apierrors.IsConflict(err) {
|
||||
// Actually fetch
|
||||
origState, err = getCurrentState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mustCheckData = false
|
||||
// Retry
|
||||
continue
|
||||
// If our data is already up to date, return the error
|
||||
if !mustCheckData {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
// It's possible we were working with stale data
|
||||
// Actually fetch
|
||||
origState, err = getCurrentState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mustCheckData = false
|
||||
// Retry
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := runtime.Encode(s.codec, ret)
|
||||
@@ -339,6 +344,7 @@ func (s *store) GuaranteedUpdate(
|
||||
}
|
||||
trace.Step("Transaction prepared")
|
||||
|
||||
startTime := time.Now()
|
||||
txnResp, err := s.client.KV.Txn(ctx).If(
|
||||
clientv3.Compare(clientv3.ModRevision(key), "=", origState.rev),
|
||||
).Then(
|
||||
@@ -346,6 +352,7 @@ func (s *store) GuaranteedUpdate(
|
||||
).Else(
|
||||
clientv3.OpGet(key),
|
||||
).Commit()
|
||||
metrics.RecordEtcdRequestLatency("update", getTypeName(out), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -369,17 +376,25 @@ func (s *store) GuaranteedUpdate(
|
||||
|
||||
// GetToList implements storage.Interface.GetToList.
|
||||
func (s *store) GetToList(ctx context.Context, key string, resourceVersion string, pred storage.SelectionPredicate, listObj runtime.Object) error {
|
||||
trace := utiltrace.New("GetToList etcd3",
|
||||
utiltrace.Field{"key", key},
|
||||
utiltrace.Field{"resourceVersion", resourceVersion},
|
||||
utiltrace.Field{"limit", pred.Limit},
|
||||
utiltrace.Field{"continue", pred.Continue})
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
listPtr, err := meta.GetItemsPtr(listObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v, err := conversion.EnforcePtr(listPtr)
|
||||
if err != nil || v.Kind() != reflect.Slice {
|
||||
panic("need ptr to slice")
|
||||
return fmt.Errorf("need ptr to slice: %v", err)
|
||||
}
|
||||
|
||||
key = path.Join(s.pathPrefix, key)
|
||||
startTime := time.Now()
|
||||
getResp, err := s.client.KV.Get(ctx, key, s.getOps...)
|
||||
metrics.RecordEtcdRequestLatency("get", getTypeName(listPtr), startTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -394,12 +409,14 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
|
||||
}
|
||||
}
|
||||
// update version with cluster level revision
|
||||
return s.versioner.UpdateList(listObj, uint64(getResp.Header.Revision), "")
|
||||
return s.versioner.UpdateList(listObj, uint64(getResp.Header.Revision), "", nil)
|
||||
}
|
||||
|
||||
func (s *store) Count(key string) (int64, error) {
|
||||
key = path.Join(s.pathPrefix, key)
|
||||
startTime := time.Now()
|
||||
getResp, err := s.client.KV.Get(context.Background(), key, clientv3.WithRange(clientv3.GetPrefixRangeEnd(key)), clientv3.WithCountOnly())
|
||||
metrics.RecordEtcdRequestLatency("listWithCount", key, startTime)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -468,13 +485,19 @@ func encodeContinue(key, keyPrefix string, resourceVersion int64) (string, error
|
||||
|
||||
// List implements storage.Interface.List.
|
||||
func (s *store) List(ctx context.Context, key, resourceVersion string, pred storage.SelectionPredicate, listObj runtime.Object) error {
|
||||
trace := utiltrace.New("List etcd3",
|
||||
utiltrace.Field{"key", key},
|
||||
utiltrace.Field{"resourceVersion", resourceVersion},
|
||||
utiltrace.Field{"limit", pred.Limit},
|
||||
utiltrace.Field{"continue", pred.Continue})
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
listPtr, err := meta.GetItemsPtr(listObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v, err := conversion.EnforcePtr(listPtr)
|
||||
if err != nil || v.Kind() != reflect.Slice {
|
||||
panic("need ptr to slice")
|
||||
return fmt.Errorf("need ptr to slice: %v", err)
|
||||
}
|
||||
|
||||
if s.pathPrefix != "" {
|
||||
@@ -553,8 +576,11 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
|
||||
// loop until we have filled the requested limit from etcd or there are no more results
|
||||
var lastKey []byte
|
||||
var hasMore bool
|
||||
var getResp *clientv3.GetResponse
|
||||
for {
|
||||
getResp, err := s.client.KV.Get(ctx, key, options...)
|
||||
startTime := time.Now()
|
||||
getResp, err = s.client.KV.Get(ctx, key, options...)
|
||||
metrics.RecordEtcdRequestLatency("list", getTypeName(listPtr), startTime)
|
||||
if err != nil {
|
||||
return interpretListError(err, len(pred.Continue) > 0, continueKey, keyPrefix)
|
||||
}
|
||||
@@ -614,11 +640,21 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.versioner.UpdateList(listObj, uint64(returnedRV), next)
|
||||
var remainingItemCount *int64
|
||||
// getResp.Count counts in objects that do not match the pred.
|
||||
// Instead of returning inaccurate count for non-empty selectors, we return nil.
|
||||
// Only set remainingItemCount if the predicate is empty.
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.RemainingItemCount) {
|
||||
if pred.Empty() {
|
||||
c := int64(getResp.Count - pred.Limit)
|
||||
remainingItemCount = &c
|
||||
}
|
||||
}
|
||||
return s.versioner.UpdateList(listObj, uint64(returnedRV), next, remainingItemCount)
|
||||
}
|
||||
|
||||
// no continuation
|
||||
return s.versioner.UpdateList(listObj, uint64(returnedRV), "")
|
||||
return s.versioner.UpdateList(listObj, uint64(returnedRV), "", nil)
|
||||
}
|
||||
|
||||
// growSlice takes a slice value and grows its capacity up
|
||||
@@ -673,9 +709,15 @@ func (s *store) watch(ctx context.Context, key string, rv string, pred storage.S
|
||||
|
||||
func (s *store) getState(getResp *clientv3.GetResponse, key string, v reflect.Value, ignoreNotFound bool) (*objState, error) {
|
||||
state := &objState{
|
||||
obj: reflect.New(v.Type()).Interface().(runtime.Object),
|
||||
meta: &storage.ResponseMeta{},
|
||||
}
|
||||
|
||||
if u, ok := v.Addr().Interface().(runtime.Unstructured); ok {
|
||||
state.obj = u.NewEmptyInstance()
|
||||
} else {
|
||||
state.obj = reflect.New(v.Type()).Interface().(runtime.Object)
|
||||
}
|
||||
|
||||
if len(getResp.Kvs) == 0 {
|
||||
if !ignoreNotFound {
|
||||
return nil, storage.NewKeyNotFoundError(key, 0)
|
||||
@@ -721,7 +763,9 @@ func (s *store) getStateFromObject(obj runtime.Object) (*objState, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.versioner.UpdateObject(state.obj, uint64(rv))
|
||||
if err := s.versioner.UpdateObject(state.obj, uint64(rv)); err != nil {
|
||||
klog.Errorf("failed to update object version: %v", err)
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
@@ -758,14 +802,16 @@ func (s *store) ttlOpts(ctx context.Context, ttl int64) ([]clientv3.OpOption, er
|
||||
// On success, objPtr would be set to the object.
|
||||
func decode(codec runtime.Codec, versioner storage.Versioner, value []byte, objPtr runtime.Object, rev int64) error {
|
||||
if _, err := conversion.EnforcePtr(objPtr); err != nil {
|
||||
panic("unable to convert output object to pointer")
|
||||
return fmt.Errorf("unable to convert output object to pointer: %v", err)
|
||||
}
|
||||
_, _, err := codec.Decode(value, nil, objPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// being unable to set the version does not prevent the object from being extracted
|
||||
versioner.UpdateObject(objPtr, uint64(rev))
|
||||
if err := versioner.UpdateObject(objPtr, uint64(rev)); err != nil {
|
||||
klog.Errorf("failed to update object version: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -776,7 +822,9 @@ func appendListItem(v reflect.Value, data []byte, rev uint64, pred storage.Selec
|
||||
return err
|
||||
}
|
||||
// being unable to set the version does not prevent the object from being extracted
|
||||
versioner.UpdateObject(obj, rev)
|
||||
if err := versioner.UpdateObject(obj, rev); err != nil {
|
||||
klog.Errorf("failed to update object version: %v", err)
|
||||
}
|
||||
if matched, err := pred.Matches(obj); err == nil && matched {
|
||||
v.Set(reflect.Append(v, reflect.ValueOf(obj).Elem()))
|
||||
}
|
||||
@@ -786,3 +834,8 @@ func appendListItem(v reflect.Value, data []byte, rev uint64, pred storage.Selec
|
||||
func notFound(key string) clientv3.Cmp {
|
||||
return clientv3.Compare(clientv3.ModRevision(key), "=", 0)
|
||||
}
|
||||
|
||||
// getTypeName returns type name of an object for reporting purposes.
|
||||
func getTypeName(obj interface{}) string {
|
||||
return reflect.TypeOf(obj).String()
|
||||
}
|
||||
|
||||
6
vendor/k8s.io/apiserver/pkg/storage/etcd3/watcher.go
generated
vendored
6
vendor/k8s.io/apiserver/pkg/storage/etcd3/watcher.go
generated
vendored
@@ -56,9 +56,15 @@ func testingDeferOnDecodeError() {
|
||||
|
||||
func init() {
|
||||
// check to see if we are running in a test environment
|
||||
TestOnlySetFatalOnDecodeError(true)
|
||||
fatalOnDecodeError, _ = strconv.ParseBool(os.Getenv("KUBE_PANIC_WATCH_DECODE_ERROR"))
|
||||
}
|
||||
|
||||
// TestOnlySetFatalOnDecodeError should only be used for cases where decode errors are expected and need to be tested. e.g. conversion webhooks.
|
||||
func TestOnlySetFatalOnDecodeError(b bool) {
|
||||
fatalOnDecodeError = b
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
client *clientv3.Client
|
||||
codec runtime.Codec
|
||||
|
||||
Reference in New Issue
Block a user