Unverified Commit 20b58fe4 authored by Erik Wilson's avatar Erik Wilson Committed by GitHub

Merge pull request #3331 from erikwilson/v1.18.19-k3s1

Update Kubernetes to v1.18.19-k3s1
parents d6391854 a63b1536
...@@ -33,31 +33,31 @@ replace ( ...@@ -33,31 +33,31 @@ replace (
github.com/prometheus/client_model => github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 github.com/prometheus/client_model => github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910
github.com/prometheus/common => github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 github.com/prometheus/common => github.com/prometheus/common v0.0.0-20181126121408-4724e9255275
github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a github.com/prometheus/procfs => github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a
k8s.io/api => github.com/k3s-io/kubernetes/staging/src/k8s.io/api v1.18.18-k3s1 k8s.io/api => github.com/k3s-io/kubernetes/staging/src/k8s.io/api v1.18.19-k3s1
k8s.io/apiextensions-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v1.18.18-k3s1 k8s.io/apiextensions-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v1.18.19-k3s1
k8s.io/apimachinery => github.com/k3s-io/kubernetes/staging/src/k8s.io/apimachinery v1.18.18-k3s1 k8s.io/apimachinery => github.com/k3s-io/kubernetes/staging/src/k8s.io/apimachinery v1.18.19-k3s1
k8s.io/apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiserver v1.18.18-k3s1 k8s.io/apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiserver v1.18.19-k3s1
k8s.io/cli-runtime => github.com/k3s-io/kubernetes/staging/src/k8s.io/cli-runtime v1.18.18-k3s1 k8s.io/cli-runtime => github.com/k3s-io/kubernetes/staging/src/k8s.io/cli-runtime v1.18.19-k3s1
k8s.io/client-go => github.com/k3s-io/kubernetes/staging/src/k8s.io/client-go v1.18.18-k3s1 k8s.io/client-go => github.com/k3s-io/kubernetes/staging/src/k8s.io/client-go v1.18.19-k3s1
k8s.io/cloud-provider => github.com/k3s-io/kubernetes/staging/src/k8s.io/cloud-provider v1.18.18-k3s1 k8s.io/cloud-provider => github.com/k3s-io/kubernetes/staging/src/k8s.io/cloud-provider v1.18.19-k3s1
k8s.io/cluster-bootstrap => github.com/k3s-io/kubernetes/staging/src/k8s.io/cluster-bootstrap v1.18.18-k3s1 k8s.io/cluster-bootstrap => github.com/k3s-io/kubernetes/staging/src/k8s.io/cluster-bootstrap v1.18.19-k3s1
k8s.io/code-generator => github.com/k3s-io/kubernetes/staging/src/k8s.io/code-generator v1.18.18-k3s1 k8s.io/code-generator => github.com/k3s-io/kubernetes/staging/src/k8s.io/code-generator v1.18.19-k3s1
k8s.io/component-base => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-base v1.18.18-k3s1 k8s.io/component-base => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-base v1.18.19-k3s1
k8s.io/cri-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/cri-api v1.18.18-k3s1 k8s.io/cri-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/cri-api v1.18.19-k3s1
k8s.io/csi-translation-lib => github.com/k3s-io/kubernetes/staging/src/k8s.io/csi-translation-lib v1.18.18-k3s1 k8s.io/csi-translation-lib => github.com/k3s-io/kubernetes/staging/src/k8s.io/csi-translation-lib v1.18.19-k3s1
k8s.io/kube-aggregator => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-aggregator v1.18.18-k3s1 k8s.io/kube-aggregator => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-aggregator v1.18.19-k3s1
k8s.io/kube-controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-controller-manager v1.18.18-k3s1 k8s.io/kube-controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-controller-manager v1.18.19-k3s1
k8s.io/kube-proxy => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-proxy v1.18.18-k3s1 k8s.io/kube-proxy => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-proxy v1.18.19-k3s1
k8s.io/kube-scheduler => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-scheduler v1.18.18-k3s1 k8s.io/kube-scheduler => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-scheduler v1.18.19-k3s1
k8s.io/kubectl => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubectl v1.18.18-k3s1 k8s.io/kubectl => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubectl v1.18.19-k3s1
k8s.io/kubelet => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubelet v1.18.18-k3s1 k8s.io/kubelet => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubelet v1.18.19-k3s1
k8s.io/kubernetes => github.com/k3s-io/kubernetes v1.18.18-k3s1 k8s.io/kubernetes => github.com/k3s-io/kubernetes v1.18.19-k3s1
k8s.io/legacy-cloud-providers => github.com/k3s-io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v1.18.18-k3s1 k8s.io/legacy-cloud-providers => github.com/k3s-io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v1.18.19-k3s1
k8s.io/metrics => github.com/k3s-io/kubernetes/staging/src/k8s.io/metrics v1.18.18-k3s1 k8s.io/metrics => github.com/k3s-io/kubernetes/staging/src/k8s.io/metrics v1.18.19-k3s1
k8s.io/node-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/node-api v1.18.18-k3s1 k8s.io/node-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/node-api v1.18.19-k3s1
k8s.io/sample-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-apiserver v1.18.18-k3s1 k8s.io/sample-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-apiserver v1.18.19-k3s1
k8s.io/sample-cli-plugin => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-cli-plugin v1.18.18-k3s1 k8s.io/sample-cli-plugin => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-cli-plugin v1.18.19-k3s1
k8s.io/sample-controller => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-controller v1.18.18-k3s1 k8s.io/sample-controller => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-controller v1.18.19-k3s1
mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34
) )
...@@ -117,13 +117,13 @@ require ( ...@@ -117,13 +117,13 @@ require (
gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 // indirect gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 // indirect
gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 v2.2.8
gotest.tools/v3 v3.0.3 // indirect gotest.tools/v3 v3.0.3 // indirect
k8s.io/api v0.18.0 k8s.io/api v0.18.19
k8s.io/apimachinery v0.18.0 k8s.io/apimachinery v0.18.19
k8s.io/apiserver v0.0.0 k8s.io/apiserver v0.18.19
k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
k8s.io/cloud-provider v0.0.0 k8s.io/cloud-provider v0.18.19
k8s.io/component-base v0.0.0 k8s.io/component-base v0.18.19
k8s.io/cri-api v0.0.0 k8s.io/cri-api v0.18.19
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0
k8s.io/kubernetes v1.18.18 k8s.io/kubernetes v1.18.19
) )
...@@ -166,7 +166,7 @@ func (m *Quantity) Unmarshal(data []byte) error { ...@@ -166,7 +166,7 @@ func (m *Quantity) Unmarshal(data []byte) error {
if err != nil { if err != nil {
return err return err
} }
if skippy < 0 { if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenerated return ErrInvalidLengthGenerated
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
......
...@@ -78,6 +78,8 @@ type Connection interface { ...@@ -78,6 +78,8 @@ type Connection interface {
// SetIdleTimeout sets the amount of time the connection may remain idle before // SetIdleTimeout sets the amount of time the connection may remain idle before
// it is automatically closed. // it is automatically closed.
SetIdleTimeout(timeout time.Duration) SetIdleTimeout(timeout time.Duration)
// RemoveStreams can be used to remove a set of streams from the Connection.
RemoveStreams(streams ...Stream)
} }
// Stream represents a bidirectional communications channel that is part of an // Stream represents a bidirectional communications channel that is part of an
......
...@@ -31,7 +31,7 @@ import ( ...@@ -31,7 +31,7 @@ import (
// streams. // streams.
type connection struct { type connection struct {
conn *spdystream.Connection conn *spdystream.Connection
streams []httpstream.Stream streams map[uint32]httpstream.Stream
streamLock sync.Mutex streamLock sync.Mutex
newStreamHandler httpstream.NewStreamHandler newStreamHandler httpstream.NewStreamHandler
} }
...@@ -64,7 +64,11 @@ func NewServerConnection(conn net.Conn, newStreamHandler httpstream.NewStreamHan ...@@ -64,7 +64,11 @@ func NewServerConnection(conn net.Conn, newStreamHandler httpstream.NewStreamHan
// will be invoked when the server receives a newly created stream from the // will be invoked when the server receives a newly created stream from the
// client. // client.
func newConnection(conn *spdystream.Connection, newStreamHandler httpstream.NewStreamHandler) httpstream.Connection { func newConnection(conn *spdystream.Connection, newStreamHandler httpstream.NewStreamHandler) httpstream.Connection {
c := &connection{conn: conn, newStreamHandler: newStreamHandler} c := &connection{
conn: conn,
newStreamHandler: newStreamHandler,
streams: make(map[uint32]httpstream.Stream),
}
go conn.Serve(c.newSpdyStream) go conn.Serve(c.newSpdyStream)
return c return c
} }
...@@ -81,7 +85,7 @@ func (c *connection) Close() error { ...@@ -81,7 +85,7 @@ func (c *connection) Close() error {
// calling Reset instead of Close ensures that all streams are fully torn down // calling Reset instead of Close ensures that all streams are fully torn down
s.Reset() s.Reset()
} }
c.streams = make([]httpstream.Stream, 0) c.streams = make(map[uint32]httpstream.Stream, 0)
c.streamLock.Unlock() c.streamLock.Unlock()
// now that all streams are fully torn down, it's safe to call close on the underlying connection, // now that all streams are fully torn down, it's safe to call close on the underlying connection,
...@@ -90,6 +94,15 @@ func (c *connection) Close() error { ...@@ -90,6 +94,15 @@ func (c *connection) Close() error {
return c.conn.Close() return c.conn.Close()
} }
// RemoveStreams can be used to removes a set of streams from the Connection.
func (c *connection) RemoveStreams(streams ...httpstream.Stream) {
c.streamLock.Lock()
for _, stream := range streams {
delete(c.streams, stream.Identifier())
}
c.streamLock.Unlock()
}
// CreateStream creates a new stream with the specified headers and registers // CreateStream creates a new stream with the specified headers and registers
// it with the connection. // it with the connection.
func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error) { func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error) {
...@@ -109,7 +122,7 @@ func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error ...@@ -109,7 +122,7 @@ func (c *connection) CreateStream(headers http.Header) (httpstream.Stream, error
// it owns. // it owns.
func (c *connection) registerStream(s httpstream.Stream) { func (c *connection) registerStream(s httpstream.Stream) {
c.streamLock.Lock() c.streamLock.Lock()
c.streams = append(c.streams, s) c.streams[s.Identifier()] = s
c.streamLock.Unlock() c.streamLock.Unlock()
} }
......
...@@ -64,6 +64,7 @@ var ( ...@@ -64,6 +64,7 @@ var (
} }
SuggestedFlowSchemas = []*flowcontrol.FlowSchema{ SuggestedFlowSchemas = []*flowcontrol.FlowSchema{
SuggestedFlowSchemaSystemNodes, // references "system" priority-level SuggestedFlowSchemaSystemNodes, // references "system" priority-level
SuggestedFlowSchemaProbes, // references "exempt" priority-level
SuggestedFlowSchemaSystemLeaderElection, // references "leader-election" priority-level SuggestedFlowSchemaSystemLeaderElection, // references "leader-election" priority-level
SuggestedFlowSchemaWorkloadLeaderElection, // references "leader-election" priority-level SuggestedFlowSchemaWorkloadLeaderElection, // references "leader-election" priority-level
SuggestedFlowSchemaKubeControllerManager, // references "workload-high" priority-level SuggestedFlowSchemaKubeControllerManager, // references "workload-high" priority-level
...@@ -394,6 +395,19 @@ var ( ...@@ -394,6 +395,19 @@ var (
}, },
}, },
) )
// the following flow schema exempts probes
SuggestedFlowSchemaProbes = newFlowSchema(
"probes", "exempt", 2,
"", // distinguisherMethodType
flowcontrol.PolicyRulesWithSubjects{
Subjects: groups(user.AllUnauthenticated, user.AllAuthenticated),
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
nonResourceRule(
[]string{"get"},
[]string{"/healthz", "/readyz", "/livez"}),
},
},
)
) )
func newPriorityLevelConfiguration(name string, spec flowcontrol.PriorityLevelConfigurationSpec) *flowcontrol.PriorityLevelConfiguration { func newPriorityLevelConfiguration(name string, spec flowcontrol.PriorityLevelConfigurationSpec) *flowcontrol.PriorityLevelConfiguration {
......
...@@ -3,8 +3,8 @@ package version ...@@ -3,8 +3,8 @@ package version
var ( var (
gitMajor = "1" gitMajor = "1"
gitMinor = "18" gitMinor = "18"
gitVersion = "v1.18.18-k3s1" gitVersion = "v1.18.19-k3s1"
gitCommit = "7f66ff2c4928917b0998444e155edbd5fa8e9783" gitCommit = "fd4904f8d39be0e2bc4ed96b76fe71f22a74d3e3"
gitTreeState = "clean" gitTreeState = "clean"
buildDate = "2021-04-15T17:59:26Z" buildDate = "2021-05-14T11:55:20Z"
) )
...@@ -181,8 +181,8 @@ k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C ...@@ -181,8 +181,8 @@ k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.1 h1:ISORLGKzslMY5RWkCSGNy5uDb3OHyEkGEhuSATvSp3A=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.1/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
...@@ -3,8 +3,8 @@ package version ...@@ -3,8 +3,8 @@ package version
var ( var (
gitMajor = "1" gitMajor = "1"
gitMinor = "18" gitMinor = "18"
gitVersion = "v1.18.18-k3s1" gitVersion = "v1.18.19-k3s1"
gitCommit = "7f66ff2c4928917b0998444e155edbd5fa8e9783" gitCommit = "fd4904f8d39be0e2bc4ed96b76fe71f22a74d3e3"
gitTreeState = "clean" gitTreeState = "clean"
buildDate = "2021-04-15T17:59:26Z" buildDate = "2021-05-14T11:55:20Z"
) )
...@@ -162,8 +162,8 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= ...@@ -162,8 +162,8 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.1 h1:ISORLGKzslMY5RWkCSGNy5uDb3OHyEkGEhuSATvSp3A=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.1/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
...@@ -4013,7 +4013,7 @@ func ValidateService(service *core.Service, allowAppProtocol bool) field.ErrorLi ...@@ -4013,7 +4013,7 @@ func ValidateService(service *core.Service, allowAppProtocol bool) field.ErrorLi
allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i])) allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
} }
} else { } else {
allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...) allErrs = append(allErrs, ValidateNonSpecialIP(ip, idxPath)...)
} }
} }
...@@ -5542,15 +5542,19 @@ func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path) ...@@ -5542,15 +5542,19 @@ func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path)
allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg)) allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg))
} }
} }
allErrs = append(allErrs, validateNonSpecialIP(address.IP, fldPath.Child("ip"))...) allErrs = append(allErrs, ValidateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
return allErrs return allErrs
} }
func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList { // ValidateNonSpecialIP is used to validate Endpoints, EndpointSlices, and
// We disallow some IPs as endpoints or external-ips. Specifically, // external IPs. Specifically, this disallows unspecified and loopback addresses
// unspecified and loopback addresses are nonsensical and link-local // are nonsensical and link-local addresses tend to be used for node-centric
// addresses tend to be used for node-centric purposes (e.g. metadata // purposes (e.g. metadata service).
// service). //
// IPv6 references
// - https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
// - https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
func ValidateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
ip := net.ParseIP(ipAddress) ip := net.ParseIP(ipAddress)
if ip == nil { if ip == nil {
......
...@@ -103,8 +103,10 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres ...@@ -103,8 +103,10 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres
} }
case discovery.AddressTypeIPv4: case discovery.AddressTypeIPv4:
allErrs = append(allErrs, validation.IsValidIPv4Address(addressPath.Index(i), address)...) allErrs = append(allErrs, validation.IsValidIPv4Address(addressPath.Index(i), address)...)
allErrs = append(allErrs, apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
case discovery.AddressTypeIPv6: case discovery.AddressTypeIPv6:
allErrs = append(allErrs, validation.IsValidIPv6Address(addressPath.Index(i), address)...) allErrs = append(allErrs, validation.IsValidIPv6Address(addressPath.Index(i), address)...)
allErrs = append(allErrs, apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
case discovery.AddressTypeFQDN: case discovery.AddressTypeFQDN:
allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...) allErrs = append(allErrs, validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
} }
......
...@@ -17,21 +17,42 @@ limitations under the License. ...@@ -17,21 +17,42 @@ limitations under the License.
package config package config
import ( import (
"k8s.io/api/core/v1" "time"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/klog"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types" kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
) )
// WaitForAPIServerSyncPeriod is the period between checks for the node list/watch initial sync
const WaitForAPIServerSyncPeriod = 1 * time.Second
// NewSourceApiserver creates a config source that watches and pulls from the apiserver. // NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(c clientset.Interface, nodeName types.NodeName, updates chan<- interface{}) { func NewSourceApiserver(c clientset.Interface, nodeName types.NodeName, nodeHasSynced func() bool, updates chan<- interface{}) {
lw := cache.NewListWatchFromClient(c.CoreV1().RESTClient(), "pods", metav1.NamespaceAll, fields.OneTermEqualSelector(api.PodHostField, string(nodeName))) lw := cache.NewListWatchFromClient(c.CoreV1().RESTClient(), "pods", metav1.NamespaceAll, fields.OneTermEqualSelector(api.PodHostField, string(nodeName)))
newSourceApiserverFromLW(lw, updates)
// The Reflector responsible for watching pods at the apiserver should be run only after
// the node sync with the apiserver has completed.
klog.Info("Waiting for node sync before watching apiserver pods")
go func() {
for {
if nodeHasSynced() {
klog.V(4).Info("node sync completed")
break
}
time.Sleep(WaitForAPIServerSyncPeriod)
klog.V(4).Info("node sync has not completed yet")
}
klog.Info("Watching apiserver")
newSourceApiserverFromLW(lw, updates)
}()
} }
// newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver. // newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver.
......
...@@ -128,9 +128,6 @@ const ( ...@@ -128,9 +128,6 @@ const (
// Max amount of time to wait for the container runtime to come up. // Max amount of time to wait for the container runtime to come up.
maxWaitForContainerRuntime = 30 * time.Second maxWaitForContainerRuntime = 30 * time.Second
// Max amount of time to wait for node list/watch to initially sync
maxWaitForAPIServerSync = 10 * time.Second
// nodeStatusUpdateRetry specifies how many times kubelet retries when posting node status failed. // nodeStatusUpdateRetry specifies how many times kubelet retries when posting node status failed.
nodeStatusUpdateRetry = 5 nodeStatusUpdateRetry = 5
...@@ -273,7 +270,7 @@ type Dependencies struct { ...@@ -273,7 +270,7 @@ type Dependencies struct {
// makePodSourceConfig creates a config.PodConfig from the given // makePodSourceConfig creates a config.PodConfig from the given
// KubeletConfiguration or returns an error. // KubeletConfiguration or returns an error.
func makePodSourceConfig(kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *Dependencies, nodeName types.NodeName, bootstrapCheckpointPath string) (*config.PodConfig, error) { func makePodSourceConfig(kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *Dependencies, nodeName types.NodeName, bootstrapCheckpointPath string, nodeHasSynced func() bool) (*config.PodConfig, error) {
manifestURLHeader := make(http.Header) manifestURLHeader := make(http.Header)
if len(kubeCfg.StaticPodURLHeader) > 0 { if len(kubeCfg.StaticPodURLHeader) > 0 {
for k, v := range kubeCfg.StaticPodURLHeader { for k, v := range kubeCfg.StaticPodURLHeader {
...@@ -313,11 +310,11 @@ func makePodSourceConfig(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ku ...@@ -313,11 +310,11 @@ func makePodSourceConfig(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ku
} }
if kubeDeps.KubeClient != nil { if kubeDeps.KubeClient != nil {
klog.Infof("Watching apiserver") klog.Info("Adding apiserver pod source")
if updatechannel == nil { if updatechannel == nil {
updatechannel = cfg.Channel(kubetypes.ApiserverSource) updatechannel = cfg.Channel(kubetypes.ApiserverSource)
} }
config.NewSourceApiserver(kubeDeps.KubeClient, nodeName, updatechannel) config.NewSourceApiserver(kubeDeps.KubeClient, nodeName, nodeHasSynced, updatechannel)
} }
return cfg, nil return cfg, nil
} }
...@@ -469,9 +466,32 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -469,9 +466,32 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
klog.V(2).Infof("cloud provider determined current node name to be %s", nodeName) klog.V(2).Infof("cloud provider determined current node name to be %s", nodeName)
} }
var nodeHasSynced cache.InformerSynced
var nodeLister corelisters.NodeLister
// If kubeClient == nil, we are running in standalone mode (i.e. no API servers)
// If not nil, we are running as part of a cluster and should sync w/API
if kubeDeps.KubeClient != nil {
kubeInformers := informers.NewSharedInformerFactoryWithOptions(kubeDeps.KubeClient, 0, informers.WithTweakListOptions(func(options *metav1.ListOptions) {
options.FieldSelector = fields.Set{api.ObjectNameField: string(nodeName)}.String()
}))
nodeLister = kubeInformers.Core().V1().Nodes().Lister()
nodeHasSynced = func() bool {
return kubeInformers.Core().V1().Nodes().Informer().HasSynced()
}
kubeInformers.Start(wait.NeverStop)
klog.Info("Attempting to sync node with API server")
} else {
// we don't have a client to sync!
nodeIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
nodeLister = corelisters.NewNodeLister(nodeIndexer)
nodeHasSynced = func() bool { return true }
klog.Info("Kubelet is running in standalone mode, will skip API server sync")
}
if kubeDeps.PodConfig == nil { if kubeDeps.PodConfig == nil {
var err error var err error
kubeDeps.PodConfig, err = makePodSourceConfig(kubeCfg, kubeDeps, nodeName, bootstrapCheckpointPath) kubeDeps.PodConfig, err = makePodSourceConfig(kubeCfg, kubeDeps, nodeName, bootstrapCheckpointPath, nodeHasSynced)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -518,31 +538,6 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -518,31 +538,6 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
} }
serviceLister := corelisters.NewServiceLister(serviceIndexer) serviceLister := corelisters.NewServiceLister(serviceIndexer)
var nodeHasSynced cache.InformerSynced
var nodeLister corelisters.NodeLister
if kubeDeps.KubeClient != nil {
kubeInformers := informers.NewSharedInformerFactoryWithOptions(kubeDeps.KubeClient, 0, informers.WithTweakListOptions(func(options *metav1.ListOptions) {
options.FieldSelector = fields.Set{api.ObjectNameField: string(nodeName)}.String()
}))
nodeLister = kubeInformers.Core().V1().Nodes().Lister()
nodeHasSynced = func() bool {
if kubeInformers.Core().V1().Nodes().Informer().HasSynced() {
return true
}
klog.Infof("kubelet nodes not sync")
return false
}
kubeInformers.Start(wait.NeverStop)
klog.Info("Kubelet client is not nil")
} else {
// we dont have a client to sync!
nodeIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
nodeLister = corelisters.NewNodeLister(nodeIndexer)
nodeHasSynced = func() bool { return true }
klog.Info("Kubelet client is nil")
}
// TODO: get the real node object of ourself, // TODO: get the real node object of ourself,
// and use the real node name and UID. // and use the real node name and UID.
// TODO: what is namespace for node? // TODO: what is namespace for node?
......
...@@ -22,7 +22,6 @@ import ( ...@@ -22,7 +22,6 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"path/filepath" "path/filepath"
"time"
cadvisorapiv1 "github.com/google/cadvisor/info/v1" cadvisorapiv1 "github.com/google/cadvisor/info/v1"
"k8s.io/klog" "k8s.io/klog"
...@@ -31,7 +30,6 @@ import ( ...@@ -31,7 +30,6 @@ import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/cm"
"k8s.io/kubernetes/pkg/kubelet/config" "k8s.io/kubernetes/pkg/kubelet/config"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
...@@ -234,15 +232,6 @@ func (kl *Kubelet) GetNode() (*v1.Node, error) { ...@@ -234,15 +232,6 @@ func (kl *Kubelet) GetNode() (*v1.Node, error) {
if kl.kubeClient == nil { if kl.kubeClient == nil {
return kl.initialNode(context.TODO()) return kl.initialNode(context.TODO())
} }
// if we have a valid kube client, we wait for initial lister to sync
if !kl.nodeHasSynced() {
err := wait.PollImmediate(time.Second, maxWaitForAPIServerSync, func() (bool, error) {
return kl.nodeHasSynced(), nil
})
if err != nil {
return nil, fmt.Errorf("nodes have not yet been read at least once, cannot construct node object")
}
}
return kl.nodeLister.Get(string(kl.nodeName)) return kl.nodeLister.Get(string(kl.nodeName))
} }
...@@ -253,7 +242,7 @@ func (kl *Kubelet) GetNode() (*v1.Node, error) { ...@@ -253,7 +242,7 @@ func (kl *Kubelet) GetNode() (*v1.Node, error) {
// zero capacity, and the default labels. // zero capacity, and the default labels.
func (kl *Kubelet) getNodeAnyWay() (*v1.Node, error) { func (kl *Kubelet) getNodeAnyWay() (*v1.Node, error) {
if kl.kubeClient != nil { if kl.kubeClient != nil {
if n, err := kl.GetNode(); err == nil { if n, err := kl.nodeLister.Get(string(kl.nodeName)); err == nil {
return n, nil return n, nil
} }
} }
......
...@@ -243,8 +243,9 @@ func (w *worker) doProbe() (keepGoing bool) { ...@@ -243,8 +243,9 @@ func (w *worker) doProbe() (keepGoing bool) {
if c.Started != nil && *c.Started { if c.Started != nil && *c.Started {
// Stop probing for startup once container has started. // Stop probing for startup once container has started.
// we keep it running to make sure it will work for restarted container.
if w.probeType == startup { if w.probeType == startup {
return false return true
} }
} else { } else {
// Disable other probes until container has started. // Disable other probes until container has started.
......
...@@ -163,6 +163,10 @@ func (h *httpStreamHandler) removeStreamPair(requestID string) { ...@@ -163,6 +163,10 @@ func (h *httpStreamHandler) removeStreamPair(requestID string) {
h.streamPairsLock.Lock() h.streamPairsLock.Lock()
defer h.streamPairsLock.Unlock() defer h.streamPairsLock.Unlock()
if h.conn != nil {
pair := h.streamPairs[requestID]
h.conn.RemoveStreams(pair.dataStream, pair.errorStream)
}
delete(h.streamPairs, requestID) delete(h.streamPairs, requestID)
} }
......
...@@ -19,6 +19,8 @@ package fieldpath ...@@ -19,6 +19,8 @@ package fieldpath
import ( import (
"sort" "sort"
"strings" "strings"
"sigs.k8s.io/structured-merge-diff/v3/schema"
) )
// Set identifies a set of fields. // Set identifies a set of fields.
...@@ -94,6 +96,30 @@ func (s *Set) Difference(s2 *Set) *Set { ...@@ -94,6 +96,30 @@ func (s *Set) Difference(s2 *Set) *Set {
} }
} }
// EnsureNamedFieldsAreMembers returns a Set that contains all the
// fields in s, as well as all the named fields that are typically not
// included. For example, a set made of "a.b.c" will end-up also owning
// "a" if it's a named fields but not "a.b" if it's a map.
func (s *Set) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.TypeRef) *Set {
members := PathElementSet{
members: make(sortedPathElements, 0, s.Members.Size()+len(s.Children.members)),
}
atom, _ := sc.Resolve(tr)
members.members = append(members.members, s.Members.members...)
for _, node := range s.Children.members {
// Only insert named fields.
if node.pathElement.FieldName != nil && atom.Map != nil {
if _, has := atom.Map.FindField(*node.pathElement.FieldName); has {
members.Insert(node.pathElement)
}
}
}
return &Set{
Members: members,
Children: *s.Children.EnsureNamedFieldsAreMembers(sc, tr),
}
}
// Size returns the number of members of the set. // Size returns the number of members of the set.
func (s *Set) Size() int { func (s *Set) Size() int {
return s.Members.Size() + s.Children.Size() return s.Members.Size() + s.Children.Size()
...@@ -333,6 +359,31 @@ func (s *SetNodeMap) Difference(s2 *Set) *SetNodeMap { ...@@ -333,6 +359,31 @@ func (s *SetNodeMap) Difference(s2 *Set) *SetNodeMap {
return out return out
} }
// EnsureNamedFieldsAreMembers returns a set that contains all the named fields along with the leaves.
func (s *SetNodeMap) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.TypeRef) *SetNodeMap {
out := make(sortedSetNode, 0, s.Size())
atom, _ := sc.Resolve(tr)
for _, member := range s.members {
tr := schema.TypeRef{}
if member.pathElement.FieldName != nil && atom.Map != nil {
tr = atom.Map.ElementType
if sf, ok := atom.Map.FindField(*member.pathElement.FieldName); ok {
tr = sf.Type
}
} else if member.pathElement.Key != nil && atom.List != nil {
tr = atom.List.ElementType
}
out = append(out, setNode{
pathElement: member.pathElement,
set: member.set.EnsureNamedFieldsAreMembers(sc, tr),
})
}
return &SetNodeMap{
members: out,
}
}
// Iterate calls f for each PathElement in the set. // Iterate calls f for each PathElement in the set.
func (s *SetNodeMap) Iterate(f func(PathElement)) { func (s *SetNodeMap) Iterate(f func(PathElement)) {
for _, n := range s.members { for _, n := range s.members {
......
...@@ -197,7 +197,7 @@ func shallowCopyManagers(managers fieldpath.ManagedFields) fieldpath.ManagedFiel ...@@ -197,7 +197,7 @@ func shallowCopyManagers(managers fieldpath.ManagedFields) fieldpath.ManagedFiel
return newManagers return newManagers
} }
// prune will remove a list or map item, iff: // prune will remove a field, list or map item, iff:
// * applyingManager applied it last time // * applyingManager applied it last time
// * applyingManager didn't apply it this time // * applyingManager didn't apply it this time
// * no other applier claims to manage it // * no other applier claims to manage it
...@@ -213,7 +213,8 @@ func (s *Updater) prune(merged *typed.TypedValue, managers fieldpath.ManagedFiel ...@@ -213,7 +213,8 @@ func (s *Updater) prune(merged *typed.TypedValue, managers fieldpath.ManagedFiel
return nil, fmt.Errorf("failed to convert merged object to last applied version: %v", err) return nil, fmt.Errorf("failed to convert merged object to last applied version: %v", err)
} }
pruned := convertedMerged.RemoveItems(lastSet.Set()) sc, tr := convertedMerged.Schema(), convertedMerged.TypeRef()
pruned := convertedMerged.RemoveItems(lastSet.Set().EnsureNamedFieldsAreMembers(sc, tr))
pruned, err = s.addBackOwnedItems(convertedMerged, pruned, managers, applyingManager) pruned, err = s.addBackOwnedItems(convertedMerged, pruned, managers, applyingManager)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed add back owned items: %v", err) return nil, fmt.Errorf("failed add back owned items: %v", err)
...@@ -225,18 +226,16 @@ func (s *Updater) prune(merged *typed.TypedValue, managers fieldpath.ManagedFiel ...@@ -225,18 +226,16 @@ func (s *Updater) prune(merged *typed.TypedValue, managers fieldpath.ManagedFiel
return s.Converter.Convert(pruned, managers[applyingManager].APIVersion()) return s.Converter.Convert(pruned, managers[applyingManager].APIVersion())
} }
// addBackOwnedItems adds back any list and map items that were removed by prune, // addBackOwnedItems adds back any fields, list and map items that were removed by prune,
// but other appliers (or the current applier's new config) claim to own. // but other appliers or updaters (or the current applier's new config) claim to own.
func (s *Updater) addBackOwnedItems(merged, pruned *typed.TypedValue, managedFields fieldpath.ManagedFields, applyingManager string) (*typed.TypedValue, error) { func (s *Updater) addBackOwnedItems(merged, pruned *typed.TypedValue, managedFields fieldpath.ManagedFields, applyingManager string) (*typed.TypedValue, error) {
var err error var err error
managedAtVersion := map[fieldpath.APIVersion]*fieldpath.Set{} managedAtVersion := map[fieldpath.APIVersion]*fieldpath.Set{}
for _, managerSet := range managedFields { for _, managerSet := range managedFields {
if managerSet.Applied() { if _, ok := managedAtVersion[managerSet.APIVersion()]; !ok {
if _, ok := managedAtVersion[managerSet.APIVersion()]; !ok { managedAtVersion[managerSet.APIVersion()] = fieldpath.NewSet()
managedAtVersion[managerSet.APIVersion()] = fieldpath.NewSet()
}
managedAtVersion[managerSet.APIVersion()] = managedAtVersion[managerSet.APIVersion()].Union(managerSet.Set())
} }
managedAtVersion[managerSet.APIVersion()] = managedAtVersion[managerSet.APIVersion()].Union(managerSet.Set())
} }
for version, managed := range managedAtVersion { for version, managed := range managedAtVersion {
merged, err = s.Converter.Convert(merged, version) merged, err = s.Converter.Convert(merged, version)
...@@ -261,14 +260,15 @@ func (s *Updater) addBackOwnedItems(merged, pruned *typed.TypedValue, managedFie ...@@ -261,14 +260,15 @@ func (s *Updater) addBackOwnedItems(merged, pruned *typed.TypedValue, managedFie
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create field set from pruned object at version %v: %v", version, err) return nil, fmt.Errorf("failed to create field set from pruned object at version %v: %v", version, err)
} }
pruned = merged.RemoveItems(mergedSet.Difference(prunedSet.Union(managed))) sc, tr := merged.Schema(), merged.TypeRef()
pruned = merged.RemoveItems(mergedSet.EnsureNamedFieldsAreMembers(sc, tr).Difference(prunedSet.EnsureNamedFieldsAreMembers(sc, tr).Union(managed.EnsureNamedFieldsAreMembers(sc, tr))))
} }
return pruned, nil return pruned, nil
} }
// addBackDanglingItems makes sure that the only items removed by prune are items that were // addBackDanglingItems makes sure that the fields list and map items removed by prune were
// previously owned by the currently applying manager. This will add back unowned items and items // previously owned by the currently applying manager. This will add back fields list and map items
// which are owned by Updaters that shouldn't be removed. // that are unowned or that are owned by Updaters and shouldn't be removed.
func (s *Updater) addBackDanglingItems(merged, pruned *typed.TypedValue, lastSet fieldpath.VersionedSet) (*typed.TypedValue, error) { func (s *Updater) addBackDanglingItems(merged, pruned *typed.TypedValue, lastSet fieldpath.VersionedSet) (*typed.TypedValue, error) {
convertedPruned, err := s.Converter.Convert(pruned, lastSet.APIVersion()) convertedPruned, err := s.Converter.Convert(pruned, lastSet.APIVersion())
if err != nil { if err != nil {
...@@ -285,5 +285,9 @@ func (s *Updater) addBackDanglingItems(merged, pruned *typed.TypedValue, lastSet ...@@ -285,5 +285,9 @@ func (s *Updater) addBackDanglingItems(merged, pruned *typed.TypedValue, lastSet
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create field set from merged object in last applied version: %v", err) return nil, fmt.Errorf("failed to create field set from merged object in last applied version: %v", err)
} }
return merged.RemoveItems(mergedSet.Difference(prunedSet).Intersection(lastSet.Set())), nil sc, tr := merged.Schema(), merged.TypeRef()
prunedSet = prunedSet.EnsureNamedFieldsAreMembers(sc, tr)
mergedSet = mergedSet.EnsureNamedFieldsAreMembers(sc, tr)
last := lastSet.Set().EnsureNamedFieldsAreMembers(sc, tr)
return merged.RemoveItems(mergedSet.Difference(prunedSet).Intersection(last)), nil
} }
...@@ -95,10 +95,9 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { ...@@ -95,10 +95,9 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
fieldType := t.ElementType fieldType := t.ElementType
if ft, ok := fieldTypes[k]; ok { if ft, ok := fieldTypes[k]; ok {
fieldType = ft fieldType = ft
} else { }
if w.toRemove.Has(path) { if w.toRemove.Has(path) {
return true return true
}
} }
if subset := w.toRemove.WithPrefix(pe); !subset.Empty() { if subset := w.toRemove.WithPrefix(pe); !subset.Empty() {
val = removeItemsWithSchema(val, subset, w.schema, fieldType) val = removeItemsWithSchema(val, subset, w.schema, fieldType)
......
...@@ -137,7 +137,9 @@ func (v *toFieldSetWalker) visitMapItems(t *schema.Map, m value.Map) (errs Valid ...@@ -137,7 +137,9 @@ func (v *toFieldSetWalker) visitMapItems(t *schema.Map, m value.Map) (errs Valid
v2 := v.prepareDescent(pe, tr) v2 := v.prepareDescent(pe, tr)
v2.value = val v2.value = val
errs = append(errs, v2.toFieldSet()...) errs = append(errs, v2.toFieldSet()...)
if _, ok := t.FindField(key); !ok { if val.IsNull() || (val.IsMap() && val.AsMap().Length() == 0) {
v2.set.Insert(v2.path)
} else if _, ok := t.FindField(key); !ok {
v2.set.Insert(v2.path) v2.set.Insert(v2.path)
} }
v.finishDescent(v2) v.finishDescent(v2)
......
...@@ -61,11 +61,21 @@ type TypedValue struct { ...@@ -61,11 +61,21 @@ type TypedValue struct {
schema *schema.Schema schema *schema.Schema
} }
// TypeRef is the type of the value.
func (tv TypedValue) TypeRef() schema.TypeRef {
return tv.typeRef
}
// AsValue removes the type from the TypedValue and only keeps the value. // AsValue removes the type from the TypedValue and only keeps the value.
func (tv TypedValue) AsValue() value.Value { func (tv TypedValue) AsValue() value.Value {
return tv.value return tv.value
} }
// Schema gets the schema from the TypedValue.
func (tv TypedValue) Schema() *schema.Schema {
return tv.schema
}
// Validate returns an error with a list of every spec violation. // Validate returns an error with a list of every spec violation.
func (tv TypedValue) Validate() error { func (tv TypedValue) Validate() error {
w := tv.walker() w := tv.walker()
......
...@@ -70,11 +70,11 @@ func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool { ...@@ -70,11 +70,11 @@ func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool {
return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal)) return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal))
} }
// GetUsing returns the field identified by this FieldCacheEntry from the provided struct. // GetFrom returns the field identified by this FieldCacheEntry from the provided struct.
func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value { func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value {
// field might be nested within 'inline' structs // field might be nested within 'inline' structs
for _, elem := range f.fieldPath { for _, elem := range f.fieldPath {
structVal = structVal.FieldByIndex(elem) structVal = dereference(structVal).FieldByIndex(elem)
} }
return structVal return structVal
} }
...@@ -150,7 +150,11 @@ func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fi ...@@ -150,7 +150,11 @@ func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fi
continue continue
} }
if isInline { if isInline {
buildStructCacheEntry(field.Type, infos, append(fieldPath, field.Index)) e := field.Type
if field.Type.Kind() == reflect.Ptr {
e = field.Type.Elem()
}
buildStructCacheEntry(e, infos, append(fieldPath, field.Index))
continue continue
} }
info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type} info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment