Unverified Commit 6223e3e8 authored by Hussein Galal's avatar Hussein Galal Committed by GitHub

Update to v1.20.12 (#4351)

* Update to v1.20.12 Signed-off-by: 's avatargalal-hussein <hussein.galal.ahmed.11@gmail.com> * Update to v1.20.12 Signed-off-by: 's avatargalal-hussein <hussein.galal.ahmed.11@gmail.com>
parent c57c7646
...@@ -37,34 +37,34 @@ replace ( ...@@ -37,34 +37,34 @@ replace (
google.golang.org/genproto => google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 google.golang.org/genproto => google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63
google.golang.org/grpc => google.golang.org/grpc v1.27.1 google.golang.org/grpc => google.golang.org/grpc v1.27.1
gopkg.in/square/go-jose.v2 => gopkg.in/square/go-jose.v2 v2.2.2 gopkg.in/square/go-jose.v2 => gopkg.in/square/go-jose.v2 v2.2.2
k8s.io/api => github.com/k3s-io/kubernetes/staging/src/k8s.io/api v1.20.11-k3s1 k8s.io/api => github.com/k3s-io/kubernetes/staging/src/k8s.io/api v1.20.12-k3s1
k8s.io/apiextensions-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v1.20.11-k3s1 k8s.io/apiextensions-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiextensions-apiserver v1.20.12-k3s1
k8s.io/apimachinery => github.com/k3s-io/kubernetes/staging/src/k8s.io/apimachinery v1.20.11-k3s1 k8s.io/apimachinery => github.com/k3s-io/kubernetes/staging/src/k8s.io/apimachinery v1.20.12-k3s1
k8s.io/apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiserver v1.20.11-k3s1 k8s.io/apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/apiserver v1.20.12-k3s1
k8s.io/cli-runtime => github.com/k3s-io/kubernetes/staging/src/k8s.io/cli-runtime v1.20.11-k3s1 k8s.io/cli-runtime => github.com/k3s-io/kubernetes/staging/src/k8s.io/cli-runtime v1.20.12-k3s1
k8s.io/client-go => github.com/k3s-io/kubernetes/staging/src/k8s.io/client-go v1.20.11-k3s1 k8s.io/client-go => github.com/k3s-io/kubernetes/staging/src/k8s.io/client-go v1.20.12-k3s1
k8s.io/cloud-provider => github.com/k3s-io/kubernetes/staging/src/k8s.io/cloud-provider v1.20.11-k3s1 k8s.io/cloud-provider => github.com/k3s-io/kubernetes/staging/src/k8s.io/cloud-provider v1.20.12-k3s1
k8s.io/cluster-bootstrap => github.com/k3s-io/kubernetes/staging/src/k8s.io/cluster-bootstrap v1.20.11-k3s1 k8s.io/cluster-bootstrap => github.com/k3s-io/kubernetes/staging/src/k8s.io/cluster-bootstrap v1.20.12-k3s1
k8s.io/code-generator => github.com/k3s-io/kubernetes/staging/src/k8s.io/code-generator v1.20.11-k3s1 k8s.io/code-generator => github.com/k3s-io/kubernetes/staging/src/k8s.io/code-generator v1.20.12-k3s1
k8s.io/component-base => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-base v1.20.11-k3s1 k8s.io/component-base => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-base v1.20.12-k3s1
k8s.io/component-helpers => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-helpers v1.20.11-k3s1 k8s.io/component-helpers => github.com/k3s-io/kubernetes/staging/src/k8s.io/component-helpers v1.20.12-k3s1
k8s.io/controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/controller-manager v1.20.11-k3s1 k8s.io/controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/controller-manager v1.20.12-k3s1
k8s.io/cri-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/cri-api v1.20.11-k3s1 k8s.io/cri-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/cri-api v1.20.12-k3s1
k8s.io/csi-translation-lib => github.com/k3s-io/kubernetes/staging/src/k8s.io/csi-translation-lib v1.20.11-k3s1 k8s.io/csi-translation-lib => github.com/k3s-io/kubernetes/staging/src/k8s.io/csi-translation-lib v1.20.12-k3s1
k8s.io/kube-aggregator => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-aggregator v1.20.11-k3s1 k8s.io/kube-aggregator => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-aggregator v1.20.12-k3s1
k8s.io/kube-controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-controller-manager v1.20.11-k3s1 k8s.io/kube-controller-manager => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-controller-manager v1.20.12-k3s1
k8s.io/kube-proxy => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-proxy v1.20.11-k3s1 k8s.io/kube-proxy => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-proxy v1.20.12-k3s1
k8s.io/kube-scheduler => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-scheduler v1.20.11-k3s1 k8s.io/kube-scheduler => github.com/k3s-io/kubernetes/staging/src/k8s.io/kube-scheduler v1.20.12-k3s1
k8s.io/kubectl => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubectl v1.20.11-k3s1 k8s.io/kubectl => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubectl v1.20.12-k3s1
k8s.io/kubelet => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubelet v1.20.11-k3s1 k8s.io/kubelet => github.com/k3s-io/kubernetes/staging/src/k8s.io/kubelet v1.20.12-k3s1
k8s.io/kubernetes => github.com/k3s-io/kubernetes v1.20.11-k3s1 k8s.io/kubernetes => github.com/k3s-io/kubernetes v1.20.12-k3s1
k8s.io/legacy-cloud-providers => github.com/k3s-io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v1.20.11-k3s1 k8s.io/legacy-cloud-providers => github.com/k3s-io/kubernetes/staging/src/k8s.io/legacy-cloud-providers v1.20.12-k3s1
k8s.io/metrics => github.com/k3s-io/kubernetes/staging/src/k8s.io/metrics v1.20.11-k3s1 k8s.io/metrics => github.com/k3s-io/kubernetes/staging/src/k8s.io/metrics v1.20.12-k3s1
k8s.io/mount-utils => github.com/k3s-io/kubernetes/staging/src/k8s.io/mount-utils v1.20.11-k3s1 k8s.io/mount-utils => github.com/k3s-io/kubernetes/staging/src/k8s.io/mount-utils v1.20.12-k3s1
k8s.io/node-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/node-api v1.20.11-k3s1 k8s.io/node-api => github.com/k3s-io/kubernetes/staging/src/k8s.io/node-api v1.20.12-k3s1
k8s.io/sample-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-apiserver v1.20.11-k3s1 k8s.io/sample-apiserver => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-apiserver v1.20.12-k3s1
k8s.io/sample-cli-plugin => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-cli-plugin v1.20.11-k3s1 k8s.io/sample-cli-plugin => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-cli-plugin v1.20.12-k3s1
k8s.io/sample-controller => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-controller v1.20.11-k3s1 k8s.io/sample-controller => github.com/k3s-io/kubernetes/staging/src/k8s.io/sample-controller v1.20.12-k3s1
mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34
) )
...@@ -130,7 +130,7 @@ require ( ...@@ -130,7 +130,7 @@ require (
k8s.io/cri-api v1.20.11 k8s.io/cri-api v1.20.11
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0
k8s.io/kubectl v1.20.11 k8s.io/kubectl v1.20.11
k8s.io/kubernetes v1.20.11 k8s.io/kubernetes v1.20.12
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 k8s.io/utils v0.0.0-20201110183641-67b214c5f920
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.10
// +build go1.10 // +build go1.10
package bidirule package bidirule
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.10
// +build !go1.10 // +build !go1.10
package bidirule package bidirule
......
...@@ -12,15 +12,14 @@ ...@@ -12,15 +12,14 @@
// and without notice. // and without notice.
package bidi // import "golang.org/x/text/unicode/bidi" package bidi // import "golang.org/x/text/unicode/bidi"
// TODO: // TODO
// The following functionality would not be hard to implement, but hinges on
// the definition of a Segmenter interface. For now this is up to the user.
// - Iterate over paragraphs
// - Segmenter to iterate over runs directly from a given text.
// Also:
// - Transformer for reordering? // - Transformer for reordering?
// - Transformer (validator, really) for Bidi Rule. // - Transformer (validator, really) for Bidi Rule.
import (
"bytes"
)
// This API tries to avoid dealing with embedding levels for now. Under the hood // This API tries to avoid dealing with embedding levels for now. Under the hood
// these will be computed, but the question is to which extent the user should // these will be computed, but the question is to which extent the user should
// know they exist. We should at some point allow the user to specify an // know they exist. We should at some point allow the user to specify an
...@@ -49,7 +48,9 @@ const ( ...@@ -49,7 +48,9 @@ const (
Neutral Neutral
) )
type options struct{} type options struct {
defaultDirection Direction
}
// An Option is an option for Bidi processing. // An Option is an option for Bidi processing.
type Option func(*options) type Option func(*options)
...@@ -66,12 +67,62 @@ type Option func(*options) ...@@ -66,12 +67,62 @@ type Option func(*options)
// DefaultDirection sets the default direction for a Paragraph. The direction is // DefaultDirection sets the default direction for a Paragraph. The direction is
// overridden if the text contains directional characters. // overridden if the text contains directional characters.
func DefaultDirection(d Direction) Option { func DefaultDirection(d Direction) Option {
panic("unimplemented") return func(opts *options) {
opts.defaultDirection = d
}
} }
// A Paragraph holds a single Paragraph for Bidi processing. // A Paragraph holds a single Paragraph for Bidi processing.
type Paragraph struct { type Paragraph struct {
// buffers p []byte
o Ordering
opts []Option
types []Class
pairTypes []bracketType
pairValues []rune
runes []rune
options options
}
// Initialize the p.pairTypes, p.pairValues and p.types from the input previously
// set by p.SetBytes() or p.SetString(). Also limit the input up to (and including) a paragraph
// separator (bidi class B).
//
// The function p.Order() needs these values to be set, so this preparation could be postponed.
// But since the SetBytes and SetStrings functions return the length of the input up to the paragraph
// separator, the whole input needs to be processed anyway and should not be done twice.
//
// The function has the same return values as SetBytes() / SetString()
func (p *Paragraph) prepareInput() (n int, err error) {
p.runes = bytes.Runes(p.p)
bytecount := 0
// clear slices from previous SetString or SetBytes
p.pairTypes = nil
p.pairValues = nil
p.types = nil
for _, r := range p.runes {
props, i := LookupRune(r)
bytecount += i
cls := props.Class()
if cls == B {
return bytecount, nil
}
p.types = append(p.types, cls)
if props.IsOpeningBracket() {
p.pairTypes = append(p.pairTypes, bpOpen)
p.pairValues = append(p.pairValues, r)
} else if props.IsBracket() {
// this must be a closing bracket,
// since IsOpeningBracket is not true
p.pairTypes = append(p.pairTypes, bpClose)
p.pairValues = append(p.pairValues, r)
} else {
p.pairTypes = append(p.pairTypes, bpNone)
p.pairValues = append(p.pairValues, 0)
}
}
return bytecount, nil
} }
// SetBytes configures p for the given paragraph text. It replaces text // SetBytes configures p for the given paragraph text. It replaces text
...@@ -80,70 +131,150 @@ type Paragraph struct { ...@@ -80,70 +131,150 @@ type Paragraph struct {
// consumed from b including this separator. Error may be non-nil if options are // consumed from b including this separator. Error may be non-nil if options are
// given. // given.
func (p *Paragraph) SetBytes(b []byte, opts ...Option) (n int, err error) { func (p *Paragraph) SetBytes(b []byte, opts ...Option) (n int, err error) {
panic("unimplemented") p.p = b
p.opts = opts
return p.prepareInput()
} }
// SetString configures p for the given paragraph text. It replaces text // SetString configures s for the given paragraph text. It replaces text
// previously set by SetBytes or SetString. If b contains a paragraph separator // previously set by SetBytes or SetString. If s contains a paragraph separator
// it will only process the first paragraph and report the number of bytes // it will only process the first paragraph and report the number of bytes
// consumed from b including this separator. Error may be non-nil if options are // consumed from s including this separator. Error may be non-nil if options are
// given. // given.
func (p *Paragraph) SetString(s string, opts ...Option) (n int, err error) { func (p *Paragraph) SetString(s string, opts ...Option) (n int, err error) {
panic("unimplemented") p.p = []byte(s)
p.opts = opts
return p.prepareInput()
} }
// IsLeftToRight reports whether the principle direction of rendering for this // IsLeftToRight reports whether the principle direction of rendering for this
// paragraphs is left-to-right. If this returns false, the principle direction // paragraphs is left-to-right. If this returns false, the principle direction
// of rendering is right-to-left. // of rendering is right-to-left.
func (p *Paragraph) IsLeftToRight() bool { func (p *Paragraph) IsLeftToRight() bool {
panic("unimplemented") return p.Direction() == LeftToRight
} }
// Direction returns the direction of the text of this paragraph. // Direction returns the direction of the text of this paragraph.
// //
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral. // The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
func (p *Paragraph) Direction() Direction { func (p *Paragraph) Direction() Direction {
panic("unimplemented") return p.o.Direction()
} }
// TODO: what happens if the position is > len(input)? This should return an error.
// RunAt reports the Run at the given position of the input text. // RunAt reports the Run at the given position of the input text.
// //
// This method can be used for computing line breaks on paragraphs. // This method can be used for computing line breaks on paragraphs.
func (p *Paragraph) RunAt(pos int) Run { func (p *Paragraph) RunAt(pos int) Run {
panic("unimplemented") c := 0
runNumber := 0
for i, r := range p.o.runes {
c += len(r)
if pos < c {
runNumber = i
}
}
return p.o.Run(runNumber)
}
func calculateOrdering(levels []level, runes []rune) Ordering {
var curDir Direction
prevDir := Neutral
prevI := 0
o := Ordering{}
// lvl = 0,2,4,...: left to right
// lvl = 1,3,5,...: right to left
for i, lvl := range levels {
if lvl%2 == 0 {
curDir = LeftToRight
} else {
curDir = RightToLeft
}
if curDir != prevDir {
if i > 0 {
o.runes = append(o.runes, runes[prevI:i])
o.directions = append(o.directions, prevDir)
o.startpos = append(o.startpos, prevI)
}
prevI = i
prevDir = curDir
}
}
o.runes = append(o.runes, runes[prevI:])
o.directions = append(o.directions, prevDir)
o.startpos = append(o.startpos, prevI)
return o
} }
// Order computes the visual ordering of all the runs in a Paragraph. // Order computes the visual ordering of all the runs in a Paragraph.
func (p *Paragraph) Order() (Ordering, error) { func (p *Paragraph) Order() (Ordering, error) {
panic("unimplemented") if len(p.types) == 0 {
return Ordering{}, nil
}
for _, fn := range p.opts {
fn(&p.options)
}
lvl := level(-1)
if p.options.defaultDirection == RightToLeft {
lvl = 1
}
para, err := newParagraph(p.types, p.pairTypes, p.pairValues, lvl)
if err != nil {
return Ordering{}, err
}
levels := para.getLevels([]int{len(p.types)})
p.o = calculateOrdering(levels, p.runes)
return p.o, nil
} }
// Line computes the visual ordering of runs for a single line starting and // Line computes the visual ordering of runs for a single line starting and
// ending at the given positions in the original text. // ending at the given positions in the original text.
func (p *Paragraph) Line(start, end int) (Ordering, error) { func (p *Paragraph) Line(start, end int) (Ordering, error) {
panic("unimplemented") lineTypes := p.types[start:end]
para, err := newParagraph(lineTypes, p.pairTypes[start:end], p.pairValues[start:end], -1)
if err != nil {
return Ordering{}, err
}
levels := para.getLevels([]int{len(lineTypes)})
o := calculateOrdering(levels, p.runes[start:end])
return o, nil
} }
// An Ordering holds the computed visual order of runs of a Paragraph. Calling // An Ordering holds the computed visual order of runs of a Paragraph. Calling
// SetBytes or SetString on the originating Paragraph invalidates an Ordering. // SetBytes or SetString on the originating Paragraph invalidates an Ordering.
// The methods of an Ordering should only be called by one goroutine at a time. // The methods of an Ordering should only be called by one goroutine at a time.
type Ordering struct{} type Ordering struct {
runes [][]rune
directions []Direction
startpos []int
}
// Direction reports the directionality of the runs. // Direction reports the directionality of the runs.
// //
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral. // The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
func (o *Ordering) Direction() Direction { func (o *Ordering) Direction() Direction {
panic("unimplemented") return o.directions[0]
} }
// NumRuns returns the number of runs. // NumRuns returns the number of runs.
func (o *Ordering) NumRuns() int { func (o *Ordering) NumRuns() int {
panic("unimplemented") return len(o.runes)
} }
// Run returns the ith run within the ordering. // Run returns the ith run within the ordering.
func (o *Ordering) Run(i int) Run { func (o *Ordering) Run(i int) Run {
panic("unimplemented") r := Run{
runes: o.runes[i],
direction: o.directions[i],
startpos: o.startpos[i],
}
return r
} }
// TODO: perhaps with options. // TODO: perhaps with options.
...@@ -155,16 +286,19 @@ func (o *Ordering) Run(i int) Run { ...@@ -155,16 +286,19 @@ func (o *Ordering) Run(i int) Run {
// A Run is a continuous sequence of characters of a single direction. // A Run is a continuous sequence of characters of a single direction.
type Run struct { type Run struct {
runes []rune
direction Direction
startpos int
} }
// String returns the text of the run in its original order. // String returns the text of the run in its original order.
func (r *Run) String() string { func (r *Run) String() string {
panic("unimplemented") return string(r.runes)
} }
// Bytes returns the text of the run in its original order. // Bytes returns the text of the run in its original order.
func (r *Run) Bytes() []byte { func (r *Run) Bytes() []byte {
panic("unimplemented") return []byte(r.String())
} }
// TODO: methods for // TODO: methods for
...@@ -174,25 +308,52 @@ func (r *Run) Bytes() []byte { ...@@ -174,25 +308,52 @@ func (r *Run) Bytes() []byte {
// Direction reports the direction of the run. // Direction reports the direction of the run.
func (r *Run) Direction() Direction { func (r *Run) Direction() Direction {
panic("unimplemented") return r.direction
} }
// Position of the Run within the text passed to SetBytes or SetString of the // Pos returns the position of the Run within the text passed to SetBytes or SetString of the
// originating Paragraph value. // originating Paragraph value.
func (r *Run) Pos() (start, end int) { func (r *Run) Pos() (start, end int) {
panic("unimplemented") return r.startpos, r.startpos + len(r.runes) - 1
} }
// AppendReverse reverses the order of characters of in, appends them to out, // AppendReverse reverses the order of characters of in, appends them to out,
// and returns the result. Modifiers will still follow the runes they modify. // and returns the result. Modifiers will still follow the runes they modify.
// Brackets are replaced with their counterparts. // Brackets are replaced with their counterparts.
func AppendReverse(out, in []byte) []byte { func AppendReverse(out, in []byte) []byte {
panic("unimplemented") ret := make([]byte, len(in)+len(out))
copy(ret, out)
inRunes := bytes.Runes(in)
for i, r := range inRunes {
prop, _ := LookupRune(r)
if prop.IsBracket() {
inRunes[i] = prop.reverseBracket(r)
}
}
for i, j := 0, len(inRunes)-1; i < j; i, j = i+1, j-1 {
inRunes[i], inRunes[j] = inRunes[j], inRunes[i]
}
copy(ret[len(out):], string(inRunes))
return ret
} }
// ReverseString reverses the order of characters in s and returns a new string. // ReverseString reverses the order of characters in s and returns a new string.
// Modifiers will still follow the runes they modify. Brackets are replaced with // Modifiers will still follow the runes they modify. Brackets are replaced with
// their counterparts. // their counterparts.
func ReverseString(s string) string { func ReverseString(s string) string {
panic("unimplemented") input := []rune(s)
li := len(input)
ret := make([]rune, li)
for i, r := range input {
prop, _ := LookupRune(r)
if prop.IsBracket() {
ret[li-i-1] = prop.reverseBracket(r)
} else {
ret[li-i-1] = r
}
}
return string(ret)
} }
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
package bidi package bidi
import "log" import (
"fmt"
"log"
)
// This implementation is a port based on the reference implementation found at: // This implementation is a port based on the reference implementation found at:
// https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/ // https://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/
...@@ -97,13 +100,20 @@ type paragraph struct { ...@@ -97,13 +100,20 @@ type paragraph struct {
// rune (suggested is the rune of the open bracket for opening and matching // rune (suggested is the rune of the open bracket for opening and matching
// close brackets, after normalization). The embedding levels are optional, but // close brackets, after normalization). The embedding levels are optional, but
// may be supplied to encode embedding levels of styled text. // may be supplied to encode embedding levels of styled text.
// func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) (*paragraph, error) {
// TODO: return an error. var err error
func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) *paragraph { if err = validateTypes(types); err != nil {
validateTypes(types) return nil, err
validatePbTypes(pairTypes) }
validatePbValues(pairValues, pairTypes) if err = validatePbTypes(pairTypes); err != nil {
validateParagraphEmbeddingLevel(levels) return nil, err
}
if err = validatePbValues(pairValues, pairTypes); err != nil {
return nil, err
}
if err = validateParagraphEmbeddingLevel(levels); err != nil {
return nil, err
}
p := &paragraph{ p := &paragraph{
initialTypes: append([]Class(nil), types...), initialTypes: append([]Class(nil), types...),
...@@ -115,7 +125,7 @@ func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, lev ...@@ -115,7 +125,7 @@ func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, lev
resultTypes: append([]Class(nil), types...), resultTypes: append([]Class(nil), types...),
} }
p.run() p.run()
return p return p, nil
} }
func (p *paragraph) Len() int { return len(p.initialTypes) } func (p *paragraph) Len() int { return len(p.initialTypes) }
...@@ -1001,58 +1011,61 @@ func typeForLevel(level level) Class { ...@@ -1001,58 +1011,61 @@ func typeForLevel(level level) Class {
return R return R
} }
// TODO: change validation to not panic func validateTypes(types []Class) error {
func validateTypes(types []Class) {
if len(types) == 0 { if len(types) == 0 {
log.Panic("types is null") return fmt.Errorf("types is null")
} }
for i, t := range types[:len(types)-1] { for i, t := range types[:len(types)-1] {
if t == B { if t == B {
log.Panicf("B type before end of paragraph at index: %d", i) return fmt.Errorf("B type before end of paragraph at index: %d", i)
} }
} }
return nil
} }
func validateParagraphEmbeddingLevel(embeddingLevel level) { func validateParagraphEmbeddingLevel(embeddingLevel level) error {
if embeddingLevel != implicitLevel && if embeddingLevel != implicitLevel &&
embeddingLevel != 0 && embeddingLevel != 0 &&
embeddingLevel != 1 { embeddingLevel != 1 {
log.Panicf("illegal paragraph embedding level: %d", embeddingLevel) return fmt.Errorf("illegal paragraph embedding level: %d", embeddingLevel)
} }
return nil
} }
func validateLineBreaks(linebreaks []int, textLength int) { func validateLineBreaks(linebreaks []int, textLength int) error {
prev := 0 prev := 0
for i, next := range linebreaks { for i, next := range linebreaks {
if next <= prev { if next <= prev {
log.Panicf("bad linebreak: %d at index: %d", next, i) return fmt.Errorf("bad linebreak: %d at index: %d", next, i)
} }
prev = next prev = next
} }
if prev != textLength { if prev != textLength {
log.Panicf("last linebreak was %d, want %d", prev, textLength) return fmt.Errorf("last linebreak was %d, want %d", prev, textLength)
} }
return nil
} }
func validatePbTypes(pairTypes []bracketType) { func validatePbTypes(pairTypes []bracketType) error {
if len(pairTypes) == 0 { if len(pairTypes) == 0 {
log.Panic("pairTypes is null") return fmt.Errorf("pairTypes is null")
} }
for i, pt := range pairTypes { for i, pt := range pairTypes {
switch pt { switch pt {
case bpNone, bpOpen, bpClose: case bpNone, bpOpen, bpClose:
default: default:
log.Panicf("illegal pairType value at %d: %v", i, pairTypes[i]) return fmt.Errorf("illegal pairType value at %d: %v", i, pairTypes[i])
} }
} }
return nil
} }
func validatePbValues(pairValues []rune, pairTypes []bracketType) { func validatePbValues(pairValues []rune, pairTypes []bracketType) error {
if pairValues == nil { if pairValues == nil {
log.Panic("pairValues is null") return fmt.Errorf("pairValues is null")
} }
if len(pairTypes) != len(pairValues) { if len(pairTypes) != len(pairValues) {
log.Panic("pairTypes is different length from pairValues") return fmt.Errorf("pairTypes is different length from pairValues")
} }
return nil
} }
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.10 && !go1.13
// +build go1.10,!go1.13 // +build go1.10,!go1.13
package bidi package bidi
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.13 && !go1.14
// +build go1.13,!go1.14 // +build go1.13,!go1.14
package bidi package bidi
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.14 && !go1.16
// +build go1.14,!go1.16 // +build go1.14,!go1.16
package bidi package bidi
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.16
// +build go1.16 // +build go1.16
package bidi package bidi
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build !go1.10
// +build !go1.10 // +build !go1.10
package bidi package bidi
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.10 && !go1.13
// +build go1.10,!go1.13 // +build go1.10,!go1.13
package norm package norm
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.13 && !go1.14
// +build go1.13,!go1.14 // +build go1.13,!go1.14
package norm package norm
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.14 && !go1.16
// +build go1.14,!go1.16 // +build go1.14,!go1.16
package norm package norm
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.16
// +build go1.16 // +build go1.16
package norm package norm
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build !go1.10
// +build !go1.10 // +build !go1.10
package norm package norm
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.10 && !go1.13
// +build go1.10,!go1.13 // +build go1.10,!go1.13
package width package width
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.13 && !go1.14
// +build go1.13,!go1.14 // +build go1.13,!go1.14
package width package width
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.14 && !go1.16
// +build go1.14,!go1.16 // +build go1.14,!go1.16
package width package width
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.16
// +build go1.16 // +build go1.16
package width package width
......
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build !go1.10
// +build !go1.10 // +build !go1.10
package width package width
......
...@@ -17,6 +17,8 @@ limitations under the License. ...@@ -17,6 +17,8 @@ limitations under the License.
package v1 package v1
import ( import (
"bytes"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiequality "k8s.io/apimachinery/pkg/api/equality" apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
...@@ -36,20 +38,29 @@ func Convert_apiextensions_JSONSchemaProps_To_v1_JSONSchemaProps(in *apiextensio ...@@ -36,20 +38,29 @@ func Convert_apiextensions_JSONSchemaProps_To_v1_JSONSchemaProps(in *apiextensio
return nil return nil
} }
var nullLiteral = []byte(`null`)
func Convert_apiextensions_JSON_To_v1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error { func Convert_apiextensions_JSON_To_v1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
raw, err := json.Marshal(*in) raw, err := json.Marshal(*in)
if err != nil { if err != nil {
return err return err
} }
out.Raw = raw if len(raw) == 0 || bytes.Equal(raw, nullLiteral) {
// match JSON#UnmarshalJSON treatment of literal nulls
out.Raw = nil
} else {
out.Raw = raw
}
return nil return nil
} }
func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error { func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
if in != nil { if in != nil {
var i interface{} var i interface{}
if err := json.Unmarshal(in.Raw, &i); err != nil { if len(in.Raw) > 0 && !bytes.Equal(in.Raw, nullLiteral) {
return err if err := json.Unmarshal(in.Raw, &i); err != nil {
return err
}
} }
*out = i *out = i
} else { } else {
...@@ -103,7 +114,7 @@ func Convert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefi ...@@ -103,7 +114,7 @@ func Convert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefi
func Convert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in *CustomResourceDefinitionSpec, out *apiextensions.CustomResourceDefinitionSpec, s conversion.Scope) error { func Convert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in *CustomResourceDefinitionSpec, out *apiextensions.CustomResourceDefinitionSpec, s conversion.Scope) error {
if err := autoConvert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in, out, s); err != nil { if err := autoConvert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in, out, s); err != nil {
return nil return err
} }
if len(out.Versions) == 0 { if len(out.Versions) == 0 {
......
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package v1 package v1
import ( import (
"bytes"
"errors" "errors"
"k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/json"
...@@ -128,7 +129,7 @@ func (s JSON) MarshalJSON() ([]byte, error) { ...@@ -128,7 +129,7 @@ func (s JSON) MarshalJSON() ([]byte, error) {
} }
func (s *JSON) UnmarshalJSON(data []byte) error { func (s *JSON) UnmarshalJSON(data []byte) error {
if len(data) > 0 && string(data) != "null" { if len(data) > 0 && !bytes.Equal(data, nullLiteral) {
s.Raw = data s.Raw = data
} }
return nil return nil
......
...@@ -17,6 +17,8 @@ limitations under the License. ...@@ -17,6 +17,8 @@ limitations under the License.
package v1beta1 package v1beta1
import ( import (
"bytes"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/json"
...@@ -36,20 +38,29 @@ func Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in *apiext ...@@ -36,20 +38,29 @@ func Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in *apiext
return nil return nil
} }
var nullLiteral = []byte(`null`)
func Convert_apiextensions_JSON_To_v1beta1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error { func Convert_apiextensions_JSON_To_v1beta1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
raw, err := json.Marshal(*in) raw, err := json.Marshal(*in)
if err != nil { if err != nil {
return err return err
} }
out.Raw = raw if len(raw) == 0 || bytes.Equal(raw, nullLiteral) {
// match JSON#UnmarshalJSON treatment of literal nulls
out.Raw = nil
} else {
out.Raw = raw
}
return nil return nil
} }
func Convert_v1beta1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error { func Convert_v1beta1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
if in != nil { if in != nil {
var i interface{} var i interface{}
if err := json.Unmarshal(in.Raw, &i); err != nil { if len(in.Raw) > 0 && !bytes.Equal(in.Raw, nullLiteral) {
return err if err := json.Unmarshal(in.Raw, &i); err != nil {
return err
}
} }
*out = i *out = i
} else { } else {
......
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package v1beta1 package v1beta1
import ( import (
"bytes"
"errors" "errors"
"k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/json"
...@@ -128,7 +129,7 @@ func (s JSON) MarshalJSON() ([]byte, error) { ...@@ -128,7 +129,7 @@ func (s JSON) MarshalJSON() ([]byte, error) {
} }
func (s *JSON) UnmarshalJSON(data []byte) error { func (s *JSON) UnmarshalJSON(data []byte) error {
if len(data) > 0 && string(data) != "null" { if len(data) > 0 && !bytes.Equal(data, nullLiteral) {
s.Raw = data s.Raw = data
} }
return nil return nil
......
...@@ -62,7 +62,15 @@ import ( ...@@ -62,7 +62,15 @@ import (
// undesired becomes completely unused, all the config objects are // undesired becomes completely unused, all the config objects are
// read and processed as a whole. // read and processed as a whole.
// StartFunction begins the process of handlig a request. If the // The funcs in this package follow the naming convention that the suffix
// "Locked" means the relevant mutex must be locked at the start of each
// call and will be locked upon return. For a configController, the
// suffix "ReadLocked" stipulates a read lock while just "Locked"
// stipulates a full lock. Absence of either suffix means that either
// (a) the lock must NOT be held at call time and will not be held
// upon return or (b) locking is irrelevant.
// StartFunction begins the process of handling a request. If the
// request gets queued then this function uses the given hashValue as // request gets queued then this function uses the given hashValue as
// the source of entropy as it shuffle-shards the request into a // the source of entropy as it shuffle-shards the request into a
// queue. The descr1 and descr2 values play no role in the logic but // queue. The descr1 and descr2 values play no role in the logic but
...@@ -109,9 +117,14 @@ type configController struct { ...@@ -109,9 +117,14 @@ type configController struct {
requestWaitLimit time.Duration requestWaitLimit time.Duration
// This must be locked while accessing flowSchemas or // This must be locked while accessing flowSchemas or
// priorityLevelStates. It is the lock involved in // priorityLevelStates. A lock for writing is needed
// LockingWriteMultiple. // for writing to any of the following:
lock sync.Mutex // - the flowSchemas field
// - the slice held in the flowSchemas field
// - the priorityLevelStates field
// - the map held in the priorityLevelStates field
// - any field of a priorityLevelState held in that map
lock sync.RWMutex
// flowSchemas holds the flow schema objects, sorted by increasing // flowSchemas holds the flow schema objects, sorted by increasing
// numerical (decreasing logical) matching precedence. Every // numerical (decreasing logical) matching precedence. Every
...@@ -236,8 +249,8 @@ func (cfgCtlr *configController) MaintainObservations(stopCh <-chan struct{}) { ...@@ -236,8 +249,8 @@ func (cfgCtlr *configController) MaintainObservations(stopCh <-chan struct{}) {
} }
func (cfgCtlr *configController) updateObservations() { func (cfgCtlr *configController) updateObservations() {
cfgCtlr.lock.Lock() cfgCtlr.lock.RLock()
defer cfgCtlr.lock.Unlock() defer cfgCtlr.lock.RUnlock()
for _, plc := range cfgCtlr.priorityLevelStates { for _, plc := range cfgCtlr.priorityLevelStates {
if plc.queues != nil { if plc.queues != nil {
plc.queues.UpdateObservations() plc.queues.UpdateObservations()
...@@ -668,8 +681,8 @@ func (immediateRequest) Finish(execute func()) bool { ...@@ -668,8 +681,8 @@ func (immediateRequest) Finish(execute func()) bool {
// waiting in its queue, or `Time{}` if this did not happen. // waiting in its queue, or `Time{}` if this did not happen.
func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDigest, queueNoteFn fq.QueueNoteFn) (fs *flowcontrol.FlowSchema, pl *flowcontrol.PriorityLevelConfiguration, isExempt bool, req fq.Request, startWaitingTime time.Time) { func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDigest, queueNoteFn fq.QueueNoteFn) (fs *flowcontrol.FlowSchema, pl *flowcontrol.PriorityLevelConfiguration, isExempt bool, req fq.Request, startWaitingTime time.Time) {
klog.V(7).Infof("startRequest(%#+v)", rd) klog.V(7).Infof("startRequest(%#+v)", rd)
cfgCtlr.lock.Lock() cfgCtlr.lock.RLock()
defer cfgCtlr.lock.Unlock() defer cfgCtlr.lock.RUnlock()
var selectedFlowSchema *flowcontrol.FlowSchema var selectedFlowSchema *flowcontrol.FlowSchema
for _, fs := range cfgCtlr.flowSchemas { for _, fs := range cfgCtlr.flowSchemas {
if matchesFlowSchema(rd, fs) { if matchesFlowSchema(rd, fs) {
...@@ -716,15 +729,15 @@ func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDig ...@@ -716,15 +729,15 @@ func (cfgCtlr *configController) startRequest(ctx context.Context, rd RequestDig
klog.V(7).Infof("startRequest(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, numQueues=%d", rd, selectedFlowSchema.Name, selectedFlowSchema.Spec.DistinguisherMethod, plName, numQueues) klog.V(7).Infof("startRequest(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, numQueues=%d", rd, selectedFlowSchema.Name, selectedFlowSchema.Spec.DistinguisherMethod, plName, numQueues)
req, idle := plState.queues.StartRequest(ctx, hashValue, flowDistinguisher, selectedFlowSchema.Name, rd.RequestInfo, rd.User, queueNoteFn) req, idle := plState.queues.StartRequest(ctx, hashValue, flowDistinguisher, selectedFlowSchema.Name, rd.RequestInfo, rd.User, queueNoteFn)
if idle { if idle {
cfgCtlr.maybeReapLocked(plName, plState) cfgCtlr.maybeReapReadLocked(plName, plState)
} }
return selectedFlowSchema, plState.pl, false, req, startWaitingTime return selectedFlowSchema, plState.pl, false, req, startWaitingTime
} }
// Call this after getting a clue that the given priority level is undesired and idle // Call this after getting a clue that the given priority level is undesired and idle
func (cfgCtlr *configController) maybeReap(plName string) { func (cfgCtlr *configController) maybeReap(plName string) {
cfgCtlr.lock.Lock() cfgCtlr.lock.RLock()
defer cfgCtlr.lock.Unlock() defer cfgCtlr.lock.RUnlock()
plState := cfgCtlr.priorityLevelStates[plName] plState := cfgCtlr.priorityLevelStates[plName]
if plState == nil { if plState == nil {
klog.V(7).Infof("plName=%s, plState==nil", plName) klog.V(7).Infof("plName=%s, plState==nil", plName)
...@@ -741,9 +754,12 @@ func (cfgCtlr *configController) maybeReap(plName string) { ...@@ -741,9 +754,12 @@ func (cfgCtlr *configController) maybeReap(plName string) {
cfgCtlr.configQueue.Add(0) cfgCtlr.configQueue.Add(0)
} }
// Call this if both (1) plState.queues is non-nil and reported being // maybeReapLocked requires the cfgCtlr's lock to already be held and
// idle, and (2) cfgCtlr's lock has not been released since then. // will remove the last internal traces of the named priority level if
func (cfgCtlr *configController) maybeReapLocked(plName string, plState *priorityLevelState) { // it has no more use. Call this if both (1) plState.queues is
// non-nil and reported being idle, and (2) cfgCtlr's lock has not
// been released since then.
func (cfgCtlr *configController) maybeReapReadLocked(plName string, plState *priorityLevelState) {
if !(plState.quiescing && plState.numPending == 0) { if !(plState.quiescing && plState.numPending == 0) {
return return
} }
......
...@@ -3,8 +3,8 @@ package version ...@@ -3,8 +3,8 @@ package version
var ( var (
gitMajor = "1" gitMajor = "1"
gitMinor = "20" gitMinor = "20"
gitVersion = "v1.20.11-k3s1" gitVersion = "v1.20.12-k3s1"
gitCommit = "6849e26e8428f3b8365b3dc276ddc1627e3fcaf2" gitCommit = "ea9c1b99bd42e157dae782e2add8321cc3a6165a"
gitTreeState = "clean" gitTreeState = "clean"
buildDate = "2021-09-16T14:28:21Z" buildDate = "2021-10-28T17:00:10Z"
) )
...@@ -165,7 +165,7 @@ func Convert_Map_string_To_runtime_Object_To_Slice_v1_NamedExtension(in *map[str ...@@ -165,7 +165,7 @@ func Convert_Map_string_To_runtime_Object_To_Slice_v1_NamedExtension(in *map[str
newExtension := (*in)[key] newExtension := (*in)[key]
oldExtension := runtime.RawExtension{} oldExtension := runtime.RawExtension{}
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&newExtension, &oldExtension, s); err != nil { if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&newExtension, &oldExtension, s); err != nil {
return nil return err
} }
namedExtension := NamedExtension{key, oldExtension} namedExtension := NamedExtension{key, oldExtension}
*out = append(*out, namedExtension) *out = append(*out, namedExtension)
......
...@@ -517,8 +517,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= ...@@ -517,8 +517,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
......
...@@ -3,8 +3,8 @@ package version ...@@ -3,8 +3,8 @@ package version
var ( var (
gitMajor = "1" gitMajor = "1"
gitMinor = "20" gitMinor = "20"
gitVersion = "v1.20.11-k3s1" gitVersion = "v1.20.12-k3s1"
gitCommit = "6849e26e8428f3b8365b3dc276ddc1627e3fcaf2" gitCommit = "ea9c1b99bd42e157dae782e2add8321cc3a6165a"
gitTreeState = "clean" gitTreeState = "clean"
buildDate = "2021-09-16T14:28:21Z" buildDate = "2021-10-28T17:00:10Z"
) )
...@@ -144,8 +144,8 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w ...@@ -144,8 +144,8 @@ golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
......
...@@ -581,7 +581,7 @@ func startPVCProtectionController(ctx ControllerContext) (http.Handler, bool, er ...@@ -581,7 +581,7 @@ func startPVCProtectionController(ctx ControllerContext) (http.Handler, bool, er
ctx.InformerFactory.Core().V1().Pods(), ctx.InformerFactory.Core().V1().Pods(),
ctx.ClientBuilder.ClientOrDie("pvc-protection-controller"), ctx.ClientBuilder.ClientOrDie("pvc-protection-controller"),
utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection), utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection),
utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection), utilfeature.DefaultFeatureGate.Enabled(features.GenericEphemeralVolume),
) )
if err != nil { if err != nil {
return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err) return nil, true, fmt.Errorf("failed to start the pvc protection controller: %v", err)
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"reflect" "reflect"
"time" "time"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
eventsv1beta1 "k8s.io/api/events/v1beta1" eventsv1beta1 "k8s.io/api/events/v1beta1"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...@@ -140,7 +140,7 @@ func legacyValidateEvent(event *core.Event) field.ErrorList { ...@@ -140,7 +140,7 @@ func legacyValidateEvent(event *core.Event) field.ErrorList {
} }
} else { } else {
if len(event.InvolvedObject.Namespace) == 0 && event.Namespace != metav1.NamespaceSystem { if len(event.InvolvedObject.Namespace) == 0 && event.Namespace != metav1.NamespaceDefault && event.Namespace != metav1.NamespaceSystem {
allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace")) allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace"))
} }
if len(event.ReportingController) == 0 { if len(event.ReportingController) == 0 {
......
...@@ -189,7 +189,7 @@ func Convert_networking_IngressBackend_To_v1beta1_IngressBackend(in *networking. ...@@ -189,7 +189,7 @@ func Convert_networking_IngressBackend_To_v1beta1_IngressBackend(in *networking.
func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *extensionsv1beta1.IngressSpec, out *networking.IngressSpec, s conversion.Scope) error { func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *extensionsv1beta1.IngressSpec, out *networking.IngressSpec, s conversion.Scope) error {
if err := autoConvert_v1beta1_IngressSpec_To_networking_IngressSpec(in, out, s); err != nil { if err := autoConvert_v1beta1_IngressSpec_To_networking_IngressSpec(in, out, s); err != nil {
return nil return err
} }
if in.Backend != nil { if in.Backend != nil {
out.DefaultBackend = &networking.IngressBackend{} out.DefaultBackend = &networking.IngressBackend{}
...@@ -202,7 +202,7 @@ func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *extensionsv1beta1 ...@@ -202,7 +202,7 @@ func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *extensionsv1beta1
func Convert_networking_IngressSpec_To_v1beta1_IngressSpec(in *networking.IngressSpec, out *extensionsv1beta1.IngressSpec, s conversion.Scope) error { func Convert_networking_IngressSpec_To_v1beta1_IngressSpec(in *networking.IngressSpec, out *extensionsv1beta1.IngressSpec, s conversion.Scope) error {
if err := autoConvert_networking_IngressSpec_To_v1beta1_IngressSpec(in, out, s); err != nil { if err := autoConvert_networking_IngressSpec_To_v1beta1_IngressSpec(in, out, s); err != nil {
return nil return err
} }
if in.DefaultBackend != nil { if in.DefaultBackend != nil {
out.Backend = &extensionsv1beta1.IngressBackend{} out.Backend = &extensionsv1beta1.IngressBackend{}
......
...@@ -52,7 +52,7 @@ func Convert_networking_IngressBackend_To_v1beta1_IngressBackend(in *networking. ...@@ -52,7 +52,7 @@ func Convert_networking_IngressBackend_To_v1beta1_IngressBackend(in *networking.
} }
func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *v1beta1.IngressSpec, out *networking.IngressSpec, s conversion.Scope) error { func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *v1beta1.IngressSpec, out *networking.IngressSpec, s conversion.Scope) error {
if err := autoConvert_v1beta1_IngressSpec_To_networking_IngressSpec(in, out, s); err != nil { if err := autoConvert_v1beta1_IngressSpec_To_networking_IngressSpec(in, out, s); err != nil {
return nil return err
} }
if in.Backend != nil { if in.Backend != nil {
out.DefaultBackend = &networking.IngressBackend{} out.DefaultBackend = &networking.IngressBackend{}
...@@ -65,7 +65,7 @@ func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *v1beta1.IngressSp ...@@ -65,7 +65,7 @@ func Convert_v1beta1_IngressSpec_To_networking_IngressSpec(in *v1beta1.IngressSp
func Convert_networking_IngressSpec_To_v1beta1_IngressSpec(in *networking.IngressSpec, out *v1beta1.IngressSpec, s conversion.Scope) error { func Convert_networking_IngressSpec_To_v1beta1_IngressSpec(in *networking.IngressSpec, out *v1beta1.IngressSpec, s conversion.Scope) error {
if err := autoConvert_networking_IngressSpec_To_v1beta1_IngressSpec(in, out, s); err != nil { if err := autoConvert_networking_IngressSpec_To_v1beta1_IngressSpec(in, out, s); err != nil {
return nil return err
} }
if in.DefaultBackend != nil { if in.DefaultBackend != nil {
out.Backend = &v1beta1.IngressBackend{} out.Backend = &v1beta1.IngressBackend{}
......
...@@ -410,7 +410,7 @@ func getAddressTypesForService(service *corev1.Service) map[discovery.AddressTyp ...@@ -410,7 +410,7 @@ func getAddressTypesForService(service *corev1.Service) map[discovery.AddressTyp
addrType = discovery.AddressTypeIPv6 addrType = discovery.AddressTypeIPv6
} }
serviceSupportedAddresses[addrType] = struct{}{} serviceSupportedAddresses[addrType] = struct{}{}
klog.V(2).Infof("couldn't find ipfamilies for headless service: %v/%v. This could happen if controller manager is connected to an old apiserver that does not support ip families yet. EndpointSlices for this Service will use %s as the IP Family based on familyOf(ClusterIP:%v).", service.Namespace, service.Name, addrType, service.Spec.ClusterIP) klog.V(2).Infof("couldn't find ipfamilies for service: %v/%v. This could happen if controller manager is connected to an old apiserver that does not support ip families yet. EndpointSlices for this Service will use %s as the IP Family based on familyOf(ClusterIP:%v).", service.Namespace, service.Name, addrType, service.Spec.ClusterIP)
return serviceSupportedAddresses return serviceSupportedAddresses
} }
......
...@@ -744,6 +744,12 @@ func (rs *REST) handleClusterIPsForUpdatedService(oldService *api.Service, servi ...@@ -744,6 +744,12 @@ func (rs *REST) handleClusterIPsForUpdatedService(oldService *api.Service, servi
} }
// CASE B: // CASE B:
// if headless service then we bail out early (no clusterIPs management needed)
if len(oldService.Spec.ClusterIPs) > 0 && oldService.Spec.ClusterIPs[0] == api.ClusterIPNone {
return nil, nil, nil
}
// Update service from non-ExternalName to ExternalName, should release ClusterIP if exists. // Update service from non-ExternalName to ExternalName, should release ClusterIP if exists.
if oldService.Spec.Type != api.ServiceTypeExternalName && service.Spec.Type == api.ServiceTypeExternalName { if oldService.Spec.Type != api.ServiceTypeExternalName && service.Spec.Type == api.ServiceTypeExternalName {
toRelease = make(map[api.IPFamily]string) toRelease = make(map[api.IPFamily]string)
...@@ -760,11 +766,6 @@ func (rs *REST) handleClusterIPsForUpdatedService(oldService *api.Service, servi ...@@ -760,11 +766,6 @@ func (rs *REST) handleClusterIPsForUpdatedService(oldService *api.Service, servi
return nil, toRelease, nil return nil, toRelease, nil
} }
// if headless service then we bail out early (no clusterIPs management needed)
if len(oldService.Spec.ClusterIPs) > 0 && oldService.Spec.ClusterIPs[0] == api.ClusterIPNone {
return nil, nil, nil
}
// upgrade and downgrade are specific to dualstack // upgrade and downgrade are specific to dualstack
if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) { if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
return nil, nil, nil return nil, nil, nil
......
...@@ -80,16 +80,12 @@ func NewBalancedAllocation(_ runtime.Object, h framework.Handle) (framework.Plug ...@@ -80,16 +80,12 @@ func NewBalancedAllocation(_ runtime.Object, h framework.Handle) (framework.Plug
// todo: use resource weights in the scorer function // todo: use resource weights in the scorer function
func balancedResourceScorer(requested, allocable resourceToValueMap, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 { func balancedResourceScorer(requested, allocable resourceToValueMap, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 {
// This to find a node which has most balanced CPU, memory and volume usage.
cpuFraction := fractionOfCapacity(requested[v1.ResourceCPU], allocable[v1.ResourceCPU]) cpuFraction := fractionOfCapacity(requested[v1.ResourceCPU], allocable[v1.ResourceCPU])
memoryFraction := fractionOfCapacity(requested[v1.ResourceMemory], allocable[v1.ResourceMemory]) memoryFraction := fractionOfCapacity(requested[v1.ResourceMemory], allocable[v1.ResourceMemory])
// fractions might be greater than 1 because pods with no requests get minimum // This to find a node which has most balanced CPU, memory and volume usage.
// values. if cpuFraction >= 1 || memoryFraction >= 1 {
if cpuFraction > 1 { // if requested >= capacity, the corresponding host should never be preferred.
cpuFraction = 1 return 0
}
if memoryFraction > 1 {
memoryFraction = 1
} }
if includeVolumes && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && allocatableVolumes > 0 { if includeVolumes && utilfeature.DefaultFeatureGate.Enabled(features.BalanceAttachedNodeVolumes) && allocatableVolumes > 0 {
......
...@@ -453,5 +453,8 @@ func getValidCreationData(subscriptionID, resourceGroup, sourceResourceID, sourc ...@@ -453,5 +453,8 @@ func getValidCreationData(subscriptionID, resourceGroup, sourceResourceID, sourc
func isInstanceNotFoundError(err error) bool { func isInstanceNotFoundError(err error) bool {
errMsg := strings.ToLower(err.Error()) errMsg := strings.ToLower(err.Error())
if strings.Contains(errMsg, strings.ToLower(vmssVMNotActiveErrorMessage)) {
return true
}
return strings.Contains(errMsg, errStatusCode400) && strings.Contains(errMsg, errInvalidParameter) && strings.Contains(errMsg, errTargetInstanceIds) return strings.Contains(errMsg, errStatusCode400) && strings.Contains(errMsg, errInvalidParameter) && strings.Contains(errMsg, errTargetInstanceIds)
} }
...@@ -20,6 +20,7 @@ package azure ...@@ -20,6 +20,7 @@ package azure
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"math" "math"
"reflect" "reflect"
...@@ -313,7 +314,7 @@ func (az *Cloud) cleanBackendpoolForPrimarySLB(primarySLB *network.LoadBalancer, ...@@ -313,7 +314,7 @@ func (az *Cloud) cleanBackendpoolForPrimarySLB(primarySLB *network.LoadBalancer,
ipConf := (*bp.BackendIPConfigurations)[i] ipConf := (*bp.BackendIPConfigurations)[i]
ipConfigID := to.String(ipConf.ID) ipConfigID := to.String(ipConf.ID)
_, vmSetName, err := az.VMSet.GetNodeNameByIPConfigurationID(ipConfigID) _, vmSetName, err := az.VMSet.GetNodeNameByIPConfigurationID(ipConfigID)
if err != nil { if err != nil && !errors.Is(err, cloudprovider.InstanceNotFound) {
return nil, err return nil, err
} }
primaryVMSetName := az.VMSet.GetPrimaryVMSetName() primaryVMSetName := az.VMSet.GetPrimaryVMSetName()
...@@ -1138,13 +1139,10 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service, ...@@ -1138,13 +1139,10 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service,
for _, ipConf := range *bp.BackendIPConfigurations { for _, ipConf := range *bp.BackendIPConfigurations {
ipConfID := to.String(ipConf.ID) ipConfID := to.String(ipConf.ID)
nodeName, _, err := az.VMSet.GetNodeNameByIPConfigurationID(ipConfID) nodeName, _, err := az.VMSet.GetNodeNameByIPConfigurationID(ipConfID)
if err != nil { if err != nil && !errors.Is(err, cloudprovider.InstanceNotFound) {
return nil, err return nil, err
} }
if nodeName == "" {
// VM may under deletion
continue
}
// If a node is not supposed to be included in the LB, it // If a node is not supposed to be included in the LB, it
// would not be in the `nodes` slice. We need to check the nodes that // would not be in the `nodes` slice. We need to check the nodes that
// have been added to the LB's backendpool, find the unwanted ones and // have been added to the LB's backendpool, find the unwanted ones and
...@@ -2155,15 +2153,13 @@ func shouldReleaseExistingOwnedPublicIP(existingPip *network.PublicIPAddress, lb ...@@ -2155,15 +2153,13 @@ func shouldReleaseExistingOwnedPublicIP(existingPip *network.PublicIPAddress, lb
// ensurePIPTagged ensures the public IP of the service is tagged as configured // ensurePIPTagged ensures the public IP of the service is tagged as configured
func (az *Cloud) ensurePIPTagged(service *v1.Service, pip *network.PublicIPAddress) bool { func (az *Cloud) ensurePIPTagged(service *v1.Service, pip *network.PublicIPAddress) bool {
changed := false
configTags := parseTags(az.Tags) configTags := parseTags(az.Tags)
annotationTags := make(map[string]*string) annotationTags := make(map[string]*string)
if _, ok := service.Annotations[ServiceAnnotationAzurePIPTags]; ok { if _, ok := service.Annotations[ServiceAnnotationAzurePIPTags]; ok {
annotationTags = parseTags(service.Annotations[ServiceAnnotationAzurePIPTags]) annotationTags = parseTags(service.Annotations[ServiceAnnotationAzurePIPTags])
} }
for k, v := range annotationTags { configTags, _ = reconcileTags(configTags, annotationTags)
configTags[k] = v
}
// include the cluster name and service names tags when comparing // include the cluster name and service names tags when comparing
var clusterName, serviceNames *string var clusterName, serviceNames *string
if v, ok := pip.Tags[clusterNameKey]; ok { if v, ok := pip.Tags[clusterNameKey]; ok {
...@@ -2178,12 +2174,10 @@ func (az *Cloud) ensurePIPTagged(service *v1.Service, pip *network.PublicIPAddre ...@@ -2178,12 +2174,10 @@ func (az *Cloud) ensurePIPTagged(service *v1.Service, pip *network.PublicIPAddre
if serviceNames != nil { if serviceNames != nil {
configTags[serviceTagKey] = serviceNames configTags[serviceTagKey] = serviceNames
} }
for k, v := range configTags {
if vv, ok := pip.Tags[k]; !ok || !strings.EqualFold(to.String(v), to.String(vv)) { tags, changed := reconcileTags(pip.Tags, configTags)
pip.Tags[k] = v pip.Tags = tags
changed = true
}
}
return changed return changed
} }
...@@ -2744,7 +2738,6 @@ func unbindServiceFromPIP(pip *network.PublicIPAddress, serviceName string) erro ...@@ -2744,7 +2738,6 @@ func unbindServiceFromPIP(pip *network.PublicIPAddress, serviceName string) erro
// ensureLoadBalancerTagged ensures every load balancer in the resource group is tagged as configured // ensureLoadBalancerTagged ensures every load balancer in the resource group is tagged as configured
func (az *Cloud) ensureLoadBalancerTagged(lb *network.LoadBalancer) bool { func (az *Cloud) ensureLoadBalancerTagged(lb *network.LoadBalancer) bool {
changed := false
if az.Tags == "" { if az.Tags == "" {
return false return false
} }
...@@ -2752,18 +2745,15 @@ func (az *Cloud) ensureLoadBalancerTagged(lb *network.LoadBalancer) bool { ...@@ -2752,18 +2745,15 @@ func (az *Cloud) ensureLoadBalancerTagged(lb *network.LoadBalancer) bool {
if lb.Tags == nil { if lb.Tags == nil {
lb.Tags = make(map[string]*string) lb.Tags = make(map[string]*string)
} }
for k, v := range tags {
if vv, ok := lb.Tags[k]; !ok || !strings.EqualFold(to.String(v), to.String(vv)) { tags, changed := reconcileTags(lb.Tags, tags)
lb.Tags[k] = v lb.Tags = tags
changed = true
}
}
return changed return changed
} }
// ensureSecurityGroupTagged ensures the security group is tagged as configured // ensureSecurityGroupTagged ensures the security group is tagged as configured
func (az *Cloud) ensureSecurityGroupTagged(sg *network.SecurityGroup) bool { func (az *Cloud) ensureSecurityGroupTagged(sg *network.SecurityGroup) bool {
changed := false
if az.Tags == "" { if az.Tags == "" {
return false return false
} }
...@@ -2771,11 +2761,9 @@ func (az *Cloud) ensureSecurityGroupTagged(sg *network.SecurityGroup) bool { ...@@ -2771,11 +2761,9 @@ func (az *Cloud) ensureSecurityGroupTagged(sg *network.SecurityGroup) bool {
if sg.Tags == nil { if sg.Tags == nil {
sg.Tags = make(map[string]*string) sg.Tags = make(map[string]*string)
} }
for k, v := range tags {
if vv, ok := sg.Tags[k]; !ok || !strings.EqualFold(to.String(v), to.String(vv)) { tags, changed := reconcileTags(sg.Tags, tags)
sg.Tags[k] = v sg.Tags = tags
changed = true
}
}
return changed return changed
} }
...@@ -508,16 +508,13 @@ func (az *Cloud) ensureRouteTableTagged(rt *network.RouteTable) (map[string]*str ...@@ -508,16 +508,13 @@ func (az *Cloud) ensureRouteTableTagged(rt *network.RouteTable) (map[string]*str
if az.Tags == "" { if az.Tags == "" {
return nil, false return nil, false
} }
changed := false
tags := parseTags(az.Tags) tags := parseTags(az.Tags)
if rt.Tags == nil { if rt.Tags == nil {
rt.Tags = make(map[string]*string) rt.Tags = make(map[string]*string)
} }
for k, v := range tags {
if vv, ok := rt.Tags[k]; !ok || !strings.EqualFold(to.String(v), to.String(vv)) { tags, changed := reconcileTags(rt.Tags, tags)
rt.Tags[k] = v rt.Tags = tags
changed = true
}
}
return rt.Tags, changed return rt.Tags, changed
} }
...@@ -458,6 +458,7 @@ func (as *availabilitySet) GetInstanceIDByNodeName(name string) (string, error) ...@@ -458,6 +458,7 @@ func (as *availabilitySet) GetInstanceIDByNodeName(name string) (string, error)
machine, err = as.getVirtualMachine(types.NodeName(name), azcache.CacheReadTypeUnsafe) machine, err = as.getVirtualMachine(types.NodeName(name), azcache.CacheReadTypeUnsafe)
if err == cloudprovider.InstanceNotFound { if err == cloudprovider.InstanceNotFound {
klog.Warningf("Unable to find node %s: %v", name, cloudprovider.InstanceNotFound)
return "", cloudprovider.InstanceNotFound return "", cloudprovider.InstanceNotFound
} }
if err != nil { if err != nil {
...@@ -965,13 +966,16 @@ func (as *availabilitySet) EnsureBackendPoolDeleted(service *v1.Service, backend ...@@ -965,13 +966,16 @@ func (as *availabilitySet) EnsureBackendPoolDeleted(service *v1.Service, backend
} }
} }
nicUpdaters := make([]func() error, 0) nicUpdaters := make([]func() error, 0)
errors := make([]error, 0) allErrs := make([]error, 0)
for i := range ipConfigurationIDs { for i := range ipConfigurationIDs {
ipConfigurationID := ipConfigurationIDs[i] ipConfigurationID := ipConfigurationIDs[i]
nodeName, _, err := as.GetNodeNameByIPConfigurationID(ipConfigurationID) nodeName, _, err := as.GetNodeNameByIPConfigurationID(ipConfigurationID)
if err != nil { if err != nil && !errors.Is(err, cloudprovider.InstanceNotFound) {
klog.Errorf("Failed to GetNodeNameByIPConfigurationID(%s): %v", ipConfigurationID, err) klog.Errorf("Failed to GetNodeNameByIPConfigurationID(%s): %v", ipConfigurationID, err)
errors = append(errors, err) allErrs = append(allErrs, err)
continue
}
if nodeName == "" {
continue continue
} }
...@@ -1038,9 +1042,9 @@ func (as *availabilitySet) EnsureBackendPoolDeleted(service *v1.Service, backend ...@@ -1038,9 +1042,9 @@ func (as *availabilitySet) EnsureBackendPoolDeleted(service *v1.Service, backend
if errs != nil { if errs != nil {
return utilerrors.Flatten(errs) return utilerrors.Flatten(errs)
} }
// Fail if there are other errors. // Fail if there are other allErrs.
if len(errors) > 0 { if len(allErrs) > 0 {
return utilerrors.Flatten(utilerrors.NewAggregate(errors)) return utilerrors.Flatten(utilerrors.NewAggregate(allErrs))
} }
isOperationSucceeded = true isOperationSucceeded = true
...@@ -1104,7 +1108,8 @@ func (as *availabilitySet) GetNodeNameByIPConfigurationID(ipConfigurationID stri ...@@ -1104,7 +1108,8 @@ func (as *availabilitySet) GetNodeNameByIPConfigurationID(ipConfigurationID stri
vm, err := as.getVirtualMachine(types.NodeName(vmName), azcache.CacheReadTypeDefault) vm, err := as.getVirtualMachine(types.NodeName(vmName), azcache.CacheReadTypeDefault)
if err != nil { if err != nil {
return "", "", fmt.Errorf("cannot get the virtual machine by node name %s", vmName) klog.Errorf("Unable to get the virtual machine by node name %s: %v", vmName, err)
return "", "", err
} }
asID := "" asID := ""
if vm.VirtualMachineProperties != nil && vm.AvailabilitySet != nil { if vm.VirtualMachineProperties != nil && vm.AvailabilitySet != nil {
...@@ -1116,7 +1121,7 @@ func (as *availabilitySet) GetNodeNameByIPConfigurationID(ipConfigurationID stri ...@@ -1116,7 +1121,7 @@ func (as *availabilitySet) GetNodeNameByIPConfigurationID(ipConfigurationID stri
asName, err := getAvailabilitySetNameByID(asID) asName, err := getAvailabilitySetNameByID(asID)
if err != nil { if err != nil {
return "", "", fmt.Errorf("cannot get the availability set name by the availability set ID %s", asID) return "", "", fmt.Errorf("cannot get the availability set name by the availability set ID %s: %v", asID, err)
} }
return vmName, strings.ToLower(asName), nil return vmName, strings.ToLower(asName), nil
} }
...@@ -138,3 +138,28 @@ func parseTags(tags string) map[string]*string { ...@@ -138,3 +138,28 @@ func parseTags(tags string) map[string]*string {
} }
return formatted return formatted
} }
func findKeyInMapCaseInsensitive(targetMap map[string]*string, key string) (bool, string) {
for k := range targetMap {
if strings.EqualFold(k, key) {
return true, k
}
}
return false, ""
}
func reconcileTags(currentTagsOnResource, newTags map[string]*string) (reconciledTags map[string]*string, changed bool) {
for k, v := range newTags {
found, key := findKeyInMapCaseInsensitive(currentTagsOnResource, k)
if !found {
currentTagsOnResource[k] = v
changed = true
} else if !strings.EqualFold(to.String(v), to.String(currentTagsOnResource[key])) {
currentTagsOnResource[key] = v
changed = true
}
}
return currentTagsOnResource, changed
}
...@@ -194,6 +194,7 @@ func (ss *scaleSet) getVmssVMByNodeIdentity(node *nodeIdentity, crt azcache.Azur ...@@ -194,6 +194,7 @@ func (ss *scaleSet) getVmssVMByNodeIdentity(node *nodeIdentity, crt azcache.Azur
} }
if !found || vm == nil { if !found || vm == nil {
klog.Warningf("Unable to find node %s: %v", node.nodeName, cloudprovider.InstanceNotFound)
return "", "", nil, cloudprovider.InstanceNotFound return "", "", nil, cloudprovider.InstanceNotFound
} }
return vmssName, instanceID, vm, nil return vmssName, instanceID, vm, nil
...@@ -341,6 +342,7 @@ func (ss *scaleSet) GetInstanceIDByNodeName(name string) (string, error) { ...@@ -341,6 +342,7 @@ func (ss *scaleSet) GetInstanceIDByNodeName(name string) (string, error) {
_, _, vm, err := ss.getVmssVM(name, azcache.CacheReadTypeUnsafe) _, _, vm, err := ss.getVmssVM(name, azcache.CacheReadTypeUnsafe)
if err != nil { if err != nil {
klog.Errorf("Unable to find node %s: %v", name, err)
return "", err return "", err
} }
...@@ -388,6 +390,7 @@ func (ss *scaleSet) GetNodeNameByProviderID(providerID string) (types.NodeName, ...@@ -388,6 +390,7 @@ func (ss *scaleSet) GetNodeNameByProviderID(providerID string) (types.NodeName,
vm, err := ss.getVmssVMByInstanceID(resourceGroup, scaleSetName, instanceID, azcache.CacheReadTypeUnsafe) vm, err := ss.getVmssVMByInstanceID(resourceGroup, scaleSetName, instanceID, azcache.CacheReadTypeUnsafe)
if err != nil { if err != nil {
klog.Errorf("Unable to find node by providerID %s: %v", providerID, err)
return "", err return "", err
} }
...@@ -708,6 +711,7 @@ func (ss *scaleSet) getNodeIdentityByNodeName(nodeName string, crt azcache.Azure ...@@ -708,6 +711,7 @@ func (ss *scaleSet) getNodeIdentityByNodeName(nodeName string, crt azcache.Azure
return nil, err return nil, err
} }
if node.vmssName == "" { if node.vmssName == "" {
klog.Warningf("Unable to find node %s: %v", nodeName, cloudprovider.InstanceNotFound)
return nil, cloudprovider.InstanceNotFound return nil, cloudprovider.InstanceNotFound
} }
return node, nil return node, nil
...@@ -720,7 +724,7 @@ func (ss *scaleSet) listScaleSetVMs(scaleSetName, resourceGroup string) ([]compu ...@@ -720,7 +724,7 @@ func (ss *scaleSet) listScaleSetVMs(scaleSetName, resourceGroup string) ([]compu
allVMs, rerr := ss.VirtualMachineScaleSetVMsClient.List(ctx, resourceGroup, scaleSetName, string(compute.InstanceView)) allVMs, rerr := ss.VirtualMachineScaleSetVMsClient.List(ctx, resourceGroup, scaleSetName, string(compute.InstanceView))
if rerr != nil { if rerr != nil {
klog.Errorf("VirtualMachineScaleSetVMsClient.List failed: %v", rerr) klog.Errorf("VirtualMachineScaleSetVMsClient.List(%s, %s) failed: %v", resourceGroup, scaleSetName, rerr)
if rerr.IsNotFound() { if rerr.IsNotFound() {
return nil, cloudprovider.InstanceNotFound return nil, cloudprovider.InstanceNotFound
} }
...@@ -959,6 +963,11 @@ func (ss *scaleSet) EnsureHostInPool(service *v1.Service, nodeName types.NodeNam ...@@ -959,6 +963,11 @@ func (ss *scaleSet) EnsureHostInPool(service *v1.Service, nodeName types.NodeNam
vmName := mapNodeNameToVMName(nodeName) vmName := mapNodeNameToVMName(nodeName)
ssName, instanceID, vm, err := ss.getVmssVM(vmName, azcache.CacheReadTypeDefault) ssName, instanceID, vm, err := ss.getVmssVM(vmName, azcache.CacheReadTypeDefault)
if err != nil { if err != nil {
if errors.Is(err, cloudprovider.InstanceNotFound) {
klog.Infof("EnsureHostInPool: skipping node %s because it is not found", vmName)
return "", "", "", nil, nil
}
return "", "", "", nil, err return "", "", "", nil, err
} }
...@@ -1335,6 +1344,11 @@ func (ss *scaleSet) EnsureHostsInPool(service *v1.Service, nodes []*v1.Node, bac ...@@ -1335,6 +1344,11 @@ func (ss *scaleSet) EnsureHostsInPool(service *v1.Service, nodes []*v1.Node, bac
func (ss *scaleSet) ensureBackendPoolDeletedFromNode(nodeName, backendPoolID string) (string, string, string, *compute.VirtualMachineScaleSetVM, error) { func (ss *scaleSet) ensureBackendPoolDeletedFromNode(nodeName, backendPoolID string) (string, string, string, *compute.VirtualMachineScaleSetVM, error) {
ssName, instanceID, vm, err := ss.getVmssVM(nodeName, azcache.CacheReadTypeDefault) ssName, instanceID, vm, err := ss.getVmssVM(nodeName, azcache.CacheReadTypeDefault)
if err != nil { if err != nil {
if errors.Is(err, cloudprovider.InstanceNotFound) {
klog.Infof("ensureBackendPoolDeletedFromNode: skipping node %s because it is not found", nodeName)
return "", "", "", nil, nil
}
return "", "", "", nil, err return "", "", "", nil, err
} }
...@@ -1408,7 +1422,7 @@ func (ss *scaleSet) GetNodeNameByIPConfigurationID(ipConfigurationID string) (st ...@@ -1408,7 +1422,7 @@ func (ss *scaleSet) GetNodeNameByIPConfigurationID(ipConfigurationID string) (st
klog.V(4).Infof("Can not extract scale set name from ipConfigurationID (%s), assuming it is managed by availability set", ipConfigurationID) klog.V(4).Infof("Can not extract scale set name from ipConfigurationID (%s), assuming it is managed by availability set", ipConfigurationID)
name, rg, err := ss.availabilitySet.GetNodeNameByIPConfigurationID(ipConfigurationID) name, rg, err := ss.availabilitySet.GetNodeNameByIPConfigurationID(ipConfigurationID)
if err != nil { if err != nil && !errors.Is(err, cloudprovider.InstanceNotFound) {
klog.Errorf("GetNodeNameByIPConfigurationID: failed to invoke availabilitySet.GetNodeNameByIPConfigurationID: %s", err.Error()) klog.Errorf("GetNodeNameByIPConfigurationID: failed to invoke availabilitySet.GetNodeNameByIPConfigurationID: %s", err.Error())
return "", "", err return "", "", err
} }
...@@ -1420,6 +1434,7 @@ func (ss *scaleSet) GetNodeNameByIPConfigurationID(ipConfigurationID string) (st ...@@ -1420,6 +1434,7 @@ func (ss *scaleSet) GetNodeNameByIPConfigurationID(ipConfigurationID string) (st
instanceID := matches[3] instanceID := matches[3]
vm, err := ss.getVmssVMByInstanceID(resourceGroup, scaleSetName, instanceID, azcache.CacheReadTypeUnsafe) vm, err := ss.getVmssVMByInstanceID(resourceGroup, scaleSetName, instanceID, azcache.CacheReadTypeUnsafe)
if err != nil { if err != nil {
klog.Errorf("Unable to find node by ipConfigurationID %s: %v", ipConfigurationID, err)
return "", "", err return "", "", err
} }
...@@ -1581,7 +1596,7 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID, ...@@ -1581,7 +1596,7 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID,
hostUpdates := make([]func() error, 0, len(ipConfigurationIDs)) hostUpdates := make([]func() error, 0, len(ipConfigurationIDs))
nodeUpdates := make(map[vmssMetaInfo]map[string]compute.VirtualMachineScaleSetVM) nodeUpdates := make(map[vmssMetaInfo]map[string]compute.VirtualMachineScaleSetVM)
errors := make([]error, 0) allErrs := make([]error, 0)
for i := range ipConfigurationIDs { for i := range ipConfigurationIDs {
ipConfigurationID := ipConfigurationIDs[i] ipConfigurationID := ipConfigurationIDs[i]
...@@ -1601,14 +1616,16 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID, ...@@ -1601,14 +1616,16 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID,
} }
klog.Errorf("Failed to GetNodeNameByIPConfigurationID(%s): %v", ipConfigurationID, err) klog.Errorf("Failed to GetNodeNameByIPConfigurationID(%s): %v", ipConfigurationID, err)
errors = append(errors, err) allErrs = append(allErrs, err)
continue continue
} }
nodeResourceGroup, nodeVMSS, nodeInstanceID, nodeVMSSVM, err := ss.ensureBackendPoolDeletedFromNode(nodeName, backendPoolID) nodeResourceGroup, nodeVMSS, nodeInstanceID, nodeVMSSVM, err := ss.ensureBackendPoolDeletedFromNode(nodeName, backendPoolID)
if err != nil { if err != nil {
klog.Errorf("EnsureBackendPoolDeleted(%s): backendPoolID(%s) - failed with error %v", getServiceName(service), backendPoolID, err) if !errors.Is(err, ErrorNotVmssInstance) { // Do nothing for the VMAS nodes.
errors = append(errors, err) klog.Errorf("EnsureBackendPoolDeleted(%s): backendPoolID(%s) - failed with error %v", getServiceName(service), backendPoolID, err)
allErrs = append(allErrs, err)
}
continue continue
} }
...@@ -1654,8 +1671,8 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID, ...@@ -1654,8 +1671,8 @@ func (ss *scaleSet) EnsureBackendPoolDeleted(service *v1.Service, backendPoolID,
} }
// Fail if there are other errors. // Fail if there are other errors.
if len(errors) > 0 { if len(allErrs) > 0 {
return utilerrors.Flatten(utilerrors.NewAggregate(errors)) return utilerrors.Flatten(utilerrors.NewAggregate(allErrs))
} }
// Ensure the backendPoolID is also deleted on VMSS itself. // Ensure the backendPoolID is also deleted on VMSS itself.
......
...@@ -76,7 +76,7 @@ func (err *Error) Error() error { ...@@ -76,7 +76,7 @@ func (err *Error) Error() error {
retryAfterSeconds = int(err.RetryAfter.Sub(curTime) / time.Second) retryAfterSeconds = int(err.RetryAfter.Sub(curTime) / time.Second)
} }
return fmt.Errorf("Retriable: %v, RetryAfter: %ds, HTTPStatusCode: %d, RawError: %v", return fmt.Errorf("Retriable: %v, RetryAfter: %ds, HTTPStatusCode: %d, RawError: %w",
err.Retriable, retryAfterSeconds, err.HTTPStatusCode, err.RawError) err.Retriable, retryAfterSeconds, err.HTTPStatusCode, err.RawError)
} }
......
...@@ -311,6 +311,17 @@ func (nm *NodeManager) GetNodeDetails() ([]NodeDetails, error) { ...@@ -311,6 +311,17 @@ func (nm *NodeManager) GetNodeDetails() ([]NodeDetails, error) {
return nodeDetails, nil return nodeDetails, nil
} }
// GetNodeNames returns list of nodes that are known to vsphere cloudprovider.
// These are typically nodes that make up k8s cluster.
func (nm *NodeManager) GetNodeNames() []k8stypes.NodeName {
nodes := nm.getNodes()
var nodeNameList []k8stypes.NodeName
for _, node := range nodes {
nodeNameList = append(nodeNameList, k8stypes.NodeName(node.Name))
}
return nodeNameList
}
func (nm *NodeManager) refreshNodes() (errList []error) { func (nm *NodeManager) refreshNodes() (errList []error) {
for nodeName := range nm.getNodes() { for nodeName := range nm.getNodes() {
nodeInfo, err := nm.getRefreshedNodeInfo(convertToK8sType(nodeName)) nodeInfo, err := nm.getRefreshedNodeInfo(convertToK8sType(nodeName))
......
...@@ -1220,9 +1220,15 @@ func (vs *VSphere) DisksAreAttached(nodeVolumes map[k8stypes.NodeName][]string) ...@@ -1220,9 +1220,15 @@ func (vs *VSphere) DisksAreAttached(nodeVolumes map[k8stypes.NodeName][]string)
} }
} }
klog.V(4).Infof("DisksAreAttached successfully executed. result: %+v", attached)
// There could be nodes in cluster which do not have any pods with vsphere volumes running on them
// such nodes won't be part of nodeVolumes map because attach-detach controller does not keep track
// such nodes. But such nodes may still have dangling volumes on them and hence we need to scan all the
// remaining nodes which weren't scanned by code previously.
vs.BuildMissingVolumeNodeMap(ctx)
// any volume which we could not verify will be removed from the map. // any volume which we could not verify will be removed from the map.
vs.vsphereVolumeMap.RemoveUnverified() vs.vsphereVolumeMap.RemoveUnverified()
klog.V(4).Infof("DisksAreAttach successfully executed. result: %+v", attached) klog.V(4).Infof("current node volume map is: %+v", vs.vsphereVolumeMap.volumeNodeMap)
return disksAttached, nil return disksAttached, nil
} }
requestTime := time.Now() requestTime := time.Now()
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"time" "time"
"github.com/vmware/govmomi/find" "github.com/vmware/govmomi/find"
...@@ -608,6 +609,123 @@ func (vs *VSphere) checkDiskAttached(ctx context.Context, nodes []k8stypes.NodeN ...@@ -608,6 +609,123 @@ func (vs *VSphere) checkDiskAttached(ctx context.Context, nodes []k8stypes.NodeN
return nodesToRetry, nil return nodesToRetry, nil
} }
// BuildMissingVolumeNodeMap builds a map of volumes and nodes which are not known to attach detach controller.
// There could be nodes in cluster which do not have any pods with vsphere volumes running on them
// such nodes won't be part of disk verification check because attach-detach controller does not keep track
// such nodes. But such nodes may still have dangling volumes on them and hence we need to scan all the
// remaining nodes which weren't scanned by code previously.
func (vs *VSphere) BuildMissingVolumeNodeMap(ctx context.Context) {
nodeNames := vs.nodeManager.GetNodeNames()
// Segregate nodes according to VC-DC
dcNodes := make(map[string][]k8stypes.NodeName)
for _, nodeName := range nodeNames {
// if given node is not in node volume map
if !vs.vsphereVolumeMap.CheckForNode(nodeName) {
nodeInfo, err := vs.nodeManager.GetNodeInfo(nodeName)
if err != nil {
klog.V(4).Infof("Failed to get node info: %+v. err: %+v", nodeInfo.vm, err)
continue
}
vcDC := nodeInfo.vcServer + nodeInfo.dataCenter.String()
dcNodes[vcDC] = append(dcNodes[vcDC], nodeName)
}
}
var wg sync.WaitGroup
for _, nodeNames := range dcNodes {
// Start go routines per VC-DC to check disks are attached
wg.Add(1)
go func(nodes []k8stypes.NodeName) {
err := vs.checkNodeDisks(ctx, nodes)
if err != nil {
klog.Errorf("Failed to check disk attached for nodes: %+v. err: %+v", nodes, err)
}
wg.Done()
}(nodeNames)
}
wg.Wait()
}
func (vs *VSphere) checkNodeDisks(ctx context.Context, nodeNames []k8stypes.NodeName) error {
var vmList []*vclib.VirtualMachine
var nodeInfo NodeInfo
var err error
for _, nodeName := range nodeNames {
nodeInfo, err = vs.nodeManager.GetNodeInfo(nodeName)
if err != nil {
return err
}
vmList = append(vmList, nodeInfo.vm)
}
// Making sure session is valid
_, err = vs.getVSphereInstanceForServer(nodeInfo.vcServer, ctx)
if err != nil {
return err
}
// If any of the nodes are not present property collector query will fail for entire operation
vmMoList, err := nodeInfo.dataCenter.GetVMMoList(ctx, vmList, []string{"config.hardware.device", "name", "config.uuid"})
if err != nil {
if vclib.IsManagedObjectNotFoundError(err) {
klog.V(4).Infof("checkNodeDisks: ManagedObjectNotFound for property collector query for nodes: %+v vms: %+v", nodeNames, vmList)
// Property Collector Query failed
// VerifyVolumePaths per VM
for _, nodeName := range nodeNames {
nodeInfo, err := vs.nodeManager.GetNodeInfo(nodeName)
if err != nil {
return err
}
devices, err := nodeInfo.vm.VirtualMachine.Device(ctx)
if err != nil {
if vclib.IsManagedObjectNotFoundError(err) {
klog.V(4).Infof("checkNodeDisks: ManagedObjectNotFound for Kubernetes node: %s with vSphere Virtual Machine reference: %v", nodeName, nodeInfo.vm)
continue
}
return err
}
klog.V(4).Infof("Verifying Volume Paths by devices for node %s and VM %s", nodeName, nodeInfo.vm)
vs.vsphereVolumeMap.Add(nodeName, devices)
}
return nil
}
return err
}
vmMoMap := make(map[string]mo.VirtualMachine)
for _, vmMo := range vmMoList {
if vmMo.Config == nil {
klog.Errorf("Config is not available for VM: %q", vmMo.Name)
continue
}
klog.V(9).Infof("vmMoMap vmname: %q vmuuid: %s", vmMo.Name, strings.ToLower(vmMo.Config.Uuid))
vmMoMap[strings.ToLower(vmMo.Config.Uuid)] = vmMo
}
klog.V(9).Infof("vmMoMap: +%v", vmMoMap)
for _, nodeName := range nodeNames {
node, err := vs.nodeManager.GetNode(nodeName)
if err != nil {
return err
}
nodeUUID, err := GetNodeUUID(&node)
if err != nil {
klog.Errorf("Node Discovery failed to get node uuid for node %s with error: %v", node.Name, err)
return err
}
nodeUUID = strings.ToLower(nodeUUID)
klog.V(9).Infof("Verifying volume for node %s with nodeuuid %q: %v", nodeName, nodeUUID, vmMoMap)
vmMo := vmMoMap[nodeUUID]
vmDevices := object.VirtualDeviceList(vmMo.Config.Hardware.Device)
vs.vsphereVolumeMap.Add(nodeName, vmDevices)
}
return nil
}
func (vs *VSphere) GetNodeNameFromProviderID(providerID string) (string, error) { func (vs *VSphere) GetNodeNameFromProviderID(providerID string) (string, error) {
var nodeName string var nodeName string
nodes, err := vs.nodeManager.GetNodeDetails() nodes, err := vs.nodeManager.GetNodeDetails()
......
...@@ -36,12 +36,14 @@ type nodeVolumeStatus struct { ...@@ -36,12 +36,14 @@ type nodeVolumeStatus struct {
// VsphereVolumeMap stores last known state of node and volume mapping // VsphereVolumeMap stores last known state of node and volume mapping
type VsphereVolumeMap struct { type VsphereVolumeMap struct {
volumeNodeMap map[volumePath]nodeVolumeStatus volumeNodeMap map[volumePath]nodeVolumeStatus
nodeMap map[k8stypes.NodeName]bool
lock sync.RWMutex lock sync.RWMutex
} }
func NewVsphereVolumeMap() *VsphereVolumeMap { func NewVsphereVolumeMap() *VsphereVolumeMap {
return &VsphereVolumeMap{ return &VsphereVolumeMap{
volumeNodeMap: map[volumePath]nodeVolumeStatus{}, volumeNodeMap: map[volumePath]nodeVolumeStatus{},
nodeMap: map[k8stypes.NodeName]bool{},
} }
} }
...@@ -54,6 +56,9 @@ func (vsphereVolume *VsphereVolumeMap) StartDiskVerification() { ...@@ -54,6 +56,9 @@ func (vsphereVolume *VsphereVolumeMap) StartDiskVerification() {
v.verified = false v.verified = false
vsphereVolume.volumeNodeMap[k] = v vsphereVolume.volumeNodeMap[k] = v
} }
// reset nodeMap to empty so that any node we could not verify via usual verification process
// can still be verified.
vsphereVolume.nodeMap = map[k8stypes.NodeName]bool{}
} }
// CheckForVolume verifies if disk is attached to some node in the cluster. // CheckForVolume verifies if disk is attached to some node in the cluster.
...@@ -69,6 +74,16 @@ func (vsphereVolume *VsphereVolumeMap) CheckForVolume(path string) (k8stypes.Nod ...@@ -69,6 +74,16 @@ func (vsphereVolume *VsphereVolumeMap) CheckForVolume(path string) (k8stypes.Nod
return "", false return "", false
} }
// CheckForNode returns true if given node has already been processed by volume
// verification mechanism. This is used to skip verifying attached disks on nodes
// which were previously verified.
func (vsphereVolume *VsphereVolumeMap) CheckForNode(nodeName k8stypes.NodeName) bool {
vsphereVolume.lock.RLock()
defer vsphereVolume.lock.RUnlock()
_, ok := vsphereVolume.nodeMap[nodeName]
return ok
}
// Add all devices found on a node to the device map // Add all devices found on a node to the device map
func (vsphereVolume *VsphereVolumeMap) Add(node k8stypes.NodeName, vmDevices object.VirtualDeviceList) { func (vsphereVolume *VsphereVolumeMap) Add(node k8stypes.NodeName, vmDevices object.VirtualDeviceList) {
vsphereVolume.lock.Lock() vsphereVolume.lock.Lock()
...@@ -79,6 +94,7 @@ func (vsphereVolume *VsphereVolumeMap) Add(node k8stypes.NodeName, vmDevices obj ...@@ -79,6 +94,7 @@ func (vsphereVolume *VsphereVolumeMap) Add(node k8stypes.NodeName, vmDevices obj
if backing, ok := virtualDevice.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok { if backing, ok := virtualDevice.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok {
filename := volumePath(backing.FileName) filename := volumePath(backing.FileName)
vsphereVolume.volumeNodeMap[filename] = nodeVolumeStatus{node, true} vsphereVolume.volumeNodeMap[filename] = nodeVolumeStatus{node, true}
vsphereVolume.nodeMap[node] = true
} }
} }
} }
...@@ -91,6 +107,7 @@ func (vsphereVolume *VsphereVolumeMap) RemoveUnverified() { ...@@ -91,6 +107,7 @@ func (vsphereVolume *VsphereVolumeMap) RemoveUnverified() {
for k, v := range vsphereVolume.volumeNodeMap { for k, v := range vsphereVolume.volumeNodeMap {
if !v.verified { if !v.verified {
delete(vsphereVolume.volumeNodeMap, k) delete(vsphereVolume.volumeNodeMap, k)
delete(vsphereVolume.nodeMap, v.nodeName)
} }
} }
} }
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