Update dependencies (#5518)

This commit is contained in:
hongming
2023-02-12 23:09:20 +08:00
committed by GitHub
parent d3b35fb2da
commit a979342f56
1486 changed files with 126660 additions and 71128 deletions

View File

@@ -29,6 +29,9 @@ import (
"google.golang.org/grpc"
"k8s.io/klog/v2"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics"
commonmetrics "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)
@@ -131,6 +134,9 @@ type grpcTunnel struct {
// closing should only be accessed through atomic methods.
// TODO: switch this to an atomic.Bool once the client is exclusively buit with go1.19+
closing uint32
// Stores the current metrics.ClientConnectionStatus
prevStatus atomic.Value
}
type clientConn interface {
@@ -139,6 +145,11 @@ type clientConn interface {
var _ clientConn = &grpc.ClientConn{}
var (
// Expose metrics for client to register.
Metrics = metrics.Metrics
)
// CreateSingleUseGrpcTunnel creates a Tunnel to dial to a remote server through a
// gRPC based proxy service.
// Currently, a single tunnel supports a single connection, and the tunnel is closed when the connection is terminated
@@ -177,7 +188,7 @@ func CreateSingleUseGrpcTunnelWithContext(createCtx, tunnelCtx context.Context,
}
func newUnstartedTunnel(stream client.ProxyService_ProxyClient, c clientConn) *grpcTunnel {
return &grpcTunnel{
t := grpcTunnel{
stream: stream,
clientConn: c,
pendingDial: pendingDialManager{pendingDials: make(map[int64]pendingDial)},
@@ -185,6 +196,36 @@ func newUnstartedTunnel(stream client.ProxyService_ProxyClient, c clientConn) *g
readTimeoutSeconds: 10,
done: make(chan struct{}),
}
s := metrics.ClientConnectionStatusCreated
t.prevStatus.Store(s)
metrics.Metrics.GetClientConnectionsMetric().WithLabelValues(string(s)).Inc()
return &t
}
func (t *grpcTunnel) updateMetric(status metrics.ClientConnectionStatus) {
select {
case <-t.Done():
return
default:
}
prevStatus := t.prevStatus.Swap(status).(metrics.ClientConnectionStatus)
m := metrics.Metrics.GetClientConnectionsMetric()
m.WithLabelValues(string(prevStatus)).Dec()
m.WithLabelValues(string(status)).Inc()
}
// closeMetric should be called exactly once to finalize client_connections metric.
func (t *grpcTunnel) closeMetric() {
select {
case <-t.Done():
return
default:
}
prevStatus := t.prevStatus.Load().(metrics.ClientConnectionStatus)
metrics.Metrics.GetClientConnectionsMetric().WithLabelValues(string(prevStatus)).Dec()
}
func (t *grpcTunnel) serve(tunnelCtx context.Context) {
@@ -196,19 +237,29 @@ func (t *grpcTunnel) serve(tunnelCtx context.Context) {
// close any channels remaining for these connections.
t.conns.closeAll()
t.closeMetric()
close(t.done)
}()
for {
pkt, err := t.stream.Recv()
if err == io.EOF || t.isClosing() {
if err == io.EOF {
return
}
const segment = commonmetrics.SegmentToClient
isClosing := t.isClosing()
if err != nil || pkt == nil {
klog.ErrorS(err, "stream read failure")
if !isClosing {
klog.ErrorS(err, "stream read failure")
}
metrics.Metrics.ObserveStreamErrorNoPacket(segment, err)
return
}
metrics.Metrics.ObservePacket(segment, pkt.Type)
if isClosing {
return
}
klog.V(5).InfoS("[tracing] recv packet", "type", pkt.Type)
switch pkt.Type {
@@ -222,13 +273,19 @@ func (t *grpcTunnel) serve(tunnelCtx context.Context) {
// 2. grpcTunnel.DialContext() returned early due to a dial timeout or the client canceling the context
//
// In either scenario, we should return here and close the tunnel as it is no longer needed.
klog.V(1).InfoS("DialResp not recognized; dropped", "connectionID", resp.ConnectID, "dialID", resp.Random)
kvs := []interface{}{"dialID", resp.Random, "connectID", resp.ConnectID}
if resp.Error != "" {
kvs = append(kvs, "error", resp.Error)
}
klog.V(1).InfoS("DialResp not recognized; dropped", kvs...)
return
}
result := dialResult{connid: resp.ConnectID}
if resp.Error != "" {
result.err = &dialFailure{resp.Error, DialFailureEndpoint}
result.err = &dialFailure{resp.Error, metrics.DialFailureEndpoint}
} else {
t.updateMetric(metrics.ClientConnectionStatusOk)
}
select {
// try to send to the result channel
@@ -263,7 +320,7 @@ func (t *grpcTunnel) serve(tunnelCtx context.Context) {
klog.V(1).InfoS("DIAL_CLS after dial finished", "dialID", resp.Random)
} else {
result := dialResult{
err: &dialFailure{"dial closed", DialFailureDialClosed},
err: &dialFailure{"dial closed", metrics.DialFailureDialClosed},
}
select {
case pendingDial.resultCh <- result:
@@ -316,6 +373,15 @@ func (t *grpcTunnel) serve(tunnelCtx context.Context) {
// Dial connects to the address on the named network, similar to
// what net.Dial does. The only supported protocol is tcp.
func (t *grpcTunnel) DialContext(requestCtx context.Context, protocol, address string) (net.Conn, error) {
conn, err := t.dialContext(requestCtx, protocol, address)
if err != nil {
_, reason := GetDialFailureReason(err)
metrics.Metrics.ObserveDialFailure(reason)
}
return conn, err
}
func (t *grpcTunnel) dialContext(requestCtx context.Context, protocol, address string) (net.Conn, error) {
select {
case <-t.done:
return nil, errors.New("tunnel is closed")
@@ -326,6 +392,8 @@ func (t *grpcTunnel) DialContext(requestCtx context.Context, protocol, address s
return nil, errors.New("protocol not supported")
}
t.updateMetric(metrics.ClientConnectionStatusDialing)
random := rand.Int63() /* #nosec G404 */
// This channel is closed once we're returning and no longer waiting on resultCh
@@ -350,8 +418,11 @@ func (t *grpcTunnel) DialContext(requestCtx context.Context, protocol, address s
}
klog.V(5).InfoS("[tracing] send packet", "type", req.Type)
const segment = commonmetrics.SegmentFromClient
metrics.Metrics.ObservePacket(segment, req.Type)
err := t.stream.Send(req)
if err != nil {
metrics.Metrics.ObserveStreamError(segment, err, req.Type)
return nil, err
}
@@ -375,14 +446,14 @@ func (t *grpcTunnel) DialContext(requestCtx context.Context, protocol, address s
case <-time.After(30 * time.Second):
klog.V(5).InfoS("Timed out waiting for DialResp", "dialID", random)
go t.closeDial(random)
return nil, &dialFailure{"dial timeout, backstop", DialFailureTimeout}
return nil, &dialFailure{"dial timeout, backstop", metrics.DialFailureTimeout}
case <-requestCtx.Done():
klog.V(5).InfoS("Context canceled waiting for DialResp", "ctxErr", requestCtx.Err(), "dialID", random)
go t.closeDial(random)
return nil, &dialFailure{"dial timeout, context", DialFailureContext}
return nil, &dialFailure{"dial timeout, context", metrics.DialFailureContext}
case <-t.done:
klog.V(5).InfoS("Tunnel closed while waiting for DialResp", "dialID", random)
return nil, &dialFailure{"tunnel closed", DialFailureTunnelClosed}
return nil, &dialFailure{"tunnel closed", metrics.DialFailureTunnelClosed}
}
return c, nil
@@ -402,7 +473,10 @@ func (t *grpcTunnel) closeDial(dialID int64) {
},
},
}
const segment = commonmetrics.SegmentFromClient
metrics.Metrics.ObservePacket(segment, req.Type)
if err := t.stream.Send(req); err != nil {
metrics.Metrics.ObserveStreamError(segment, err, req.Type)
klog.V(5).InfoS("Failed to send DIAL_CLS", "err", err, "dialID", dialID)
}
t.closeTunnel()
@@ -417,38 +491,19 @@ func (t *grpcTunnel) isClosing() bool {
return atomic.LoadUint32(&t.closing) != 0
}
func GetDialFailureReason(err error) (isDialFailure bool, reason DialFailureReason) {
func GetDialFailureReason(err error) (isDialFailure bool, reason metrics.DialFailureReason) {
var df *dialFailure
if errors.As(err, &df) {
return true, df.reason
}
return false, DialFailureUnknown
return false, metrics.DialFailureUnknown
}
type dialFailure struct {
msg string
reason DialFailureReason
reason metrics.DialFailureReason
}
func (df *dialFailure) Error() string {
return df.msg
}
type DialFailureReason string
const (
DialFailureUnknown DialFailureReason = "unknown"
// DialFailureTimeout indicates the hard 30 second timeout was hit.
DialFailureTimeout DialFailureReason = "timeout"
// DialFailureContext indicates that the context was cancelled or reached it's deadline before
// the dial response was returned.
DialFailureContext DialFailureReason = "context"
// DialFailureEndpoint indicates that the konnectivity-agent was unable to reach the backend endpoint.
DialFailureEndpoint DialFailureReason = "endpoint"
// DialFailureDialClosed indicates that the client received a CloseDial response, indicating the
// connection was closed before the dial could complete.
DialFailureDialClosed DialFailureReason = "dialclosed"
// DialFailureTunnelClosed indicates that the client connection was closed before the dial could
// complete.
DialFailureTunnelClosed DialFailureReason = "tunnelclosed"
)

View File

@@ -23,6 +23,9 @@ import (
"time"
"k8s.io/klog/v2"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics"
commonmetrics "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)
@@ -62,8 +65,11 @@ func (c *conn) Write(data []byte) (n int, err error) {
klog.V(5).InfoS("[tracing] send req", "type", req.Type)
const segment = commonmetrics.SegmentFromClient
metrics.Metrics.ObservePacket(segment, req.Type)
err = c.stream.Send(req)
if err != nil {
metrics.Metrics.ObserveStreamError(segment, err, req.Type)
return 0, err
}
return len(data), err
@@ -147,7 +153,10 @@ func (c *conn) Close() error {
klog.V(5).InfoS("[tracing] send req", "type", req.Type)
const segment = commonmetrics.SegmentFromClient
metrics.Metrics.ObservePacket(segment, req.Type)
if err := c.stream.Send(req); err != nil {
metrics.Metrics.ObserveStreamError(segment, err, req.Type)
return err
}

View File

@@ -0,0 +1,162 @@
/*
Copyright 2022 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"
"github.com/prometheus/client_golang/prometheus"
commonmetrics "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)
const (
Namespace = "konnectivity_network_proxy"
Subsystem = "client"
)
var (
// Metrics provides access to all client metrics. The client
// application is responsible for registering (via Metrics.RegisterMetrics).
Metrics = newMetrics()
)
// ClientMetrics includes all the metrics of the konnectivity-client.
type ClientMetrics struct {
registerOnce sync.Once
streamPackets *prometheus.CounterVec
streamErrors *prometheus.CounterVec
dialFailures *prometheus.CounterVec
clientConns *prometheus.GaugeVec
}
type DialFailureReason string
const (
DialFailureUnknown DialFailureReason = "unknown"
// DialFailureTimeout indicates the hard 30 second timeout was hit.
DialFailureTimeout DialFailureReason = "timeout"
// DialFailureContext indicates that the context was cancelled or reached it's deadline before
// the dial response was returned.
DialFailureContext DialFailureReason = "context"
// DialFailureEndpoint indicates that the konnectivity-agent was unable to reach the backend endpoint.
DialFailureEndpoint DialFailureReason = "endpoint"
// DialFailureDialClosed indicates that the client received a CloseDial response, indicating the
// connection was closed before the dial could complete.
DialFailureDialClosed DialFailureReason = "dialclosed"
// DialFailureTunnelClosed indicates that the client connection was closed before the dial could
// complete.
DialFailureTunnelClosed DialFailureReason = "tunnelclosed"
)
type ClientConnectionStatus string
const (
// The connection is created but has not yet been dialed.
ClientConnectionStatusCreated ClientConnectionStatus = "created"
// The connection is pending dial response.
ClientConnectionStatusDialing ClientConnectionStatus = "dialing"
// The connection is established.
ClientConnectionStatusOk ClientConnectionStatus = "ok"
// The connection is closing.
ClientConnectionStatusClosing ClientConnectionStatus = "closing"
)
func newMetrics() *ClientMetrics {
// The denominator (total dials started) for both
// dial_failure_total and dial_duration_seconds is the
// stream_packets_total (common metric), where segment is
// "from_client" and packet_type is "DIAL_REQ".
dialFailures := prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: Namespace,
Subsystem: Subsystem,
Name: "dial_failure_total",
Help: "Number of dial failures observed, by reason (example: remote endpoint error)",
},
[]string{
"reason",
},
)
clientConns := prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: Namespace,
Subsystem: Subsystem,
Name: "client_connections",
Help: "Number of open client connections, by status (Example: dialing)",
},
[]string{
"status",
},
)
return &ClientMetrics{
streamPackets: commonmetrics.MakeStreamPacketsTotalMetric(Namespace, Subsystem),
streamErrors: commonmetrics.MakeStreamErrorsTotalMetric(Namespace, Subsystem),
dialFailures: dialFailures,
clientConns: clientConns,
}
}
// RegisterMetrics registers all metrics with the client application.
func (c *ClientMetrics) RegisterMetrics(r prometheus.Registerer) {
c.registerOnce.Do(func() {
r.MustRegister(c.streamPackets)
r.MustRegister(c.streamErrors)
r.MustRegister(c.dialFailures)
r.MustRegister(c.clientConns)
})
}
// LegacyRegisterMetrics registers all metrics via MustRegister func.
// TODO: remove this once https://github.com/kubernetes/kubernetes/pull/114293 is available.
func (c *ClientMetrics) LegacyRegisterMetrics(mustRegisterFn func(...prometheus.Collector)) {
c.registerOnce.Do(func() {
mustRegisterFn(c.streamPackets)
mustRegisterFn(c.streamErrors)
mustRegisterFn(c.dialFailures)
mustRegisterFn(c.clientConns)
})
}
// Reset resets the metrics.
func (c *ClientMetrics) Reset() {
c.streamPackets.Reset()
c.streamErrors.Reset()
c.dialFailures.Reset()
c.clientConns.Reset()
}
func (c *ClientMetrics) ObserveDialFailure(reason DialFailureReason) {
c.dialFailures.WithLabelValues(string(reason)).Inc()
}
func (c *ClientMetrics) GetClientConnectionsMetric() *prometheus.GaugeVec {
return c.clientConns
}
func (c *ClientMetrics) ObservePacket(segment commonmetrics.Segment, packetType client.PacketType) {
commonmetrics.ObservePacket(c.streamPackets, segment, packetType)
}
func (c *ClientMetrics) ObserveStreamErrorNoPacket(segment commonmetrics.Segment, err error) {
commonmetrics.ObserveStreamErrorNoPacket(c.streamErrors, segment, err)
}
func (c *ClientMetrics) ObserveStreamError(segment commonmetrics.Segment, err error, packetType client.PacketType) {
commonmetrics.ObserveStreamError(c.streamErrors, segment, err, packetType)
}

View File

@@ -0,0 +1,78 @@
/*
Copyright 2022 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 metric definitions and helpers used
// across konnectivity client, server, and agent.
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"google.golang.org/grpc/status"
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
)
// Segment identifies one of four tunnel segments (e.g. from server to agent).
type Segment string
const (
// SegmentFromClient indicates a packet from client to server.
SegmentFromClient Segment = "from_client"
// SegmentToClient indicates a packet from server to client.
SegmentToClient Segment = "to_client"
// SegmentFromAgent indicates a packet from agent to server.
SegmentFromAgent Segment = "from_agent"
// SegmentToAgent indicates a packet from server to agent.
SegmentToAgent Segment = "to_agent"
)
func MakeStreamPacketsTotalMetric(namespace, subsystem string) *prometheus.CounterVec {
return prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "stream_packets_total",
Help: "Count of packets processed, by segment and packet type (example: from_client, DIAL_REQ)",
},
[]string{"segment", "packet_type"},
)
}
func MakeStreamErrorsTotalMetric(namespace, subsystem string) *prometheus.CounterVec {
return prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "stream_errors_total",
Help: "Count of gRPC stream errors, by segment, grpc Code, packet type. (example: from_agent, Code.Unavailable, DIAL_RSP)",
},
[]string{"segment", "code", "packet_type"},
)
}
func ObservePacket(m *prometheus.CounterVec, segment Segment, packetType client.PacketType) {
m.WithLabelValues(string(segment), packetType.String()).Inc()
}
func ObserveStreamErrorNoPacket(m *prometheus.CounterVec, segment Segment, err error) {
code := status.Code(err)
m.WithLabelValues(string(segment), code.String(), "Unknown").Inc()
}
func ObserveStreamError(m *prometheus.CounterVec, segment Segment, err error, packetType client.PacketType) {
code := status.Code(err)
m.WithLabelValues(string(segment), code.String(), packetType.String()).Inc()
}

View File

@@ -93,7 +93,7 @@ import (
// Instead, they are replaced by the Unicode replacement
// character U+FFFD.
//
func Unmarshal(data []byte, v interface{}, opts ...UnmarshalOpt) error {
func Unmarshal(data []byte, v any, opts ...UnmarshalOpt) error {
// Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
@@ -167,16 +167,16 @@ func (e *InvalidUnmarshalError) Error() string {
return "json: Unmarshal(nil)"
}
if e.Type.Kind() != reflect.Ptr {
if e.Type.Kind() != reflect.Pointer {
return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
}
return "json: Unmarshal(nil " + e.Type.String() + ")"
}
*/
func (d *decodeState) unmarshal(v interface{}) error {
func (d *decodeState) unmarshal(v any) error {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
if rv.Kind() != reflect.Pointer || rv.IsNil() {
return &InvalidUnmarshalError{reflect.TypeOf(v)}
}
@@ -233,7 +233,7 @@ type decodeState struct {
disallowUnknownFields bool
savedStrictErrors []error
seenStrictErrors map[string]struct{}
seenStrictErrors map[strictError]struct{}
strictFieldStack []string
caseSensitive bool
@@ -425,7 +425,7 @@ type unquotedValue struct{}
// quoted string literal or literal null into an interface value.
// If it finds anything other than a quoted string literal or null,
// valueQuoted returns unquotedValue{}.
func (d *decodeState) valueQuoted() interface{} {
func (d *decodeState) valueQuoted() any {
switch d.opcode {
default:
panic(phasePanicMsg)
@@ -467,7 +467,7 @@ func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnm
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() {
haveAddr = true
v = v.Addr()
}
@@ -476,14 +476,14 @@ func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnm
// usefully addressable.
if v.Kind() == reflect.Interface && !v.IsNil() {
e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) {
haveAddr = false
v = e
continue
}
}
if v.Kind() != reflect.Ptr {
if v.Kind() != reflect.Pointer {
break
}
@@ -678,7 +678,7 @@ func (d *decodeState) object(v reflect.Value) error {
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
default:
if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) {
d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)})
d.skip()
return nil
@@ -695,7 +695,7 @@ func (d *decodeState) object(v reflect.Value) error {
seenKeys = map[string]struct{}{}
}
if _, seen := seenKeys[fieldName]; seen {
d.saveStrictError(d.newFieldError("duplicate field", fieldName))
d.saveStrictError(d.newFieldError(duplicateStrictErrType, fieldName))
} else {
seenKeys[fieldName] = struct{}{}
}
@@ -711,7 +711,7 @@ func (d *decodeState) object(v reflect.Value) error {
var seenKeys uint64
checkDuplicateField = func(fieldNameIndex int, fieldName string) {
if seenKeys&(1<<fieldNameIndex) != 0 {
d.saveStrictError(d.newFieldError("duplicate field", fieldName))
d.saveStrictError(d.newFieldError(duplicateStrictErrType, fieldName))
} else {
seenKeys = seenKeys | (1 << fieldNameIndex)
}
@@ -724,7 +724,7 @@ func (d *decodeState) object(v reflect.Value) error {
seenIndexes = make([]bool, len(fields.list))
}
if seenIndexes[fieldNameIndex] {
d.saveStrictError(d.newFieldError("duplicate field", fieldName))
d.saveStrictError(d.newFieldError(duplicateStrictErrType, fieldName))
} else {
seenIndexes[fieldNameIndex] = true
}
@@ -808,7 +808,7 @@ func (d *decodeState) object(v reflect.Value) error {
subv = v
destring = f.quoted
for _, i := range f.index {
if subv.Kind() == reflect.Ptr {
if subv.Kind() == reflect.Pointer {
if subv.IsNil() {
// If a struct embeds a pointer to an unexported type,
// it is not possible to set a newly allocated value
@@ -836,7 +836,7 @@ func (d *decodeState) object(v reflect.Value) error {
d.errorContext.Struct = t
d.appendStrictFieldStackKey(f.name)
} else if d.disallowUnknownFields {
d.saveStrictError(d.newFieldError("unknown field", string(key)))
d.saveStrictError(d.newFieldError(unknownStrictErrType, string(key)))
}
}
@@ -874,7 +874,7 @@ func (d *decodeState) object(v reflect.Value) error {
kt := t.Key()
var kv reflect.Value
switch {
case reflect.PtrTo(kt).Implements(textUnmarshalerType):
case reflect.PointerTo(kt).Implements(textUnmarshalerType):
kv = reflect.New(kt)
if err := d.literalStore(item, kv, true); err != nil {
return err
@@ -934,7 +934,7 @@ func (d *decodeState) object(v reflect.Value) error {
// convertNumber converts the number literal s to a float64 or a Number
// depending on the setting of d.useNumber.
func (d *decodeState) convertNumber(s string) (interface{}, error) {
func (d *decodeState) convertNumber(s string) (any, error) {
if d.useNumber {
return Number(s), nil
}
@@ -1010,7 +1010,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
break
}
switch v.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice:
v.Set(reflect.Zero(v.Type()))
// otherwise, ignore null for primitives/string
}
@@ -1140,7 +1140,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
// but they avoid the weight of reflection in this common case.
// valueInterface is like value but returns interface{}
func (d *decodeState) valueInterface() (val interface{}) {
func (d *decodeState) valueInterface() (val any) {
switch d.opcode {
default:
panic(phasePanicMsg)
@@ -1157,14 +1157,14 @@ func (d *decodeState) valueInterface() (val interface{}) {
}
// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface() []interface{} {
func (d *decodeState) arrayInterface() []any {
origStrictFieldStackLen := len(d.strictFieldStack)
defer func() {
// Reset to original length and reuse the allocated space for the strict FieldStack slice.
d.strictFieldStack = d.strictFieldStack[:origStrictFieldStackLen]
}()
var v = make([]interface{}, 0)
var v = make([]any, 0)
for {
// Look ahead for ] - can only happen on first iteration.
d.scanWhile(scanSkipSpace)
@@ -1192,14 +1192,14 @@ func (d *decodeState) arrayInterface() []interface{} {
}
// objectInterface is like object but returns map[string]interface{}.
func (d *decodeState) objectInterface() map[string]interface{} {
func (d *decodeState) objectInterface() map[string]any {
origStrictFieldStackLen := len(d.strictFieldStack)
defer func() {
// Reset to original length and reuse the allocated space for the strict FieldStack slice.
d.strictFieldStack = d.strictFieldStack[:origStrictFieldStackLen]
}()
m := make(map[string]interface{})
m := make(map[string]any)
for {
// Read opening " of string key or closing }.
d.scanWhile(scanSkipSpace)
@@ -1231,7 +1231,7 @@ func (d *decodeState) objectInterface() map[string]interface{} {
if d.disallowDuplicateFields {
if _, exists := m[key]; exists {
d.saveStrictError(d.newFieldError("duplicate field", key))
d.saveStrictError(d.newFieldError(duplicateStrictErrType, key))
}
}
@@ -1258,7 +1258,7 @@ func (d *decodeState) objectInterface() map[string]interface{} {
// literalInterface consumes and returns a literal from d.data[d.off-1:] and
// it reads the following byte ahead. The first byte of the literal has been
// read already (that's how the caller knows it's a literal).
func (d *decodeState) literalInterface() interface{} {
func (d *decodeState) literalInterface() any {
// All bytes inside literal return scanContinue op code.
start := d.readIndex()
d.rescanLiteral()

View File

@@ -155,7 +155,7 @@ import (
// handle them. Passing cyclic structures to Marshal will result in
// an error.
//
func Marshal(v interface{}) ([]byte, error) {
func Marshal(v any) ([]byte, error) {
e := newEncodeState()
err := e.marshal(v, encOpts{escapeHTML: true})
@@ -172,7 +172,7 @@ func Marshal(v interface{}) ([]byte, error) {
// MarshalIndent is like Marshal but applies Indent to format the output.
// Each JSON element in the output will begin on a new line beginning with prefix
// followed by one or more copies of indent according to the indentation nesting.
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
b, err := Marshal(v)
if err != nil {
return nil, err
@@ -294,7 +294,7 @@ type encodeState struct {
// startDetectingCyclesAfter, so that we skip the work if we're within a
// reasonable amount of nested pointers deep.
ptrLevel uint
ptrSeen map[interface{}]struct{}
ptrSeen map[any]struct{}
}
const startDetectingCyclesAfter = 1000
@@ -311,7 +311,7 @@ func newEncodeState() *encodeState {
e.ptrLevel = 0
return e
}
return &encodeState{ptrSeen: make(map[interface{}]struct{})}
return &encodeState{ptrSeen: make(map[any]struct{})}
}
// jsonError is an error wrapper type for internal use only.
@@ -319,7 +319,7 @@ func newEncodeState() *encodeState {
// can distinguish intentional panics from this package.
type jsonError struct{ error }
func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
func (e *encodeState) marshal(v any, opts encOpts) (err error) {
defer func() {
if r := recover(); r != nil {
if je, ok := r.(jsonError); ok {
@@ -350,7 +350,7 @@ func isEmptyValue(v reflect.Value) bool {
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
case reflect.Interface, reflect.Pointer:
return v.IsNil()
}
return false
@@ -419,13 +419,13 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
// Marshaler with a value receiver, then we're better off taking
// the address of the value - otherwise we end up with an
// allocation as we cast the value to an interface.
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) {
if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(marshalerType) {
return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
}
if t.Implements(marshalerType) {
return marshalerEncoder
}
if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) {
if t.Kind() != reflect.Pointer && allowAddr && reflect.PointerTo(t).Implements(textMarshalerType) {
return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
}
if t.Implements(textMarshalerType) {
@@ -455,7 +455,7 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
return newSliceEncoder(t)
case reflect.Array:
return newArrayEncoder(t)
case reflect.Ptr:
case reflect.Pointer:
return newPtrEncoder(t)
default:
return unsupportedTypeEncoder
@@ -467,7 +467,7 @@ func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {
}
func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Kind() == reflect.Ptr && v.IsNil() {
if v.Kind() == reflect.Pointer && v.IsNil() {
e.WriteString("null")
return
}
@@ -504,7 +504,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
}
func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
if v.Kind() == reflect.Ptr && v.IsNil() {
if v.Kind() == reflect.Pointer && v.IsNil() {
e.WriteString("null")
return
}
@@ -738,7 +738,7 @@ FieldLoop:
// Find the nested struct field by following f.index.
fv := v
for _, i := range f.index {
if fv.Kind() == reflect.Ptr {
if fv.Kind() == reflect.Pointer {
if fv.IsNil() {
continue FieldLoop
}
@@ -893,7 +893,7 @@ func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
func newSliceEncoder(t reflect.Type) encoderFunc {
// Byte slices get special treatment; arrays don't.
if t.Elem().Kind() == reflect.Uint8 {
p := reflect.PtrTo(t.Elem())
p := reflect.PointerTo(t.Elem())
if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
return encodeByteSlice
}
@@ -989,7 +989,7 @@ func isValidTag(s string) bool {
func typeByIndex(t reflect.Type, index []int) reflect.Type {
for _, i := range index {
if t.Kind() == reflect.Ptr {
if t.Kind() == reflect.Pointer {
t = t.Elem()
}
t = t.Field(i).Type
@@ -1009,7 +1009,7 @@ func (w *reflectWithString) resolve() error {
return nil
}
if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok {
if w.k.Kind() == reflect.Ptr && w.k.IsNil() {
if w.k.Kind() == reflect.Pointer && w.k.IsNil() {
return nil
}
buf, err := tm.MarshalText()
@@ -1243,7 +1243,7 @@ func typeFields(t reflect.Type) structFields {
sf := f.typ.Field(i)
if sf.Anonymous {
t := sf.Type
if t.Kind() == reflect.Ptr {
if t.Kind() == reflect.Pointer {
t = t.Elem()
}
if !sf.IsExported() && t.Kind() != reflect.Struct {
@@ -1269,7 +1269,7 @@ func typeFields(t reflect.Type) structFields {
index[len(f.index)] = i
ft := sf.Type
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
if ft.Name() == "" && ft.Kind() == reflect.Pointer {
// Follow pointer.
ft = ft.Elem()
}

View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build gofuzz
// +build gofuzz
package json
@@ -12,10 +11,10 @@ import (
)
func Fuzz(data []byte) (score int) {
for _, ctor := range []func() interface{}{
func() interface{} { return new(interface{}) },
func() interface{} { return new(map[string]interface{}) },
func() interface{} { return new([]interface{}) },
for _, ctor := range []func() any{
func() any { return new(any) },
func() any { return new(map[string]any) },
func() any { return new([]any) },
} {
v := ctor()
err := Unmarshal(data, v)

View File

@@ -18,7 +18,6 @@ package json
import (
gojson "encoding/json"
"fmt"
"strconv"
"strings"
)
@@ -71,32 +70,37 @@ func (d *Decoder) DisallowDuplicateFields() {
d.d.disallowDuplicateFields = true
}
func (d *decodeState) newFieldError(msg, field string) error {
func (d *decodeState) newFieldError(errType strictErrType, field string) *strictError {
if len(d.strictFieldStack) > 0 {
return fmt.Errorf("%s %q", msg, strings.Join(d.strictFieldStack, "")+"."+field)
return &strictError{
ErrType: errType,
Path: strings.Join(d.strictFieldStack, "") + "." + field,
}
} else {
return fmt.Errorf("%s %q", msg, field)
return &strictError{
ErrType: errType,
Path: field,
}
}
}
// saveStrictError saves a strict decoding error,
// for reporting at the end of the unmarshal if no other errors occurred.
func (d *decodeState) saveStrictError(err error) {
func (d *decodeState) saveStrictError(err *strictError) {
// prevent excessive numbers of accumulated errors
if len(d.savedStrictErrors) >= 100 {
return
}
// dedupe accumulated strict errors
if d.seenStrictErrors == nil {
d.seenStrictErrors = map[string]struct{}{}
d.seenStrictErrors = map[strictError]struct{}{}
}
msg := err.Error()
if _, seen := d.seenStrictErrors[msg]; seen {
if _, seen := d.seenStrictErrors[*err]; seen {
return
}
// accumulate the error
d.seenStrictErrors[msg] = struct{}{}
d.seenStrictErrors[*err] = struct{}{}
d.savedStrictErrors = append(d.savedStrictErrors, err)
}
@@ -118,6 +122,33 @@ func (d *decodeState) appendStrictFieldStackIndex(i int) {
d.strictFieldStack = append(d.strictFieldStack, "[", strconv.Itoa(i), "]")
}
type strictErrType string
const (
unknownStrictErrType strictErrType = "unknown field"
duplicateStrictErrType strictErrType = "duplicate field"
)
// strictError is a strict decoding error
// It has an ErrType (either unknown or duplicate)
// and a path to the erroneous field
type strictError struct {
ErrType strictErrType
Path string
}
func (e *strictError) Error() string {
return string(e.ErrType) + " " + strconv.Quote(e.Path)
}
func (e *strictError) FieldPath() string {
return e.Path
}
func (e *strictError) SetFieldPath(path string) {
e.Path = path
}
// UnmarshalStrictError holds errors resulting from use of strict disallow___ decoder directives.
// If this is returned from Unmarshal(), it means the decoding was successful in all other respects.
type UnmarshalStrictError struct {

View File

@@ -83,7 +83,7 @@ type scanner struct {
}
var scannerPool = sync.Pool{
New: func() interface{} {
New: func() any {
return &scanner{}
},
}

View File

@@ -45,7 +45,7 @@ func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true
//
// See the documentation for Unmarshal for details about
// the conversion of JSON into a Go value.
func (dec *Decoder) Decode(v interface{}) error {
func (dec *Decoder) Decode(v any) error {
if dec.err != nil {
return dec.err
}
@@ -197,7 +197,7 @@ func NewEncoder(w io.Writer) *Encoder {
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
func (enc *Encoder) Encode(v interface{}) error {
func (enc *Encoder) Encode(v any) error {
if enc.err != nil {
return enc.err
}
@@ -290,7 +290,7 @@ var _ Unmarshaler = (*RawMessage)(nil)
// string, for JSON string literals
// nil, for JSON null
//
type Token interface{}
type Token any
*/
const (
@@ -457,7 +457,7 @@ func (dec *Decoder) Token() (Token, error) {
if !dec.tokenValueAllowed() {
return dec.tokenError(c)
}
var x interface{}
var x any
if err := dec.Decode(&x); err != nil {
return nil, err
}

View File

@@ -15,10 +15,8 @@ type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
tag, opt, _ := strings.Cut(tag, ",")
return tag, tagOptions(opt)
}
// Contains reports whether a comma-separated list of options
@@ -30,15 +28,11 @@ func (o tagOptions) Contains(optionName string) bool {
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
var name string
name, s, _ = strings.Cut(s, ",")
if name == optionName {
return true
}
s = next
}
return false
}

11
vendor/sigs.k8s.io/json/json.go generated vendored
View File

@@ -84,6 +84,8 @@ const (
// and a list of the strict failures (if any) are returned. If no `strictOptions` are selected,
// all supported strict checks are performed.
//
// Strict errors returned will implement the FieldError interface for the specific erroneous fields.
//
// Currently supported strict checks are:
// - DisallowDuplicateFields: ensure the data contains no duplicate fields
// - DisallowUnknownFields: ensure the data contains no unknown fields (when decoding into typed structs)
@@ -137,3 +139,12 @@ func SyntaxErrorOffset(err error) (isSyntaxError bool, offset int64) {
return false, 0
}
}
// FieldError is an error that provides access to the path of the erroneous field
type FieldError interface {
error
// FieldPath provides the full path of the erroneous field within the json object.
FieldPath() string
// SetFieldPath updates the path of the erroneous field output in the error message.
SetFieldPath(path string)
}

4
vendor/sigs.k8s.io/yaml/.gitignore generated vendored
View File

@@ -6,6 +6,10 @@
.project
.settings/**
# Idea files
.idea/**
.idea/
# Emacs save files
*~

View File

@@ -1,8 +1,7 @@
language: go
dist: xenial
go:
- 1.12.x
- 1.13.x
arch: arm64
dist: focal
go: 1.15.x
script:
- diff -u <(echo -n) <(gofmt -d *.go)
- diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON)

2
vendor/sigs.k8s.io/yaml/README.md generated vendored
View File

@@ -107,8 +107,8 @@ func main() {
}
fmt.Println(string(y))
/* Output:
name: John
age: 30
name: John
*/
j2, err := yaml.YAMLToJSON(y)
if err != nil {