diff --git a/glide.lock b/glide.lock index b86cdd98ff..79bf684d1e 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: bf18ba8a038a73e8f11f808c8babdd34734279b050e0223f704eaabbd13830fd -updated: 2017-08-05T10:03:09.300557448-04:00 +hash: 6ccf8e8213eb31f9dd31b46c3aa3c2c01929c6230fb049cfabcabd498ade9c30 +updated: 2017-10-16T14:31:20.353977552-04:00 imports: - name: github.com/davecgh/go-spew version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d @@ -33,31 +33,8 @@ imports: - name: github.com/gogo/protobuf version: c0656edd0d9eab7c66d1eb0c568f9039345796f7 subpackages: - - gogoproto - - plugin/compare - - plugin/defaultcheck - - plugin/description - - plugin/embedcheck - - plugin/enumstringer - - plugin/equal - - plugin/face - - plugin/gostring - - plugin/marshalto - - plugin/oneofcheck - - plugin/populate - - plugin/size - - plugin/stringer - - plugin/testgen - - plugin/union - - plugin/unmarshal - proto - - protoc-gen-gogo/descriptor - - protoc-gen-gogo/generator - - protoc-gen-gogo/grpc - - protoc-gen-gogo/plugin - sortkeys - - vanity - - vanity/command - name: github.com/golang/glog version: 44145f04b68cf362d9c4df2182967c2275eaefed - name: github.com/google/gofuzz @@ -94,27 +71,19 @@ imports: version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74 subpackages: - codec - - codec/codecgen - name: golang.org/x/crypto version: d172538b2cfce0c13cee31e647d0367aa8cd2486 subpackages: - bcrypt - blowfish - - curve25519 - - ed25519 - - ed25519/internal/edwards25519 - nacl/secretbox - - pkcs12 - - pkcs12/internal/rc2 - poly1305 - salsa20/salsa - - ssh - ssh/terminal - name: golang.org/x/net version: f2499483f923065a842d38eb4c7f1927e6fc6e6d subpackages: - context - - context/ctxhttp - html - html/atom - http2 @@ -122,24 +91,17 @@ imports: - idna - internal/timeseries - lex/httplex - - proxy - trace - websocket - name: golang.org/x/sys version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 subpackages: - unix - - windows - name: golang.org/x/text version: 2910a502d2bf9e43193af9d68ca516529614eed3 subpackages: - cases - - encoding - - encoding/internal - - encoding/internal/identifier - - encoding/unicode - internal/tag - - internal/utf8internal - language - runes - secure/bidirule @@ -153,7 +115,7 @@ imports: - name: gopkg.in/yaml.v2 version: 53feefa2559fb8dfa8d81baad31be332c97d6c77 - name: k8s.io/apimachinery - version: abe34e4f5b4413c282a83011892cbeea5b32223b + version: 917740426ad66ff818da4809990480bcc0786a77 subpackages: - pkg/api/equality - pkg/api/errors @@ -200,11 +162,15 @@ imports: - pkg/watch - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: ab57ed5a72c3b67058f665d660e23bae18339fc2 + version: a7f02eb8e3920e446965036c9610ec52a7ede92f + subpackages: + - pkg/util/flag + - pkg/util/logs - name: k8s.io/client-go - version: e356aa2e77ab4a5914c216c12ba14cce25a25ab0 + version: ec52d278b25c8fef82a965d93afdc74771ea6963 subpackages: - discovery + - discovery/fake - kubernetes/scheme - pkg/api - pkg/api/v1 @@ -245,6 +211,7 @@ imports: - pkg/version - rest - rest/watch + - testing - tools/auth - tools/cache - tools/clientcmd @@ -260,7 +227,7 @@ imports: - name: k8s.io/gengo version: c79c13d131b0a8f42d05faa6491c12e94ccc6f30 - name: k8s.io/kubernetes - version: ebb8d6e0fadfc95f3d64ccecc36c8ed2ac9224ef + version: 4bc5e7f9a6c25dc4c03d4d656f2cefd21540e28c subpackages: - pkg/api - pkg/api/install @@ -312,27 +279,48 @@ imports: - pkg/apis/storage/v1 - pkg/apis/storage/v1beta1 - pkg/client/clientset_generated/clientset + - pkg/client/clientset_generated/clientset/fake - pkg/client/clientset_generated/clientset/scheme - pkg/client/clientset_generated/clientset/typed/admissionregistration/v1alpha1 + - pkg/client/clientset_generated/clientset/typed/admissionregistration/v1alpha1/fake - pkg/client/clientset_generated/clientset/typed/apps/v1beta1 + - pkg/client/clientset_generated/clientset/typed/apps/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/authentication/v1 + - pkg/client/clientset_generated/clientset/typed/authentication/v1/fake - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1 + - pkg/client/clientset_generated/clientset/typed/authentication/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/authorization/v1 + - pkg/client/clientset_generated/clientset/typed/authorization/v1/fake - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1 + - pkg/client/clientset_generated/clientset/typed/authorization/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/autoscaling/v1 + - pkg/client/clientset_generated/clientset/typed/autoscaling/v1/fake - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1 + - pkg/client/clientset_generated/clientset/typed/autoscaling/v2alpha1/fake - pkg/client/clientset_generated/clientset/typed/batch/v1 + - pkg/client/clientset_generated/clientset/typed/batch/v1/fake - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1 + - pkg/client/clientset_generated/clientset/typed/batch/v2alpha1/fake - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1 + - pkg/client/clientset_generated/clientset/typed/certificates/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/core/v1 + - pkg/client/clientset_generated/clientset/typed/core/v1/fake - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1 + - pkg/client/clientset_generated/clientset/typed/extensions/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/networking/v1 + - pkg/client/clientset_generated/clientset/typed/networking/v1/fake - pkg/client/clientset_generated/clientset/typed/policy/v1beta1 + - pkg/client/clientset_generated/clientset/typed/policy/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1 + - pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1/fake - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1 + - pkg/client/clientset_generated/clientset/typed/rbac/v1beta1/fake - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1 + - pkg/client/clientset_generated/clientset/typed/settings/v1alpha1/fake - pkg/client/clientset_generated/clientset/typed/storage/v1 + - pkg/client/clientset_generated/clientset/typed/storage/v1/fake - pkg/client/clientset_generated/clientset/typed/storage/v1beta1 + - pkg/client/clientset_generated/clientset/typed/storage/v1beta1/fake - pkg/client/listers/core/v1 - pkg/kubelet/types - pkg/util diff --git a/glide.yaml b/glide.yaml index 2c9702e415..3fd7c16417 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,13 +1,13 @@ package: github.com/kubernetes-incubator/descheduler import: - package: k8s.io/client-go - version: e356aa2e77ab4a5914c216c12ba14cce25a25ab0 # kube 1.7.0 + version: ec52d278b25c8fef82a965d93afdc74771ea6963 - package: k8s.io/apiserver - version: ab57ed5a72c3b67058f665d660e23bae18339fc2 + version: release-1.7 - package: k8s.io/apimachinery - version: abe34e4f5b4413c282a83011892cbeea5b32223b # kube 1.7.0 + version: 917740426ad66ff818da4809990480bcc0786a77 - package: k8s.io/kubernetes - version: ebb8d6e0fadfc95f3d64ccecc36c8ed2ac9224ef # kube 1.7.0 + version: 1.7.6 - package: github.com/kubernetes/repo-infra - package: github.com/spf13/cobra version: f62e98d28ab7ad31d707ba837a966378465c7b57 diff --git a/pkg/descheduler/pod/pods_test.go b/pkg/descheduler/pod/pods_test.go index 4802968e35..336566aca9 100644 --- a/pkg/descheduler/pod/pods_test.go +++ b/pkg/descheduler/pod/pods_test.go @@ -46,7 +46,7 @@ func TestPodTypes(t *testing.T) { VolumeSource: v1.VolumeSource{ HostPath: &v1.HostPathVolumeSource{Path: "somePath"}, EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(int64(10), resource.BinarySI)}, + SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)}, }, }, } diff --git a/pkg/descheduler/strategies/duplicates_test.go b/pkg/descheduler/strategies/duplicates_test.go index 4ee448d155..89d6833a72 100644 --- a/pkg/descheduler/strategies/duplicates_test.go +++ b/pkg/descheduler/strategies/duplicates_test.go @@ -54,7 +54,7 @@ func TestFindDuplicatePods(t *testing.T) { VolumeSource: v1.VolumeSource{ HostPath: &v1.HostPathVolumeSource{Path: "somePath"}, EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(int64(10), resource.BinarySI)}, + SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)}, }, }, } diff --git a/pkg/descheduler/strategies/lownodeutilization_test.go b/pkg/descheduler/strategies/lownodeutilization_test.go index 65db0dfd78..e1f332c0af 100644 --- a/pkg/descheduler/strategies/lownodeutilization_test.go +++ b/pkg/descheduler/strategies/lownodeutilization_test.go @@ -67,7 +67,7 @@ func TestLowNodeUtilization(t *testing.T) { VolumeSource: v1.VolumeSource{ HostPath: &v1.HostPathVolumeSource{Path: "somePath"}, EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(int64(10), resource.BinarySI)}, + SizeLimit: resource.NewQuantity(int64(10), resource.BinarySI)}, }, }, } diff --git a/vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go b/vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go index ad300e28b5..12bef075da 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go +++ b/vendor/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go @@ -158,15 +158,16 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) { return nil, err } - if s.tlsConfig == nil { - s.tlsConfig = &tls.Config{} + tlsConfig := s.tlsConfig + switch { + case tlsConfig == nil: + tlsConfig = &tls.Config{ServerName: host} + case len(tlsConfig.ServerName) == 0: + tlsConfig = tlsConfig.Clone() + tlsConfig.ServerName = host } - if len(s.tlsConfig.ServerName) == 0 { - s.tlsConfig.ServerName = host - } - - tlsConn := tls.Client(rwc, s.tlsConfig) + tlsConn := tls.Client(rwc, tlsConfig) // need to manually call Handshake() so we can call VerifyHostname() below if err := tlsConn.Handshake(); err != nil { @@ -174,11 +175,11 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) { } // Return if we were configured to skip validation - if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify { + if tlsConfig.InsecureSkipVerify { return tlsConn, nil } - if err := tlsConn.VerifyHostname(host); err != nil { + if err := tlsConn.VerifyHostname(tlsConfig.ServerName); err != nil { return nil, err } @@ -218,6 +219,9 @@ func (s *SpdyRoundTripper) dialWithoutProxy(url *url.URL) (net.Conn, error) { if err != nil { return nil, err } + if s.tlsConfig != nil && len(s.tlsConfig.ServerName) > 0 { + host = s.tlsConfig.ServerName + } err = conn.VerifyHostname(host) if err != nil { return nil, err diff --git a/vendor/k8s.io/apiserver/Godeps/Godeps.json b/vendor/k8s.io/apiserver/Godeps/Godeps.json index d973c75dbf..89b9bc8272 100644 --- a/vendor/k8s.io/apiserver/Godeps/Godeps.json +++ b/vendor/k8s.io/apiserver/Godeps/Godeps.json @@ -1,1764 +1,1526 @@ { - "ImportPath": "k8s.io/apiserver", - "GoVersion": "go1.8", - "GodepVersion": "v79", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "bitbucket.org/ww/goautoneg", - "Comment": "null-5", - "Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675" - }, - { - "ImportPath": "github.com/PuerkitoBio/purell", - "Comment": "v1.0.0", - "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" - }, - { - "ImportPath": "github.com/PuerkitoBio/urlesc", - "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" - }, - { - "ImportPath": "github.com/beorn7/perks/quantile", - "Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4" - }, - { - "ImportPath": "github.com/boltdb/bolt", - "Comment": "v1.3.0", - "Rev": "583e8937c61f1af6513608ccc75c97b6abdf4ff9" - }, - { - "ImportPath": "github.com/coreos/etcd/alarm", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/auth", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/auth/authpb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/client", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/clientv3", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/compactor", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/discovery", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/error", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/api", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http/httptypes", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/auth", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/etcdserverpb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/membership", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/etcdserver/stats", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/integration", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/lease", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/lease/leasehttp", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/lease/leasepb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/mvcc", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/mvcc/backend", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/mvcc/mvccpb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/adt", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/contention", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/cpuutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/crc", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/fileutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/httputil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/idutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/ioutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/logutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/monotime", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/netutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/pathutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/pbutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/runtime", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/schedule", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/testutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/tlsutil", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/transport", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/types", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/pkg/wait", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy/cache", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/raft", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/raft/raftpb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/rafthttp", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/snap", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/snap/snappb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/store", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/version", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/wal", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/etcd/wal/walpb", - "Comment": "v3.1.5", - "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" - }, - { - "ImportPath": "github.com/coreos/go-oidc/http", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/jose", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/key", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/oauth2", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/oidc", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-semver/semver", - "Rev": "568e959cd89871e61434c1143528d9162da89ef2" - }, - { - "ImportPath": "github.com/coreos/go-systemd/daemon", - "Comment": "v14", - "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" - }, - { - "ImportPath": "github.com/coreos/go-systemd/journal", - "Comment": "v14", - "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" - }, - { - "ImportPath": "github.com/coreos/pkg/capnslog", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/coreos/pkg/health", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/coreos/pkg/httputil", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/coreos/pkg/timeutil", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/davecgh/go-spew/spew", - "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d" - }, - { - "ImportPath": "github.com/docker/distribution/digest", - "Comment": "v2.4.0-rc.1-38-gcd27f17", - "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" - }, - { - "ImportPath": "github.com/docker/distribution/reference", - "Comment": "v2.4.0-rc.1-38-gcd27f17", - "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" - }, - { - "ImportPath": "github.com/elazarl/go-bindata-assetfs", - "Rev": "3dcc96556217539f50599357fb481ac0dc7439b9" - }, - { - "ImportPath": "github.com/emicklei/go-restful", - "Comment": "2.2.0-4-gff4f55a", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/emicklei/go-restful-swagger12", - "Comment": "1.0.1", - "Rev": "dcef7f55730566d41eae5db10e7d6981829720f6" - }, - { - "ImportPath": "github.com/emicklei/go-restful/log", - "Comment": "2.2.0-4-gff4f55a", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/evanphx/json-patch", - "Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" - }, - { - "ImportPath": "github.com/ghodss/yaml", - "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" - }, - { - "ImportPath": "github.com/go-openapi/analysis", - "Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b" - }, - { - "ImportPath": "github.com/go-openapi/jsonpointer", - "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" - }, - { - "ImportPath": "github.com/go-openapi/jsonreference", - "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" - }, - { - "ImportPath": "github.com/go-openapi/loads", - "Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38" - }, - { - "ImportPath": "github.com/go-openapi/spec", - "Rev": "6aced65f8501fe1217321abf0749d354824ba2ff" - }, - { - "ImportPath": "github.com/go-openapi/swag", - "Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72" - }, - { - "ImportPath": "github.com/gogo/protobuf/proto", - "Comment": "v0.4-3-gc0656ed", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/sortkeys", - "Comment": "v0.4-3-gc0656ed", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/golang/glog", - "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" - }, - { - "ImportPath": "github.com/golang/protobuf/jsonpb", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/golang/protobuf/proto", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/any", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/duration", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/golang/protobuf/ptypes/timestamp", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/google/btree", - "Rev": "7d79101e329e5a3adf994758c578dab82b90c017" - }, - { - "ImportPath": "github.com/google/gofuzz", - "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" - }, - { - "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", - "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" - }, - { - "ImportPath": "github.com/googleapis/gnostic/compiler", - "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" - }, - { - "ImportPath": "github.com/googleapis/gnostic/extensions", - "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" - }, - { - "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", - "Comment": "v1.1-4-g2500245", - "Rev": "2500245aa6110c562d17020fb31a2c133d737799" - }, - { - "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime", - "Comment": "v1.1.0-25-g84398b9", - "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" - }, - { - "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime/internal", - "Comment": "v1.1.0-25-g84398b9", - "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" - }, - { - "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/utilities", - "Comment": "v1.1.0-25-g84398b9", - "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" - }, - { - "ImportPath": "github.com/hashicorp/golang-lru", - "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" - }, - { - "ImportPath": "github.com/hashicorp/golang-lru/simplelru", - "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" - }, - { - "ImportPath": "github.com/howeyc/gopass", - "Rev": "bf9dde6d0d2c004a008c27aaee91170c786f6db8" - }, - { - "ImportPath": "github.com/imdario/mergo", - "Comment": "0.1.3-8-g6633656", - "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" - }, - { - "ImportPath": "github.com/jonboulle/clockwork", - "Rev": "72f9bd7c4e0c2a40055ab3d0f09654f730cce982" - }, - { - "ImportPath": "github.com/juju/ratelimit", - "Rev": "5b9ff866471762aa2ab2dced63c9fb6f53921342" - }, - { - "ImportPath": "github.com/karlseguin/ccache", - "Comment": "v2.0.2-5-g3ba9789", - "Rev": "3ba9789cfd2cb7b4fb4657efc994cc1c599a648c" - }, - { - "ImportPath": "github.com/mailru/easyjson/buffer", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/mailru/easyjson/jlexer", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/mailru/easyjson/jwriter", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil", - "Rev": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a" - }, - { - "ImportPath": "github.com/mxk/go-flowrate/flowrate", - "Rev": "cca7078d478f8520f85629ad7c68962d31ed7682" - }, - { - "ImportPath": "github.com/pborman/uuid", - "Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4" - }, - { - "ImportPath": "github.com/pkg/errors", - "Comment": "v0.7.0-13-ga221380", - "Rev": "a22138067af1c4942683050411a841ade67fe1eb" - }, - { - "ImportPath": "github.com/pmezard/go-difflib/difflib", - "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" - }, - { - "ImportPath": "github.com/prometheus/client_golang/prometheus", - "Comment": "v0.8.0-83-ge7e9030", - "Rev": "e7e903064f5e9eb5da98208bae10b475d4db0f8c" - }, - { - "ImportPath": "github.com/prometheus/client_model/go", - "Comment": "model-0.0.2-12-gfa8ad6f", - "Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6" - }, - { - "ImportPath": "github.com/prometheus/common/expfmt", - "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" - }, - { - "ImportPath": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg", - "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" - }, - { - "ImportPath": "github.com/prometheus/common/model", - "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" - }, - { - "ImportPath": "github.com/prometheus/procfs", - "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" - }, - { - "ImportPath": "github.com/prometheus/procfs/xfs", - "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" - }, - { - "ImportPath": "github.com/spf13/pflag", - "Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7" - }, - { - "ImportPath": "github.com/stretchr/testify/assert", - "Comment": "v1.0-88-ge3a8ff8", - "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" - }, - { - "ImportPath": "github.com/stretchr/testify/require", - "Comment": "v1.0-88-ge3a8ff8", - "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" - }, - { - "ImportPath": "github.com/ugorji/go/codec", - "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" - }, - { - "ImportPath": "github.com/xiang90/probing", - "Rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2" - }, - { - "ImportPath": "golang.org/x/crypto/bcrypt", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/crypto/blowfish", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/crypto/nacl/secretbox", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/crypto/poly1305", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/crypto/salsa20/salsa", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/crypto/ssh/terminal", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/net/context", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/html", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/html/atom", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/http2", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/http2/hpack", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/idna", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/internal/timeseries", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/lex/httplex", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/trace", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/websocket", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/sys/unix", - "Rev": "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9" - }, - { - "ImportPath": "golang.org/x/text/cases", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/internal/tag", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/language", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/runes", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/secure/bidirule", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/secure/precis", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/transform", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/unicode/bidi", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/unicode/norm", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/width", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/time/rate", - "Rev": "f51c12702a4d776e4c1fa9b0fabab841babae631" - }, - { - "ImportPath": "google.golang.org/grpc", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/codes", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/credentials", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/grpclog", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/internal", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/metadata", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/naming", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/peer", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "google.golang.org/grpc/transport", - "Comment": "v1.0.4", - "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" - }, - { - "ImportPath": "gopkg.in/inf.v0", - "Comment": "v0.9.0", - "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" - }, - { - "ImportPath": "gopkg.in/natefinch/lumberjack.v2", - "Comment": "v1.0-16-g20b71e5", - "Rev": "20b71e5b60d756d3d2f80def009790325acc2b23" - }, - { - "ImportPath": "gopkg.in/yaml.v2", - "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/equality", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/errors", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/meta", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/resource", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/testing", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/validation", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/validation/path", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/validation", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion/unstructured", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/fields", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/labels", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/openapi", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/selection", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/types", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/cache", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/clock", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/diff", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/errors", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/framer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/net", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/rand", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/sets", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/uuid", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/wait", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/version", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/watch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/client-go/discovery", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/discovery/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/admissionregistration", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/admissionregistration/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/apps", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/apps/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/autoscaling", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/autoscaling/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/autoscaling/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/batch", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/batch/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/batch/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/certificates", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/certificates/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/core", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/core/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/extensions", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/extensions/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/internalinterfaces", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/networking", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/networking/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/policy", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/policy/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/rbac", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/rbac/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/rbac/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/settings", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/settings/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/storage", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/storage/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/informers/storage/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/scheme", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2alpha1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/admissionregistration/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/apps/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/autoscaling/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/autoscaling/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/batch/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/batch/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/certificates/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/core/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/extensions/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/networking/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/policy/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/rbac/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/rbac/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/settings/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/storage/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/listers/storage/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/api", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/api/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/api/v1/ref", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/admissionregistration", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/admissionregistration/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/apps", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/apps/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authentication", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authentication/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authentication/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authorization", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authorization/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/authorization/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/batch", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/batch/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/batch/v2alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/certificates", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/certificates/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/extensions", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/extensions/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/networking", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/networking/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/policy", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/policy/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/rbac", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/rbac/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/rbac/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/settings", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/settings/v1alpha1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/storage", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/storage/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/apis/storage/v1beta1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/util", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/util/parsers", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/pkg/version", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/rest", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/rest/watch", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/testing", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/auth", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/cache", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api/latest", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/clientcmd/api/v1", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/tools/metrics", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/transport", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/util/cert", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/util/flowcontrol", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/util/homedir", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - }, - { - "ImportPath": "k8s.io/client-go/util/integer", - "Comment": "v2.0.0-alpha.0-398-gcc44961", - "Rev": "cc44961f935a644fb82c0f4b6591543704578db7" - } - ] + "ImportPath": "k8s.io/apiserver", + "GoVersion": "go1.8", + "GodepVersion": "v79", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "bitbucket.org/ww/goautoneg", + "Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675" + }, + { + "ImportPath": "github.com/PuerkitoBio/purell", + "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" + }, + { + "ImportPath": "github.com/PuerkitoBio/urlesc", + "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" + }, + { + "ImportPath": "github.com/beorn7/perks/quantile", + "Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4" + }, + { + "ImportPath": "github.com/boltdb/bolt", + "Rev": "583e8937c61f1af6513608ccc75c97b6abdf4ff9" + }, + { + "ImportPath": "github.com/coreos/etcd/alarm", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/auth", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/auth/authpb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/client", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/clientv3", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/compactor", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/discovery", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/error", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/api", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http/httptypes", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/auth", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/etcdserverpb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/membership", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/stats", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/integration", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/lease", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/lease/leasehttp", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/lease/leasepb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc/backend", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc/mvccpb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/adt", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/contention", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/cpuutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/crc", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/fileutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/httputil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/idutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/ioutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/logutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/monotime", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/netutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/pathutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/pbutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/runtime", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/schedule", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/testutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/tlsutil", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/transport", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/types", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/wait", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy/cache", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/raft", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/raft/raftpb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/rafthttp", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/snap", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/snap/snappb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/store", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/version", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/wal", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/etcd/wal/walpb", + "Rev": "20490caaf0dcd96bb4a95e40625559def8ef5b04" + }, + { + "ImportPath": "github.com/coreos/go-oidc/http", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/jose", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/key", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/oauth2", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/oidc", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-semver/semver", + "Rev": "568e959cd89871e61434c1143528d9162da89ef2" + }, + { + "ImportPath": "github.com/coreos/go-systemd/daemon", + "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" + }, + { + "ImportPath": "github.com/coreos/go-systemd/journal", + "Rev": "48702e0da86bd25e76cfef347e2adeb434a0d0a6" + }, + { + "ImportPath": "github.com/coreos/pkg/capnslog", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/coreos/pkg/health", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/coreos/pkg/httputil", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/coreos/pkg/timeutil", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/davecgh/go-spew/spew", + "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d" + }, + { + "ImportPath": "github.com/docker/distribution/digest", + "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" + }, + { + "ImportPath": "github.com/docker/distribution/reference", + "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" + }, + { + "ImportPath": "github.com/elazarl/go-bindata-assetfs", + "Rev": "3dcc96556217539f50599357fb481ac0dc7439b9" + }, + { + "ImportPath": "github.com/emicklei/go-restful", + "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" + }, + { + "ImportPath": "github.com/emicklei/go-restful-swagger12", + "Rev": "dcef7f55730566d41eae5db10e7d6981829720f6" + }, + { + "ImportPath": "github.com/emicklei/go-restful/log", + "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" + }, + { + "ImportPath": "github.com/evanphx/json-patch", + "Rev": "ba18e35c5c1b36ef6334cad706eb681153d2d379" + }, + { + "ImportPath": "github.com/ghodss/yaml", + "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" + }, + { + "ImportPath": "github.com/go-openapi/analysis", + "Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b" + }, + { + "ImportPath": "github.com/go-openapi/jsonpointer", + "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" + }, + { + "ImportPath": "github.com/go-openapi/jsonreference", + "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" + }, + { + "ImportPath": "github.com/go-openapi/loads", + "Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38" + }, + { + "ImportPath": "github.com/go-openapi/spec", + "Rev": "6aced65f8501fe1217321abf0749d354824ba2ff" + }, + { + "ImportPath": "github.com/go-openapi/swag", + "Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72" + }, + { + "ImportPath": "github.com/gogo/protobuf/proto", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/gogo/protobuf/sortkeys", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/golang/glog", + "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" + }, + { + "ImportPath": "github.com/golang/protobuf/jsonpb", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/golang/protobuf/proto", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/any", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/duration", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/golang/protobuf/ptypes/timestamp", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/google/btree", + "Rev": "7d79101e329e5a3adf994758c578dab82b90c017" + }, + { + "ImportPath": "github.com/google/gofuzz", + "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" + }, + { + "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", + "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" + }, + { + "ImportPath": "github.com/googleapis/gnostic/compiler", + "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" + }, + { + "ImportPath": "github.com/googleapis/gnostic/extensions", + "Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/gophercloud/gophercloud/pagination", + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" + }, + { + "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", + "Rev": "2500245aa6110c562d17020fb31a2c133d737799" + }, + { + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime", + "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" + }, + { + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime/internal", + "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" + }, + { + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/utilities", + "Rev": "84398b94e188ee336f307779b57b3aa91af7063c" + }, + { + "ImportPath": "github.com/hashicorp/golang-lru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + }, + { + "ImportPath": "github.com/hashicorp/golang-lru/simplelru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + }, + { + "ImportPath": "github.com/howeyc/gopass", + "Rev": "bf9dde6d0d2c004a008c27aaee91170c786f6db8" + }, + { + "ImportPath": "github.com/imdario/mergo", + "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" + }, + { + "ImportPath": "github.com/jonboulle/clockwork", + "Rev": "72f9bd7c4e0c2a40055ab3d0f09654f730cce982" + }, + { + "ImportPath": "github.com/juju/ratelimit", + "Rev": "5b9ff866471762aa2ab2dced63c9fb6f53921342" + }, + { + "ImportPath": "github.com/karlseguin/ccache", + "Rev": "3ba9789cfd2cb7b4fb4657efc994cc1c599a648c" + }, + { + "ImportPath": "github.com/mailru/easyjson/buffer", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/mailru/easyjson/jlexer", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/mailru/easyjson/jwriter", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil", + "Rev": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a" + }, + { + "ImportPath": "github.com/mxk/go-flowrate/flowrate", + "Rev": "cca7078d478f8520f85629ad7c68962d31ed7682" + }, + { + "ImportPath": "github.com/pborman/uuid", + "Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4" + }, + { + "ImportPath": "github.com/pkg/errors", + "Rev": "a22138067af1c4942683050411a841ade67fe1eb" + }, + { + "ImportPath": "github.com/pmezard/go-difflib/difflib", + "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" + }, + { + "ImportPath": "github.com/prometheus/client_golang/prometheus", + "Rev": "e7e903064f5e9eb5da98208bae10b475d4db0f8c" + }, + { + "ImportPath": "github.com/prometheus/client_model/go", + "Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6" + }, + { + "ImportPath": "github.com/prometheus/common/expfmt", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" + }, + { + "ImportPath": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" + }, + { + "ImportPath": "github.com/prometheus/common/model", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" + }, + { + "ImportPath": "github.com/prometheus/procfs", + "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" + }, + { + "ImportPath": "github.com/prometheus/procfs/xfs", + "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" + }, + { + "ImportPath": "github.com/spf13/pflag", + "Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7" + }, + { + "ImportPath": "github.com/stretchr/testify/assert", + "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" + }, + { + "ImportPath": "github.com/stretchr/testify/require", + "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" + }, + { + "ImportPath": "github.com/ugorji/go/codec", + "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" + }, + { + "ImportPath": "github.com/xiang90/probing", + "Rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2" + }, + { + "ImportPath": "golang.org/x/crypto/bcrypt", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/crypto/blowfish", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/crypto/nacl/secretbox", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/crypto/poly1305", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/crypto/salsa20/salsa", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/crypto/ssh/terminal", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/net/context", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/html", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/html/atom", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/http2", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/http2/hpack", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/idna", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/internal/timeseries", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/lex/httplex", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/trace", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/websocket", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9" + }, + { + "ImportPath": "golang.org/x/text/cases", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/internal/tag", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/language", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/runes", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/secure/bidirule", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/secure/precis", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/transform", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/unicode/bidi", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/unicode/norm", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/width", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/time/rate", + "Rev": "f51c12702a4d776e4c1fa9b0fabab841babae631" + }, + { + "ImportPath": "google.golang.org/grpc", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/codes", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/credentials", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/grpclog", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/internal", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/metadata", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/naming", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/peer", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "google.golang.org/grpc/transport", + "Rev": "777daa17ff9b5daef1cfdf915088a2ada3332bf0" + }, + { + "ImportPath": "gopkg.in/inf.v0", + "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" + }, + { + "ImportPath": "gopkg.in/natefinch/lumberjack.v2", + "Rev": "20b71e5b60d756d3d2f80def009790325acc2b23" + }, + { + "ImportPath": "gopkg.in/yaml.v2", + "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/equality", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/errors", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/meta", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/resource", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/testing", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/validation", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/validation/path", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/validation", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/unstructured", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/fields", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/labels", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/openapi", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/selection", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/types", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/cache", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/clock", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/diff", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/errors", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/framer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/net", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/rand", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/sets", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/uuid", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/wait", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/version", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/watch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/client-go/discovery", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/discovery/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/admissionregistration", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/admissionregistration/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/certificates", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/certificates/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/core", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/core/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/extensions", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/extensions/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/internalinterfaces", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/networking", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/networking/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/policy", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/policy/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/settings", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/settings/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/scheme", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2alpha1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/admissionregistration/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/apps/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/autoscaling/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/autoscaling/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/batch/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/batch/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/certificates/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/core/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/extensions/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/networking/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/policy/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/rbac/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/rbac/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/settings/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/storage/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/listers/storage/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/api", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/api/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/api/v1/ref", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/admissionregistration", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/admissionregistration/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/apps", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/apps/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authentication", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authentication/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authentication/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authorization", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authorization/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/authorization/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/autoscaling/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/batch", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/batch/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/batch/v2alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/certificates", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/certificates/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/extensions", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/extensions/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/networking", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/networking/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/policy", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/policy/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/rbac", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/rbac/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/rbac/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/settings", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/settings/v1alpha1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/storage", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/storage/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/storage/v1beta1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/util", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/util/parsers", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/pkg/version", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/rest", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/rest/watch", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/testing", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/auth", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/cache", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/latest", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/v1", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/tools/metrics", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/transport", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/util/cert", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/util/flowcontrol", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/util/homedir", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + }, + { + "ImportPath": "k8s.io/client-go/util/integer", + "Rev": "ec52d278b25c8fef82a965d93afdc74771ea6963" + } + ] } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go index e01445621e..2ee881a604 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go @@ -105,6 +105,11 @@ func (l *lifecycle) Admit(a admission.Attributes) error { return nil } + // always allow deletion of other resources + if a.GetOperation() == admission.Delete { + return nil + } + // always allow access review checks. Returning status about the namespace would be leaking information if isAccessReview(a) { return nil diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index 7b2e2b0641..0fd9d7ab56 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -135,6 +135,24 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { } t.Errorf("expected error returned from admission handler: %v", actions) } + + // verify create operations in the namespace cause an error + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + if err == nil { + t.Errorf("Expected error rejecting creates in a namespace when it is missing") + } + + // verify update operations in the namespace cause an error + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + if err == nil { + t.Errorf("Expected error rejecting updates in a namespace when it is missing") + } + + // verify delete operations in the namespace can proceed + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + if err != nil { + t.Errorf("Unexpected error returned from admission handler: %v", err) + } } // TestAdmissionNamespaceActive verifies a resource is admitted when the namespace is active. diff --git a/vendor/k8s.io/apiserver/pkg/audit/metrics.go b/vendor/k8s.io/apiserver/pkg/audit/metrics.go index db2280e316..10280e0d88 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/metrics.go +++ b/vendor/k8s.io/apiserver/pkg/audit/metrics.go @@ -32,13 +32,13 @@ var ( eventCounter = prometheus.NewCounter( prometheus.CounterOpts{ Subsystem: subsystem, - Name: "event_count", + Name: "event_total", Help: "Counter of audit events generated and sent to the audit backend.", }) errorCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ Subsystem: subsystem, - Name: "error_count", + Name: "error_total", Help: "Counter of audit events that failed to be audited properly. " + "Plugin identifies the plugin affected by the error.", }, @@ -47,7 +47,7 @@ var ( levelCounter = prometheus.NewCounterVec( prometheus.CounterOpts{ Subsystem: subsystem, - Name: "level_count", + Name: "level_total", Help: "Counter of policy levels for audit events (1 per request).", }, []string{"level"}, diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/installer.go b/vendor/k8s.io/apiserver/pkg/endpoints/installer.go index d0ecf6c6d2..971fff58ef 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/installer.go @@ -575,6 +575,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag routes := []*restful.RouteBuilder{} + // If there is a subresource, kind should be the parent's kind. + if hasSubresource { + fqParentKind, err := a.getResourceKind(resource, a.group.Storage[resource]) + if err != nil { + return nil, err + } + kind = fqParentKind.Kind + } switch action.Verb { case "GET": // Get a resource. var handler restful.RouteFunction diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go index 271a30db3d..182c51796d 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go @@ -63,10 +63,6 @@ func GetOperationIDAndTags(r *restful.Route) (string, []string, error) { op := r.Operation path := r.Path var tags []string - // TODO: This is hacky, figure out where this name conflict is created and fix it at the root. - if strings.HasPrefix(path, "/apis/extensions/v1beta1/namespaces/{namespace}/") && strings.HasSuffix(op, "ScaleScale") { - op = op[:len(op)-10] + strings.Title(strings.Split(path[48:], "/")[0]) + "Scale" - } prefix, exists := verbs.GetPrefix(op) if !exists { return op, tags, fmt.Errorf("operation names should start with a verb. Cannot determine operation verb from %v", op) diff --git a/vendor/k8s.io/apiserver/pkg/storage/tests/cacher_test.go b/vendor/k8s.io/apiserver/pkg/storage/tests/cacher_test.go index ef0c4f38de..447be77997 100644 --- a/vendor/k8s.io/apiserver/pkg/storage/tests/cacher_test.go +++ b/vendor/k8s.io/apiserver/pkg/storage/tests/cacher_test.go @@ -537,6 +537,70 @@ func TestStartingResourceVersion(t *testing.T) { } } +func TestEmptyWatchEventCache(t *testing.T) { + server, etcdStorage := newEtcdTestStorage(t, etcdtest.PathPrefix()) + defer server.Terminate(t) + + // add a few objects + updatePod(t, etcdStorage, makeTestPod("pod1"), nil) + updatePod(t, etcdStorage, makeTestPod("pod2"), nil) + updatePod(t, etcdStorage, makeTestPod("pod3"), nil) + updatePod(t, etcdStorage, makeTestPod("pod4"), nil) + updatePod(t, etcdStorage, makeTestPod("pod5"), nil) + + fooCreated := updatePod(t, etcdStorage, makeTestPod("foo"), nil) + + // get rv of last pod created + rv, err := storage.ParseWatchResourceVersion(fooCreated.ResourceVersion) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + cacher := newTestCacher(etcdStorage, 10) + defer cacher.Stop() + + // We now have a cacher with an empty cache of watch events and a resourceVersion of rv. + // It should support establishing watches from rv and higher, but not older. + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv-1)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + expectedGoneError := errors.NewGone("").ErrStatus + verifyWatchEvent(t, watcher, watch.Error, &expectedGoneError) + } + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv+1)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + select { + case e := <-watcher.ResultChan(): + t.Errorf("unexpected event %#v", e) + case <-time.After(3 * time.Second): + // watch from rv+1 remained established successfully + } + } + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + select { + case e := <-watcher.ResultChan(): + t.Errorf("unexpected event %#v", e) + case <-time.After(3 * time.Second): + // watch from rv remained established successfully + } + } +} + func TestRandomWatchDeliver(t *testing.T) { server, etcdStorage := newEtcdTestStorage(t, etcdtest.PathPrefix()) defer server.Terminate(t) diff --git a/vendor/k8s.io/apiserver/pkg/storage/watch_cache.go b/vendor/k8s.io/apiserver/pkg/storage/watch_cache.go index 1268b9d7a5..602312b605 100644 --- a/vendor/k8s.io/apiserver/pkg/storage/watch_cache.go +++ b/vendor/k8s.io/apiserver/pkg/storage/watch_cache.go @@ -412,7 +412,9 @@ func (w *watchCache) SetOnEvent(onEvent func(*watchCacheEvent)) { func (w *watchCache) GetAllEventsSinceThreadUnsafe(resourceVersion uint64) ([]*watchCacheEvent, error) { size := w.endIndex - w.startIndex - oldest := w.resourceVersion + // if we have no watch events in our cache, the oldest one we can successfully deliver to a watcher + // is the *next* event we'll receive, which will be at least one greater than our current resourceVersion + oldest := w.resourceVersion + 1 if size > 0 { oldest = w.cache[w.startIndex%w.capacity].resourceVersion } diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/flags.go b/vendor/k8s.io/apiserver/pkg/util/flag/flags.go index 8d9a132218..6dd62bdc08 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flag/flags.go +++ b/vendor/k8s.io/apiserver/pkg/util/flag/flags.go @@ -49,6 +49,6 @@ func InitFlags() { pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) pflag.Parse() pflag.VisitAll(func(flag *pflag.Flag) { - glog.Infof("FLAG: --%s=%q", flag.Name, flag.Value) + glog.V(4).Infof("FLAG: --%s=%q", flag.Name, flag.Value) }) } diff --git a/vendor/k8s.io/apiserver/pkg/util/proxy/dial.go b/vendor/k8s.io/apiserver/pkg/util/proxy/dial.go index d9fbb85b7b..e737319094 100644 --- a/vendor/k8s.io/apiserver/pkg/util/proxy/dial.go +++ b/vendor/k8s.io/apiserver/pkg/util/proxy/dial.go @@ -94,6 +94,9 @@ func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) { // Verify host, _, _ := net.SplitHostPort(dialAddr) + if tlsConfig != nil && len(tlsConfig.ServerName) > 0 { + host = tlsConfig.ServerName + } if err := tlsConn.VerifyHostname(host); err != nil { tlsConn.Close() return nil, err diff --git a/vendor/k8s.io/client-go/Godeps/Godeps.json b/vendor/k8s.io/client-go/Godeps/Godeps.json index 3e8a6d893b..8c8b90616c 100644 --- a/vendor/k8s.io/client-go/Godeps/Godeps.json +++ b/vendor/k8s.io/client-go/Godeps/Godeps.json @@ -1,538 +1,522 @@ { - "ImportPath": "k8s.io/client-go", - "GoVersion": "go1.8", - "GodepVersion": "v79", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "cloud.google.com/go/compute/metadata", - "Comment": "v0.1.0-115-g3b1ae45", - "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" - }, - { - "ImportPath": "cloud.google.com/go/internal", - "Comment": "v0.1.0-115-g3b1ae45", - "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" - }, - { - "ImportPath": "github.com/Azure/go-autorest/autorest", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" - }, - { - "ImportPath": "github.com/Azure/go-autorest/autorest/azure", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" - }, - { - "ImportPath": "github.com/Azure/go-autorest/autorest/date", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" - }, - { - "ImportPath": "github.com/PuerkitoBio/purell", - "Comment": "v1.0.0", - "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" - }, - { - "ImportPath": "github.com/PuerkitoBio/urlesc", - "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" - }, - { - "ImportPath": "github.com/coreos/go-oidc/http", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/jose", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/key", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/oauth2", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/go-oidc/oidc", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" - }, - { - "ImportPath": "github.com/coreos/pkg/health", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/coreos/pkg/httputil", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/coreos/pkg/timeutil", - "Comment": "v2-8-gfa29b1d", - "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" - }, - { - "ImportPath": "github.com/davecgh/go-spew/spew", - "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d" - }, - { - "ImportPath": "github.com/dgrijalva/jwt-go", - "Comment": "v3.0.0-4-g01aeca5", - "Rev": "01aeca54ebda6e0fbfafd0a524d234159c05ec20" - }, - { - "ImportPath": "github.com/docker/distribution/digest", - "Comment": "v2.4.0-rc.1-38-gcd27f17", - "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" - }, - { - "ImportPath": "github.com/docker/distribution/reference", - "Comment": "v2.4.0-rc.1-38-gcd27f17", - "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" - }, - { - "ImportPath": "github.com/docker/spdystream", - "Rev": "449fdfce4d962303d702fec724ef0ad181c92528" - }, - { - "ImportPath": "github.com/docker/spdystream/spdy", - "Rev": "449fdfce4d962303d702fec724ef0ad181c92528" - }, - { - "ImportPath": "github.com/emicklei/go-restful", - "Comment": "2.2.0-4-gff4f55a", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/emicklei/go-restful-swagger12", - "Comment": "1.0.1", - "Rev": "dcef7f55730566d41eae5db10e7d6981829720f6" - }, - { - "ImportPath": "github.com/emicklei/go-restful/log", - "Comment": "2.2.0-4-gff4f55a", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/ghodss/yaml", - "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" - }, - { - "ImportPath": "github.com/go-openapi/analysis", - "Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b" - }, - { - "ImportPath": "github.com/go-openapi/jsonpointer", - "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" - }, - { - "ImportPath": "github.com/go-openapi/jsonreference", - "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" - }, - { - "ImportPath": "github.com/go-openapi/loads", - "Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38" - }, - { - "ImportPath": "github.com/go-openapi/spec", - "Rev": "6aced65f8501fe1217321abf0749d354824ba2ff" - }, - { - "ImportPath": "github.com/go-openapi/swag", - "Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72" - }, - { - "ImportPath": "github.com/gogo/protobuf/proto", - "Comment": "v0.4-3-gc0656ed", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/sortkeys", - "Comment": "v0.4-3-gc0656ed", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/golang/glog", - "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" - }, - { - "ImportPath": "github.com/golang/groupcache/lru", - "Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433" - }, - { - "ImportPath": "github.com/golang/protobuf/proto", - "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" - }, - { - "ImportPath": "github.com/google/gofuzz", - "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" - }, - { - "ImportPath": "github.com/hashicorp/golang-lru", - "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" - }, - { - "ImportPath": "github.com/hashicorp/golang-lru/simplelru", - "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" - }, - { - "ImportPath": "github.com/howeyc/gopass", - "Rev": "bf9dde6d0d2c004a008c27aaee91170c786f6db8" - }, - { - "ImportPath": "github.com/imdario/mergo", - "Comment": "0.1.3-8-g6633656", - "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" - }, - { - "ImportPath": "github.com/jonboulle/clockwork", - "Rev": "72f9bd7c4e0c2a40055ab3d0f09654f730cce982" - }, - { - "ImportPath": "github.com/juju/ratelimit", - "Rev": "5b9ff866471762aa2ab2dced63c9fb6f53921342" - }, - { - "ImportPath": "github.com/mailru/easyjson/buffer", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/mailru/easyjson/jlexer", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/mailru/easyjson/jwriter", - "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" - }, - { - "ImportPath": "github.com/pmezard/go-difflib/difflib", - "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" - }, - { - "ImportPath": "github.com/spf13/pflag", - "Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7" - }, - { - "ImportPath": "github.com/stretchr/testify/assert", - "Comment": "v1.0-88-ge3a8ff8", - "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" - }, - { - "ImportPath": "github.com/ugorji/go/codec", - "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" - }, - { - "ImportPath": "golang.org/x/crypto/ssh/terminal", - "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" - }, - { - "ImportPath": "golang.org/x/net/context", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/context/ctxhttp", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/http2", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/http2/hpack", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/idna", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/net/lex/httplex", - "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" - }, - { - "ImportPath": "golang.org/x/oauth2", - "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" - }, - { - "ImportPath": "golang.org/x/oauth2/google", - "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" - }, - { - "ImportPath": "golang.org/x/oauth2/internal", - "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" - }, - { - "ImportPath": "golang.org/x/oauth2/jws", - "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" - }, - { - "ImportPath": "golang.org/x/oauth2/jwt", - "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" - }, - { - "ImportPath": "golang.org/x/sys/unix", - "Rev": "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9" - }, - { - "ImportPath": "golang.org/x/text/cases", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/internal/tag", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/language", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/runes", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/secure/bidirule", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/secure/precis", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/transform", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/unicode/bidi", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/unicode/norm", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "golang.org/x/text/width", - "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" - }, - { - "ImportPath": "gopkg.in/inf.v0", - "Comment": "v0.9.0", - "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" - }, - { - "ImportPath": "gopkg.in/yaml.v2", - "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/equality", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/errors", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/meta", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/resource", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/api/testing", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/conversion/unstructured", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/fields", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/labels", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/openapi", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/selection", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/types", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/cache", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/clock", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/diff", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/errors", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/framer", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/net", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/rand", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/sets", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/wait", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/version", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/pkg/watch", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - }, - { - "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", - "Rev": "abe34e4f5b4413c282a83011892cbeea5b32223b" - } - ] + "ImportPath": "k8s.io/client-go", + "GoVersion": "go1.8", + "GodepVersion": "v79", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "cloud.google.com/go/compute/metadata", + "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" + }, + { + "ImportPath": "cloud.google.com/go/internal", + "Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest/adal", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest/azure", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest/date", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/PuerkitoBio/purell", + "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" + }, + { + "ImportPath": "github.com/PuerkitoBio/urlesc", + "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" + }, + { + "ImportPath": "github.com/coreos/go-oidc/http", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/jose", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/key", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/oauth2", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/go-oidc/oidc", + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" + }, + { + "ImportPath": "github.com/coreos/pkg/health", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/coreos/pkg/httputil", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/coreos/pkg/timeutil", + "Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8" + }, + { + "ImportPath": "github.com/davecgh/go-spew/spew", + "Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d" + }, + { + "ImportPath": "github.com/dgrijalva/jwt-go", + "Rev": "01aeca54ebda6e0fbfafd0a524d234159c05ec20" + }, + { + "ImportPath": "github.com/docker/distribution/digest", + "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" + }, + { + "ImportPath": "github.com/docker/distribution/reference", + "Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51" + }, + { + "ImportPath": "github.com/docker/spdystream", + "Rev": "449fdfce4d962303d702fec724ef0ad181c92528" + }, + { + "ImportPath": "github.com/docker/spdystream/spdy", + "Rev": "449fdfce4d962303d702fec724ef0ad181c92528" + }, + { + "ImportPath": "github.com/emicklei/go-restful", + "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" + }, + { + "ImportPath": "github.com/emicklei/go-restful-swagger12", + "Rev": "dcef7f55730566d41eae5db10e7d6981829720f6" + }, + { + "ImportPath": "github.com/emicklei/go-restful/log", + "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" + }, + { + "ImportPath": "github.com/ghodss/yaml", + "Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee" + }, + { + "ImportPath": "github.com/go-openapi/analysis", + "Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b" + }, + { + "ImportPath": "github.com/go-openapi/jsonpointer", + "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" + }, + { + "ImportPath": "github.com/go-openapi/jsonreference", + "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" + }, + { + "ImportPath": "github.com/go-openapi/loads", + "Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38" + }, + { + "ImportPath": "github.com/go-openapi/spec", + "Rev": "6aced65f8501fe1217321abf0749d354824ba2ff" + }, + { + "ImportPath": "github.com/go-openapi/swag", + "Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72" + }, + { + "ImportPath": "github.com/gogo/protobuf/proto", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/gogo/protobuf/sortkeys", + "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + }, + { + "ImportPath": "github.com/golang/glog", + "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" + }, + { + "ImportPath": "github.com/golang/groupcache/lru", + "Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433" + }, + { + "ImportPath": "github.com/golang/protobuf/proto", + "Rev": "4bd1920723d7b7c925de087aa32e2187708897f7" + }, + { + "ImportPath": "github.com/google/gofuzz", + "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" + }, + { + "ImportPath": "github.com/hashicorp/golang-lru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + }, + { + "ImportPath": "github.com/hashicorp/golang-lru/simplelru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + }, + { + "ImportPath": "github.com/howeyc/gopass", + "Rev": "bf9dde6d0d2c004a008c27aaee91170c786f6db8" + }, + { + "ImportPath": "github.com/imdario/mergo", + "Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc" + }, + { + "ImportPath": "github.com/jonboulle/clockwork", + "Rev": "72f9bd7c4e0c2a40055ab3d0f09654f730cce982" + }, + { + "ImportPath": "github.com/juju/ratelimit", + "Rev": "5b9ff866471762aa2ab2dced63c9fb6f53921342" + }, + { + "ImportPath": "github.com/mailru/easyjson/buffer", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/mailru/easyjson/jlexer", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/mailru/easyjson/jwriter", + "Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0" + }, + { + "ImportPath": "github.com/pmezard/go-difflib/difflib", + "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" + }, + { + "ImportPath": "github.com/spf13/pflag", + "Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7" + }, + { + "ImportPath": "github.com/stretchr/testify/assert", + "Rev": "e3a8ff8ce36581f87a15341206f205b1da467059" + }, + { + "ImportPath": "github.com/ugorji/go/codec", + "Rev": "ded73eae5db7e7a0ef6f55aace87a2873c5d2b74" + }, + { + "ImportPath": "golang.org/x/crypto/ssh/terminal", + "Rev": "d172538b2cfce0c13cee31e647d0367aa8cd2486" + }, + { + "ImportPath": "golang.org/x/net/context", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/context/ctxhttp", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/http2", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/http2/hpack", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/idna", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/net/lex/httplex", + "Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d" + }, + { + "ImportPath": "golang.org/x/oauth2", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/oauth2/google", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/oauth2/internal", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/oauth2/jws", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/oauth2/jwt", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9" + }, + { + "ImportPath": "golang.org/x/text/cases", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/internal/tag", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/language", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/runes", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/secure/bidirule", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/secure/precis", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/transform", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/unicode/bidi", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/unicode/norm", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "golang.org/x/text/width", + "Rev": "2910a502d2bf9e43193af9d68ca516529614eed3" + }, + { + "ImportPath": "gopkg.in/inf.v0", + "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" + }, + { + "ImportPath": "gopkg.in/yaml.v2", + "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/equality", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/errors", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/meta", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/resource", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/testing", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/unstructured", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/fields", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/labels", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/openapi", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/selection", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/types", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/cache", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/clock", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/diff", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/errors", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/framer", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/net", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/rand", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/sets", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/wait", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/version", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/watch", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", + "Rev": "917740426ad66ff818da4809990480bcc0786a77" + } + ] } diff --git a/vendor/k8s.io/client-go/kubernetes-sha b/vendor/k8s.io/client-go/kubernetes-sha deleted file mode 100644 index a138efbc44..0000000000 --- a/vendor/k8s.io/client-go/kubernetes-sha +++ /dev/null @@ -1 +0,0 @@ -797dc10a0ccd89bec0b29c41613025035ed23a0f diff --git a/vendor/k8s.io/client-go/pkg/util/util.go b/vendor/k8s.io/client-go/pkg/util/util.go index 356b295a3e..389e145e84 100644 --- a/vendor/k8s.io/client-go/pkg/util/util.go +++ b/vendor/k8s.io/client-go/pkg/util/util.go @@ -84,6 +84,15 @@ func FileExists(filename string) (bool, error) { return true, nil } +func FileOrSymlinkExists(filename string) (bool, error) { + if _, err := os.Lstat(filename); os.IsNotExist(err) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + // ReadDirNoStat returns a string of files/directories contained // in dirname without calling lstat on them. func ReadDirNoStat(dirname string) ([]string, error) { diff --git a/vendor/k8s.io/client-go/pkg/version/base.go b/vendor/k8s.io/client-go/pkg/version/base.go index 5dbc70eaf1..ee83eb5859 100644 --- a/vendor/k8s.io/client-go/pkg/version/base.go +++ b/vendor/k8s.io/client-go/pkg/version/base.go @@ -39,8 +39,8 @@ var ( // them irrelevant. (Next we'll take it out, which may muck with // scripts consuming the kubectl version output - but most of // these should be looking at gitVersion already anyways.) - gitMajor string = "1" // major version, always numeric - gitMinor string = "7" // minor version, numeric possibly followed by "+" + gitMajor string = "1" // major version, always numeric + gitMinor string = "7+" // minor version, numeric possibly followed by "+" // semantic version, derived by build scripts (see // https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md @@ -51,7 +51,7 @@ var ( // semantic version is a git hash, but the version itself is no // longer the direct output of "git describe", but a slight // translation to be semver compliant. - gitVersion string = "v1.7.0+$Format:%h$" + gitVersion string = "v1.7.4-beta.0+$Format:%h$" gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD) gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty" diff --git a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD index 0c8f309549..00c96d666d 100644 --- a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD +++ b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD @@ -13,7 +13,7 @@ go_test( srcs = ["azure_test.go"], library = ":go_default_library", tags = ["automanaged"], - deps = ["//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library"], + deps = ["//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library"], ) go_library( @@ -22,6 +22,7 @@ go_library( tags = ["automanaged"], deps = [ "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", diff --git a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go index 342fbb78f5..06744e7424 100644 --- a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go +++ b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go @@ -24,6 +24,7 @@ import ( "sync" "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/azure" "github.com/golang/glog" @@ -137,7 +138,7 @@ func (r *azureRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) } type azureToken struct { - token azure.Token + token adal.Token clientID string tenantID string apiserverID string @@ -234,7 +235,7 @@ func (ts *azureTokenSource) retrieveTokenFromCfg() (*azureToken, error) { } return &azureToken{ - token: azure.Token{ + token: adal.Token{ AccessToken: accessToken, RefreshToken: refreshToken, ExpiresIn: expiresIn, @@ -268,15 +269,15 @@ func (ts *azureTokenSource) storeTokenInCfg(token *azureToken) error { } func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error) { - oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(token.tenantID) + oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, token.tenantID) if err != nil { return nil, fmt.Errorf("building the OAuth configuration for token refresh: %v", err) } - callback := func(t azure.Token) error { + callback := func(t adal.Token) error { return nil } - spt, err := azure.NewServicePrincipalTokenFromManualToken( + spt, err := adal.NewServicePrincipalTokenFromManualToken( *oauthConfig, token.clientID, token.apiserverID, @@ -324,12 +325,12 @@ func newAzureTokenSourceDeviceCode(environment azure.Environment, clientID strin } func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) { - oauthConfig, err := ts.environment.OAuthConfigForTenant(ts.tenantID) + oauthConfig, err := adal.NewOAuthConfig(ts.environment.ActiveDirectoryEndpoint, ts.tenantID) if err != nil { return nil, fmt.Errorf("building the OAuth configuration for device code authentication: %v", err) } client := &autorest.Client{} - deviceCode, err := azure.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID) + deviceCode, err := adal.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID) if err != nil { return nil, fmt.Errorf("initialing the device code authentication: %v", err) } @@ -339,7 +340,7 @@ func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) { return nil, fmt.Errorf("prompting the device code message: %v", err) } - token, err := azure.WaitForUserCompletion(client, deviceCode) + token, err := adal.WaitForUserCompletion(client, deviceCode) if err != nil { return nil, fmt.Errorf("waiting for device code authentication to complete: %v", err) } diff --git a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go index 78d28b6e2f..b420712bc1 100644 --- a/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go +++ b/vendor/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go @@ -23,7 +23,7 @@ import ( "testing" "time" - "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/adal" ) func TestAzureTokenSource(t *testing.T) { @@ -120,8 +120,8 @@ func token2Cfg(token *azureToken) map[string]string { return cfg } -func newFackeAzureToken(accessToken string, expiresOn string) azure.Token { - return azure.Token{ +func newFackeAzureToken(accessToken string, expiresOn string) adal.Token { + return adal.Token{ AccessToken: accessToken, RefreshToken: "fake", ExpiresIn: "3600", diff --git a/vendor/k8s.io/kubernetes/Godeps/Godeps.json b/vendor/k8s.io/kubernetes/Godeps/Godeps.json index 7e279a4196..61c441087b 100644 --- a/vendor/k8s.io/kubernetes/Godeps/Godeps.json +++ b/vendor/k8s.io/kubernetes/Godeps/Godeps.json @@ -30,28 +30,33 @@ }, { "ImportPath": "github.com/Azure/azure-sdk-for-go/arm/compute", - "Comment": "v7.0.1-beta", - "Rev": "0984e0641ae43b89283223034574d6465be93bf4" + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" }, { "ImportPath": "github.com/Azure/azure-sdk-for-go/arm/containerregistry", - "Comment": "v7.0.1-beta", - "Rev": "0984e0641ae43b89283223034574d6465be93bf4" + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" + }, + { + "ImportPath": "github.com/Azure/azure-sdk-for-go/arm/disk", + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" }, { "ImportPath": "github.com/Azure/azure-sdk-for-go/arm/network", - "Comment": "v7.0.1-beta", - "Rev": "0984e0641ae43b89283223034574d6465be93bf4" + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" }, { "ImportPath": "github.com/Azure/azure-sdk-for-go/arm/storage", - "Comment": "v7.0.1-beta", - "Rev": "0984e0641ae43b89283223034574d6465be93bf4" + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" }, { "ImportPath": "github.com/Azure/azure-sdk-for-go/storage", - "Comment": "v7.0.1-beta", - "Rev": "0984e0641ae43b89283223034574d6465be93bf4" + "Comment": "v10.0.4-beta-1-g786cc84", + "Rev": "786cc84138518bf7fd6d60e92fad1ac9d1a117ad" }, { "ImportPath": "github.com/Azure/go-ansiterm", @@ -63,28 +68,33 @@ }, { "ImportPath": "github.com/Azure/go-autorest/autorest", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest/adal", + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/azure", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/date", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/to", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/validation", - "Comment": "v7.2.3", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Comment": "v8.0.0", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/MakeNowJust/heredoc", @@ -726,23 +736,23 @@ }, { "ImportPath": "github.com/coreos/go-oidc/http", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/jose", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/key", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oauth2", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oidc", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-semver/semver", @@ -1482,123 +1492,123 @@ }, { "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/common/extensions", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/images", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/servers", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/pools", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/vips", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/ports", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gorilla/context", @@ -2353,6 +2363,11 @@ "ImportPath": "github.com/samuel/go-zookeeper/zk", "Rev": "177002e16a0061912f02377e2dd8951a8b3551bc" }, + { + "ImportPath": "github.com/satori/uuid", + "Comment": "v1.1.0-8-g5bf94b6", + "Rev": "5bf94b69c6b68ee1b541973bb8e1144db23a194b" + }, { "ImportPath": "github.com/seccomp/libseccomp-golang", "Rev": "1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1" @@ -2870,19 +2885,23 @@ }, { "ImportPath": "gopkg.in/gcfg.v1", - "Rev": "083575c3955c85df16fe9590cceab64d03f5eb6e" + "Comment": "v1.2.0", + "Rev": "27e4946190b4a327b539185f2b5b1f7c84730728" }, { "ImportPath": "gopkg.in/gcfg.v1/scanner", - "Rev": "083575c3955c85df16fe9590cceab64d03f5eb6e" + "Comment": "v1.2.0", + "Rev": "27e4946190b4a327b539185f2b5b1f7c84730728" }, { "ImportPath": "gopkg.in/gcfg.v1/token", - "Rev": "083575c3955c85df16fe9590cceab64d03f5eb6e" + "Comment": "v1.2.0", + "Rev": "27e4946190b4a327b539185f2b5b1f7c84730728" }, { "ImportPath": "gopkg.in/gcfg.v1/types", - "Rev": "083575c3955c85df16fe9590cceab64d03f5eb6e" + "Comment": "v1.2.0", + "Rev": "27e4946190b4a327b539185f2b5b1f7c84730728" }, { "ImportPath": "gopkg.in/inf.v0", @@ -2893,6 +2912,11 @@ "Comment": "v1.0-16-g20b71e5", "Rev": "20b71e5b60d756d3d2f80def009790325acc2b23" }, + { + "ImportPath": "gopkg.in/warnings.v0", + "Comment": "v0.1.1", + "Rev": "8a331561fe74dadba6edfc59f3be66c22c3b065d" + }, { "ImportPath": "gopkg.in/yaml.v2", "Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77" diff --git a/vendor/k8s.io/kubernetes/Godeps/LICENSES b/vendor/k8s.io/kubernetes/Godeps/LICENSES index 72a219de0c..f6de48f61e 100644 --- a/vendor/k8s.io/kubernetes/Godeps/LICENSES +++ b/vendor/k8s.io/kubernetes/Godeps/LICENSES @@ -8952,6 +8952,216 @@ SOFTWARE. ================================================================================ +================================================================================ += vendor/github.com/Azure/azure-sdk-for-go/arm/disk licensed under: = + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 Microsoft Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + += vendor/github.com/Azure/azure-sdk-for-go/LICENSE cce6fd055830ca30ff78fdf077e870d6 - +================================================================================ + + ================================================================================ = vendor/github.com/Azure/azure-sdk-for-go/arm/network licensed under: = @@ -9839,6 +10049,205 @@ THE SOFTWARE. ================================================================================ +================================================================================ += vendor/github.com/Azure/go-autorest/autorest/adal licensed under: = + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 Microsoft Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + += vendor/github.com/Azure/go-autorest/LICENSE a250e5ac3848f2acadb5adcb9555c18b - +================================================================================ + + ================================================================================ = vendor/github.com/Azure/go-autorest/autorest/azure licensed under: = @@ -75366,6 +75775,34 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ +================================================================================ += vendor/github.com/satori/uuid licensed under: = + +Copyright (C) 2013-2016 by Maxim Bublis + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + += vendor/github.com/satori/uuid/LICENSE 02d5d17de0c82a23a09863acccc026f6 - +================================================================================ + + ================================================================================ = vendor/github.com/seccomp/libseccomp-golang licensed under: = @@ -84997,6 +85434,38 @@ SOFTWARE. ================================================================================ +================================================================================ += vendor/gopkg.in/warnings.v0 licensed under: = + +Copyright (c) 2016 Péter Surányi. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + += vendor/gopkg.in/warnings.v0/LICENSE c6775875c9d604beb22447dfae3d7049 - +================================================================================ + + ================================================================================ = vendor/gopkg.in/yaml.v2 licensed under: = diff --git a/vendor/k8s.io/kubernetes/api/openapi-spec/swagger.json b/vendor/k8s.io/kubernetes/api/openapi-spec/swagger.json index 3f0dc1172f..9975f7d715 100644 --- a/vendor/k8s.io/kubernetes/api/openapi-spec/swagger.json +++ b/vendor/k8s.io/kubernetes/api/openapi-spec/swagger.json @@ -2,7 +2,7 @@ "swagger": "2.0", "info": { "title": "Kubernetes", - "version": "v1.7.1" + "version": "v1.7.6" }, "paths": { "/api/": { @@ -3813,7 +3813,7 @@ }, "/api/v1/namespaces/{namespace}/pods/{name}/binding": { "post": { - "description": "create binding of a Binding", + "description": "create binding of a Pod", "consumes": [ "*/*" ], @@ -3828,7 +3828,7 @@ "tags": [ "core_v1" ], - "operationId": "createCoreV1NamespacedBindingBinding", + "operationId": "createCoreV1NamespacedPodBinding", "parameters": [ { "name": "body", @@ -3885,7 +3885,7 @@ }, "/api/v1/namespaces/{namespace}/pods/{name}/eviction": { "post": { - "description": "create eviction of an Eviction", + "description": "create eviction of a Pod", "consumes": [ "*/*" ], @@ -3900,7 +3900,7 @@ "tags": [ "core_v1" ], - "operationId": "createCoreV1NamespacedEvictionEviction", + "operationId": "createCoreV1NamespacedPodEviction", "parameters": [ { "name": "body", @@ -5888,7 +5888,7 @@ }, "/api/v1/namespaces/{namespace}/replicationcontrollers/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified ReplicationController", "consumes": [ "*/*" ], @@ -5903,7 +5903,7 @@ "tags": [ "core_v1" ], - "operationId": "readCoreV1NamespacedScaleScale", + "operationId": "readCoreV1NamespacedReplicationControllerScale", "responses": { "200": { "description": "OK", @@ -5923,7 +5923,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified ReplicationController", "consumes": [ "*/*" ], @@ -5938,7 +5938,7 @@ "tags": [ "core_v1" ], - "operationId": "replaceCoreV1NamespacedScaleScale", + "operationId": "replaceCoreV1NamespacedReplicationControllerScale", "parameters": [ { "name": "body", @@ -5968,7 +5968,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified ReplicationController", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -5985,7 +5985,7 @@ "tags": [ "core_v1" ], - "operationId": "patchCoreV1NamespacedScaleScale", + "operationId": "patchCoreV1NamespacedReplicationControllerScale", "parameters": [ { "name": "body", @@ -20501,7 +20501,7 @@ }, "/apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/rollback": { "post": { - "description": "create rollback of a DeploymentRollback", + "description": "create rollback of a Deployment", "consumes": [ "*/*" ], @@ -20516,7 +20516,7 @@ "tags": [ "apps_v1beta1" ], - "operationId": "createAppsV1beta1NamespacedDeploymentRollbackRollback", + "operationId": "createAppsV1beta1NamespacedDeploymentRollback", "parameters": [ { "name": "body", @@ -20573,7 +20573,7 @@ }, "/apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified Deployment", "consumes": [ "*/*" ], @@ -20588,7 +20588,7 @@ "tags": [ "apps_v1beta1" ], - "operationId": "readAppsV1beta1NamespacedScaleScale", + "operationId": "readAppsV1beta1NamespacedDeploymentScale", "responses": { "200": { "description": "OK", @@ -20608,7 +20608,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified Deployment", "consumes": [ "*/*" ], @@ -20623,7 +20623,7 @@ "tags": [ "apps_v1beta1" ], - "operationId": "replaceAppsV1beta1NamespacedScaleScale", + "operationId": "replaceAppsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -20653,7 +20653,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified Deployment", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -20670,7 +20670,7 @@ "tags": [ "apps_v1beta1" ], - "operationId": "patchAppsV1beta1NamespacedScaleScale", + "operationId": "patchAppsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -30553,7 +30553,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/rollback": { "post": { - "description": "create rollback of a DeploymentRollback", + "description": "create rollback of a Deployment", "consumes": [ "*/*" ], @@ -30568,7 +30568,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "createExtensionsV1beta1NamespacedDeploymentRollbackRollback", + "operationId": "createExtensionsV1beta1NamespacedDeploymentRollback", "parameters": [ { "name": "body", @@ -30625,7 +30625,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified Deployment", "consumes": [ "*/*" ], @@ -30640,7 +30640,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "readExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "readExtensionsV1beta1NamespacedDeploymentScale", "responses": { "200": { "description": "OK", @@ -30660,7 +30660,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified Deployment", "consumes": [ "*/*" ], @@ -30675,7 +30675,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "replaceExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "replaceExtensionsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -30705,7 +30705,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified Deployment", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -30722,7 +30722,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "patchExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "patchExtensionsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -32467,7 +32467,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified ReplicaSet", "consumes": [ "*/*" ], @@ -32482,7 +32482,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "readExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "readExtensionsV1beta1NamespacedReplicaSetScale", "responses": { "200": { "description": "OK", @@ -32502,7 +32502,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified ReplicaSet", "consumes": [ "*/*" ], @@ -32517,7 +32517,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "replaceExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "replaceExtensionsV1beta1NamespacedReplicaSetScale", "parameters": [ { "name": "body", @@ -32547,7 +32547,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified ReplicaSet", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -32564,7 +32564,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "patchExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "patchExtensionsV1beta1NamespacedReplicaSetScale", "parameters": [ { "name": "body", @@ -32775,7 +32775,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/replicationcontrollers/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified ReplicationControllerDummy", "consumes": [ "*/*" ], @@ -32790,7 +32790,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "readExtensionsV1beta1NamespacedReplicationcontrollersScale", + "operationId": "readExtensionsV1beta1NamespacedReplicationControllerDummyScale", "responses": { "200": { "description": "OK", @@ -32810,7 +32810,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified ReplicationControllerDummy", "consumes": [ "*/*" ], @@ -32825,7 +32825,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "replaceExtensionsV1beta1NamespacedReplicationcontrollersScale", + "operationId": "replaceExtensionsV1beta1NamespacedReplicationControllerDummyScale", "parameters": [ { "name": "body", @@ -32855,7 +32855,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified ReplicationControllerDummy", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -32872,7 +32872,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "patchExtensionsV1beta1NamespacedReplicationcontrollersScale", + "operationId": "patchExtensionsV1beta1NamespacedReplicationControllerDummyScale", "parameters": [ { "name": "body", diff --git a/vendor/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json b/vendor/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json index 69eb5c27eb..6b2ac61d94 100644 --- a/vendor/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json +++ b/vendor/k8s.io/kubernetes/api/swagger-spec/apps_v1beta1.json @@ -1737,8 +1737,8 @@ { "type": "v1beta1.DeploymentRollback", "method": "POST", - "summary": "create rollback of a DeploymentRollback", - "nickname": "createNamespacedDeploymentRollbackRollback", + "summary": "create rollback of a Deployment", + "nickname": "createNamespacedDeploymentRollback", "parameters": [ { "type": "string", @@ -1798,8 +1798,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified Deployment", + "nickname": "readNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -1845,8 +1845,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified Deployment", + "nickname": "replaceNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -1900,8 +1900,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified Deployment", + "nickname": "patchNamespacedDeploymentScale", "parameters": [ { "type": "string", diff --git a/vendor/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json b/vendor/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json index 0739c0d082..1e441fb3d4 100644 --- a/vendor/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json +++ b/vendor/k8s.io/kubernetes/api/swagger-spec/extensions_v1beta1.json @@ -1902,8 +1902,8 @@ { "type": "v1beta1.DeploymentRollback", "method": "POST", - "summary": "create rollback of a DeploymentRollback", - "nickname": "createNamespacedDeploymentRollbackRollback", + "summary": "create rollback of a Deployment", + "nickname": "createNamespacedDeploymentRollback", "parameters": [ { "type": "string", @@ -1963,8 +1963,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified Deployment", + "nickname": "readNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -2010,8 +2010,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified Deployment", + "nickname": "replaceNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -2065,8 +2065,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified Deployment", + "nickname": "patchNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -5656,8 +5656,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified ReplicaSet", + "nickname": "readNamespacedReplicaSetScale", "parameters": [ { "type": "string", @@ -5703,8 +5703,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified ReplicaSet", + "nickname": "replaceNamespacedReplicaSetScale", "parameters": [ { "type": "string", @@ -5758,8 +5758,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified ReplicaSet", + "nickname": "patchNamespacedReplicaSetScale", "parameters": [ { "type": "string", @@ -5986,8 +5986,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified ReplicationControllerDummy", + "nickname": "readNamespacedReplicationControllerDummyScale", "parameters": [ { "type": "string", @@ -6033,8 +6033,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified ReplicationControllerDummy", + "nickname": "replaceNamespacedReplicationControllerDummyScale", "parameters": [ { "type": "string", @@ -6088,8 +6088,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified ReplicationControllerDummy", + "nickname": "patchNamespacedReplicationControllerDummyScale", "parameters": [ { "type": "string", diff --git a/vendor/k8s.io/kubernetes/api/swagger-spec/v1.json b/vendor/k8s.io/kubernetes/api/swagger-spec/v1.json index d9c4839866..077b121403 100644 --- a/vendor/k8s.io/kubernetes/api/swagger-spec/v1.json +++ b/vendor/k8s.io/kubernetes/api/swagger-spec/v1.json @@ -9271,8 +9271,8 @@ { "type": "v1.Binding", "method": "POST", - "summary": "create binding of a Binding", - "nickname": "createNamespacedBindingBinding", + "summary": "create binding of a Pod", + "nickname": "createNamespacedPodBinding", "parameters": [ { "type": "string", @@ -9332,8 +9332,8 @@ { "type": "v1beta1.Eviction", "method": "POST", - "summary": "create eviction of an Eviction", - "nickname": "createNamespacedEvictionEviction", + "summary": "create eviction of a Pod", + "nickname": "createNamespacedPodEviction", "parameters": [ { "type": "string", @@ -12234,8 +12234,8 @@ { "type": "v1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified ReplicationController", + "nickname": "readNamespacedReplicationControllerScale", "parameters": [ { "type": "string", @@ -12281,8 +12281,8 @@ { "type": "v1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified ReplicationController", + "nickname": "replaceNamespacedReplicationControllerScale", "parameters": [ { "type": "string", @@ -12336,8 +12336,8 @@ { "type": "v1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified ReplicationController", + "nickname": "patchNamespacedReplicationControllerScale", "parameters": [ { "type": "string", diff --git a/vendor/k8s.io/kubernetes/build/common.sh b/vendor/k8s.io/kubernetes/build/common.sh index 9ec643b1d9..d2e114035f 100755 --- a/vendor/k8s.io/kubernetes/build/common.sh +++ b/vendor/k8s.io/kubernetes/build/common.sh @@ -383,7 +383,13 @@ function kube::build::short_hash() { # a workaround for bug https://github.com/docker/docker/issues/3968. function kube::build::destroy_container() { "${DOCKER[@]}" kill "$1" >/dev/null 2>&1 || true - "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true + if [[ $("${DOCKER[@]}" version --format '{{.Server.Version}}') = 17.06.0* ]]; then + # Workaround https://github.com/moby/moby/issues/33948. + # TODO: remove when 17.06.0 is not relevant anymore + DOCKER_API_VERSION=v1.29 "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true + else + "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true + fi "${DOCKER[@]}" rm -f -v "$1" >/dev/null 2>&1 || true } diff --git a/vendor/k8s.io/kubernetes/build/lib/release.sh b/vendor/k8s.io/kubernetes/build/lib/release.sh index 9cd448369e..6aa35abb8b 100644 --- a/vendor/k8s.io/kubernetes/build/lib/release.sh +++ b/vendor/k8s.io/kubernetes/build/lib/release.sh @@ -287,7 +287,7 @@ function kube::release::create_docker_images_for_server() { local docker_build_path="${binary_dir}/${binary_name}.dockerbuild" local docker_file_path="${docker_build_path}/Dockerfile" local binary_file_path="${binary_dir}/${binary_name}" - local docker_image_tag="${KUBE_DOCKER_REGISTRY:-gcr.io/google_containers}" + local docker_image_tag="gcr.io/google_containers" rm -rf ${docker_build_path} mkdir -p ${docker_build_path} diff --git a/vendor/k8s.io/kubernetes/build/root/.bazelrc b/vendor/k8s.io/kubernetes/build/root/.bazelrc index 8e989c90f1..e607627357 100644 --- a/vendor/k8s.io/kubernetes/build/root/.bazelrc +++ b/vendor/k8s.io/kubernetes/build/root/.bazelrc @@ -7,3 +7,7 @@ build --workspace_status_command hack/print-workspace-status.sh # Make /tmp hermetic build --sandbox_tmpfs_path=/tmp + +# Ensure that Bazel never runs as root, which can cause unit tests to fail. +# This flag requires Bazel 0.5.0+ +build --sandbox_fake_username diff --git a/vendor/k8s.io/kubernetes/build/root/Makefile b/vendor/k8s.io/kubernetes/build/root/Makefile index ea5eec81dd..9ae9416723 100644 --- a/vendor/k8s.io/kubernetes/build/root/Makefile +++ b/vendor/k8s.io/kubernetes/build/root/Makefile @@ -238,6 +238,11 @@ define TEST_E2E_NODE_HELP_INFO # IMAGE_SERVICE_ENDPOINT: remote image endpoint to connect to, to prepull images. # Used when RUNTIME is set to "remote". # IMAGE_CONFIG_FILE: path to a file containing image configuration. +# SYSTEM_SPEC_NAME: The name of the system spec to be used for validating the +# image in the node conformance test. The specs are located at +# test/e2e_node/system/specs/. For example, "SYSTEM_SPEC_NAME=gke" will use +# the spec at test/e2e_node/system/specs/gke.yaml. If unspecified, the +# default built-in spec (system.DefaultSpec) will be used. # # Example: # make test-e2e-node FOCUS=Kubelet SKIP=container diff --git a/vendor/k8s.io/kubernetes/build/root/WORKSPACE b/vendor/k8s.io/kubernetes/build/root/WORKSPACE index f57923a8bc..7fe550356a 100644 --- a/vendor/k8s.io/kubernetes/build/root/WORKSPACE +++ b/vendor/k8s.io/kubernetes/build/root/WORKSPACE @@ -1,15 +1,15 @@ http_archive( name = "io_bazel_rules_go", - sha256 = "a1596c14c799d5a1b5f49ca28fa948414c2242110d69ef324d6ed160ec890dbf", - strip_prefix = "rules_go-03c634753160632c00f506afeafc819fbea4c422", - urls = ["https://github.com/bazelbuild/rules_go/archive/03c634753160632c00f506afeafc819fbea4c422.tar.gz"], + sha256 = "08969d1cb8ad523f451098da53117108ae564698bcee281c9a2890836e5be0ee", + strip_prefix = "rules_go-473417ec48310325e1fcb1c154621a83197a17fe", + urls = ["https://github.com/bazelbuild/rules_go/archive/473417ec48310325e1fcb1c154621a83197a17fe.tar.gz"], ) http_archive( name = "io_kubernetes_build", - sha256 = "a9fb7027f060b868cdbd235a0de0971b557b9d26f9c89e422feb80f48d8c0e90", - strip_prefix = "repo-infra-9dedd5f4093884c133ad5ea73695b28338b954ab", - urls = ["https://github.com/kubernetes/repo-infra/archive/9dedd5f4093884c133ad5ea73695b28338b954ab.tar.gz"], + sha256 = "232fec0ffcb53df5e87fc036ae3e966ea32122fc89ead4c32581b3255c1ab7d0", + strip_prefix = "repo-infra-f521b5d472e00e05da5394994942064510a6e8bf", + urls = ["https://github.com/kubernetes/repo-infra/archive/f521b5d472e00e05da5394994942064510a6e8bf.tar.gz"], ) # This contains a patch to not prepend ./ to tarfiles produced by pkg_tar. @@ -17,7 +17,7 @@ http_archive( # https://bazel-review.googlesource.com/#/c/10390/ http_archive( name = "io_bazel", - sha256 = "667d32da016b1e2f63cf345cd3583989ec4a165034df383a01996d93635753a0", + sha256 = "892a84aa1e7c1f99fb57bb056cb648745c513077252815324579a012d263defb", strip_prefix = "bazel-df2c687c22bdd7c76f3cdcc85f38fefd02f0b844", urls = ["https://github.com/ixdy/bazel/archive/df2c687c22bdd7c76f3cdcc85f38fefd02f0b844.tar.gz"], ) diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/README.md b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/README.md index 920cb84d2c..7ef70eede2 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/README.md +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/README.md @@ -9,6 +9,6 @@ Calico is an implementation of the Kubernetes network policy API. The provided ### Learn More -Learn more about Calico at http://docs.projectcalico.org +Learn more about Calico at https://docs.projectcalico.org [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/cluster/addons/calico-policy-controller/README.md?pixel)]() diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrole.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrole.yaml new file mode 100644 index 0000000000..a23589cd3c --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrole.yaml @@ -0,0 +1,67 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: calico + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +rules: + - apiGroups: [""] + resources: + - namespaces + verbs: + - get + - list + - watch + - apiGroups: [""] + resources: + - endpoints + verbs: + - get + - apiGroups: [""] + resources: + - services + verbs: + - get + - apiGroups: [""] + resources: + - pods/status + verbs: + - update + - apiGroups: [""] + resources: + - pods + verbs: + - get + - list + - watch + - apiGroups: [""] + resources: + - nodes + verbs: + - get + - list + - update + - watch + - apiGroups: ["extensions"] + resources: + - networkpolicies + verbs: + - get + - list + - watch + - apiGroups: ["crd.projectcalico.org"] + resources: + - globalfelixconfigs + - globalbgpconfigs + - ippools + - globalnetworkpolicies + verbs: + - create + - get + - list + - update + - patch + - delete + - watch diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrolebinding.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrolebinding.yaml new file mode 100644 index 0000000000..b40c21875f --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: calico + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: calico +subjects: +- kind: ServiceAccount + name: calico + namespace: kube-system diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrole.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrole.yaml new file mode 100644 index 0000000000..658b126aca --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrole.yaml @@ -0,0 +1,14 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: calico-cpva + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] + - apiGroups: ["apps", "extensions"] + resources: ["deployments", "daemonsets"] + verbs: ["patch"] diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrolebinding.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrolebinding.yaml new file mode 100644 index 0000000000..f2b88270fa --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-clusterrolebinding.yaml @@ -0,0 +1,15 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: calico-cpva + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +subjects: + - kind: ServiceAccount + name: calico-cpva + namespace: kube-system +roleRef: + kind: ClusterRole + name: calico-cpva + apiGroup: rbac.authorization.k8s.io diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-serviceaccount.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-serviceaccount.yaml new file mode 100644 index 0000000000..a8e1b4fe07 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-cpva-serviceaccount.yaml @@ -0,0 +1,8 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: calico-cpva + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-daemonset.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-daemonset.yaml index 48e1dac449..7015b4145f 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-daemonset.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-daemonset.yaml @@ -23,12 +23,13 @@ spec: nodeSelector: projectcalico.org/ds-ready: "true" hostNetwork: true + serviceAccountName: calico containers: # Runs calico/node container on each Kubernetes node. This # container programs network policy and routes on each # host. - name: calico-node - image: calico/node:v1.3.0 + image: calico/node:v2.5.1 env: - name: CALICO_DISABLE_FILE_LOGGING value: "true" @@ -46,6 +47,8 @@ spec: value: "none" - name: FELIX_PROMETHEUSMETRICSENABLED value: "true" + - name: FELIX_HEALTHENABLED + value: "true" - name: IP value: "" - name: NO_DEFAULT_POOLS @@ -58,9 +61,18 @@ spec: value: "true" securityContext: privileged: true - resources: - requests: - cpu: __CALICO_NODE_CPU__ + livenessProbe: + httpGet: + path: /liveness + port: 9099 + periodSeconds: 10 + initialDelaySeconds: 10 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /readiness + port: 9099 + periodSeconds: 10 volumeMounts: - mountPath: /lib/modules name: lib-modules @@ -71,7 +83,7 @@ spec: # This container installs the Calico CNI binaries # and CNI network config file on each node. - name: install-cni - image: calico/cni:v1.9.1 + image: calico/cni:v1.10.0 command: ["/install-cni.sh"] env: - name: CNI_CONF_NAME @@ -103,7 +115,7 @@ spec: { "type": "portmap", "capabilities": {"portMappings": true}, - "noSnat": true + "snat": true } ] } diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-configmap.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-configmap.yaml new file mode 100644 index 0000000000..37dd40410e --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-configmap.yaml @@ -0,0 +1,22 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: calico-node-vertical-autoscaler + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +data: + node-autoscaler: |- + { + "calico-node": { + "requests": { + "cpu": { + "base": "80m", + "step": "20m", + "nodesPerStep": 10, + "max": "500m" + } + } + } + } diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-deployment.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-deployment.yaml new file mode 100644 index 0000000000..c66c3e0720 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-node-vertical-autoscaler-deployment.yaml @@ -0,0 +1,37 @@ +kind: Deployment +apiVersion: extensions/v1beta1 +metadata: + name: calico-node-vertical-autoscaler + namespace: kube-system + labels: + k8s-app: calico-node-autoscaler + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + replicas: 1 + template: + metadata: + labels: + k8s-app: calico-node-autoscaler + annotations: + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + containers: + - image: gcr.io/google_containers/cpvpa-amd64:v0.6.0 + name: autoscaler + command: + - /cpvpa + - --target=daemonset/calico-node + - --namespace=kube-system + - --logtostderr=true + - --poll-period-seconds=30 + - --v=2 + - --config-file=/etc/config/node-autoscaler + volumeMounts: + - name: config + mountPath: /etc/config + volumes: + - name: config + configMap: + name: calico-node-vertical-autoscaler + serviceAccountName: calico-cpva diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-serviceaccount.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-serviceaccount.yaml new file mode 100644 index 0000000000..b24b07595a --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/calico-serviceaccount.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: calico + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalbgpconfig-crd.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalbgpconfig-crd.yaml new file mode 100644 index 0000000000..2d3e6bd284 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalbgpconfig-crd.yaml @@ -0,0 +1,16 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +description: Calico Global BGP Configuration +kind: CustomResourceDefinition +metadata: + name: globalbgpconfigs.crd.projectcalico.org + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: GlobalBGPConfig + plural: globalbgpconfigs + singular: globalbgpconfig diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalfelixconfig-crd.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalfelixconfig-crd.yaml new file mode 100644 index 0000000000..7e5c7b1969 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalfelixconfig-crd.yaml @@ -0,0 +1,16 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +description: Calico Global Felix Configuration +kind: CustomResourceDefinition +metadata: + name: globalfelixconfigs.crd.projectcalico.org + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: GlobalFelixConfig + plural: globalfelixconfigs + singular: globalfelixconfig diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalnetworkpolicy-crd.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalnetworkpolicy-crd.yaml new file mode 100644 index 0000000000..398c05949b --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/globalnetworkpolicy-crd.yaml @@ -0,0 +1,16 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +description: Calico Global Network Policies +kind: CustomResourceDefinition +metadata: + name: globalnetworkpolicies.crd.projectcalico.org + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: GlobalNetworkPolicy + plural: globalnetworkpolicies + singular: globalnetworkpolicy diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/ippool-crd.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/ippool-crd.yaml new file mode 100644 index 0000000000..c09f73c188 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/ippool-crd.yaml @@ -0,0 +1,16 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +description: Calico IP Pools +kind: CustomResourceDefinition +metadata: + name: ippools.crd.projectcalico.org + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: IPPool + plural: ippools + singular: ippool diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-deployment.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-deployment.yaml index 2b49b09e5c..f2442ffd02 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-deployment.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-deployment.yaml @@ -8,7 +8,6 @@ metadata: addonmanager.kubernetes.io/mode: Reconcile k8s-app: calico-typha spec: - replicas: __CALICO_TYPHA_REPLICAS__ revisionHistoryLimit: 2 template: metadata: @@ -21,8 +20,9 @@ spec: - key: CriticalAddonsOnly operator: Exists hostNetwork: true + serviceAccountName: calico containers: - - image: calico/typha:v0.2.2 + - image: calico/typha:v0.4.1 name: calico-typha ports: - containerPort: 5473 @@ -45,13 +45,23 @@ spec: value: "kubernetes" - name: TYPHA_MAXCONNECTIONSLOWERLIMIT value: "1" + - name: TYPHA_HEALTHENABLED + value: "true" volumeMounts: - mountPath: /etc/calico name: etc-calico readOnly: true - resources: - requests: - cpu: __CALICO_TYPHA_CPU__ + livenessProbe: + httpGet: + path: /liveness + port: 9098 + periodSeconds: 30 + initialDelaySeconds: 30 + readinessProbe: + httpGet: + path: /readiness + port: 9098 + periodSeconds: 10 volumes: - name: etc-calico hostPath: diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-configmap.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-configmap.yaml new file mode 100644 index 0000000000..2f1c2b53eb --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-configmap.yaml @@ -0,0 +1,24 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: calico-typha-horizontal-autoscaler + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +data: + ladder: |- + { + "coresToReplicas": [], + "nodesToReplicas": + [ + [1, 1], + [10, 2], + [100, 3], + [250, 4], + [500, 5], + [1000, 6], + [1500, 7], + [2000, 8] + ] + } diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-deployment.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-deployment.yaml new file mode 100644 index 0000000000..b5d7f657d5 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-horizontal-autoscaler-deployment.yaml @@ -0,0 +1,33 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: calico-typha-horizontal-autoscaler + namespace: kube-system + labels: + k8s-app: calico-typha-autoscaler + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + replicas: 1 + template: + metadata: + labels: + k8s-app: calico-typha-autoscaler + annotations: + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + containers: + - image: gcr.io/google_containers/cluster-proportional-autoscaler-amd64:1.1.2 + name: autoscaler + command: + - /cluster-proportional-autoscaler + - --namespace=kube-system + - --configmap=calico-typha-horizontal-autoscaler + - --target=deployment/calico-typha + - --logtostderr=true + - --v=2 + resources: + requests: + cpu: 10m + limits: + cpu: 10m diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-configmap.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-configmap.yaml new file mode 100644 index 0000000000..4300761e78 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-configmap.yaml @@ -0,0 +1,22 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: calico-typha-vertical-autoscaler + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +data: + typha-autoscaler: |- + { + "calico-typha": { + "requests": { + "cpu": { + "base": "120m", + "step": "80m", + "nodesPerStep": 10, + "max": "1000m" + } + } + } + } diff --git a/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-deployment.yaml b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-deployment.yaml new file mode 100644 index 0000000000..c59be9af62 --- /dev/null +++ b/vendor/k8s.io/kubernetes/cluster/addons/calico-policy-controller/typha-vertical-autoscaler-deployment.yaml @@ -0,0 +1,37 @@ +kind: Deployment +apiVersion: extensions/v1beta1 +metadata: + name: calico-typha-vertical-autoscaler + namespace: kube-system + labels: + k8s-app: calico-typha-autoscaler + kubernetes.io/cluster-service: "true" + addonmanager.kubernetes.io/mode: Reconcile +spec: + replicas: 1 + template: + metadata: + labels: + k8s-app: calico-typha-autoscaler + annotations: + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + containers: + - image: gcr.io/google_containers/cpvpa-amd64:v0.6.0 + name: autoscaler + command: + - /cpvpa + - --target=deployment/calico-typha + - --namespace=kube-system + - --logtostderr=true + - --poll-period-seconds=30 + - --v=2 + - --config-file=/etc/config/typha-autoscaler + volumeMounts: + - name: config + mountPath: /etc/config + volumes: + - name: config + configMap: + name: calico-typha-vertical-autoscaler + serviceAccountName: calico-cpva diff --git a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/google/heapster-controller.yaml b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/google/heapster-controller.yaml index a8aeb03c0a..501932772f 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/google/heapster-controller.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/google/heapster-controller.yaml @@ -23,29 +23,29 @@ metadata: apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: heapster-v1.4.0 + name: heapster-v1.4.2 namespace: kube-system labels: k8s-app: heapster kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile - version: v1.4.0 + version: v1.4.2 spec: replicas: 1 selector: matchLabels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 template: metadata: labels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: containers: - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: heapster livenessProbe: httpGet: @@ -65,7 +65,7 @@ spec: - name: usr-ca-certs mountPath: /usr/share/ca-certificates readOnly: true - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: eventer command: - /eventer @@ -103,7 +103,7 @@ spec: - --memory={{ base_metrics_memory }} - --extra-memory={{metrics_memory_per_node}}Mi - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=heapster - --poll-period=300000 - --estimator=exponential @@ -132,7 +132,7 @@ spec: - --memory={{base_eventer_memory}} - --extra-memory={{eventer_memory_per_node}}Ki - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=eventer - --poll-period=300000 - --estimator=exponential diff --git a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/googleinfluxdb/heapster-controller-combined.yaml b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/googleinfluxdb/heapster-controller-combined.yaml index 71b132a5c5..70e8a0693d 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/googleinfluxdb/heapster-controller-combined.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/googleinfluxdb/heapster-controller-combined.yaml @@ -23,29 +23,29 @@ metadata: apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: heapster-v1.4.0 + name: heapster-v1.4.2 namespace: kube-system labels: k8s-app: heapster kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile - version: v1.4.0 + version: v1.4.2 spec: replicas: 1 selector: matchLabels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 template: metadata: labels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: containers: - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: heapster livenessProbe: httpGet: @@ -66,7 +66,7 @@ spec: - name: usr-ca-certs mountPath: /usr/share/ca-certificates readOnly: true - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: eventer command: - /eventer @@ -104,7 +104,7 @@ spec: - --memory={{ base_metrics_memory }} - --extra-memory={{ metrics_memory_per_node }}Mi - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=heapster - --poll-period=300000 - --estimator=exponential @@ -133,7 +133,7 @@ spec: - --memory={{ base_eventer_memory }} - --extra-memory={{ eventer_memory_per_node }}Ki - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=eventer - --poll-period=300000 - --estimator=exponential diff --git a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/influxdb/heapster-controller.yaml b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/influxdb/heapster-controller.yaml index 9d9d616b9f..cce7040c6d 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/influxdb/heapster-controller.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/influxdb/heapster-controller.yaml @@ -23,29 +23,29 @@ metadata: apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: heapster-v1.4.0 + name: heapster-v1.4.2 namespace: kube-system labels: k8s-app: heapster kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile - version: v1.4.0 + version: v1.4.2 spec: replicas: 1 selector: matchLabels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 template: metadata: labels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: containers: - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: heapster livenessProbe: httpGet: @@ -58,7 +58,7 @@ spec: - /heapster - --source=kubernetes.summary_api:'' - --sink=influxdb:http://monitoring-influxdb:8086 - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: eventer command: - /eventer @@ -89,7 +89,7 @@ spec: - --memory={{ base_metrics_memory }} - --extra-memory={{ metrics_memory_per_node }}Mi - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=heapster - --poll-period=300000 - --estimator=exponential @@ -118,7 +118,7 @@ spec: - --memory={{ base_eventer_memory }} - --extra-memory={{ eventer_memory_per_node }}Ki - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=eventer - --poll-period=300000 - --estimator=exponential diff --git a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/stackdriver/heapster-controller.yaml b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/stackdriver/heapster-controller.yaml index ed78824e7b..8fec6ba9ab 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/stackdriver/heapster-controller.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/stackdriver/heapster-controller.yaml @@ -21,29 +21,29 @@ metadata: apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: heapster-v1.4.0 + name: heapster-v1.4.2 namespace: kube-system labels: k8s-app: heapster kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile - version: v1.4.0 + version: v1.4.2 spec: replicas: 1 selector: matchLabels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 template: metadata: labels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: containers: - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: heapster livenessProbe: httpGet: @@ -55,8 +55,7 @@ spec: command: - /heapster - --source=kubernetes.summary_api:'' - - --sink=stackdriver - # TODO: add --disable_export when it's merged into Heapster release + - --sink=stackdriver:?cluster_name={{ cluster_name }}&min_interval_sec=100&batch_export_timeout_sec=110 volumeMounts: - name: ssl-certs mountPath: /etc/ssl/certs @@ -64,6 +63,26 @@ spec: - name: usr-ca-certs mountPath: /usr/share/ca-certificates readOnly: true + - name: prom-to-sd + image: gcr.io/google-containers/prometheus-to-sd:v0.2.1 + command: + - /monitor + - --source=heapster:http://localhost:8082?whitelisted=stackdriver_requests_count,stackdriver_timeseries_count + - --stackdriver-prefix=container.googleapis.com/internal/addons + - --pod-id=$(POD_NAME) + - --namespace-id=$(POD_NAMESPACE) + volumeMounts: + - name: ssl-certs + mountPath: /etc/ssl/certs + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace - image: gcr.io/google_containers/addon-resizer:1.7 name: heapster-nanny resources: @@ -89,7 +108,7 @@ spec: - --memory={{ base_metrics_memory }} - --extra-memory={{metrics_memory_per_node}}Mi - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=heapster - --poll-period=300000 - --estimator=exponential diff --git a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/standalone/heapster-controller.yaml b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/standalone/heapster-controller.yaml index 79b701dae9..4004e61e9b 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/standalone/heapster-controller.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/cluster-monitoring/standalone/heapster-controller.yaml @@ -21,29 +21,29 @@ metadata: apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: heapster-v1.4.0 + name: heapster-v1.4.2 namespace: kube-system labels: k8s-app: heapster kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile - version: v1.4.0 + version: v1.4.2 spec: replicas: 1 selector: matchLabels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 template: metadata: labels: k8s-app: heapster - version: v1.4.0 + version: v1.4.2 annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: containers: - - image: gcr.io/google_containers/heapster-amd64:v1.4.0 + - image: gcr.io/google_containers/heapster-amd64:v1.4.2 name: heapster livenessProbe: httpGet: @@ -80,7 +80,7 @@ spec: - --memory={{ base_metrics_memory }} - --extra-memory={{ metrics_memory_per_node }}Mi - --threshold=5 - - --deployment=heapster-v1.4.0 + - --deployment=heapster-v1.4.2 - --container=heapster - --poll-period=300000 - --estimator=exponential diff --git a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/event-exporter.yaml b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/event-exporter.yaml index e3953d65d4..c3fff97484 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/event-exporter.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/event-exporter.yaml @@ -29,10 +29,11 @@ subjects: apiVersion: apps/v1beta1 kind: Deployment metadata: - name: event-exporter-v0.1.4 + name: event-exporter namespace: kube-system labels: k8s-app: event-exporter + version: v0.1.5 kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile spec: @@ -41,16 +42,17 @@ spec: metadata: labels: k8s-app: event-exporter + version: v0.1.5 spec: serviceAccountName: event-exporter-sa containers: # TODO: Add resources in 1.8 - name: event-exporter - image: gcr.io/google-containers/event-exporter:v0.1.0-r2 + image: gcr.io/google-containers/event-exporter:v0.1.5 command: - '/event-exporter' - name: prometheus-to-sd-exporter - image: gcr.io/google-containers/prometheus-to-sd:v0.1.2-r2 + image: gcr.io/google-containers/prometheus-to-sd:v0.2.1 command: - /monitor - --component=event_exporter diff --git a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml index a1d7a5d1ab..2d227331fa 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml @@ -70,27 +70,14 @@ data: # Detect exceptions in the log output and forward them as one log entry. - @type copy - - - @type prometheus - - - type counter - name logging_line_count - desc Total number of lines generated by application containers - - - - @type detect_exceptions - - remove_tag_prefix raw - message log - stream stream - multiline_flush_interval 5 - max_bytes 500000 - max_lines 1000 - + @type detect_exceptions + + remove_tag_prefix raw + message log + stream stream + multiline_flush_interval 5 + max_bytes 500000 + max_lines 1000 system.input.conf: |- # Example: @@ -337,85 +324,70 @@ data: + # TODO(instrumentation): Reconsider this workaround later. + # Trim the entries which exceed slightly less than 100KB, to avoid + # dropping them. It is a necessity, because Stackdriver only supports + # entries that are up to 100KB in size. + + @type record_transformer + enable_ruby true + + log ${record['log'].length > 100000 ? "[Trimmed]#{record['log'][0..100000]}..." : record['log']} + + + # We use 2 output stanzas - one to handle the container logs and one to handle # the node daemon logs, the latter of which explicitly sends its logs to the # compute.googleapis.com service rather than container.googleapis.com to keep # them separate since most users don't care about the node logs. - @type copy - - - @type google_cloud - - # Set the buffer type to file to improve the reliability and reduce the memory consumption - buffer_type file - buffer_path /var/log/fluentd-buffers/kubernetes.containers.buffer - # Set queue_full action to block because we want to pause gracefully - # in case of the off-the-limits load instead of throwing an exception - buffer_queue_full_action block - # Set the chunk limit conservatively to avoid exceeding the GCL limit - # of 10MiB per write request. - buffer_chunk_limit 2M - # Cap the combined memory usage of this buffer and the one below to - # 2MiB/chunk * (6 + 2) chunks = 16 MiB - buffer_queue_limit 6 - # Never wait more than 5 seconds before flushing logs in the non-error case. - flush_interval 5s - # Never wait longer than 30 seconds between retries. - max_retry_wait 30 - # Disable the limit on the number of retries (retry forever). - disable_retry_limit - # Use multiple threads for processing. - num_threads 2 - - - @type prometheus - - - type counter - name logging_entry_count - desc Total number of log entries generated by either application containers or system components - - component container - - - + @type google_cloud + + # Collect metrics in Prometheus registry about plugin activity. + enable_monitoring true + monitoring_type prometheus + # Set the buffer type to file to improve the reliability and reduce the memory consumption + buffer_type file + buffer_path /var/log/fluentd-buffers/kubernetes.containers.buffer + # Set queue_full action to block because we want to pause gracefully + # in case of the off-the-limits load instead of throwing an exception + buffer_queue_full_action block + # Set the chunk limit conservatively to avoid exceeding the GCL limit + # of 10MiB per write request. + buffer_chunk_limit 2M + # Cap the combined memory usage of this buffer and the one below to + # 2MiB/chunk * (6 + 2) chunks = 16 MiB + buffer_queue_limit 6 + # Never wait more than 5 seconds before flushing logs in the non-error case. + flush_interval 5s + # Never wait longer than 30 seconds between retries. + max_retry_wait 30 + # Disable the limit on the number of retries (retry forever). + disable_retry_limit + # Use multiple threads for processing. + num_threads 2 # Keep a smaller buffer here since these logs are less important than the user's # container logs. - @type copy - - - @type google_cloud - - detect_subservice false - buffer_type file - buffer_path /var/log/fluentd-buffers/kubernetes.system.buffer - buffer_queue_full_action block - buffer_chunk_limit 2M - buffer_queue_limit 2 - flush_interval 5s - max_retry_wait 30 - disable_retry_limit - num_threads 2 - - - @type prometheus - - - type counter - name logging_entry_count - desc Total number of log entries generated by either application containers or system components - - component system - - - + @type google_cloud + + enable_monitoring true + monitoring_type prometheus + detect_subservice false + buffer_type file + buffer_path /var/log/fluentd-buffers/kubernetes.system.buffer + buffer_queue_full_action block + buffer_chunk_limit 2M + buffer_queue_limit 2 + flush_interval 5s + max_retry_wait 30 + disable_retry_limit + num_threads 2 metadata: - name: fluentd-gcp-config-v1.1 + name: fluentd-gcp-config-v1.1.1 namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile diff --git a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml index ba7bc37676..013a3b1da9 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml @@ -27,7 +27,7 @@ spec: hostNetwork: true containers: - name: fluentd-gcp - image: gcr.io/google-containers/fluentd-gcp:2.0.7 + image: gcr.io/google-containers/fluentd-gcp:2.0.8 # If fluentd consumes its own logs, the following situation may happen: # fluentd fails to send a chunk to the server => writes it to the log => # tries to send this message to the server => fails to send a chunk and so on. @@ -90,13 +90,13 @@ spec: exit 1; fi; - name: prometheus-to-sd-exporter - image: gcr.io/google-containers/prometheus-to-sd:v0.1.0 + image: gcr.io/google-containers/prometheus-to-sd:v0.1.3 command: - /monitor - --component=fluentd - --target-port=31337 - --stackdriver-prefix=container.googleapis.com/internal/addons - - --whitelisted-metrics=logging_line_count,logging_entry_count + - --whitelisted-metrics=stackdriver_successful_requests_count,stackdriver_failed_requests_count,stackdriver_ingested_entries_count,stackdriver_dropped_entries_count volumeMounts: - name: ssl-certs mountPath: /etc/ssl/certs @@ -107,6 +107,9 @@ spec: effect: "NoSchedule" - operator: "Exists" effect: "NoExecute" + #TODO: remove this toleration once #44445 is properly fixed. + - operator: "Exists" + effect: "NoSchedule" terminationGracePeriodSeconds: 30 volumes: - name: varlog @@ -120,7 +123,7 @@ spec: path: /usr/lib64 - name: config-volume configMap: - name: fluentd-gcp-config-v1.1 + name: fluentd-gcp-config-v1.1.1 - name: ssl-certs hostPath: path: /etc/ssl/certs diff --git a/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy-configmap.yaml b/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy-configmap.yaml index 5be4cbe3b6..2d23f42ad6 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy-configmap.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy-configmap.yaml @@ -20,40 +20,68 @@ data: access_log /dev/stdout; server { listen 127.0.0.1:988; + # When serving 301s, don't redirect to port 988. + port_in_redirect off; # By default, return 403. This protects us from new API versions. location / { - return 403; + return 403 "This metadata API is not allowed by the metadata proxy."; } # Allow for REST discovery. location = / { + if ($args ~* "^(.+&)?recursive=") { + return 403 "?recursive calls are not allowed by the metadata proxy."; + } proxy_pass http://169.254.169.254; } location = /computeMetadata/ { + if ($args ~* "^(.+&)?recursive=") { + return 403 "?recursive calls are not allowed by the metadata proxy."; + } proxy_pass http://169.254.169.254; } # By default, allow the v0.1, v1beta1, and v1 APIs. location /0.1/ { + if ($args ~* "^(.+&)?recursive=") { + return 403 "?recursive calls are not allowed by the metadata proxy."; + } proxy_pass http://169.254.169.254; } location /computeMetadata/v1beta1/ { + if ($args ~* "^(.+&)?recursive=") { + return 403 "?recursive calls are not allowed by the metadata proxy."; + } proxy_pass http://169.254.169.254; } location /computeMetadata/v1/ { + if ($args ~* "^(.+&)?recursive=") { + return 403 "?recursive calls are not allowed by the metadata proxy."; + } proxy_pass http://169.254.169.254; } # Return a 403 for the kube-env attribute in all allowed API versions. location /0.1/meta-data/attributes/kube-env { - return 403; + return 403 "This metadata endpoint is concealed."; } location /computeMetadata/v1beta1/instance/attributes/kube-env { - return 403; + return 403 "This metadata endpoint is concealed."; } location /computeMetadata/v1/instance/attributes/kube-env { - return 403; + return 403 "This metadata endpoint is concealed."; + } + + # Return a 403 for instance identity in all allowed API versions. + location ~ /0.1/meta-data/service-accounts/.+/identity { + return 403 "This metadata endpoint is concealed."; + } + location ~ /computeMetadata/v1beta1/instance/service-accounts/.+/identity { + return 403 "This metadata endpoint is concealed."; + } + location ~ /computeMetadata/v1/instance/service-accounts/.+/identity { + return 403 "This metadata endpoint is concealed."; } } } diff --git a/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy.yaml b/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy.yaml index a9a1935ea7..2095345098 100644 --- a/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy.yaml +++ b/vendor/k8s.io/kubernetes/cluster/addons/metadata-proxy/gce/metadata-proxy.yaml @@ -27,7 +27,7 @@ spec: dnsPolicy: Default containers: - name: metadata-proxy - image: gcr.io/google-containers/metadata-proxy:0.1.2 + image: gcr.io/google-containers/metadata-proxy:0.1.3 imagePullPolicy: Always securityContext: privileged: true diff --git a/vendor/k8s.io/kubernetes/cluster/common.sh b/vendor/k8s.io/kubernetes/cluster/common.sh index 0bcc69685f..2b298bf6b6 100755 --- a/vendor/k8s.io/kubernetes/cluster/common.sh +++ b/vendor/k8s.io/kubernetes/cluster/common.sh @@ -605,6 +605,7 @@ function build-kube-env { rm -f ${file} cat >$file <>$file <>$file <>/srv/salt-overlay/pillar/cluster-params.sls storage_media_type: '$(echo "$STORAGE_MEDIA_TYPE" | sed -e "s/'/''/g")' +EOF + fi + if [ -n "${KUBE_APISERVER_REQUEST_TIMEOUT_SEC:-}" ]; then + cat <>/srv/salt-overlay/pillar/cluster-params.sls +kube_apiserver_request_timeout_sec: '$(echo "$KUBE_APISERVER_REQUEST_TIMEOUT_SEC" | sed -e "s/'/''/g")' EOF fi if [ -n "${ADMISSION_CONTROL:-}" ] && [ ${ADMISSION_CONTROL} == *"ImagePolicyWebhook"* ]; then diff --git a/vendor/k8s.io/kubernetes/cluster/gce/container-linux/configure-helper.sh b/vendor/k8s.io/kubernetes/cluster/gce/container-linux/configure-helper.sh index 3a6748172b..113d2b4bcf 100755 --- a/vendor/k8s.io/kubernetes/cluster/gce/container-linux/configure-helper.sh +++ b/vendor/k8s.io/kubernetes/cluster/gce/container-linux/configure-helper.sh @@ -34,54 +34,6 @@ function create-dirs { fi } -# Vars assumed: -# NUM_NODES -function get-calico-node-cpu { - local suggested_calico_cpus=100m - if [[ "${NUM_NODES}" -gt "10" ]]; then - suggested_calico_cpus=250m - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - suggested_calico_cpus=500m - fi - if [[ "${NUM_NODES}" -gt "500" ]]; then - suggested_calico_cpus=1000m - fi - echo "${suggested_calico_cpus}" -} - -# Vars assumed: -# NUM_NODES -function get-calico-typha-replicas { - local typha_count=1 - if [[ "${NUM_NODES}" -gt "10" ]]; then - typha_count=2 - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - typha_count=3 - fi - if [[ "${NUM_NODES}" -gt "250" ]]; then - typha_count=4 - fi - if [[ "${NUM_NODES}" -gt "500" ]]; then - typha_count=5 - fi - echo "${typha_count}" -} - -# Vars assumed: -# NUM_NODES -function get-calico-typha-cpu { - local typha_cpu=200m - if [[ "${NUM_NODES}" -gt "10" ]]; then - typha_cpu=500m - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - typha_cpu=1000m - fi - echo "${typha_cpu}" -} - # Create directories referenced in the kube-controller-manager manifest for # bindmounts. This is used under the rkt runtime to work around # https://github.com/kubernetes/kubernetes/issues/26816 @@ -867,6 +819,9 @@ function start-kube-apiserver { if [[ -n "${STORAGE_MEDIA_TYPE:-}" ]]; then params+=" --storage-media-type=${STORAGE_MEDIA_TYPE}" fi + if [[ -n "${KUBE_APISERVER_REQUEST_TIMEOUT_SEC:-}" ]]; then + params+=" --request-timeout=${KUBE_APISERVER_REQUEST_TIMEOUT_SEC}s" + fi if [[ -n "${ENABLE_GARBAGE_COLLECTOR:-}" ]]; then params+=" --enable-garbage-collector=${ENABLE_GARBAGE_COLLECTOR}" fi @@ -1129,7 +1084,7 @@ function start-cluster-autoscaler { local -r src_file="${KUBE_HOME}/kube-manifests/kubernetes/gci-trusty/cluster-autoscaler.manifest" remove-salt-config-comments "${src_file}" - local params="${AUTOSCALER_MIG_CONFIG} ${CLOUD_CONFIG_OPT} ${AUTOSCALER_EXPANDER_CONFIG:-}" + local params="${AUTOSCALER_MIG_CONFIG} ${CLOUD_CONFIG_OPT} ${AUTOSCALER_EXPANDER_CONFIG:---expander=price}" sed -i -e "s@{{params}}@${params}@g" "${src_file}" sed -i -e "s@{{cloud_config_mount}}@${CLOUD_CONFIG_MOUNT}@g" "${src_file}" sed -i -e "s@{{cloud_config_volume}}@${CLOUD_CONFIG_VOLUME}@g" "${src_file}" @@ -1168,6 +1123,8 @@ function setup-addon-manifests { } # Prepares the manifests of k8s addons, and starts the addon manager. +# Vars assumed: +# CLUSTER_NAME function start-kube-addons { echo "Prepare kube-addons manifests and start kube addon manager" local -r src_dir="${KUBE_HOME}/kube-manifests/kubernetes/gci-trusty" @@ -1205,6 +1162,7 @@ function start-kube-addons { controller_yaml="${controller_yaml}/heapster-controller.yaml" fi remove-salt-config-comments "${controller_yaml}" + sed -i -e "s@{{ cluster_name }}@${CLUSTER_NAME}@g" "${controller_yaml}" sed -i -e "s@{{ *base_metrics_memory *}}@${base_metrics_memory}@g" "${controller_yaml}" sed -i -e "s@{{ *base_metrics_cpu *}}@${base_metrics_cpu}@g" "${controller_yaml}" sed -i -e "s@{{ *base_eventer_memory *}}@${base_eventer_memory}@g" "${controller_yaml}" @@ -1260,20 +1218,9 @@ function start-kube-addons { if [[ "${NETWORK_POLICY_PROVIDER:-}" == "calico" ]]; then setup-addon-manifests "addons" "calico-policy-controller" - # Configure Calico based on cluster size and image type. + # Configure Calico CNI directory. local -r ds_file="${dst_dir}/calico-policy-controller/calico-node-daemonset.yaml" - local -r typha_dep_file="${dst_dir}/calico-policy-controller/typha-deployment.yaml" sed -i -e "s@__CALICO_CNI_DIR__@/opt/cni/bin@g" "${ds_file}" - sed -i -e "s@__CALICO_NODE_CPU__@$(get-calico-node-cpu)@g" "${ds_file}" - sed -i -e "s@__CALICO_TYPHA_CPU__@$(get-calico-typha-cpu)@g" "${typha_dep_file}" - sed -i -e "s@__CALICO_TYPHA_REPLICAS__@$(get-calico-typha-replicas)@g" "${typha_dep_file}" - else - # If not configured to use Calico, the set the typha replica count to 0, but only if the - # addon is present. - local -r typha_dep_file="${dst_dir}/calico-policy-controller/typha-deployment.yaml" - if [[ -e $typha_dep_file ]]; then - sed -i -e "s@__CALICO_TYPHA_REPLICAS__@0@g" "${typha_dep_file}" - fi fi if [[ "${ENABLE_DEFAULT_STORAGE_CLASS:-}" == "true" ]]; then setup-addon-manifests "addons" "storage-class/gce" diff --git a/vendor/k8s.io/kubernetes/cluster/gce/gci/configure-helper.sh b/vendor/k8s.io/kubernetes/cluster/gce/gci/configure-helper.sh index 09727c71b5..4416c02648 100644 --- a/vendor/k8s.io/kubernetes/cluster/gce/gci/configure-helper.sh +++ b/vendor/k8s.io/kubernetes/cluster/gce/gci/configure-helper.sh @@ -32,55 +32,6 @@ function setup-os-params { echo "core.%e.%p.%t" > /proc/sys/kernel/core_pattern } -# Vars assumed: -# NUM_NODES -function get-calico-node-cpu { - local suggested_calico_cpus=100m - if [[ "${NUM_NODES}" -gt "10" ]]; then - suggested_calico_cpus=250m - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - suggested_calico_cpus=500m - fi - if [[ "${NUM_NODES}" -gt "500" ]]; then - suggested_calico_cpus=1000m - fi - echo "${suggested_calico_cpus}" -} - -# Vars assumed: -# NUM_NODES -function get-calico-typha-replicas { - local typha_count=1 - if [[ "${NUM_NODES}" -gt "10" ]]; then - typha_count=2 - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - typha_count=3 - fi - if [[ "${NUM_NODES}" -gt "250" ]]; then - typha_count=4 - fi - if [[ "${NUM_NODES}" -gt "500" ]]; then - typha_count=5 - fi - echo "${typha_count}" -} - -# Vars assumed: -# NUM_NODES -function get-calico-typha-cpu { - local typha_cpu=200m - if [[ "${NUM_NODES}" -gt "10" ]]; then - typha_cpu=500m - fi - if [[ "${NUM_NODES}" -gt "100" ]]; then - typha_cpu=1000m - fi - echo "${typha_cpu}" -} - - function config-ip-firewall { echo "Configuring IP firewall rules" # The GCI image has host firewall which drop most inbound/forwarded packets. @@ -239,10 +190,13 @@ function append_or_replace_prefixed_line { local -r file="${1:-}" local -r prefix="${2:-}" local -r suffix="${3:-}" + local -r dirname="$(dirname ${file})" + local -r tmpfile="$(mktemp -t filtered.XXXX --tmpdir=${dirname})" touch "${file}" - awk "substr(\$0,0,length(\"${prefix}\")) != \"${prefix}\" { print }" "${file}" > "${file}.filtered" && mv "${file}.filtered" "${file}" - echo "${prefix}${suffix}" >> "${file}" + awk "substr(\$0,0,length(\"${prefix}\")) != \"${prefix}\" { print }" "${file}" > "${tmpfile}" + echo "${prefix}${suffix}" >> "${tmpfile}" + mv "${tmpfile}" "${file}" } function create-node-pki { @@ -356,7 +310,11 @@ function create-master-auth { fi append_or_replace_prefixed_line "${basic_auth_csv}" "${KUBE_PASSWORD},${KUBE_USER}," "admin,system:masters" fi + local -r known_tokens_csv="${auth_dir}/known_tokens.csv" + if [[ -e "${known_tokens_csv}" && "${METADATA_CLOBBERS_CONFIG:-false}" == "true" ]]; then + rm "${known_tokens_csv}" + fi if [[ -n "${KUBE_BEARER_TOKEN:-}" ]]; then append_or_replace_prefixed_line "${known_tokens_csv}" "${KUBE_BEARER_TOKEN}," "admin,admin,system:masters" fi @@ -788,20 +746,26 @@ function assemble-docker-flags { # If using a network plugin, extend the docker configuration to always remove # the network checkpoint to avoid corrupt checkpoints. # (https://github.com/docker/docker/issues/18283). - echo "Extend the default docker.service configuration" + echo "Extend the docker.service configuration to remove the network checkpiont" mkdir -p /etc/systemd/system/docker.service.d cat </etc/systemd/system/docker.service.d/01network.conf [Service] ExecStartPre=/bin/sh -x -c "rm -rf /var/lib/docker/network" EOF + fi - systemctl daemon-reload + # Ensure TasksMax is sufficient for docker. + # (https://github.com/kubernetes/kubernetes/issues/51977) + echo "Extend the docker.service configuration to set a higher pids limit" + mkdir -p /etc/systemd/system/docker.service.d + cat </etc/systemd/system/docker.service.d/02tasksmax.conf +[Service] +TasksMax=infinity +EOF - # If using a network plugin, we need to explicitly restart docker daemon, because - # kubelet will not do it. + systemctl daemon-reload echo "Docker command line is updated. Restart docker to pick it up" systemctl restart docker - fi } # A helper function for loading a docker image. It keeps trying up to 5 times. @@ -987,6 +951,8 @@ function start-node-problem-detector { flags+=" --logtostderr" flags+=" --system-log-monitors=${km_config},${dm_config}" flags+=" --apiserver-override=https://${KUBERNETES_MASTER_NAME}?inClusterConfig=false&auth=/var/lib/node-problem-detector/kubeconfig" + local -r npd_port=${NODE_PROBLEM_DETECTOR_PORT:-20256} + flags+=" --port=${npd_port}" # Write the systemd service file for node problem detector. cat </etc/systemd/system/node-problem-detector.service @@ -1186,6 +1152,7 @@ function prepare-mounter-rootfs { mount --make-rshared "${CONTAINERIZED_MOUNTER_ROOTFS}/var/lib/kubelet" mount --bind -o ro /proc "${CONTAINERIZED_MOUNTER_ROOTFS}/proc" mount --bind -o ro /dev "${CONTAINERIZED_MOUNTER_ROOTFS}/dev" + mount --bind -o ro /etc/resolv.conf "${CONTAINERIZED_MOUNTER_ROOTFS}/etc/resolv.conf" } # A helper function for removing salt configuration and comments from a file. @@ -1251,6 +1218,9 @@ function start-kube-apiserver { if [[ -n "${STORAGE_MEDIA_TYPE:-}" ]]; then params+=" --storage-media-type=${STORAGE_MEDIA_TYPE}" fi + if [[ -n "${KUBE_APISERVER_REQUEST_TIMEOUT_SEC:-}" ]]; then + params+=" --request-timeout=${KUBE_APISERVER_REQUEST_TIMEOUT_SEC}s" + fi if [[ -n "${ENABLE_GARBAGE_COLLECTOR:-}" ]]; then params+=" --enable-garbage-collector=${ENABLE_GARBAGE_COLLECTOR}" fi @@ -1562,7 +1532,7 @@ function start-cluster-autoscaler { local -r src_file="${KUBE_HOME}/kube-manifests/kubernetes/gci-trusty/cluster-autoscaler.manifest" remove-salt-config-comments "${src_file}" - local params="${AUTOSCALER_MIG_CONFIG} ${CLOUD_CONFIG_OPT} ${AUTOSCALER_EXPANDER_CONFIG:-}" + local params="${AUTOSCALER_MIG_CONFIG} ${CLOUD_CONFIG_OPT} ${AUTOSCALER_EXPANDER_CONFIG:---expander=price}" sed -i -e "s@{{params}}@${params}@g" "${src_file}" sed -i -e "s@{{cloud_config_mount}}@${CLOUD_CONFIG_MOUNT}@g" "${src_file}" sed -i -e "s@{{cloud_config_volume}}@${CLOUD_CONFIG_VOLUME}@g" "${src_file}" @@ -1600,7 +1570,29 @@ function setup-addon-manifests { chmod 644 "${dst_dir}"/* } +# Fluentd manifest is modified using kubectl, which may not be available at +# this point. Run this as a background process. +function wait-for-apiserver-and-update-fluentd { + until kubectl get nodes + do + sleep 10 + done + kubectl set resources --dry-run --local -f ${fluentd_gcp_yaml} \ + --limits=memory=${FLUENTD_GCP_MEMORY_LIMIT} \ + --requests=cpu=${FLUENTD_GCP_CPU_REQUEST},memory=${FLUENTD_GCP_MEMORY_REQUEST} \ + --containers=fluentd-gcp -o yaml > ${fluentd_gcp_yaml}.tmp + mv ${fluentd_gcp_yaml}.tmp ${fluentd_gcp_yaml} +} + +# Trigger background process that will ultimately update fluentd resource +# requirements. +function start-fluentd-resource-update { + wait-for-apiserver-and-update-fluentd & +} + # Prepares the manifests of k8s addons, and starts the addon manager. +# Vars assumed: +# CLUSTER_NAME function start-kube-addons { echo "Prepare kube-addons manifests and start kube addon manager" local -r src_dir="${KUBE_HOME}/kube-manifests/kubernetes/gci-trusty" @@ -1638,6 +1630,7 @@ function start-kube-addons { controller_yaml="${controller_yaml}/heapster-controller.yaml" fi remove-salt-config-comments "${controller_yaml}" + sed -i -e "s@{{ cluster_name }}@${CLUSTER_NAME}@g" "${controller_yaml}" sed -i -e "s@{{ *base_metrics_memory *}}@${base_metrics_memory}@g" "${controller_yaml}" sed -i -e "s@{{ *base_metrics_cpu *}}@${base_metrics_cpu}@g" "${controller_yaml}" sed -i -e "s@{{ *base_eventer_memory *}}@${base_eventer_memory}@g" "${controller_yaml}" @@ -1680,6 +1673,8 @@ function start-kube-addons { if [[ "${ENABLE_NODE_LOGGING:-}" == "true" ]] && \ [[ "${LOGGING_DESTINATION:-}" == "gcp" ]]; then setup-addon-manifests "addons" "fluentd-gcp" + local -r fluentd_gcp_yaml="${dst_dir}/fluentd-gcp/fluentd-gcp-ds.yaml" + start-fluentd-resource-update fi if [[ "${ENABLE_CLUSTER_UI:-}" == "true" ]]; then setup-addon-manifests "addons" "dashboard" @@ -1697,20 +1692,9 @@ function start-kube-addons { if [[ "${NETWORK_POLICY_PROVIDER:-}" == "calico" ]]; then setup-addon-manifests "addons" "calico-policy-controller" - # Configure Calico based on cluster size and image type. + # Configure Calico CNI directory. local -r ds_file="${dst_dir}/calico-policy-controller/calico-node-daemonset.yaml" - local -r typha_dep_file="${dst_dir}/calico-policy-controller/typha-deployment.yaml" sed -i -e "s@__CALICO_CNI_DIR__@/home/kubernetes/bin@g" "${ds_file}" - sed -i -e "s@__CALICO_NODE_CPU__@$(get-calico-node-cpu)@g" "${ds_file}" - sed -i -e "s@__CALICO_TYPHA_CPU__@$(get-calico-typha-cpu)@g" "${typha_dep_file}" - sed -i -e "s@__CALICO_TYPHA_REPLICAS__@$(get-calico-typha-replicas)@g" "${typha_dep_file}" - else - # If not configured to use Calico, the set the typha replica count to 0, but only if the - # addon is present. - local -r typha_dep_file="${dst_dir}/calico-policy-controller/typha-deployment.yaml" - if [[ -e $typha_dep_file ]]; then - sed -i -e "s@__CALICO_TYPHA_REPLICAS__@0@g" "${typha_dep_file}" - fi fi if [[ "${ENABLE_DEFAULT_STORAGE_CLASS:-}" == "true" ]]; then setup-addon-manifests "addons" "storage-class/gce" diff --git a/vendor/k8s.io/kubernetes/cluster/gce/list-resources.sh b/vendor/k8s.io/kubernetes/cluster/gce/list-resources.sh index 9790205c22..a63be2c24f 100755 --- a/vendor/k8s.io/kubernetes/cluster/gce/list-resources.sh +++ b/vendor/k8s.io/kubernetes/cluster/gce/list-resources.sh @@ -43,11 +43,12 @@ fi GREP_REGEX="" function gcloud-compute-list() { local -r resource=$1 + local -r filter=${2:-} echo -e "\n\n[ ${resource} ]" local attempt=1 local result="" while true; do - if result=$(gcloud compute ${resource} list --project=${PROJECT} ${@:2}); then + if result=$(gcloud compute ${resource} list --project=${PROJECT} ${filter:+--filter="$filter"} ${@:3}); then if [[ ! -z "${GREP_REGEX}" ]]; then result=$(echo "${result}" | grep "${GREP_REGEX}" || true) fi @@ -73,21 +74,21 @@ echo "Provider: ${KUBERNETES_PROVIDER:-}" # List resources related to instances, filtering by the instance prefix if # provided. -gcloud-compute-list instance-templates --regexp="${INSTANCE_PREFIX}.*" -gcloud-compute-list instance-groups ${ZONE:+"--zones=${ZONE}"} --regexp="${INSTANCE_PREFIX}.*" -gcloud-compute-list instances ${ZONE:+"--zones=${ZONE}"} --regexp="${INSTANCE_PREFIX}.*" +gcloud-compute-list instance-templates "name ~ '${INSTANCE_PREFIX}.*'" +gcloud-compute-list instance-groups "${ZONE:+"zone:(${ZONE}) AND "}name ~ '${INSTANCE_PREFIX}.*'" +gcloud-compute-list instances "${ZONE:+"zone:(${ZONE}) AND "}name ~ '${INSTANCE_PREFIX}.*'" -# List disk resources, filterying by instance prefix if provided. -gcloud-compute-list disks ${ZONE:+"--zones=${ZONE}"} --regexp="${INSTANCE_PREFIX}.*" +# List disk resources, filtering by instance prefix if provided. +gcloud-compute-list disks "${ZONE:+"zone:(${ZONE}) AND "}name ~ '${INSTANCE_PREFIX}.*'" # List network resources. We include names starting with "a", corresponding to # those that Kubernetes creates. -gcloud-compute-list addresses ${REGION:+"--regions=${REGION}"} --regexp="a.*|${INSTANCE_PREFIX}.*" +gcloud-compute-list addresses "${REGION:+"region=(${REGION}) AND "}name ~ 'a.*|${INSTANCE_PREFIX}.*'" # Match either the header or a line with the specified e2e network. # This assumes that the network name is the second field in the output. GREP_REGEX="^NAME\|^[^ ]\+[ ]\+\(default\|${NETWORK}\) " -gcloud-compute-list routes --regexp="default.*|${INSTANCE_PREFIX}.*" -gcloud-compute-list firewall-rules --regexp="default.*|k8s-fw.*|${INSTANCE_PREFIX}.*" +gcloud-compute-list routes "name ~ 'default.*|${INSTANCE_PREFIX}.*'" +gcloud-compute-list firewall-rules "name ~ 'default.*|k8s-fw.*|${INSTANCE_PREFIX}.*'" GREP_REGEX="" -gcloud-compute-list forwarding-rules ${REGION:+"--regions=${REGION}"} -gcloud-compute-list target-pools ${REGION:+"--regions=${REGION}"} +gcloud-compute-list forwarding-rules ${REGION:+"region=(${REGION})"} +gcloud-compute-list target-pools ${REGION:+"region=(${REGION})"} diff --git a/vendor/k8s.io/kubernetes/cluster/gce/upgrade.sh b/vendor/k8s.io/kubernetes/cluster/gce/upgrade.sh index ad84f1ff09..9ce89193de 100755 --- a/vendor/k8s.io/kubernetes/cluster/gce/upgrade.sh +++ b/vendor/k8s.io/kubernetes/cluster/gce/upgrade.sh @@ -340,8 +340,7 @@ function do-node-upgrade() { for group in ${INSTANCE_GROUPS[@]}; do old_templates+=($(gcloud compute instance-groups managed list \ --project="${PROJECT}" \ - --zones="${ZONE}" \ - --regexp="${group}" \ + --filter="name ~ '${group}' AND zone:(${ZONE})" \ --format='value(instanceTemplate)' || true)) set_instance_template_out=$(gcloud compute instance-groups managed set-instance-template "${group}" \ --template="${template_name}" \ diff --git a/vendor/k8s.io/kubernetes/cluster/gce/util.sh b/vendor/k8s.io/kubernetes/cluster/gce/util.sh index 2bfeb60ee4..d783fd58ed 100755 --- a/vendor/k8s.io/kubernetes/cluster/gce/util.sh +++ b/vendor/k8s.io/kubernetes/cluster/gce/util.sh @@ -303,9 +303,9 @@ function detect-node-names() { detect-project INSTANCE_GROUPS=() INSTANCE_GROUPS+=($(gcloud compute instance-groups managed list \ - --zones "${ZONE}" --project "${PROJECT}" \ - --regexp "${NODE_INSTANCE_PREFIX}-.+" \ - --format='value(instanceGroup)' || true)) + --project "${PROJECT}" \ + --filter "name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \ + --format='value(name)' || true)) NODE_NAMES=() if [[ -n "${INSTANCE_GROUPS[@]:-}" ]]; then for group in "${INSTANCE_GROUPS[@]}"; do @@ -1033,7 +1033,13 @@ function create-master() { # Sets MASTER_ROOT_DISK_SIZE that is used by create-master-instance get-master-root-disk-size - create-master-instance "${MASTER_RESERVED_IP}" & + if [[ "${NUM_NODES}" -ge "50" ]]; then + # We block on master creation for large clusters to avoid doing too much + # unnecessary work in case master start-up fails (like creation of nodes). + create-master-instance "${MASTER_RESERVED_IP}" + else + create-master-instance "${MASTER_RESERVED_IP}" & + fi } # Adds master replica to etcd cluster. @@ -1067,7 +1073,7 @@ function add-replica-to-etcd() { function set-existing-master() { local existing_master=$(gcloud compute instances list \ --project "${PROJECT}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter "name ~ '$(get-replica-name-regexp)'" \ --format "value(name,zone)" | head -n1) EXISTING_MASTER_NAME="$(echo "${existing_master}" | cut -f1)" EXISTING_MASTER_ZONE="$(echo "${existing_master}" | cut -f2)" @@ -1527,7 +1533,7 @@ function kube-down() { # Check if this are any remaining master replicas. local REMAINING_MASTER_COUNT=$(gcloud compute instances list \ --project "${PROJECT}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter="name ~ '$(get-replica-name-regexp)'" \ --format "value(zone)" | wc -l) # In the replicated scenario, if there's only a single master left, we should also delete load balancer in front of it. @@ -1569,8 +1575,8 @@ function kube-down() { # Find out what minions are running. local -a minions minions=( $(gcloud compute instances list \ - --project "${PROJECT}" --zones "${ZONE}" \ - --regexp "${NODE_INSTANCE_PREFIX}-.+" \ + --project "${PROJECT}" \ + --filter="name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \ --format='value(name)') ) # If any minions are running, delete them in batches. while (( "${#minions[@]}" > 0 )); do @@ -1596,7 +1602,7 @@ function kube-down() { # first allows the master to cleanup routes itself. local TRUNCATED_PREFIX="${INSTANCE_PREFIX:0:26}" routes=( $(gcloud compute routes list --project "${PROJECT}" \ - --regexp "${TRUNCATED_PREFIX}-.{8}-.{4}-.{4}-.{4}-.{12}" \ + --filter="name ~ '${TRUNCATED_PREFIX}-.{8}-.{4}-.{4}-.{4}-.{12}'" \ --format='value(name)') ) while (( "${#routes[@]}" > 0 )); do echo Deleting routes "${routes[*]::${batch}}" @@ -1662,8 +1668,7 @@ function kube-down() { function get-replica-name() { echo $(gcloud compute instances list \ --project "${PROJECT}" \ - --zones "${ZONE}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter="name ~ '$(get-replica-name-regexp)' AND zone:(${ZONE})" \ --format "value(name)" | head -n1) } @@ -1677,7 +1682,7 @@ function get-replica-name() { function get-all-replica-names() { echo $(gcloud compute instances list \ --project "${PROJECT}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter="name ~ '$(get-replica-name-regexp)'" \ --format "value(name)" | tr "\n" "," | sed 's/,$//') } @@ -1689,7 +1694,7 @@ function get-master-replicas-count() { detect-project local num_masters=$(gcloud compute instances list \ --project "${PROJECT}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter="name ~ '$(get-replica-name-regexp)'" \ --format "value(zone)" | wc -l) echo -n "${num_masters}" } @@ -1713,7 +1718,7 @@ function get-replica-name-regexp() { function set-replica-name() { local instances=$(gcloud compute instances list \ --project "${PROJECT}" \ - --regexp "$(get-replica-name-regexp)" \ + --filter="name ~ '$(get-replica-name-regexp)'" \ --format "value(name)") suffix="" @@ -1730,7 +1735,8 @@ function set-replica-name() { # # $1: project function get-template() { - gcloud compute instance-templates list -r "${NODE_INSTANCE_PREFIX}-template(-(${KUBE_RELEASE_VERSION_DASHED_REGEX}|${KUBE_CI_VERSION_DASHED_REGEX}))?" \ + gcloud compute instance-templates list \ + --filter="name ~ '${NODE_INSTANCE_PREFIX}-template(-(${KUBE_RELEASE_VERSION_DASHED_REGEX}|${KUBE_CI_VERSION_DASHED_REGEX}))?'" \ --project="${1}" --format='value(name)' } @@ -1778,8 +1784,8 @@ function check-resources() { # Find out what minions are running. local -a minions minions=( $(gcloud compute instances list \ - --project "${PROJECT}" --zones "${ZONE}" \ - --regexp "${NODE_INSTANCE_PREFIX}-.+" \ + --project "${PROJECT}" \ + --filter="name ~ '${NODE_INSTANCE_PREFIX}-.+' AND zone:(${ZONE})" \ --format='value(name)') ) if (( "${#minions[@]}" > 0 )); then KUBE_RESOURCE_FOUND="${#minions[@]} matching matching ${NODE_INSTANCE_PREFIX}-.+" @@ -1798,7 +1804,7 @@ function check-resources() { local -a routes routes=( $(gcloud compute routes list --project "${PROJECT}" \ - --regexp "${INSTANCE_PREFIX}-minion-.{4}" --format='value(name)') ) + --filter="name ~ '${INSTANCE_PREFIX}-minion-.{4}'" --format='value(name)') ) if (( "${#routes[@]}" > 0 )); then KUBE_RESOURCE_FOUND="${#routes[@]} routes matching ${INSTANCE_PREFIX}-minion-.{4}" return 1 diff --git a/vendor/k8s.io/kubernetes/cluster/gke/config-default.sh b/vendor/k8s.io/kubernetes/cluster/gke/config-default.sh index bd7459325b..b611b91ec8 100644 --- a/vendor/k8s.io/kubernetes/cluster/gke/config-default.sh +++ b/vendor/k8s.io/kubernetes/cluster/gke/config-default.sh @@ -47,3 +47,10 @@ KUBE_DELETE_NETWORK=${KUBE_DELETE_NETWORK:-false} # authentication) in metadata should be treated as canonical, and therefore disk # copies ought to be recreated/clobbered. METADATA_CLOBBERS_CONFIG=true + +# Fluentd requirements +FLUENTD_GCP_MEMORY_LIMIT="${FLUENTD_GCP_MEMORY_LIMIT:-300Mi}" +FLUENTD_GCP_CPU_REQUEST="${FLUENTD_GCP_CPU_REQUEST:-100m}" +FLUENTD_GCP_MEMORY_REQUEST="${FLUENTD_GCP_MEMORY_REQUEST:-200Mi}" +# Adding to PROVIDER_VARS, since this is GCP-specific. +PROVIDER_VARS="${PROVIDER_VARS:-} FLUENTD_GCP_MEMORY_LIMIT FLUENTD_GCP_CPU_REQUEST FLUENTD_GCP_MEMORY_REQUEST" diff --git a/vendor/k8s.io/kubernetes/cluster/log-dump.sh b/vendor/k8s.io/kubernetes/cluster/log-dump/log-dump.sh similarity index 82% rename from vendor/k8s.io/kubernetes/cluster/log-dump.sh rename to vendor/k8s.io/kubernetes/cluster/log-dump/log-dump.sh index 941df1eb5b..227c5c5487 100755 --- a/vendor/k8s.io/kubernetes/cluster/log-dump.sh +++ b/vendor/k8s.io/kubernetes/cluster/log-dump/log-dump.sh @@ -27,19 +27,21 @@ readonly report_dir="${1:-_artifacts}" # check for a function named log_dump_custom_get_instances. If it's # defined, we assume the function can me called with one argument, the # role, which is either "master" or "node". +echo "Checking for custom logdump instances, if any" if [[ $(type -t log_dump_custom_get_instances) == "function" ]]; then readonly use_custom_instance_list=yes else readonly use_custom_instance_list= fi -readonly master_ssh_supported_providers="gce aws kubemark" -readonly node_ssh_supported_providers="gce gke aws kubemark" +readonly master_ssh_supported_providers="gce aws" +readonly node_ssh_supported_providers="gce gke aws" +readonly gcloud_supported_providers="gce gke" readonly master_logfiles="kube-apiserver kube-scheduler rescheduler kube-controller-manager etcd etcd-events glbc cluster-autoscaler kube-addon-manager fluentd" readonly node_logfiles="kube-proxy fluentd node-problem-detector" readonly node_systemd_services="node-problem-detector" -readonly hollow_node_logfiles="kubelet-hollow-node-* kubeproxy-hollow-node-* npd-*" +readonly hollow_node_logfiles="kubelet-hollow-node-* kubeproxy-hollow-node-* npd-hollow-node-*" readonly aws_logfiles="cloud-init-output" readonly gce_logfiles="startupscript" readonly kern_logfile="kern" @@ -51,16 +53,17 @@ readonly systemd_services="kubelet docker" # file descriptors for large clusters. readonly max_scp_processes=25 -# This template spits out the external IPs and images for each node in the cluster in a format like so: -# 52.32.7.85 gcr.io/google_containers/kube-apiserver:1355c18c32d7bef16125120bce194fad gcr.io/google_containers/kube-controller-manager:46365cdd8d28b8207950c3c21d1f3900 [...] -readonly ips_and_images='{range .items[*]}{@.status.addresses[?(@.type == "ExternalIP")].address} {@.status.images[*].names[*]}{"\n"}{end}' - function setup() { if [[ -z "${use_custom_instance_list}" ]]; then - KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. + echo "Obtaining KUBE_ROOT" + KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../.. : ${KUBE_CONFIG_FILE:="config-test.sh"} + echo "Sourcing kube-util.sh" source "${KUBE_ROOT}/cluster/kube-util.sh" - detect-project &> /dev/null + echo "Detecting project" + detect-project 2>&1 + elif [[ "${KUBERNETES_PROVIDER}" == "gke" ]]; then + echo "Using 'use_custom_instance_list' with gke, skipping check for LOG_DUMP_SSH_KEY and LOG_DUMP_SSH_USER" elif [[ -z "${LOG_DUMP_SSH_KEY:-}" ]]; then echo "LOG_DUMP_SSH_KEY not set, but required when using log_dump_custom_get_instances" exit 1 @@ -98,20 +101,17 @@ function copy-logs-from-node() { # Comma delimit (even the singleton, or scp does the wrong thing), surround by braces. local -r scp_files="{$(printf "%s," "${files[@]}")}" - if [[ -n "${use_custom_instance_list}" ]]; then + if [[ "${gcloud_supported_providers}" =~ "${KUBERNETES_PROVIDER}" ]]; then + # get-serial-port-output lets you ask for ports 1-4, but currently (11/21/2016) only port 1 contains useful information + gcloud compute instances get-serial-port-output --project "${PROJECT}" --zone "${ZONE}" --port 1 "${node}" > "${dir}/serial-1.log" || true + gcloud compute scp --recurse --project "${PROJECT}" --zone "${ZONE}" "${node}:${scp_files}" "${dir}" > /dev/null || true + elif [[ "${KUBERNETES_PROVIDER}" == "aws" ]]; then + local ip=$(get_ssh_hostname "${node}") + scp -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${ip}:${scp_files}" "${dir}" > /dev/null || true + elif [[ -n "${use_custom_instance_list}" ]]; then scp -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${LOG_DUMP_SSH_KEY}" "${LOG_DUMP_SSH_USER}@${node}:${scp_files}" "${dir}" > /dev/null || true else - case "${KUBERNETES_PROVIDER}" in - gce|gke|kubemark) - # get-serial-port-output lets you ask for ports 1-4, but currently (11/21/2016) only port 1 contains useful information - gcloud compute instances get-serial-port-output --project "${PROJECT}" --zone "${ZONE}" --port 1 "${node}" > "${dir}/serial-1.log" || true - gcloud compute scp --recurse --project "${PROJECT}" --zone "${ZONE}" "${node}:${scp_files}" "${dir}" > /dev/null || true - ;; - aws) - local ip=$(get_ssh_hostname "${node}") - scp -oLogLevel=quiet -oConnectTimeout=30 -oStrictHostKeyChecking=no -i "${AWS_SSH_KEY}" "${SSH_USER}@${ip}:${scp_files}" "${dir}" > /dev/null || true - ;; - esac + echo "Unknown cloud-provider '${KUBERNETES_PROVIDER}' and use_custom_instance_list is unset too - skipping logdump for '${node}'" fi } @@ -130,11 +130,8 @@ function save-logs() { fi else case "${KUBERNETES_PROVIDER}" in - gce|gke|kubemark) + gce|gke) files="${files} ${gce_logfiles}" - if [[ "${KUBERNETES_PROVIDER}" == "kubemark" && "${ENABLE_HOLLOW_NODE_LOGS:-}" == "true" ]]; then - files="${files} ${hollow_node_logfiles}" - fi ;; aws) files="${files} ${aws_logfiles}" @@ -224,13 +221,18 @@ function dump_nodes() { return fi + node_logfiles_all="${node_logfiles}" + if [[ "${ENABLE_HOLLOW_NODE_LOGS:-}" == "true" ]]; then + node_logfiles_all="${node_logfiles_all} ${hollow_node_logfiles}" + fi + proc=${max_scp_processes} for node_name in "${node_names[@]}"; do node_dir="${report_dir}/${node_name}" mkdir -p "${node_dir}" # Save logs in the background. This speeds up things when there are # many nodes. - save-logs "${node_name}" "${node_dir}" "${node_logfiles}" "${node_systemd_services}" & + save-logs "${node_name}" "${node_dir}" "${node_logfiles_all}" "${node_systemd_services}" & # We don't want to run more than ${max_scp_processes} at a time, so # wait once we hit that many nodes. This isn't ideal, since one might diff --git a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/cluster-autoscaler/cluster-autoscaler.manifest b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/cluster-autoscaler/cluster-autoscaler.manifest index 68d8872afb..a949205b0f 100644 --- a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/cluster-autoscaler/cluster-autoscaler.manifest +++ b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/cluster-autoscaler/cluster-autoscaler.manifest @@ -25,7 +25,7 @@ "containers": [ { "name": "cluster-autoscaler", - "image": "gcr.io/google_containers/cluster-autoscaler:v0.6.0", + "image": "gcr.io/google_containers/cluster-autoscaler:v0.6.2", "livenessProbe": { "httpGet": { "path": "/health-check", diff --git a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest index 4f6ad7bdfd..6c0f20c80e 100644 --- a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest +++ b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/kube-apiserver/kube-apiserver.manifest @@ -66,6 +66,11 @@ {% set storage_media_type = "--storage-media-type=" + pillar['storage_media_type'] -%} {% endif -%} +{% set request_timeout = "" -%} +{% if pillar['kube_apiserver_request_timeout_sec'] is defined -%} + {% set request_timeout = "--request-timeout=" + pillar['kube_apiserver_request_timeout_sec'] + "s" -%} +{% endif -%} + {% set max_requests_inflight = "" -%} {% set target_ram_mb = "" -%} {% if pillar['num_nodes'] is defined -%} @@ -196,7 +201,7 @@ {% endif %} {% endif -%} -{% set params = address + " " + storage_backend + " " + storage_media_type + " " + etcd_servers + " " + etcd_servers_overrides + " " + cloud_provider + " " + cloud_config + " " + runtime_config + " " + feature_gates + " " + admission_control + " " + max_requests_inflight + " " + target_ram_mb + " " + service_cluster_ip_range + " " + client_ca_file + basic_auth_file + " " + min_request_timeout + " " + enable_garbage_collector + " " + etcd_quorum_read + " " + audit_log -%} +{% set params = address + " " + storage_backend + " " + storage_media_type + " " + etcd_servers + " " + etcd_servers_overrides + " " + cloud_provider + " " + cloud_config + " " + runtime_config + " " + feature_gates + " " + admission_control + " " + max_requests_inflight + " " + target_ram_mb + " " + service_cluster_ip_range + " " + client_ca_file + basic_auth_file + " " + min_request_timeout + " " + enable_garbage_collector + " " + etcd_quorum_read + " " + audit_log + " " + request_timeout -%} {% set params = params + " " + cert_file + " " + key_file + " " + kubelet_cert_file + " " + kubelet_key_file + " --secure-port=" + secure_port + token_auth_file + " " + bind_address + " " + log_level + " " + advertise_address + " " + proxy_ssh_options + authz_mode + abac_policy_file + webhook_authentication_config + webhook_authorization_config + image_review_config -%} # test_args has to be kept at the end, so they'll overwrite any prior configuration diff --git a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/l7-gcp/glbc.manifest b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/l7-gcp/glbc.manifest index 85b833248f..c790d271e6 100644 --- a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/l7-gcp/glbc.manifest +++ b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/l7-gcp/glbc.manifest @@ -1,20 +1,20 @@ apiVersion: v1 kind: Pod metadata: - name: l7-lb-controller-v0.9.5 + name: l7-lb-controller-v0.9.6 namespace: kube-system annotations: scheduler.alpha.kubernetes.io/critical-pod: '' labels: k8s-app: glbc - version: v0.9.5 + version: v0.9.6 kubernetes.io/cluster-service: "true" kubernetes.io/name: "GLBC" spec: terminationGracePeriodSeconds: 600 hostNetwork: true containers: - - image: gcr.io/google_containers/glbc:0.9.5 + - image: gcr.io/google_containers/glbc:0.9.6 livenessProbe: httpGet: path: /healthz diff --git a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/rescheduler/rescheduler.manifest b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/rescheduler/rescheduler.manifest index d647a7be97..8132a7d6fc 100644 --- a/vendor/k8s.io/kubernetes/cluster/saltbase/salt/rescheduler/rescheduler.manifest +++ b/vendor/k8s.io/kubernetes/cluster/saltbase/salt/rescheduler/rescheduler.manifest @@ -1,19 +1,19 @@ apiVersion: v1 kind: Pod metadata: - name: rescheduler-v0.3.0 + name: rescheduler-v0.3.1 namespace: kube-system annotations: scheduler.alpha.kubernetes.io/critical-pod: '' labels: k8s-app: rescheduler - version: v0.3.0 + version: v0.3.1 kubernetes.io/cluster-service: "true" kubernetes.io/name: "Rescheduler" spec: hostNetwork: true containers: - - image: gcr.io/google-containers/rescheduler:v0.3.0 + - image: gcr.io/google-containers/rescheduler:v0.3.1 name: rescheduler volumeMounts: - mountPath: /var/log/rescheduler.log diff --git a/vendor/k8s.io/kubernetes/cluster/validate-cluster.sh b/vendor/k8s.io/kubernetes/cluster/validate-cluster.sh index 3d10edd389..77e2755c0d 100755 --- a/vendor/k8s.io/kubernetes/cluster/validate-cluster.sh +++ b/vendor/k8s.io/kubernetes/cluster/validate-cluster.sh @@ -56,8 +56,8 @@ if [[ "${KUBERNETES_PROVIDER:-}" == "gce" ]]; then echo "Validating gce cluster, MULTIZONE=${MULTIZONE:-}" # In multizone mode we need to add instances for all nodes in the region. if [[ "${MULTIZONE:-}" == "true" ]]; then - EXPECTED_NUM_NODES=$(gcloud -q compute instances list --project="${PROJECT}" --format=[no-heading] --regexp="${NODE_INSTANCE_PREFIX}.*" \ - --zones=$(gcloud -q compute zones list --project="${PROJECT}" --filter=region=${REGION} --format=[no-heading]\(name\) | tr "\n" "," | sed "s/,$//") | wc -l) + EXPECTED_NUM_NODES=$(gcloud -q compute instances list --project="${PROJECT}" --format=[no-heading] \ + --filter="name ~ '${NODE_INSTANCE_PREFIX}.*' AND zone:($(gcloud -q compute zones list --project="${PROJECT}" --filter=region=${REGION} --format=csv[no-heading]\(name\) | tr "\n" "," | sed "s/,$//"))" | wc -l) echo "Computing number of nodes, NODE_INSTANCE_PREFIX=${NODE_INSTANCE_PREFIX}, REGION=${REGION}, EXPECTED_NUM_NODES=${EXPECTED_NUM_NODES}" fi fi diff --git a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/BUILD b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/BUILD index 31b6b0f9b9..335975bbf9 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/BUILD @@ -79,7 +79,6 @@ go_library( "//vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/cmd/server:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/openapi:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", @@ -98,10 +97,12 @@ go_library( "//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library", "//vendor/k8s.io/client-go/informers:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", + "//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apiserver:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion:go_default_library", + "//vendor/k8s.io/kube-aggregator/pkg/client/informers/internalversion/apiregistration/internalversion:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/controllers/autoregister:go_default_library", ], ) diff --git a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go index e146d98c9b..82cc4ef183 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go @@ -24,21 +24,24 @@ import ( "io/ioutil" "net/http" "strings" + "sync" "github.com/golang/glog" apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/healthz" genericoptions "k8s.io/apiserver/pkg/server/options" kubeexternalinformers "k8s.io/client-go/informers" + "k8s.io/client-go/tools/cache" "k8s.io/kube-aggregator/pkg/apis/apiregistration" "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1" aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver" apiregistrationclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/internalclientset/typed/apiregistration/internalversion" + apiregistrationinformers "k8s.io/kube-aggregator/pkg/client/informers/internalversion/apiregistration/internalversion" "k8s.io/kube-aggregator/pkg/controllers/autoregister" "k8s.io/kubernetes/cmd/kube-apiserver/app/options" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" @@ -104,39 +107,23 @@ func createAggregatorServer(aggregatorConfig *aggregatorapiserver.Config, delega autoRegistrationController) aggregatorServer.GenericAPIServer.AddPostStartHook("kube-apiserver-autoregistration", func(context genericapiserver.PostStartHookContext) error { - go autoRegistrationController.Run(5, context.StopCh) go tprRegistrationController.Run(5, context.StopCh) + go func() { + // let the CRD controller process the initial set of CRDs before starting the autoregistration controller. + // this prevents the autoregistration controller's initial sync from deleting APIServices for CRDs that still exist. + tprRegistrationController.WaitForInitialSync() + autoRegistrationController.Run(5, context.StopCh) + }() return nil }) - aggregatorServer.GenericAPIServer.AddHealthzChecks(healthz.NamedCheck("autoregister-completion", func(r *http.Request) error { - items, err := aggregatorServer.APIRegistrationInformers.Apiregistration().InternalVersion().APIServices().Lister().List(labels.Everything()) - if err != nil { - return err - } - missing := []apiregistration.APIService{} - for _, apiService := range apiServices { - found := false - for _, item := range items { - if item.Name != apiService.Name { - continue - } - if apiregistration.IsAPIServiceConditionTrue(item, apiregistration.Available) { - found = true - break - } - } - - if !found { - missing = append(missing, *apiService) - } - } - - if len(missing) > 0 { - return fmt.Errorf("missing APIService: %v", missing) - } - return nil - })) + aggregatorServer.GenericAPIServer.AddHealthzChecks( + makeAPIServiceAvailableHealthzCheck( + "autoregister-completion", + apiServices, + aggregatorServer.APIRegistrationInformers.Apiregistration().InternalVersion().APIServices(), + ), + ) return aggregatorServer, nil } @@ -160,6 +147,45 @@ func makeAPIService(gv schema.GroupVersion) *apiregistration.APIService { } } +// makeAPIServiceAvailableHealthzCheck returns a healthz check that returns healthy +// once all of the specified services have been observed to be available at least once. +func makeAPIServiceAvailableHealthzCheck(name string, apiServices []*apiregistration.APIService, apiServiceInformer apiregistrationinformers.APIServiceInformer) healthz.HealthzChecker { + // Track the auto-registered API services that have not been observed to be available yet + pendingServiceNamesLock := &sync.RWMutex{} + pendingServiceNames := sets.NewString() + for _, service := range apiServices { + pendingServiceNames.Insert(service.Name) + } + + // When an APIService in the list is seen as available, remove it from the pending list + handleAPIServiceChange := func(service *apiregistration.APIService) { + pendingServiceNamesLock.Lock() + defer pendingServiceNamesLock.Unlock() + if !pendingServiceNames.Has(service.Name) { + return + } + if apiregistration.IsAPIServiceConditionTrue(service, apiregistration.Available) { + pendingServiceNames.Delete(service.Name) + } + } + + // Watch add/update events for APIServices + apiServiceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { handleAPIServiceChange(obj.(*apiregistration.APIService)) }, + UpdateFunc: func(old, new interface{}) { handleAPIServiceChange(new.(*apiregistration.APIService)) }, + }) + + // Don't return healthy until the pending list is empty + return healthz.NamedCheck(name, func(r *http.Request) error { + pendingServiceNamesLock.RLock() + defer pendingServiceNamesLock.RUnlock() + if pendingServiceNames.Len() > 0 { + return fmt.Errorf("missing APIService: %v", pendingServiceNames.List()) + } + return nil + }) +} + type priority struct { group int32 version int32 @@ -202,7 +228,7 @@ func apiServicesToRegister(delegateAPIServer genericapiserver.DelegationTarget, for _, curr := range delegateAPIServer.ListedPaths() { if curr == "/api/v1" { apiService := makeAPIService(schema.GroupVersion{Group: "", Version: "v1"}) - registration.AddAPIServiceToSync(apiService) + registration.AddAPIServiceToSyncOnStart(apiService) apiServices = append(apiServices, apiService) continue } @@ -220,7 +246,7 @@ func apiServicesToRegister(delegateAPIServer genericapiserver.DelegationTarget, if apiService == nil { continue } - registration.AddAPIServiceToSync(apiService) + registration.AddAPIServiceToSyncOnStart(apiService) apiServices = append(apiServices, apiService) } diff --git a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options_test.go b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options_test.go index 06eee371d5..a9aa37bb6e 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options_test.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/options/options_test.go @@ -34,6 +34,7 @@ func TestAddFlagsFlag(t *testing.T) { args := []string{ "--enable-swagger-ui=true", + "--request-timeout=2m", } f.Parse(args) if !s.Features.EnableSwaggerUI { diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD index 4a757a8e3d..5109e1da5d 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/BUILD @@ -99,6 +99,7 @@ go_library( "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go index f30df0fa2e..e5bf649d3b 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/controllermanager.go @@ -33,6 +33,7 @@ import ( "time" "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -365,7 +366,10 @@ func GetAvailableResources(clientBuilder controller.ControllerClientBuilder) (ma resourceMap, err := discoveryClient.ServerResources() if err != nil { - return nil, fmt.Errorf("failed to get supported resources from server: %v", err) + utilruntime.HandleError(fmt.Errorf("unable to get all supported resources from server: %v", err)) + } + if len(resourceMap) == 0 { + return nil, fmt.Errorf("unable to get any supported resources from server") } allResources := map[schema.GroupVersionResource]bool{} diff --git a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/core.go b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/core.go index 6d56428e15..f4e896c524 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/core.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-controller-manager/app/core.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" @@ -285,7 +286,10 @@ func startGarbageCollectorController(ctx ControllerContext) (bool, error) { gcClientset := ctx.ClientBuilder.ClientOrDie("generic-garbage-collector") preferredResources, err := gcClientset.Discovery().ServerPreferredResources() if err != nil { - return true, fmt.Errorf("failed to get supported resources from server: %v", err) + utilruntime.HandleError(fmt.Errorf("unable to get all supported resources from server: %v", err)) + } + if len(preferredResources) == 0 { + return true, fmt.Errorf("unable to get any supported resources from server: %v", err) } deletableResources := discovery.FilteredBy(discovery.SupportsAllVerbs{Verbs: []string{"get", "list", "watch", "patch", "update", "delete"}}, preferredResources) deletableGroupVersionResources, err := discovery.GroupVersionResources(deletableResources) diff --git a/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD b/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD index 65ab9ca321..80f9bfa3a8 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/client/informers/informers_generated/internalversion:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubelet/qos:go_default_library", + "//pkg/master/ports:go_default_library", "//pkg/proxy:go_default_library", "//pkg/proxy/config:go_default_library", "//pkg/proxy/healthcheck:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go b/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go index ab9e4a722b..4d8c7b8f43 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-proxy/app/server.go @@ -53,6 +53,7 @@ import ( informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubelet/qos" + "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/proxy" proxyconfig "k8s.io/kubernetes/pkg/proxy/config" "k8s.io/kubernetes/pkg/proxy/healthcheck" @@ -129,6 +130,7 @@ func AddFlags(options *Options, fs *pflag.FlagSet) { fs.StringVar(&options.master, "master", options.master, "The address of the Kubernetes API server (overrides any value in kubeconfig)") fs.Int32Var(&options.healthzPort, "healthz-port", options.healthzPort, "The port to bind the health check server. Use 0 to disable.") fs.Var(componentconfig.IPVar{Val: &options.config.HealthzBindAddress}, "healthz-bind-address", "The IP address and port for the health check server to serve on (set to 0.0.0.0 for all interfaces)") + fs.Var(componentconfig.IPVar{Val: &options.config.MetricsBindAddress}, "metrics-bind-address", "The IP address and port for the metrics server to serve on (set to 0.0.0.0 for all interfaces)") fs.Int32Var(options.config.OOMScoreAdj, "oom-score-adj", util.Int32PtrDerefOr(options.config.OOMScoreAdj, int32(qos.KubeProxyOOMScoreAdj)), "The oom-score-adj value for kube-proxy process. Values must be within the range [-1000, 1000]") fs.StringVar(&options.config.ResourceContainer, "resource-container", options.config.ResourceContainer, "Absolute name of the resource-only container to create and run the Kube-proxy in (Default: /kube-proxy).") fs.MarkDeprecated("resource-container", "This feature will be removed in a later release.") @@ -166,7 +168,7 @@ func AddFlags(options *Options, fs *pflag.FlagSet) { func NewOptions() (*Options, error) { o := &Options{ config: new(componentconfig.KubeProxyConfiguration), - healthzPort: 10256, + healthzPort: ports.ProxyHealthzPort, } o.scheme = runtime.NewScheme() @@ -461,8 +463,10 @@ func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndEx recorder := eventBroadcaster.NewRecorder(scheme, clientv1.EventSource{Component: "kube-proxy", Host: hostname}) var healthzServer *healthcheck.HealthzServer + var healthzUpdater healthcheck.HealthzUpdater if len(config.HealthzBindAddress) > 0 { healthzServer = healthcheck.NewDefaultHealthzServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration) + healthzUpdater = healthzServer } var proxier proxy.ProxyProvider @@ -496,7 +500,7 @@ func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndEx hostname, nodeIP, recorder, - healthzServer, + healthzUpdater, ) if err != nil { return nil, fmt.Errorf("unable to create proxier: %v", err) diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/types.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/types.go index d5885fbd6b..04125b6cd6 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/types.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/types.go @@ -37,6 +37,7 @@ type MasterConfiguration struct { Networking Networking KubernetesVersion string CloudProvider string + NodeName string AuthorizationModes []string Token string @@ -93,6 +94,7 @@ type NodeConfiguration struct { DiscoveryToken string // Currently we only pay attention to one api server but hope to support >1 in the future DiscoveryTokenAPIServers []string + NodeName string TLSBootstrapToken string Token string } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go index b555cd3fa3..1a683ef102 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1/types.go @@ -30,6 +30,7 @@ type MasterConfiguration struct { Networking Networking `json:"networking"` KubernetesVersion string `json:"kubernetesVersion"` CloudProvider string `json:"cloudProvider"` + NodeName string `json:"nodeName"` AuthorizationModes []string `json:"authorizationModes"` Token string `json:"token"` @@ -85,6 +86,7 @@ type NodeConfiguration struct { DiscoveryFile string `json:"discoveryFile"` DiscoveryToken string `json:"discoveryToken"` DiscoveryTokenAPIServers []string `json:"discoveryTokenAPIServers"` + NodeName string `json:"nodeName"` TLSBootstrapToken string `json:"tlsBootstrapToken"` Token string `json:"token"` } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/BUILD index 5ff38a3945..797d7a7dae 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/BUILD @@ -15,6 +15,7 @@ go_test( tags = ["automanaged"], deps = [ "//cmd/kubeadm/app/apis/kubeadm:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", ], ) @@ -30,6 +31,8 @@ go_library( "//pkg/api/validation:go_default_library", "//pkg/kubeapiserver/authorizer/modes:go_default_library", "//pkg/registry/core/service/ipallocator:go_default_library", + "//pkg/util/node:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", ], diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index e338c4aefc..850159f12a 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -24,6 +24,8 @@ import ( "path/filepath" "strings" + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" @@ -32,6 +34,7 @@ import ( apivalidation "k8s.io/kubernetes/pkg/api/validation" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" + "k8s.io/kubernetes/pkg/util/node" ) // TODO: Break out the cloudprovider functionality out of core and only support the new flow @@ -56,6 +59,7 @@ func ValidateMasterConfiguration(c *kubeadm.MasterConfiguration) field.ErrorList allErrs = append(allErrs, ValidateNetworking(&c.Networking, field.NewPath("networking"))...) allErrs = append(allErrs, ValidateAPIServerCertSANs(c.APIServerCertSANs, field.NewPath("cert-altnames"))...) allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificates-dir"))...) + allErrs = append(allErrs, ValidateNodeName(c.NodeName, field.NewPath("node-name"))...) allErrs = append(allErrs, ValidateToken(c.Token, field.NewPath("token"))...) return allErrs } @@ -226,6 +230,14 @@ func ValidateAbsolutePath(path string, fldPath *field.Path) field.ErrorList { return allErrs } +func ValidateNodeName(nodename string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if node.GetHostname(nodename) != nodename { + allErrs = append(allErrs, field.Invalid(fldPath, nodename, "nodename is not valid")) + } + return allErrs +} + func ValidateCloudProvider(provider string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(provider) == 0 { @@ -239,3 +251,24 @@ func ValidateCloudProvider(provider string, fldPath *field.Path) field.ErrorList allErrs = append(allErrs, field.Invalid(fldPath, provider, "cloudprovider not supported")) return allErrs } + +func ValidateMixedArguments(flag *pflag.FlagSet) error { + // If --config isn't set, we have nothing to validate + if !flag.Changed("config") { + return nil + } + + mixedInvalidFlags := []string{} + flag.Visit(func(f *pflag.Flag) { + if f.Name == "config" || strings.HasPrefix(f.Name, "skip-") { + // "--skip-*" flags can be set with --config + return + } + mixedInvalidFlags = append(mixedInvalidFlags, f.Name) + }) + + if len(mixedInvalidFlags) != 0 { + return fmt.Errorf("can not mix '--config' with arguments %v", mixedInvalidFlags) + } + return nil +} diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index 4c80c082e9..e0770c4d7c 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -19,6 +19,8 @@ package validation import ( "testing" + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" ) @@ -72,6 +74,29 @@ func TestValidateAuthorizationModes(t *testing.T) { } } +func TestValidateNodeName(t *testing.T) { + var tests = []struct { + s string + f *field.Path + expected bool + }{ + {"", nil, false}, // ok if not provided + {"1234", nil, true}, // supported + {"valid-hostname", nil, true}, // supported + {"INVALID-HOSTNAME", nil, false}, // Upper cases is invalid + } + for _, rt := range tests { + actual := ValidateNodeName(rt.s, rt.f) + if (len(actual) == 0) != rt.expected { + t.Errorf( + "failed ValidateNodeName:\n\texpected: %t\n\t actual: %t", + rt.expected, + (len(actual) == 0), + ) + } + } +} + func TestValidateCloudProvider(t *testing.T) { var tests = []struct { s string @@ -169,6 +194,7 @@ func TestValidateIPNetFromString(t *testing.T) { } func TestValidateMasterConfiguration(t *testing.T) { + nodename := "valid-nodename" var tests = []struct { s *kubeadm.MasterConfiguration expected bool @@ -181,6 +207,7 @@ func TestValidateMasterConfiguration(t *testing.T) { DNSDomain: "cluster.local", }, CertificatesDir: "/some/cert/dir", + NodeName: nodename, }, false}, {&kubeadm.MasterConfiguration{ AuthorizationModes: []string{"RBAC"}, @@ -190,6 +217,7 @@ func TestValidateMasterConfiguration(t *testing.T) { }, CertificatesDir: "/some/other/cert/dir", Token: "abcdef.0123456789abcdef", + NodeName: nodename, }, true}, } for _, rt := range tests { @@ -227,3 +255,46 @@ func TestValidateNodeConfiguration(t *testing.T) { } } } + +func TestValidateMixedArguments(t *testing.T) { + var tests = []struct { + args []string + expected bool + }{ + // Expected to succeed, --config is mixed with skip-* flags only or no other flags + {[]string{"--foo=bar"}, true}, + {[]string{"--config=hello"}, true}, + {[]string{"--config=hello", "--skip-preflight-checks=true"}, true}, + {[]string{"--config=hello", "--skip-token-print=true"}, true}, + {[]string{"--config=hello", "--skip-preflight-checks", "--skip-token-print"}, true}, + // Expected to fail, --config is mixed with the --foo flag + {[]string{"--config=hello", "--skip-preflight-checks", "--foo=bar"}, false}, + {[]string{"--config=hello", "--foo=bar"}, false}, + } + + var cfgPath string + + for _, rt := range tests { + f := pflag.NewFlagSet("test", pflag.ContinueOnError) + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + f.String("foo", "", "flag bound to config object") + f.Bool("skip-preflight-checks", false, "flag not bound to config object") + f.Bool("skip-token-print", false, "flag not bound to config object") + f.StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file") + if err := f.Parse(rt.args); err != nil { + t.Fatal(err) + } + + actual := ValidateMixedArguments(f) + if (actual == nil) != rt.expected { + t.Errorf( + "failed ValidateMixedArguments:\n\texpected: %t\n\t actual: %t testdata: %v", + rt.expected, + (actual == nil), + rt.args, + ) + } + } +} diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/BUILD index 23f9c38916..5acd258682 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/BUILD @@ -46,6 +46,7 @@ go_library( "//pkg/printers:go_default_library", "//pkg/util/i18n:go_default_library", "//pkg/util/initsystem:go_default_library", + "//pkg/util/node:go_default_library", "//pkg/util/version:go_default_library", "//pkg/version:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/defaults.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/defaults.go index f9f8d3aac7..c7e2f74d45 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/defaults.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/defaults.go @@ -27,6 +27,7 @@ import ( kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" + "k8s.io/kubernetes/pkg/util/node" "k8s.io/kubernetes/pkg/util/version" ) @@ -77,6 +78,9 @@ func setInitDynamicDefaults(cfg *kubeadmapi.MasterConfiguration) error { } } + // Use cfg.NodeName if set, otherwise get that from os.Hostname(). This also makes sure the hostname is lower-cased + cfg.NodeName = node.GetHostname(cfg.NodeName) + return nil } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/init.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/init.go index 7b750984a3..3ae5ad3928 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/init.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/init.go @@ -84,7 +84,13 @@ func NewCmdInit(out io.Writer) *cobra.Command { i, err := NewInit(cfgPath, internalcfg, skipPreFlight, skipTokenPrint) kubeadmutil.CheckErr(err) - kubeadmutil.CheckErr(i.Validate()) + kubeadmutil.CheckErr(i.Validate(cmd)) + + // TODO: remove this warning in 1.9 + if !cmd.Flags().Lookup("token-ttl").Changed { + fmt.Println("[kubeadm] WARNING: starting in 1.8, tokens expire after 24 hours by default (if you require a non-expiring token use --token-ttl 0)") + } + kubeadmutil.CheckErr(i.Run(out)) }, } @@ -121,13 +127,19 @@ func NewCmdInit(out io.Writer) *cobra.Command { &cfg.APIServerCertSANs, "apiserver-cert-extra-sans", cfg.APIServerCertSANs, `Optional extra altnames to use for the API Server serving cert. Can be both IP addresses and dns names.`, ) + cmd.PersistentFlags().StringVar( + &cfg.NodeName, "node-name", cfg.NodeName, + `Specify the node name`, + ) cmd.PersistentFlags().StringVar(&cfgPath, "config", cfgPath, "Path to kubeadm config file (WARNING: Usage of a configuration file is experimental)") + // Note: All flags that are not bound to the cfg object should be whitelisted in cmd/kubeadm/app/apis/kubeadm/validation/validation.go cmd.PersistentFlags().BoolVar( &skipPreFlight, "skip-preflight-checks", skipPreFlight, "Skip preflight checks normally run before modifying the system", ) + // Note: All flags that are not bound to the cfg object should be whitelisted in cmd/kubeadm/app/apis/kubeadm/validation/validation.go cmd.PersistentFlags().BoolVar( &skipTokenPrint, "skip-token-print", skipTokenPrint, "Skip printing of the default bootstrap token generated by 'kubeadm init'", @@ -192,7 +204,10 @@ type Init struct { } // Validate validates configuration passed to "kubeadm init" -func (i *Init) Validate() error { +func (i *Init) Validate(cmd *cobra.Command) error { + if err := validation.ValidateMixedArguments(cmd.Flags()); err != nil { + return err + } return validation.ValidateMasterConfiguration(i.cfg).ToAggregate() } @@ -208,7 +223,7 @@ func (i *Init) Run(out io.Writer) error { // PHASE 2: Generate kubeconfig files for the admin and the kubelet masterEndpoint := fmt.Sprintf("https://%s:%d", i.cfg.API.AdvertiseAddress, i.cfg.API.BindPort) - err = kubeconfigphase.CreateInitKubeConfigFiles(masterEndpoint, i.cfg.CertificatesDir, kubeadmapi.GlobalEnvParams.KubernetesDir) + err = kubeconfigphase.CreateInitKubeConfigFiles(masterEndpoint, i.cfg.CertificatesDir, kubeadmapi.GlobalEnvParams.KubernetesDir, i.cfg.NodeName) if err != nil { return err } @@ -224,7 +239,7 @@ func (i *Init) Run(out io.Writer) error { return err } - if err := apiconfigphase.UpdateMasterRoleLabelsAndTaints(client); err != nil { + if err := apiconfigphase.UpdateMasterRoleLabelsAndTaints(client, i.cfg.NodeName); err != nil { return err } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/join.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/join.go index 031b89c15e..ff32031f11 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/join.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/join.go @@ -20,7 +20,6 @@ import ( "fmt" "io" "io/ioutil" - "os" "path/filepath" "github.com/renstrom/dedent" @@ -33,11 +32,12 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/discovery" - kubenode "k8s.io/kubernetes/cmd/kubeadm/app/node" + kubeadmnode "k8s.io/kubernetes/cmd/kubeadm/app/node" "k8s.io/kubernetes/cmd/kubeadm/app/preflight" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" "k8s.io/kubernetes/pkg/api" + nodeutil "k8s.io/kubernetes/pkg/util/node" ) var ( @@ -63,26 +63,26 @@ func NewCmdJoin(out io.Writer) *cobra.Command { Use: "join [DiscoveryTokenAPIServers]", Short: "Run this on any machine you wish to join an existing cluster", Long: dedent.Dedent(` - When joining a kubeadm initialized cluster, we need to establish - bidirectional trust. This is split into discovery (having the Node - trust the Kubernetes Master) and TLS bootstrap (having the Kubernetes + When joining a kubeadm initialized cluster, we need to establish + bidirectional trust. This is split into discovery (having the Node + trust the Kubernetes Master) and TLS bootstrap (having the Kubernetes Master trust the Node). - There are 2 main schemes for discovery. The first is to use a shared - token along with the IP address of the API server. The second is to - provide a file (a subset of the standard kubeconfig file). This file - can be a local file or downloaded via an HTTPS URL. The forms are - kubeadm join --discovery-token abcdef.1234567890abcdef 1.2.3.4:6443, + There are 2 main schemes for discovery. The first is to use a shared + token along with the IP address of the API server. The second is to + provide a file (a subset of the standard kubeconfig file). This file + can be a local file or downloaded via an HTTPS URL. The forms are + kubeadm join --discovery-token abcdef.1234567890abcdef 1.2.3.4:6443, kubeadm join --discovery-file path/to/file.conf, or kubeadm join - --discovery-file https://url/file.conf. Only one form can be used. If - the discovery information is loaded from a URL, HTTPS must be used and + --discovery-file https://url/file.conf. Only one form can be used. If + the discovery information is loaded from a URL, HTTPS must be used and the host installed CA bundle is used to verify the connection. - The TLS bootstrap mechanism is also driven via a shared token. This is + The TLS bootstrap mechanism is also driven via a shared token. This is used to temporarily authenticate with the Kubernetes Master to submit a - certificate signing request (CSR) for a locally created key pair. By - default kubeadm will set up the Kubernetes Master to automatically - approve these signing requests. This token is passed in with the + certificate signing request (CSR) for a locally created key pair. By + default kubeadm will set up the Kubernetes Master to automatically + approve these signing requests. This token is passed in with the --tls-bootstrap-token abcdef.1234567890abcdef flag. Often times the same token is used for both parts. In this case, the @@ -97,7 +97,7 @@ func NewCmdJoin(out io.Writer) *cobra.Command { j, err := NewJoin(cfgPath, args, internalcfg, skipPreFlight) kubeadmutil.CheckErr(err) - kubeadmutil.CheckErr(j.Validate()) + kubeadmutil.CheckErr(j.Validate(cmd)) kubeadmutil.CheckErr(j.Run(out)) }, } @@ -112,6 +112,9 @@ func NewCmdJoin(out io.Writer) *cobra.Command { cmd.PersistentFlags().StringVar( &cfg.DiscoveryToken, "discovery-token", "", "A token used to validate cluster information fetched from the master") + cmd.PersistentFlags().StringVar( + &cfg.NodeName, "node-name", "", + "Specify the node name") cmd.PersistentFlags().StringVar( &cfg.TLSBootstrapToken, "tls-bootstrap-token", "", "A token used for TLS bootstrapping") @@ -134,6 +137,10 @@ type Join struct { func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, skipPreFlight bool) (*Join, error) { fmt.Println("[kubeadm] WARNING: kubeadm is in beta, please do not use it for production clusters.") + if cfg.NodeName == "" { + cfg.NodeName = nodeutil.GetHostname("") + } + if cfgPath != "" { b, err := ioutil.ReadFile(cfgPath) if err != nil { @@ -166,7 +173,10 @@ func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, s return &Join{cfg: cfg}, nil } -func (j *Join) Validate() error { +func (j *Join) Validate(cmd *cobra.Command) error { + if err := validation.ValidateMixedArguments(cmd.PersistentFlags()); err != nil { + return err + } return validation.ValidateNodeConfiguration(j.cfg).ToAggregate() } @@ -177,18 +187,17 @@ func (j *Join) Run(out io.Writer) error { return err } - hostname, err := os.Hostname() - if err != nil { - return err - } + // Use j.cfg.NodeName if set, otherwise get that from os.Hostname(). This also makes sure the hostname is lower-cased + hostname := nodeutil.GetHostname(j.cfg.NodeName) + client, err := kubeconfigutil.KubeConfigToClientSet(cfg) if err != nil { return err } - if err := kubenode.ValidateAPIServer(client); err != nil { + if err := kubeadmnode.ValidateAPIServer(client); err != nil { return err } - if err := kubenode.PerformTLSBootstrap(cfg, hostname); err != nil { + if err := kubeadmnode.PerformTLSBootstrap(cfg, hostname); err != nil { return err } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/reset.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/reset.go index 1da7e6bb46..6761c75c33 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/reset.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/reset.go @@ -114,7 +114,7 @@ func (r *Reset) Run(out io.Writer) error { fmt.Println("[reset] docker doesn't seem to be running, skipping the removal of running kubernetes containers") } - dirsToClean := []string{"/var/lib/kubelet", "/etc/cni/net.d", "/var/lib/dockershim"} + dirsToClean := []string{"/var/lib/kubelet", "/etc/cni/net.d", "/var/lib/dockershim", "/var/run/kubernetes"} // Only clear etcd data when the etcd manifest is found. In case it is not found, we must assume that the user // provided external etcd endpoints. In that case, it is his own responsibility to reset etcd diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/token.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/token.go index ff6fdb5b02..1475885c2f 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/token.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/cmd/token.go @@ -109,6 +109,12 @@ func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command { client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile) kubeadmutil.CheckErr(err) + // TODO: remove this warning in 1.9 + if !tokenCmd.Flags().Lookup("ttl").Changed { + // sending this output to stderr s + fmt.Fprintln(errW, "[kubeadm] WARNING: starting in 1.8, tokens expire after 24 hours by default (if you require a non-expiring token use --ttl 0)") + } + err = RunCreateToken(out, client, token, tokenDuration, usages, description) kubeadmutil.CheckErr(err) }, diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/discovery/token/token.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/discovery/token/token.go index c0d139a228..d6d6edd83b 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/discovery/token/token.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/discovery/token/token.go @@ -58,7 +58,7 @@ func RetrieveValidatedClusterInfo(discoveryToken string, tokenAPIServers []strin fmt.Printf("[discovery] Created cluster-info discovery client, requesting info from %q\n", bootstrapConfig.Clusters[clusterName].Server) var clusterinfo *v1.ConfigMap - wait.PollInfinite(constants.DiscoveryRetryInterval, func() (bool, error) { + wait.PollImmediateInfinite(constants.DiscoveryRetryInterval, func() (bool, error) { var err error clusterinfo, err = client.CoreV1().ConfigMaps(metav1.NamespacePublic).Get(bootstrapapi.ConfigMapClusterInfo, metav1.GetOptions{}) if err != nil { diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go index 55fe560c46..5f7c676094 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/master/manifests.go @@ -127,13 +127,6 @@ func WriteStaticPodManifests(cfg *kubeadmapi.MasterConfiguration) error { LivenessProbe: componentProbe(2379, "/health", api.URISchemeHTTP), }, certsVolume(cfg), etcdVolume(cfg), k8sVolume()) - etcdPod.Spec.SecurityContext = &api.PodSecurityContext{ - SELinuxOptions: &api.SELinuxOptions{ - // Unconfine the etcd container so it can write to the data dir with SELinux enforcing: - Type: "spc_t", - }, - } - staticPodSpecs[etcd] = etcdPod } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/BUILD index d5df5c4b93..91e0b49550 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/BUILD @@ -21,6 +21,7 @@ go_library( "//cmd/kubeadm/app/images:go_default_library", "//cmd/kubeadm/app/util:go_default_library", "//pkg/api:go_default_library", + "//plugin/pkg/scheduler/algorithm:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/addons.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/addons.go index 3c3ab5f113..1cc6d13980 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/addons.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/addons.go @@ -32,6 +32,7 @@ import ( "k8s.io/kubernetes/cmd/kubeadm/app/images" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm" ) // CreateEssentialAddons creates the kube-proxy and kube-dns addons @@ -110,7 +111,14 @@ func CreateKubeProxyAddon(configMapBytes, daemonSetbytes []byte, client *clients if err := kuberuntime.DecodeInto(api.Codecs.UniversalDecoder(), daemonSetbytes, kubeproxyDaemonSet); err != nil { return fmt.Errorf("unable to decode kube-proxy daemonset %v", err) } - kubeproxyDaemonSet.Spec.Template.Spec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration} + kubeproxyDaemonSet.Spec.Template.Spec.Tolerations = []v1.Toleration{ + kubeadmconstants.MasterToleration, + { + Key: algorithm.TaintExternalCloudProvider, + Value: "true", + Effect: "NoSchedule", + }, + } if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(kubeproxyDaemonSet); err != nil { if !apierrors.IsAlreadyExists(err) { diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/BUILD index 3a980e63a4..37a0f3afae 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/BUILD @@ -20,7 +20,6 @@ go_library( "//cmd/kubeadm/app/util:go_default_library", "//pkg/bootstrap/api:go_default_library", "//pkg/kubelet/apis:go_default_library", - "//pkg/util/node:go_default_library", "//pkg/util/version:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/clusterroles.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/clusterroles.go index c6f4f1b6f9..47fec4c6cc 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/clusterroles.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/clusterroles.go @@ -105,7 +105,7 @@ func createRoles(clientset *clientset.Clientset) error { Namespace: metav1.NamespacePublic, }, Rules: []rbac.PolicyRule{ - rbac.NewRule("get").Groups("").Resources("configmaps").RuleOrDie(), + rbac.NewRule("get").Groups("").Resources("configmaps").Names("cluster-info").RuleOrDie(), }, }, } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster.go index 0b0bd0b94e..b5d942e145 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster.go @@ -30,20 +30,19 @@ import ( "k8s.io/client-go/pkg/api/v1" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" - "k8s.io/kubernetes/pkg/util/node" ) const apiCallRetryInterval = 500 * time.Millisecond // TODO: Can we think of any unit tests here? Or should this code just be covered through integration/e2e tests? -func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset) error { +func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset, nodeName string) error { var n *v1.Node // Wait for current node registration wait.PollInfinite(kubeadmconstants.APICallRetryInterval, func() (bool, error) { var err error - if n, err = client.Nodes().Get(node.GetHostname(""), metav1.GetOptions{}); err != nil { + if n, err = client.Nodes().Get(nodeName, metav1.GetOptions{}); err != nil { return false, nil } // The node may appear to have no labels at first, @@ -75,7 +74,7 @@ func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset) error if apierrs.IsConflict(err) { fmt.Println("[apiclient] Temporarily unable to update master node metadata due to conflict (will retry)") time.Sleep(apiCallRetryInterval) - attemptToUpdateMasterRoleLabelsAndTaints(client) + attemptToUpdateMasterRoleLabelsAndTaints(client, nodeName) } else { return err } @@ -95,9 +94,9 @@ func addTaintIfNotExists(n *v1.Node, t v1.Taint) { } // UpdateMasterRoleLabelsAndTaints taints the master and sets the master label -func UpdateMasterRoleLabelsAndTaints(client *clientset.Clientset) error { +func UpdateMasterRoleLabelsAndTaints(client *clientset.Clientset, nodeName string) error { // TODO: Use iterate instead of recursion - err := attemptToUpdateMasterRoleLabelsAndTaints(client) + err := attemptToUpdateMasterRoleLabelsAndTaints(client, nodeName) if err != nil { return fmt.Errorf("failed to update master node - [%v]", err) } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster_test.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster_test.go index 5e25a71698..48e2555aee 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster_test.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/apiconfig/setupmaster_test.go @@ -130,7 +130,7 @@ func TestUpdateMasterRoleLabelsAndTaints(t *testing.T) { t.Fatalf("UpdateMasterRoleLabelsAndTaints(%s): unexpected error building clientset: %v", tc.name, err) } - err = UpdateMasterRoleLabelsAndTaints(cs) + err = UpdateMasterRoleLabelsAndTaints(cs, hostname) if err != nil { t.Errorf("UpdateMasterRoleLabelsAndTaints(%s) returned unexpected error: %v", tc.name, err) } diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go index a19f7e6045..f60f15c48a 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/certs.go @@ -21,7 +21,6 @@ import ( "crypto/x509" "fmt" "net" - "os" setutil "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation" @@ -43,10 +42,6 @@ import ( // It generates a self-signed CA certificate and a server certificate (signed by the CA) func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error { pkiDir := cfg.CertificatesDir - hostname, err := os.Hostname() - if err != nil { - return fmt.Errorf("couldn't get the hostname: %v", err) - } _, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet) if err != nil { @@ -54,7 +49,7 @@ func CreatePKIAssets(cfg *kubeadmapi.MasterConfiguration) error { } // Build the list of SANs - altNames := getAltNames(cfg.APIServerCertSANs, hostname, cfg.Networking.DNSDomain, svcSubnet) + altNames := getAltNames(cfg.APIServerCertSANs, cfg.NodeName, cfg.Networking.DNSDomain, svcSubnet) // Append the address the API Server is advertising altNames.IPs = append(altNames.IPs, net.ParseIP(cfg.API.AdvertiseAddress)) diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD index 4e26adcd82..d5038b310e 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/BUILD @@ -18,7 +18,6 @@ go_library( "//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library", "//cmd/kubeadm/app/util/kubeconfig:go_default_library", - "//pkg/util/node:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library", "//vendor/k8s.io/client-go/util/cert:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go index d842c3eb0b..e3df1d4308 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig/kubeconfig.go @@ -29,7 +29,6 @@ import ( kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" - "k8s.io/kubernetes/pkg/util/node" ) // BuildConfigProperties holds some simple information about how this phase should build the KubeConfig object @@ -53,12 +52,7 @@ type BuildConfigProperties struct { // /etc/kubernetes/{admin,kubelet}.conf exist but not certs => certs will be generated and conflict with the kubeconfig files => error // CreateInitKubeConfigFiles is called from the main init and does the work for the default phase behaviour -func CreateInitKubeConfigFiles(masterEndpoint, pkiDir, outDir string) error { - - nodeName := node.GetHostname("") - if len(nodeName) == 0 { - return fmt.Errorf("unable to get hostname for master node") - } +func CreateInitKubeConfigFiles(masterEndpoint, pkiDir, outDir, nodeName string) error { // Create a lightweight specification for what the files should look like filesToCreateFromSpec := map[string]BuildConfigProperties{ diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD index c3fcafba25..605656385f 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD @@ -18,7 +18,6 @@ go_library( "//pkg/api/validation:go_default_library", "//pkg/kubeapiserver/authorizer/modes:go_default_library", "//pkg/util/initsystem:go_default_library", - "//pkg/util/node:go_default_library", "//test/e2e_node/system:go_default_library", "//vendor/github.com/PuerkitoBio/purell:go_default_library", "//vendor/github.com/blang/semver:go_default_library", diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go index 3ebbd6f38e..6edf5bd213 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go @@ -43,7 +43,6 @@ import ( "k8s.io/kubernetes/pkg/api/validation" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" "k8s.io/kubernetes/pkg/util/initsystem" - "k8s.io/kubernetes/pkg/util/node" "k8s.io/kubernetes/test/e2e_node/system" ) @@ -267,21 +266,22 @@ func (ipc InPathCheck) Check() (warnings, errors []error) { // HostnameCheck checks if hostname match dns sub domain regex. // If hostname doesn't match this regex, kubelet will not launch static pods like kube-apiserver/kube-controller-manager and so on. -type HostnameCheck struct{} +type HostnameCheck struct { + nodeName string +} func (hc HostnameCheck) Check() (warnings, errors []error) { errors = []error{} warnings = []error{} - hostname := node.GetHostname("") - for _, msg := range validation.ValidateNodeName(hostname, false) { - errors = append(errors, fmt.Errorf("hostname \"%s\" %s", hostname, msg)) + for _, msg := range validation.ValidateNodeName(hc.nodeName, false) { + errors = append(errors, fmt.Errorf("hostname \"%s\" %s", hc.nodeName, msg)) } - addr, err := net.LookupHost(hostname) + addr, err := net.LookupHost(hc.nodeName) if addr == nil { - warnings = append(warnings, fmt.Errorf("hostname \"%s\" could not be reached", hostname)) + warnings = append(warnings, fmt.Errorf("hostname \"%s\" could not be reached", hc.nodeName)) } if err != nil { - warnings = append(warnings, fmt.Errorf("hostname \"%s\" %s", hostname, err)) + warnings = append(warnings, fmt.Errorf("hostname \"%s\" %s", hc.nodeName, err)) } return warnings, errors } @@ -488,7 +488,7 @@ func RunInitMasterChecks(cfg *kubeadmapi.MasterConfiguration) error { checks := []Checker{ SystemVerificationCheck{}, IsRootCheck{}, - HostnameCheck{}, + HostnameCheck{nodeName: cfg.NodeName}, ServiceCheck{Service: "kubelet", CheckIfActive: false}, ServiceCheck{Service: "docker", CheckIfActive: true}, FirewalldCheck{ports: []int{int(cfg.API.BindPort), 10250}}, @@ -541,7 +541,7 @@ func RunJoinNodeChecks(cfg *kubeadmapi.NodeConfiguration) error { checks := []Checker{ SystemVerificationCheck{}, IsRootCheck{}, - HostnameCheck{}, + HostnameCheck{nodeName: cfg.NodeName}, ServiceCheck{Service: "kubelet", CheckIfActive: false}, ServiceCheck{Service: "docker", CheckIfActive: true}, PortOpenCheck{port: 10250}, diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/init_test.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/init_test.go index be6a8c3e83..9ce3b95daa 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/init_test.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/init_test.go @@ -137,3 +137,31 @@ func TestCmdInitAPIPort(t *testing.T) { kubeadmReset() } } + +func TestCmdInitArgsMixed(t *testing.T) { + if *kubeadmCmdSkip { + t.Log("kubeadm cmd tests being skipped") + t.Skip() + } + + var initTest = []struct { + args string + expected bool + }{ + {"--api-port=1000 --config=/etc/kubernets/kubeadm.config", false}, + } + + for _, rt := range initTest { + _, _, actual := RunCmd(*kubeadmPath, "init", rt.args, "--skip-preflight-checks") + if (actual == nil) != rt.expected { + t.Errorf( + "failed CmdInitArgsMixed running 'kubeadm init %s' with an error: %v\n\texpected: %t\n\t actual: %t", + rt.args, + actual, + rt.expected, + (actual == nil), + ) + } + kubeadmReset() + } +} diff --git a/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/join_test.go b/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/join_test.go index 5e82b2accb..5d73178fe5 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/join_test.go +++ b/vendor/k8s.io/kubernetes/cmd/kubeadm/test/cmd/join_test.go @@ -105,6 +105,34 @@ func TestCmdJoinDiscoveryToken(t *testing.T) { } } +func TestCmdJoinNodeName(t *testing.T) { + if *kubeadmCmdSkip { + t.Log("kubeadm cmd tests being skipped") + t.Skip() + } + + var initTest = []struct { + args string + expected bool + }{ + {"--node-name=foobar", false}, + } + + for _, rt := range initTest { + _, _, actual := RunCmd(*kubeadmPath, "join", rt.args, "--skip-preflight-checks") + if (actual == nil) != rt.expected { + t.Errorf( + "failed CmdJoinNodeName running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", + rt.args, + actual, + rt.expected, + (actual == nil), + ) + } + kubeadmReset() + } +} + func TestCmdJoinTLSBootstrapToken(t *testing.T) { if *kubeadmCmdSkip { t.Log("kubeadm cmd tests being skipped") @@ -191,3 +219,31 @@ func TestCmdJoinBadArgs(t *testing.T) { kubeadmReset() } } + +func TestCmdJoinArgsMixed(t *testing.T) { + if *kubeadmCmdSkip { + t.Log("kubeadm cmd tests being skipped") + t.Skip() + } + + var initTest = []struct { + args string + expected bool + }{ + {"--discovery-token=abcdef.1234567890abcdef --config=/etc/kubernets/kubeadm.config", false}, + } + + for _, rt := range initTest { + _, _, actual := RunCmd(*kubeadmPath, "join", rt.args, "--skip-preflight-checks") + if (actual == nil) != rt.expected { + t.Errorf( + "failed CmdJoinArgsMixed running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", + rt.args, + actual, + rt.expected, + (actual == nil), + ) + } + kubeadmReset() + } +} diff --git a/vendor/k8s.io/kubernetes/cmd/kubelet/app/server.go b/vendor/k8s.io/kubernetes/cmd/kubelet/app/server.go index 472a824246..4994536dff 100644 --- a/vendor/k8s.io/kubernetes/cmd/kubelet/app/server.go +++ b/vendor/k8s.io/kubernetes/cmd/kubelet/app/server.go @@ -996,7 +996,12 @@ func parseResourceList(m componentconfig.ConfigurationMap) (v1.ResourceList, err if q.Sign() == -1 { return nil, fmt.Errorf("resource quantity for %q cannot be negative: %v", k, v) } - rl[v1.ResourceName(k)] = q + // storage specified in configuration map is mapped to ResourceStorageScratch API + if v1.ResourceName(k) == v1.ResourceStorage { + rl[v1.ResourceStorageScratch] = q + } else { + rl[v1.ResourceName(k)] = q + } default: return nil, fmt.Errorf("cannot reserve %q resource", k) } diff --git a/vendor/k8s.io/kubernetes/docs/api-reference/apps/v1beta1/operations.html b/vendor/k8s.io/kubernetes/docs/api-reference/apps/v1beta1/operations.html index 42a491d048..42ce7aeb67 100755 --- a/vendor/k8s.io/kubernetes/docs/api-reference/apps/v1beta1/operations.html +++ b/vendor/k8s.io/kubernetes/docs/api-reference/apps/v1beta1/operations.html @@ -2735,7 +2735,7 @@

Tags

-

create rollback of a DeploymentRollback

+

create rollback of a Deployment

POST /apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
@@ -2862,7 +2862,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified Deployment

GET /apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -2981,7 +2981,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified Deployment

PUT /apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -3108,7 +3108,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified Deployment

PATCH /apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/scale
diff --git a/vendor/k8s.io/kubernetes/docs/api-reference/extensions/v1beta1/operations.html b/vendor/k8s.io/kubernetes/docs/api-reference/extensions/v1beta1/operations.html index d51388f77f..069d0ab39b 100755 --- a/vendor/k8s.io/kubernetes/docs/api-reference/extensions/v1beta1/operations.html +++ b/vendor/k8s.io/kubernetes/docs/api-reference/extensions/v1beta1/operations.html @@ -3271,7 +3271,7 @@

Tags

-

create rollback of a DeploymentRollback

+

create rollback of a Deployment

POST /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
@@ -3398,7 +3398,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified Deployment

GET /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -3517,7 +3517,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified Deployment

PUT /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -3644,7 +3644,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified Deployment

PATCH /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -7502,7 +7502,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified ReplicaSet

GET /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
@@ -7621,7 +7621,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified ReplicaSet

PUT /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
@@ -7748,7 +7748,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified ReplicaSet

PATCH /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
@@ -8260,7 +8260,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified ReplicationControllerDummy

GET /apis/extensions/v1beta1/namespaces/{namespace}/replicationcontrollers/{name}/scale
@@ -8379,7 +8379,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified ReplicationControllerDummy

PUT /apis/extensions/v1beta1/namespaces/{namespace}/replicationcontrollers/{name}/scale
@@ -8506,7 +8506,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified ReplicationControllerDummy

PATCH /apis/extensions/v1beta1/namespaces/{namespace}/replicationcontrollers/{name}/scale
diff --git a/vendor/k8s.io/kubernetes/docs/api-reference/v1/operations.html b/vendor/k8s.io/kubernetes/docs/api-reference/v1/operations.html index c3ba24f06e..373aa13a1b 100755 --- a/vendor/k8s.io/kubernetes/docs/api-reference/v1/operations.html +++ b/vendor/k8s.io/kubernetes/docs/api-reference/v1/operations.html @@ -8329,7 +8329,7 @@

Tags

-

create binding of a Binding

+

create binding of a Pod

POST /api/v1/namespaces/{namespace}/pods/{name}/binding
@@ -8456,7 +8456,7 @@

Tags

-

create eviction of an Eviction

+

create eviction of a Pod

POST /api/v1/namespaces/{namespace}/pods/{name}/eviction
@@ -12820,7 +12820,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified ReplicationController

GET /api/v1/namespaces/{namespace}/replicationcontrollers/{name}/scale
@@ -12939,7 +12939,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified ReplicationController

PUT /api/v1/namespaces/{namespace}/replicationcontrollers/{name}/scale
@@ -13066,7 +13066,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified ReplicationController

PATCH /api/v1/namespaces/{namespace}/replicationcontrollers/{name}/scale
diff --git a/vendor/k8s.io/kubernetes/federation/apis/openapi-spec/swagger.json b/vendor/k8s.io/kubernetes/federation/apis/openapi-spec/swagger.json index daee7e09c3..314c5f9d6a 100644 --- a/vendor/k8s.io/kubernetes/federation/apis/openapi-spec/swagger.json +++ b/vendor/k8s.io/kubernetes/federation/apis/openapi-spec/swagger.json @@ -2,7 +2,7 @@ "swagger": "2.0", "info": { "title": "Generic API Server", - "version": "v1.7.1" + "version": "v1.7.6" }, "paths": { "/api/": { @@ -5809,7 +5809,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/rollback": { "post": { - "description": "create rollback of a DeploymentRollback", + "description": "create rollback of a Deployment", "consumes": [ "*/*" ], @@ -5824,7 +5824,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "createExtensionsV1beta1NamespacedDeploymentRollbackRollback", + "operationId": "createExtensionsV1beta1NamespacedDeploymentRollback", "parameters": [ { "name": "body", @@ -5881,7 +5881,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified Deployment", "consumes": [ "*/*" ], @@ -5896,7 +5896,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "readExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "readExtensionsV1beta1NamespacedDeploymentScale", "responses": { "200": { "description": "OK", @@ -5916,7 +5916,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified Deployment", "consumes": [ "*/*" ], @@ -5931,7 +5931,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "replaceExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "replaceExtensionsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -5961,7 +5961,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified Deployment", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -5978,7 +5978,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "patchExtensionsV1beta1NamespacedDeploymentsScale", + "operationId": "patchExtensionsV1beta1NamespacedDeploymentScale", "parameters": [ { "name": "body", @@ -7263,7 +7263,7 @@ }, "/apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale": { "get": { - "description": "read scale of the specified Scale", + "description": "read scale of the specified ReplicaSet", "consumes": [ "*/*" ], @@ -7278,7 +7278,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "readExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "readExtensionsV1beta1NamespacedReplicaSetScale", "responses": { "200": { "description": "OK", @@ -7298,7 +7298,7 @@ } }, "put": { - "description": "replace scale of the specified Scale", + "description": "replace scale of the specified ReplicaSet", "consumes": [ "*/*" ], @@ -7313,7 +7313,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "replaceExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "replaceExtensionsV1beta1NamespacedReplicaSetScale", "parameters": [ { "name": "body", @@ -7343,7 +7343,7 @@ } }, "patch": { - "description": "partially update scale of the specified Scale", + "description": "partially update scale of the specified ReplicaSet", "consumes": [ "application/json-patch+json", "application/merge-patch+json", @@ -7360,7 +7360,7 @@ "tags": [ "extensions_v1beta1" ], - "operationId": "patchExtensionsV1beta1NamespacedReplicasetsScale", + "operationId": "patchExtensionsV1beta1NamespacedReplicaSetScale", "parameters": [ { "name": "body", diff --git a/vendor/k8s.io/kubernetes/federation/apis/swagger-spec/extensions_v1beta1.json b/vendor/k8s.io/kubernetes/federation/apis/swagger-spec/extensions_v1beta1.json index e9d3ead36a..fc226e62ed 100644 --- a/vendor/k8s.io/kubernetes/federation/apis/swagger-spec/extensions_v1beta1.json +++ b/vendor/k8s.io/kubernetes/federation/apis/swagger-spec/extensions_v1beta1.json @@ -1902,8 +1902,8 @@ { "type": "v1beta1.DeploymentRollback", "method": "POST", - "summary": "create rollback of a DeploymentRollback", - "nickname": "createNamespacedDeploymentRollbackRollback", + "summary": "create rollback of a Deployment", + "nickname": "createNamespacedDeploymentRollback", "parameters": [ { "type": "string", @@ -1963,8 +1963,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified Deployment", + "nickname": "readNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -2010,8 +2010,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified Deployment", + "nickname": "replaceNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -2065,8 +2065,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified Deployment", + "nickname": "patchNamespacedDeploymentScale", "parameters": [ { "type": "string", @@ -4180,8 +4180,8 @@ { "type": "v1beta1.Scale", "method": "GET", - "summary": "read scale of the specified Scale", - "nickname": "readNamespacedScaleScale", + "summary": "read scale of the specified ReplicaSet", + "nickname": "readNamespacedReplicaSetScale", "parameters": [ { "type": "string", @@ -4227,8 +4227,8 @@ { "type": "v1beta1.Scale", "method": "PUT", - "summary": "replace scale of the specified Scale", - "nickname": "replaceNamespacedScaleScale", + "summary": "replace scale of the specified ReplicaSet", + "nickname": "replaceNamespacedReplicaSetScale", "parameters": [ { "type": "string", @@ -4282,8 +4282,8 @@ { "type": "v1beta1.Scale", "method": "PATCH", - "summary": "partially update scale of the specified Scale", - "nickname": "patchNamespacedScaleScale", + "summary": "partially update scale of the specified ReplicaSet", + "nickname": "patchNamespacedReplicaSetScale", "parameters": [ { "type": "string", diff --git a/vendor/k8s.io/kubernetes/federation/docs/api-reference/extensions/v1beta1/operations.html b/vendor/k8s.io/kubernetes/federation/docs/api-reference/extensions/v1beta1/operations.html index da93177555..e9fcca766e 100755 --- a/vendor/k8s.io/kubernetes/federation/docs/api-reference/extensions/v1beta1/operations.html +++ b/vendor/k8s.io/kubernetes/federation/docs/api-reference/extensions/v1beta1/operations.html @@ -3271,7 +3271,7 @@

Tags

-

create rollback of a DeploymentRollback

+

create rollback of a Deployment

POST /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
@@ -3398,7 +3398,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified Deployment

GET /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -3517,7 +3517,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified Deployment

PUT /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -3644,7 +3644,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified Deployment

PATCH /apis/extensions/v1beta1/namespaces/{namespace}/deployments/{name}/scale
@@ -6513,7 +6513,7 @@

Tags

-

read scale of the specified Scale

+

read scale of the specified ReplicaSet

GET /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
@@ -6632,7 +6632,7 @@

Tags

-

replace scale of the specified Scale

+

replace scale of the specified ReplicaSet

PUT /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
@@ -6759,7 +6759,7 @@

Tags

-

partially update scale of the specified Scale

+

partially update scale of the specified ReplicaSet

PATCH /apis/extensions/v1beta1/namespaces/{namespace}/replicasets/{name}/scale
diff --git a/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD b/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD index 82628434b4..f10f895897 100644 --- a/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD +++ b/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/BUILD @@ -56,6 +56,8 @@ go_test( "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//vendor/k8s.io/client-go/discovery:go_default_library", + "//vendor/k8s.io/client-go/discovery/fake:go_default_library", "//vendor/k8s.io/client-go/dynamic:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/testing:go_default_library", diff --git a/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go b/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go index 11506ceb72..de593ff350 100644 --- a/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go +++ b/vendor/k8s.io/kubernetes/federation/pkg/federation-controller/namespace/namespace_controller_test.go @@ -24,6 +24,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/dynamic" restclient "k8s.io/client-go/rest" core "k8s.io/client-go/testing" @@ -45,6 +47,28 @@ const ( clusters string = "clusters" ) +type fakeDiscoveryForFedNSTest struct { + fakediscovery.FakeDiscovery +} + +// ServerPreferredNamespacedResources here overrides the fakeDiscovery ServerPreferredNamespacedResources() +// implementation only for this federated unit test. +func (f *fakeDiscoveryForFedNSTest) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) { + preferredFakeResources := []*metav1.APIResourceList{} + preferredFakeResources = append(preferredFakeResources, &metav1.APIResourceList{}) + + return preferredFakeResources, nil +} + +type fakeClientSetForFedNSTest struct { + fakefedclientset.Clientset +} + +// Discovery overrides the fakefedclientset Discovery() method only for this federated unit test. +func (fc *fakeClientSetForFedNSTest) Discovery() discovery.DiscoveryInterface { + return &fakeDiscoveryForFedNSTest{FakeDiscovery: fakediscovery.FakeDiscovery{Fake: &fc.Fake}} +} + func TestNamespaceController(t *testing.T) { cluster1 := NewCluster("cluster1", apiv1.ConditionTrue) cluster2 := NewCluster("cluster2", apiv1.ConditionTrue) @@ -58,7 +82,7 @@ func TestNamespaceController(t *testing.T) { }, } - fakeClient := &fakefedclientset.Clientset{} + fakeClient := &fakeClientSetForFedNSTest{} RegisterFakeList(clusters, &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}}) RegisterFakeList(namespaces, &fakeClient.Fake, &apiv1.NamespaceList{Items: []apiv1.Namespace{}}) namespaceWatch := RegisterFakeWatch(namespaces, &fakeClient.Fake) diff --git a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go index 765bbad5ff..5d55f1e34a 100644 --- a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go +++ b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go @@ -1444,7 +1444,11 @@ func tlsHandshake(t *testing.T, sCfg, cCfg *tls.Config) error { } }() - c, err := tls.Dial("tcp", s.Addr().String(), cCfg) + // workaround [::] not working in ipv4 only systems (https://github.com/golang/go/issues/18806) + // TODO: remove with Golang 1.9 with https://go-review.googlesource.com/c/45088/ + addr := strings.TrimPrefix(s.Addr().String(), "[::]") + + c, err := tls.Dial("tcp", addr, cCfg) if err != nil { // Intentionally not serializing the error received because we want to // test for the failure case in the caller test function. diff --git a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD index 19122d412f..00f65acdab 100644 --- a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD +++ b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD @@ -16,6 +16,8 @@ go_library( "//federation/client/clientset_generated/federation_clientset:go_default_library", "//pkg/api:go_default_library", "//pkg/apis/rbac:go_default_library", + "//pkg/apis/rbac/v1alpha1:go_default_library", + "//pkg/apis/rbac/v1beta1:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/kubectl/cmd:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", diff --git a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go index 049b65395b..5441a0a03b 100644 --- a/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go +++ b/vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go @@ -31,6 +31,8 @@ import ( fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/rbac" + rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -284,6 +286,15 @@ func getRBACVersion(discoveryclient discovery.CachedDiscoveryInterface) (*schema return nil, fmt.Errorf("Couldn't get clientset to create RBAC roles in the host cluster: %v", err) } + // These are the RBAC versions we can speak + knownVersions := map[schema.GroupVersion]bool{ + rbacv1alpha1.SchemeGroupVersion: true, + rbacv1beta1.SchemeGroupVersion: true, + } + + // This holds any RBAC versions listed in discovery we do not know how to speak + unknownVersions := []schema.GroupVersion{} + for _, g := range groupList.Groups { if g.Name == rbac.GroupName { if g.PreferredVersion.GroupVersion != "" { @@ -291,7 +302,9 @@ func getRBACVersion(discoveryclient discovery.CachedDiscoveryInterface) (*schema if err != nil { return nil, err } - return &gv, nil + if knownVersions[gv] { + return &gv, nil + } } for _, version := range g.Versions { if version.GroupVersion != "" { @@ -299,12 +312,20 @@ func getRBACVersion(discoveryclient discovery.CachedDiscoveryInterface) (*schema if err != nil { return nil, err } - return &gv, nil + if knownVersions[gv] { + return &gv, nil + } else { + unknownVersions = append(unknownVersions, gv) + } } } } } + if len(unknownVersions) > 0 { + return nil, &NoRBACAPIError{fmt.Sprintf("%s\nUnknown RBAC API versions: %v", rbacAPINotAvailable, unknownVersions)} + } + return nil, &NoRBACAPIError{rbacAPINotAvailable} } diff --git a/vendor/k8s.io/kubernetes/hack/.linted_packages b/vendor/k8s.io/kubernetes/hack/.linted_packages index 6a58a36ce1..e27e7889bf 100644 --- a/vendor/k8s.io/kubernetes/hack/.linted_packages +++ b/vendor/k8s.io/kubernetes/hack/.linted_packages @@ -202,6 +202,7 @@ pkg/controller/volume/attachdetach/util pkg/conversion pkg/conversion/queryparams pkg/credentialprovider/aws +pkg/credentialprovider/azure pkg/fieldpath pkg/fields pkg/hyperkube diff --git a/vendor/k8s.io/kubernetes/hack/ginkgo-e2e.sh b/vendor/k8s.io/kubernetes/hack/ginkgo-e2e.sh index 246b5ef945..c4d7cee3fc 100755 --- a/vendor/k8s.io/kubernetes/hack/ginkgo-e2e.sh +++ b/vendor/k8s.io/kubernetes/hack/ginkgo-e2e.sh @@ -76,8 +76,6 @@ fi if [[ -n "${NODE_INSTANCE_PREFIX:-}" ]]; then NODE_INSTANCE_GROUP="${NODE_INSTANCE_PREFIX}-group" -else - NODE_INSTANCE_GROUP="" fi if [[ "${KUBERNETES_PROVIDER}" == "gce" ]]; then @@ -93,7 +91,10 @@ if [[ "${KUBERNETES_PROVIDER}" == "gce" ]]; then done fi -if [[ "${KUBERNETES_PROVIDER}" == "gke" ]]; then +# TODO(kubernetes/test-infra#3330): Allow NODE_INSTANCE_GROUP to be +# set before we get here, which eliminates any cluster/gke use if +# KUBERNETES_CONFORMANCE_PROVIDER is set to "gke". +if [[ -z "${NODE_INSTANCE_GROUP:-}" ]] && [[ "${KUBERNETES_PROVIDER}" == "gke" ]]; then detect-node-instance-groups NODE_INSTANCE_GROUP=$(kube::util::join , "${NODE_INSTANCE_GROUPS[@]}") fi diff --git a/vendor/k8s.io/kubernetes/hack/make-rules/test-cmd-util.sh b/vendor/k8s.io/kubernetes/hack/make-rules/test-cmd-util.sh index fc34fe9e6c..db3d08fdd2 100644 --- a/vendor/k8s.io/kubernetes/hack/make-rules/test-cmd-util.sh +++ b/vendor/k8s.io/kubernetes/hack/make-rules/test-cmd-util.sh @@ -2435,6 +2435,9 @@ run_service_tests() { # prove role=master kube::test::get_object_assert 'services redis-master' "{{range$service_selector_field}}{{.}}:{{end}}" "redis:master:backend:" + # Set selector of a local file without talking to the server + kubectl set selector -f examples/guestbook/redis-master-service.yaml role=padawan --local -o yaml "${kube_flags[@]}" + ! kubectl set selector -f examples/guestbook/redis-master-service.yaml role=padawan --dry-run -o yaml "${kube_flags[@]}" # Set command to change the selector. kubectl set selector -f examples/guestbook/redis-master-service.yaml role=padawan # prove role=padawan @@ -2443,6 +2446,10 @@ run_service_tests() { kubectl set selector -f examples/guestbook/redis-master-service.yaml app=redis,role=master,tier=backend # prove role=master kube::test::get_object_assert 'services redis-master' "{{range$service_selector_field}}{{.}}:{{end}}" "redis:master:backend:" + # Show dry-run works on running selector + kubectl set selector services redis-master role=padawan --dry-run -o yaml "${kube_flags[@]}" + ! kubectl set selector services redis-master role=padawan --local -o yaml "${kube_flags[@]}" + kube::test::get_object_assert 'services redis-master' "{{range$service_selector_field}}{{.}}:{{end}}" "redis:master:backend:" ### Dump current redis-master service output_service=$(kubectl get service redis-master -o json --output-version=v1 "${kube_flags[@]}") diff --git a/vendor/k8s.io/kubernetes/hack/make-rules/test-e2e-node.sh b/vendor/k8s.io/kubernetes/hack/make-rules/test-e2e-node.sh index 54a8233c7e..1cff4c85d8 100755 --- a/vendor/k8s.io/kubernetes/hack/make-rules/test-e2e-node.sh +++ b/vendor/k8s.io/kubernetes/hack/make-rules/test-e2e-node.sh @@ -33,6 +33,7 @@ container_runtime_endpoint=${CONTAINER_RUNTIME_ENDPOINT:-""} image_service_endpoint=${IMAGE_SERVICE_ENDPOINT:-""} run_until_failure=${RUN_UNTIL_FAILURE:-"false"} test_args=${TEST_ARGS:-""} +system_spec_name=${SYSTEM_SPEC_NAME:-} # Parse the flags to pass to ginkgo ginkgoflags="" @@ -75,7 +76,7 @@ if [ $remote = true ] ; then if [[ $hosts == "" && $images == "" && $image_config_file == "" ]]; then image_project=${IMAGE_PROJECT:-"cos-cloud"} gci_image=$(gcloud compute images list --project $image_project \ - --no-standard-images --regexp="cos-beta.*" --format="table[no-heading](name)") + --no-standard-images --filter="name ~ 'cos-beta.*'" --format="table[no-heading](name)") images=$gci_image metadata="user-data<${KUBE_ROOT}/test/e2e_node/jenkins/gci-init.yaml,gci-update-strategy=update_disabled" fi @@ -135,7 +136,7 @@ if [ $remote = true ] ; then --results-dir="$artifacts" --ginkgo-flags="$ginkgoflags" \ --image-project="$image_project" --instance-name-prefix="$instance_prefix" \ --delete-instances="$delete_instances" --test_args="$test_args" --instance-metadata="$metadata" \ - --image-config-file="$image_config_file" \ + --image-config-file="$image_config_file" --system-spec-name="$system_spec_name" \ 2>&1 | tee -i "${artifacts}/build-log.txt" exit $? @@ -163,7 +164,8 @@ else # Test using the host the script was run on # Provided for backwards compatibility - go run test/e2e_node/runner/local/run_local.go --ginkgo-flags="$ginkgoflags" \ + go run test/e2e_node/runner/local/run_local.go \ + --system-spec-name="$system_spec_name" --ginkgo-flags="$ginkgoflags" \ --test-flags="--container-runtime=${runtime} \ --container-runtime-endpoint=${container_runtime_endpoint} \ --image-service-endpoint=${image_service_endpoint} \ diff --git a/vendor/k8s.io/kubernetes/hack/verify-flags/exceptions.txt b/vendor/k8s.io/kubernetes/hack/verify-flags/exceptions.txt index 633f76759e..0fefc7e60f 100644 --- a/vendor/k8s.io/kubernetes/hack/verify-flags/exceptions.txt +++ b/vendor/k8s.io/kubernetes/hack/verify-flags/exceptions.txt @@ -50,9 +50,7 @@ cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py: ca_cert_ cluster/juju/layers/kubernetes-worker/reactive/kubernetes_worker.py:def configure_worker_services(api_servers, dns, cluster_cidr): cluster/lib/logging.sh: local source_file=${BASH_SOURCE[$frame_no]} cluster/lib/logging.sh: local source_file=${BASH_SOURCE[$stack_skip]} -cluster/log-dump.sh: local -r node_name="${1}" -cluster/log-dump.sh: for node_name in "${node_names[@]}"; do -cluster/log-dump.sh:readonly report_dir="${1:-_artifacts}" +cluster/log-dump/log-dump.sh:readonly report_dir="${1:-_artifacts}" cluster/photon-controller/templates/salt-master.sh: api_servers: $MASTER_NAME cluster/photon-controller/templates/salt-minion.sh: hostname_override: $(ip route get 1.1.1.1 | awk '{print $7}') cluster/photon-controller/util.sh: node_ip=$(${PHOTON} vm networks "${node_id}" | grep -i $'\t'"00:0C:29" | grep -E '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1 | awk -F'\t' '{print $3}') diff --git a/vendor/k8s.io/kubernetes/hack/verify-flags/excluded-flags.txt b/vendor/k8s.io/kubernetes/hack/verify-flags/excluded-flags.txt index fc1e86d0e8..7b6cd4e4cc 100644 --- a/vendor/k8s.io/kubernetes/hack/verify-flags/excluded-flags.txt +++ b/vendor/k8s.io/kubernetes/hack/verify-flags/excluded-flags.txt @@ -24,3 +24,4 @@ valid_flag retry_time file_content_in_loop break_on_expected_content +Premium_LRS diff --git a/vendor/k8s.io/kubernetes/hack/verify-flags/known-flags.txt b/vendor/k8s.io/kubernetes/hack/verify-flags/known-flags.txt index b504324bb9..5d01fde37d 100644 --- a/vendor/k8s.io/kubernetes/hack/verify-flags/known-flags.txt +++ b/vendor/k8s.io/kubernetes/hack/verify-flags/known-flags.txt @@ -479,6 +479,7 @@ mesos-launch-grace-period mesos-master mesos-sandbox-overlay mesos-user +metrics-bind-address metrics-path min-available minimum-container-ttl-duration @@ -678,6 +679,8 @@ system-cgroups system-pods-startup-timeout system-reserved system-reserved-cgroup +system-spec-file +system-spec-name system-validate-mode target-port target-ram-mb diff --git a/vendor/k8s.io/kubernetes/pkg/api/types.go b/vendor/k8s.io/kubernetes/pkg/api/types.go index b59f7202e4..454b94ef20 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/types.go +++ b/vendor/k8s.io/kubernetes/pkg/api/types.go @@ -615,7 +615,7 @@ type EmptyDirVolumeSource struct { // The default is nil which means that the limit is undefined. // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir // +optional - SizeLimit resource.Quantity + SizeLimit *resource.Quantity } // StorageMedium defines ways that storage can be allocated to a volume. diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/generated.pb.go b/vendor/k8s.io/kubernetes/pkg/api/v1/generated.pb.go index d45d2d5e4a..f159e3e42b 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/generated.pb.go +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/generated.pb.go @@ -2591,14 +2591,16 @@ func (m *EmptyDirVolumeSource) MarshalTo(dAtA []byte) (int, error) { i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Medium))) i += copy(dAtA[i:], m.Medium) - dAtA[i] = 0x12 - i++ - i = encodeVarintGenerated(dAtA, i, uint64(m.SizeLimit.Size())) - n31, err := m.SizeLimit.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.SizeLimit != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.SizeLimit.Size())) + n31, err := m.SizeLimit.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n31 } - i += n31 return i, nil } @@ -10033,8 +10035,10 @@ func (m *EmptyDirVolumeSource) Size() (n int) { _ = l l = len(m.Medium) n += 1 + l + sovGenerated(uint64(l)) - l = m.SizeLimit.Size() - n += 1 + l + sovGenerated(uint64(l)) + if m.SizeLimit != nil { + l = m.SizeLimit.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -12949,7 +12953,7 @@ func (this *EmptyDirVolumeSource) String() string { } s := strings.Join([]string{`&EmptyDirVolumeSource{`, `Medium:` + fmt.Sprintf("%v", this.Medium) + `,`, - `SizeLimit:` + strings.Replace(strings.Replace(this.SizeLimit.String(), "Quantity", "k8s_io_apimachinery_pkg_api_resource.Quantity", 1), `&`, ``, 1) + `,`, + `SizeLimit:` + strings.Replace(fmt.Sprintf("%v", this.SizeLimit), "Quantity", "k8s_io_apimachinery_pkg_api_resource.Quantity", 1) + `,`, `}`, }, "") return s @@ -19966,6 +19970,9 @@ func (m *EmptyDirVolumeSource) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.SizeLimit == nil { + m.SizeLimit = &k8s_io_apimachinery_pkg_api_resource.Quantity{} + } if err := m.SizeLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -44391,720 +44398,720 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 11429 bytes of a gzipped FileDescriptorProto + // 11430 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x8c, 0x24, 0xc7, 0x75, 0x98, 0x7a, 0x66, 0xf6, 0x63, 0xde, 0x7e, 0xd7, 0xed, 0x1d, 0x97, 0x2b, 0xf2, 0xf6, 0xd8, 0x14, 0xe9, 0x23, 0x79, 0xdc, 0xd3, 0x1d, 0x49, 0x91, 0x12, 0x65, 0x5a, 0xbb, 0x3b, 0xbb, 0x77, 0xeb, 0xfb, 0x1a, 0xd6, 0xec, 0xdd, 0x51, 0x14, 0x43, 0xb2, 0x6f, 0xba, 0x76, 0xb7, 0x79, 0xb3, 0xdd, 0xc3, 0xee, 0x9e, 0xbd, 0x5b, 0x1a, 0x06, 0x6c, 0x45, 0xb0, 0x14, 0x40, 0x49, 0x64, 0x38, - 0x02, 0x02, 0x27, 0x80, 0x02, 0x03, 0x71, 0x94, 0x6f, 0x2b, 0x82, 0x3e, 0x0c, 0xcb, 0x09, 0xe2, - 0x48, 0x8e, 0x1c, 0x24, 0x8e, 0x00, 0x23, 0xb1, 0x02, 0xc3, 0x6b, 0x6b, 0x85, 0xf8, 0x4f, 0x80, - 0xfc, 0x48, 0xfe, 0x6d, 0x3e, 0x10, 0xd4, 0x67, 0x57, 0xf5, 0xf4, 0x6c, 0xf7, 0x2c, 0x6f, 0xd7, - 0x94, 0x90, 0x7f, 0x33, 0xf5, 0x5e, 0xbd, 0xaa, 0xae, 0x8f, 0x57, 0xef, 0xbd, 0x7a, 0xef, 0x15, - 0x9c, 0xbb, 0xfb, 0x52, 0x34, 0xef, 0x05, 0xe7, 0xef, 0x76, 0xee, 0x90, 0xd0, 0x27, 0x31, 0x89, - 0xce, 0xb7, 0xef, 0x6e, 0x9c, 0x77, 0xda, 0xde, 0xf9, 0xed, 0x0b, 0xe7, 0x37, 0x88, 0x4f, 0x42, - 0x27, 0x26, 0xee, 0x7c, 0x3b, 0x0c, 0xe2, 0x00, 0x3d, 0xc2, 0xb1, 0xe7, 0x13, 0xec, 0xf9, 0xf6, - 0xdd, 0x8d, 0x79, 0xa7, 0xed, 0xcd, 0x6f, 0x5f, 0x98, 0x7d, 0x76, 0xc3, 0x8b, 0x37, 0x3b, 0x77, - 0xe6, 0x9b, 0xc1, 0xd6, 0xf9, 0x8d, 0x60, 0x23, 0x38, 0xcf, 0x2a, 0xdd, 0xe9, 0xac, 0xb3, 0x7f, - 0xec, 0x0f, 0xfb, 0xc5, 0x89, 0xcd, 0x3e, 0x2f, 0x9a, 0x76, 0xda, 0xde, 0x96, 0xd3, 0xdc, 0xf4, - 0x7c, 0x12, 0xee, 0xa8, 0xc6, 0x43, 0x12, 0x05, 0x9d, 0xb0, 0x49, 0xd2, 0x5d, 0x38, 0xb0, 0x56, - 0x74, 0x7e, 0x8b, 0xc4, 0x4e, 0x46, 0xc7, 0x67, 0xcf, 0xf7, 0xaa, 0x15, 0x76, 0xfc, 0xd8, 0xdb, - 0xea, 0x6e, 0xe6, 0x63, 0x79, 0x15, 0xa2, 0xe6, 0x26, 0xd9, 0x72, 0xba, 0xea, 0x3d, 0xd7, 0xab, - 0x5e, 0x27, 0xf6, 0x5a, 0xe7, 0x3d, 0x3f, 0x8e, 0xe2, 0x30, 0x5d, 0xc9, 0xfe, 0x63, 0x0b, 0xce, - 0x2c, 0xdc, 0x6e, 0x2c, 0xb7, 0x9c, 0x28, 0xf6, 0x9a, 0x8b, 0xad, 0xa0, 0x79, 0xb7, 0x11, 0x07, - 0x21, 0xb9, 0x15, 0xb4, 0x3a, 0x5b, 0xa4, 0xc1, 0x06, 0x02, 0x9d, 0x83, 0xe1, 0x6d, 0xf6, 0x7f, - 0xb5, 0x36, 0x63, 0x9d, 0xb1, 0xce, 0x56, 0x17, 0x27, 0xbf, 0xbf, 0x3b, 0xf7, 0xa1, 0xbd, 0xdd, - 0xb9, 0xe1, 0x5b, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x24, 0x0c, 0xae, 0x47, 0x6b, 0x3b, 0x6d, 0x32, - 0x53, 0x62, 0xb8, 0xe3, 0x02, 0x77, 0x70, 0xa5, 0x41, 0x4b, 0xb1, 0x80, 0xa2, 0xf3, 0x50, 0x6d, - 0x3b, 0x61, 0xec, 0xc5, 0x5e, 0xe0, 0xcf, 0x94, 0xcf, 0x58, 0x67, 0x07, 0x16, 0xa7, 0x04, 0x6a, - 0xb5, 0x2e, 0x01, 0x38, 0xc1, 0xa1, 0xdd, 0x08, 0x89, 0xe3, 0xde, 0xf0, 0x5b, 0x3b, 0x33, 0x95, - 0x33, 0xd6, 0xd9, 0xe1, 0xa4, 0x1b, 0x58, 0x94, 0x63, 0x85, 0x61, 0x7f, 0xbb, 0x04, 0xc3, 0x0b, - 0xeb, 0xeb, 0x9e, 0xef, 0xc5, 0x3b, 0xe8, 0x6d, 0x18, 0xf5, 0x03, 0x97, 0xc8, 0xff, 0xec, 0x2b, - 0x46, 0x2e, 0x3e, 0x3d, 0x7f, 0xd0, 0xa2, 0x9a, 0xbf, 0xae, 0xd5, 0x58, 0x9c, 0xdc, 0xdb, 0x9d, - 0x1b, 0xd5, 0x4b, 0xb0, 0x41, 0x11, 0xbd, 0x01, 0x23, 0xed, 0xc0, 0x55, 0x0d, 0x94, 0x58, 0x03, - 0x4f, 0x1d, 0xdc, 0x40, 0x3d, 0xa9, 0xb0, 0x38, 0xb1, 0xb7, 0x3b, 0x37, 0xa2, 0x15, 0x60, 0x9d, - 0x1c, 0x6a, 0xc1, 0x04, 0xfd, 0xeb, 0xc7, 0x9e, 0x6a, 0xa1, 0xcc, 0x5a, 0x78, 0x36, 0xbf, 0x05, - 0xad, 0xd2, 0xe2, 0x89, 0xbd, 0xdd, 0xb9, 0x89, 0x54, 0x21, 0x4e, 0x93, 0xb6, 0xdf, 0x83, 0xf1, - 0x85, 0x38, 0x76, 0x9a, 0x9b, 0xc4, 0xe5, 0xf3, 0x8b, 0x9e, 0x87, 0x8a, 0xef, 0x6c, 0x11, 0x31, - 0xfb, 0x67, 0xc4, 0xb0, 0x57, 0xae, 0x3b, 0x5b, 0x64, 0x7f, 0x77, 0x6e, 0xf2, 0xa6, 0xef, 0xbd, - 0xdb, 0x11, 0x6b, 0x86, 0x96, 0x61, 0x86, 0x8d, 0x2e, 0x02, 0xb8, 0x64, 0xdb, 0x6b, 0x92, 0xba, - 0x13, 0x6f, 0x8a, 0xd5, 0x80, 0x44, 0x5d, 0xa8, 0x29, 0x08, 0xd6, 0xb0, 0xec, 0xcf, 0x5a, 0x50, - 0x5d, 0xd8, 0x0e, 0x3c, 0xb7, 0x1e, 0xb8, 0x11, 0xea, 0xc0, 0x44, 0x3b, 0x24, 0xeb, 0x24, 0x54, - 0x45, 0x33, 0xd6, 0x99, 0xf2, 0xd9, 0x91, 0x8b, 0x17, 0x73, 0xbe, 0xdb, 0xac, 0xb4, 0xec, 0xc7, - 0xe1, 0xce, 0xe2, 0x43, 0xa2, 0xe9, 0x89, 0x14, 0x14, 0xa7, 0xdb, 0xb0, 0xbf, 0x5b, 0x82, 0x93, - 0x0b, 0xef, 0x75, 0x42, 0x52, 0xf3, 0xa2, 0xbb, 0xe9, 0xad, 0xe0, 0x7a, 0xd1, 0xdd, 0xeb, 0xc9, - 0x60, 0xa8, 0x35, 0x58, 0x13, 0xe5, 0x58, 0x61, 0xa0, 0x67, 0x61, 0x88, 0xfe, 0xbe, 0x89, 0x57, - 0xc5, 0xd7, 0x9f, 0x10, 0xc8, 0x23, 0x35, 0x27, 0x76, 0x6a, 0x1c, 0x84, 0x25, 0x0e, 0xba, 0x06, - 0x23, 0x4d, 0xb6, 0x73, 0x37, 0xae, 0x05, 0x2e, 0x61, 0x33, 0x5c, 0x5d, 0x7c, 0x86, 0xa2, 0x2f, - 0x25, 0xc5, 0xfb, 0xbb, 0x73, 0x33, 0xbc, 0x6f, 0x82, 0x84, 0x06, 0xc3, 0x7a, 0x7d, 0x64, 0xab, - 0x8d, 0x58, 0x61, 0x94, 0x20, 0x63, 0x13, 0x9e, 0xd5, 0xf6, 0xd4, 0x00, 0xdb, 0x53, 0xa3, 0xd9, - 0xfb, 0x09, 0x5d, 0x80, 0xca, 0x5d, 0xcf, 0x77, 0x67, 0x06, 0x19, 0xad, 0x47, 0xe9, 0xf4, 0x5f, - 0xf1, 0x7c, 0x77, 0x7f, 0x77, 0x6e, 0xca, 0xe8, 0x0e, 0x2d, 0xc4, 0x0c, 0xd5, 0xfe, 0x47, 0x96, - 0x18, 0xc6, 0x15, 0xaf, 0x65, 0x72, 0x94, 0x8b, 0x00, 0x11, 0x69, 0x86, 0x24, 0xd6, 0x06, 0x52, - 0xad, 0x8c, 0x86, 0x82, 0x60, 0x0d, 0x8b, 0xf2, 0x8b, 0x68, 0xd3, 0x09, 0xd9, 0x02, 0x13, 0xc3, - 0xa9, 0xf8, 0x45, 0x43, 0x02, 0x70, 0x82, 0x63, 0xf0, 0x8b, 0x72, 0x2e, 0xbf, 0xf8, 0x3d, 0x0b, - 0x86, 0x16, 0x3d, 0xdf, 0xf5, 0xfc, 0x0d, 0xf4, 0x36, 0x0c, 0x53, 0x76, 0xee, 0x3a, 0xb1, 0x23, - 0x58, 0xc5, 0x47, 0xe5, 0x7a, 0xd3, 0xb9, 0xab, 0x5c, 0x71, 0xd1, 0x3c, 0xc5, 0xa6, 0xeb, 0xee, - 0xc6, 0x9d, 0x77, 0x48, 0x33, 0xbe, 0x46, 0x62, 0x27, 0xf9, 0x9c, 0xa4, 0x0c, 0x2b, 0xaa, 0xe8, - 0x26, 0x0c, 0xc6, 0x4e, 0xb8, 0x41, 0x62, 0xc1, 0x29, 0x72, 0xf6, 0x31, 0xa7, 0x81, 0xe9, 0x2a, - 0x25, 0x7e, 0x93, 0x24, 0x3c, 0x75, 0x8d, 0x11, 0xc1, 0x82, 0x98, 0xdd, 0x84, 0xd1, 0x25, 0xa7, - 0xed, 0xdc, 0xf1, 0x5a, 0x5e, 0xec, 0x91, 0x08, 0xfd, 0x0c, 0x94, 0x1d, 0xd7, 0x65, 0x7b, 0xa6, - 0xba, 0x78, 0x72, 0x6f, 0x77, 0xae, 0xbc, 0xe0, 0xd2, 0x29, 0x03, 0x85, 0xb5, 0x83, 0x29, 0x06, - 0x7a, 0x1a, 0x2a, 0x6e, 0x18, 0xb4, 0x67, 0x4a, 0x0c, 0xf3, 0x14, 0x9d, 0xdd, 0x5a, 0x18, 0xb4, - 0x53, 0xa8, 0x0c, 0xc7, 0xfe, 0x5e, 0x09, 0xd0, 0x12, 0x69, 0x6f, 0xae, 0x34, 0x8c, 0x39, 0x3d, - 0x0b, 0xc3, 0x5b, 0x81, 0xef, 0xc5, 0x41, 0x18, 0x89, 0x06, 0xd9, 0x52, 0xba, 0x26, 0xca, 0xb0, - 0x82, 0xa2, 0x33, 0x50, 0x69, 0x27, 0x1c, 0x61, 0x54, 0x72, 0x13, 0xc6, 0x0b, 0x18, 0x84, 0x62, - 0x74, 0x22, 0x12, 0x8a, 0x2d, 0xa0, 0x30, 0x6e, 0x46, 0x24, 0xc4, 0x0c, 0x92, 0xac, 0x20, 0xba, - 0xb6, 0xc4, 0x02, 0x4f, 0xad, 0x20, 0x0a, 0xc1, 0x1a, 0x16, 0x7a, 0x0b, 0xaa, 0xfc, 0x1f, 0x26, - 0xeb, 0x6c, 0xb5, 0xe7, 0xf2, 0x91, 0xab, 0x41, 0xd3, 0x69, 0xa5, 0x07, 0x7f, 0x8c, 0xad, 0x38, - 0x49, 0x08, 0x27, 0x34, 0x8d, 0x15, 0x37, 0x98, 0xbb, 0xe2, 0xfe, 0xb6, 0x05, 0x68, 0xc9, 0xf3, - 0x5d, 0x12, 0x1e, 0xc3, 0x69, 0xdb, 0xdf, 0x66, 0xf8, 0x13, 0xda, 0xb5, 0x60, 0xab, 0x1d, 0xf8, - 0xc4, 0x8f, 0x97, 0x02, 0xdf, 0xe5, 0x27, 0xf0, 0x27, 0xa0, 0x12, 0xd3, 0xa6, 0x78, 0xb7, 0x9e, - 0x94, 0xd3, 0x42, 0x1b, 0xd8, 0xdf, 0x9d, 0x3b, 0xd5, 0x5d, 0x83, 0x75, 0x81, 0xd5, 0x41, 0x1f, - 0x87, 0xc1, 0x28, 0x76, 0xe2, 0x4e, 0x24, 0x3a, 0xfa, 0x98, 0xec, 0x68, 0x83, 0x95, 0xee, 0xef, - 0xce, 0x4d, 0xa8, 0x6a, 0xbc, 0x08, 0x8b, 0x0a, 0xe8, 0x29, 0x18, 0xda, 0x22, 0x51, 0xe4, 0x6c, - 0x48, 0x9e, 0x38, 0x21, 0xea, 0x0e, 0x5d, 0xe3, 0xc5, 0x58, 0xc2, 0xd1, 0xe3, 0x30, 0x40, 0xc2, - 0x30, 0x08, 0xc5, 0x8a, 0x18, 0x13, 0x88, 0x03, 0xcb, 0xb4, 0x10, 0x73, 0x98, 0xfd, 0x5f, 0x2c, - 0x98, 0x50, 0x7d, 0xe5, 0x6d, 0x1d, 0xc3, 0x96, 0x77, 0x01, 0x9a, 0xf2, 0x03, 0x23, 0xb6, 0xd1, - 0xb4, 0x36, 0xb2, 0x97, 0x5f, 0xf7, 0x80, 0x26, 0x6d, 0xa8, 0xa2, 0x08, 0x6b, 0x74, 0xed, 0x7f, - 0x6b, 0xc1, 0x89, 0xd4, 0xb7, 0x5d, 0xf5, 0xa2, 0x18, 0xbd, 0xd1, 0xf5, 0x7d, 0xf3, 0xc5, 0xbe, - 0x8f, 0xd6, 0x66, 0x5f, 0xa7, 0xd6, 0x8b, 0x2c, 0xd1, 0xbe, 0x0d, 0xc3, 0x80, 0x17, 0x93, 0x2d, - 0xf9, 0x59, 0xcf, 0x16, 0xfc, 0x2c, 0xde, 0xbf, 0x64, 0x96, 0x56, 0x29, 0x0d, 0xcc, 0x49, 0xd9, - 0xff, 0xcb, 0x82, 0xea, 0x52, 0xe0, 0xaf, 0x7b, 0x1b, 0xd7, 0x9c, 0xf6, 0x31, 0xcc, 0x4f, 0x03, - 0x2a, 0x8c, 0x3a, 0xff, 0x84, 0x0b, 0x79, 0x9f, 0x20, 0x3a, 0x36, 0x4f, 0xcf, 0x3d, 0x2e, 0x5f, - 0x28, 0x36, 0x45, 0x8b, 0x30, 0x23, 0x36, 0xfb, 0x22, 0x54, 0x15, 0x02, 0x9a, 0x84, 0xf2, 0x5d, - 0xc2, 0x85, 0xcf, 0x2a, 0xa6, 0x3f, 0xd1, 0x34, 0x0c, 0x6c, 0x3b, 0xad, 0x8e, 0xd8, 0xbc, 0x98, - 0xff, 0xf9, 0x44, 0xe9, 0x25, 0xcb, 0xfe, 0x1e, 0xdb, 0x81, 0xa2, 0x91, 0x65, 0x7f, 0x5b, 0x30, - 0x87, 0xcf, 0x59, 0x30, 0xdd, 0xca, 0x60, 0x4a, 0x62, 0x4c, 0x0e, 0xc3, 0xce, 0x1e, 0x11, 0xdd, - 0x9e, 0xce, 0x82, 0xe2, 0xcc, 0xd6, 0x28, 0xaf, 0x0f, 0xda, 0x74, 0xc1, 0x39, 0x2d, 0xd6, 0x75, - 0x21, 0x36, 0xdc, 0x10, 0x65, 0x58, 0x41, 0xed, 0xbf, 0xb0, 0x60, 0x5a, 0x7d, 0xc7, 0x15, 0xb2, - 0xd3, 0x20, 0x2d, 0xd2, 0x8c, 0x83, 0xf0, 0x83, 0xf2, 0x25, 0x8f, 0xf2, 0x39, 0xe1, 0x3c, 0x69, - 0x44, 0x10, 0x28, 0x5f, 0x21, 0x3b, 0x7c, 0x82, 0xf4, 0x0f, 0x2d, 0x1f, 0xf8, 0xa1, 0xbf, 0x63, - 0xc1, 0x98, 0xfa, 0xd0, 0x63, 0xd8, 0x72, 0x57, 0xcd, 0x2d, 0xf7, 0x33, 0x05, 0xd7, 0x6b, 0x8f, - 0xcd, 0xf6, 0xb7, 0x4a, 0x94, 0x6d, 0x08, 0x9c, 0x7a, 0x18, 0xd0, 0x41, 0xa2, 0x1c, 0xff, 0x03, - 0x32, 0x4b, 0xfd, 0x7d, 0xec, 0x15, 0xb2, 0xb3, 0x16, 0x50, 0x69, 0x22, 0xfb, 0x63, 0x8d, 0x49, - 0xad, 0x1c, 0x38, 0xa9, 0x7f, 0x50, 0x82, 0x93, 0x6a, 0x58, 0x8c, 0x53, 0xfa, 0xa7, 0x72, 0x60, - 0x2e, 0xc0, 0x88, 0x4b, 0xd6, 0x9d, 0x4e, 0x2b, 0x56, 0x0a, 0xc8, 0x00, 0xd7, 0x4c, 0x6b, 0x49, - 0x31, 0xd6, 0x71, 0xfa, 0x18, 0xcb, 0xaf, 0x8c, 0x30, 0x7e, 0x1e, 0x3b, 0x74, 0xd5, 0x53, 0x09, - 0x4f, 0xd3, 0x28, 0x47, 0x75, 0x8d, 0x52, 0x68, 0x8f, 0x8f, 0xc3, 0x80, 0xb7, 0x45, 0xcf, 0xfc, - 0x92, 0x79, 0x94, 0xaf, 0xd2, 0x42, 0xcc, 0x61, 0xe8, 0x09, 0x18, 0x6a, 0x06, 0x5b, 0x5b, 0x8e, - 0xef, 0xce, 0x94, 0x99, 0xcc, 0x39, 0x42, 0xc5, 0x82, 0x25, 0x5e, 0x84, 0x25, 0x0c, 0x3d, 0x02, - 0x15, 0x27, 0xdc, 0x88, 0x66, 0x2a, 0x0c, 0x67, 0x98, 0xb6, 0xb4, 0x10, 0x6e, 0x44, 0x98, 0x95, - 0x52, 0x59, 0xf2, 0x5e, 0x10, 0xde, 0xf5, 0xfc, 0x8d, 0x9a, 0x17, 0x32, 0xc1, 0x50, 0x93, 0x25, - 0x6f, 0x2b, 0x08, 0xd6, 0xb0, 0x50, 0x1d, 0x06, 0xda, 0x41, 0x18, 0x47, 0x33, 0x83, 0x6c, 0xe0, - 0x9f, 0xc9, 0xdd, 0x7e, 0xfc, 0xbb, 0xeb, 0x41, 0x18, 0x27, 0x9f, 0x42, 0xff, 0x45, 0x98, 0x13, - 0x42, 0x4b, 0x50, 0x26, 0xfe, 0xf6, 0xcc, 0x10, 0xa3, 0xf7, 0x91, 0x83, 0xe9, 0x2d, 0xfb, 0xdb, - 0xb7, 0x9c, 0x30, 0xe1, 0x57, 0xcb, 0xfe, 0x36, 0xa6, 0xb5, 0x51, 0x13, 0xaa, 0xd2, 0x7e, 0x15, - 0xcd, 0x0c, 0x17, 0x59, 0x8a, 0x58, 0xa0, 0x63, 0xf2, 0x6e, 0xc7, 0x0b, 0xc9, 0x16, 0xf1, 0xe3, - 0x28, 0x51, 0xac, 0x24, 0x34, 0xc2, 0x09, 0x5d, 0xd4, 0x84, 0x51, 0x2e, 0x7f, 0x5e, 0x0b, 0x3a, - 0x7e, 0x1c, 0xcd, 0x54, 0x59, 0x97, 0x73, 0x8c, 0x1d, 0xb7, 0x92, 0x1a, 0x8b, 0xd3, 0x82, 0xfc, - 0xa8, 0x56, 0x18, 0x61, 0x83, 0x28, 0x7a, 0x03, 0xc6, 0x5a, 0xde, 0x36, 0xf1, 0x49, 0x14, 0xd5, - 0xc3, 0xe0, 0x0e, 0x99, 0x01, 0xf6, 0x35, 0x8f, 0xe7, 0x29, 0xfe, 0xc1, 0x1d, 0xb2, 0x38, 0xb5, - 0xb7, 0x3b, 0x37, 0x76, 0x55, 0xaf, 0x8d, 0x4d, 0x62, 0xe8, 0x2d, 0x18, 0xa7, 0xc2, 0xae, 0x97, - 0x90, 0x1f, 0x29, 0x4e, 0x1e, 0xed, 0xed, 0xce, 0x8d, 0x63, 0xa3, 0x3a, 0x4e, 0x91, 0x43, 0x6b, - 0x50, 0x6d, 0x79, 0xeb, 0xa4, 0xb9, 0xd3, 0x6c, 0x91, 0x99, 0x51, 0x46, 0x3b, 0x67, 0x73, 0x5e, - 0x95, 0xe8, 0x5c, 0xc1, 0x50, 0x7f, 0x71, 0x42, 0x08, 0xdd, 0x82, 0x53, 0x31, 0x09, 0xb7, 0x3c, - 0xdf, 0xa1, 0x9b, 0x4a, 0x48, 0xbf, 0xcc, 0xba, 0x32, 0xc6, 0x56, 0xed, 0x69, 0x31, 0xb0, 0xa7, - 0xd6, 0x32, 0xb1, 0x70, 0x8f, 0xda, 0xe8, 0x06, 0x4c, 0xb0, 0xfd, 0x54, 0xef, 0xb4, 0x5a, 0xf5, - 0xa0, 0xe5, 0x35, 0x77, 0x66, 0xc6, 0x19, 0xc1, 0x27, 0xa4, 0xcd, 0x64, 0xd5, 0x04, 0x53, 0xc5, - 0x30, 0xf9, 0x87, 0xd3, 0xb5, 0x51, 0x0b, 0x26, 0x22, 0xd2, 0xec, 0x84, 0x5e, 0xbc, 0x43, 0xd7, - 0x3e, 0xb9, 0x1f, 0xcf, 0x4c, 0x14, 0x51, 0x74, 0x1b, 0x66, 0x25, 0x6e, 0xb0, 0x4a, 0x15, 0xe2, - 0x34, 0x69, 0xca, 0x2a, 0xa2, 0xd8, 0xf5, 0xfc, 0x99, 0x49, 0xc6, 0x81, 0xd4, 0xfe, 0x6a, 0xd0, - 0x42, 0xcc, 0x61, 0xcc, 0x7e, 0x40, 0x7f, 0xdc, 0xa0, 0x5c, 0x7a, 0x8a, 0x21, 0x26, 0xf6, 0x03, - 0x09, 0xc0, 0x09, 0x0e, 0x15, 0x0d, 0xe2, 0x78, 0x67, 0x06, 0x31, 0x54, 0xb5, 0xd5, 0xd6, 0xd6, - 0x3e, 0x8d, 0x69, 0x39, 0xba, 0x05, 0x43, 0xc4, 0xdf, 0x5e, 0x09, 0x83, 0xad, 0x99, 0x13, 0x45, - 0x78, 0xc0, 0x32, 0x47, 0xe6, 0xe7, 0x47, 0xa2, 0xc2, 0x88, 0x62, 0x2c, 0x89, 0xa1, 0xfb, 0x30, - 0x93, 0x31, 0x4b, 0x7c, 0x52, 0xa6, 0xd9, 0xa4, 0x7c, 0x52, 0xd4, 0x9d, 0x59, 0xeb, 0x81, 0xb7, - 0x7f, 0x00, 0x0c, 0xf7, 0xa4, 0x6e, 0xdf, 0x81, 0x71, 0xc5, 0xa8, 0xd8, 0x7c, 0xa3, 0x39, 0x18, - 0xa0, 0xbc, 0x58, 0x2a, 0xf4, 0x55, 0x3a, 0xa8, 0x94, 0x45, 0x47, 0x98, 0x97, 0xb3, 0x41, 0xf5, - 0xde, 0x23, 0x8b, 0x3b, 0x31, 0xe1, 0x8a, 0x5d, 0x59, 0x1b, 0x54, 0x09, 0xc0, 0x09, 0x8e, 0xfd, - 0x7f, 0xb9, 0x98, 0x94, 0x70, 0xc3, 0x02, 0x27, 0xc1, 0x39, 0x18, 0xde, 0x0c, 0xa2, 0x98, 0x62, - 0xb3, 0x36, 0x06, 0x12, 0xc1, 0xe8, 0xb2, 0x28, 0xc7, 0x0a, 0x03, 0xbd, 0x0c, 0x63, 0x4d, 0xbd, - 0x01, 0x71, 0x8c, 0x9d, 0x14, 0x55, 0xcc, 0xd6, 0xb1, 0x89, 0x8b, 0x5e, 0x82, 0x61, 0x66, 0x18, - 0x6f, 0x06, 0x2d, 0xa1, 0x42, 0xca, 0x53, 0x79, 0xb8, 0x2e, 0xca, 0xf7, 0xb5, 0xdf, 0x58, 0x61, - 0x53, 0x45, 0x9c, 0x76, 0x61, 0xb5, 0x2e, 0x0e, 0x10, 0xa5, 0x88, 0x5f, 0x66, 0xa5, 0x58, 0x40, - 0xed, 0xdf, 0x2a, 0x69, 0xa3, 0x4c, 0x15, 0x20, 0x82, 0x5e, 0x87, 0xa1, 0x7b, 0x8e, 0x17, 0x7b, - 0xfe, 0x86, 0x90, 0x1e, 0x9e, 0x2b, 0x78, 0x9a, 0xb0, 0xea, 0xb7, 0x79, 0x55, 0x7e, 0xf2, 0x89, - 0x3f, 0x58, 0x12, 0xa4, 0xb4, 0xc3, 0x8e, 0xef, 0x53, 0xda, 0xa5, 0xfe, 0x69, 0x63, 0x5e, 0x95, - 0xd3, 0x16, 0x7f, 0xb0, 0x24, 0x88, 0xd6, 0x01, 0xe4, 0x5a, 0x22, 0xae, 0x30, 0x48, 0x7f, 0xac, - 0x1f, 0xf2, 0x6b, 0xaa, 0xf6, 0xe2, 0x38, 0x3d, 0x6b, 0x93, 0xff, 0x58, 0xa3, 0x6c, 0xc7, 0x4c, - 0x08, 0xeb, 0xee, 0x16, 0xfa, 0x0c, 0xdd, 0xd2, 0x4e, 0x18, 0x13, 0x77, 0x21, 0x4e, 0xdb, 0xf4, - 0x0f, 0x16, 0xb1, 0xd7, 0xbc, 0x2d, 0xa2, 0x6f, 0x7f, 0x41, 0x04, 0x27, 0xf4, 0xec, 0x6f, 0x95, - 0x61, 0xa6, 0x57, 0x77, 0xe9, 0x92, 0x24, 0xf7, 0xbd, 0x78, 0x89, 0x8a, 0x49, 0x96, 0xb9, 0x24, - 0x97, 0x45, 0x39, 0x56, 0x18, 0x74, 0x6d, 0x44, 0xde, 0x86, 0x54, 0x96, 0x06, 0x92, 0xb5, 0xd1, - 0x60, 0xa5, 0x58, 0x40, 0x29, 0x5e, 0x48, 0x9c, 0x48, 0xdc, 0x87, 0x68, 0x6b, 0x08, 0xb3, 0x52, - 0x2c, 0xa0, 0xba, 0x41, 0xa4, 0x92, 0x63, 0x10, 0x31, 0x86, 0x68, 0xe0, 0xc1, 0x0e, 0x11, 0x7a, - 0x13, 0x60, 0xdd, 0xf3, 0xbd, 0x68, 0x93, 0x51, 0x1f, 0xec, 0x9b, 0xba, 0x12, 0xb2, 0x56, 0x14, - 0x15, 0xac, 0x51, 0x44, 0x2f, 0xc0, 0x88, 0xda, 0x9e, 0xab, 0xb5, 0x99, 0x21, 0xd3, 0x86, 0x9e, - 0xf0, 0xaa, 0x1a, 0xd6, 0xf1, 0xec, 0x77, 0xd2, 0xeb, 0x45, 0xec, 0x0a, 0x6d, 0x7c, 0xad, 0xa2, - 0xe3, 0x5b, 0x3a, 0x78, 0x7c, 0xed, 0xff, 0x5c, 0x86, 0x09, 0xa3, 0xb1, 0x4e, 0x54, 0x80, 0xa3, - 0xbd, 0x4a, 0x0f, 0x2c, 0x27, 0x26, 0x62, 0x4f, 0x9e, 0xeb, 0x67, 0xd3, 0xe8, 0xc7, 0x1b, 0xdd, - 0x0b, 0x9c, 0x12, 0xda, 0x84, 0x6a, 0xcb, 0x89, 0x98, 0x49, 0x85, 0x88, 0xbd, 0xd8, 0x1f, 0xd9, - 0x44, 0xfd, 0x70, 0xa2, 0x58, 0x3b, 0x3d, 0x78, 0x2b, 0x09, 0x71, 0x7a, 0xda, 0x52, 0x61, 0x47, - 0x5e, 0xc2, 0xa9, 0xee, 0x50, 0x89, 0x68, 0x07, 0x73, 0x18, 0x7a, 0x09, 0x46, 0x43, 0xc2, 0x56, - 0xca, 0x12, 0x95, 0xe7, 0xd8, 0xd2, 0x1b, 0x48, 0x04, 0x3f, 0xac, 0xc1, 0xb0, 0x81, 0x99, 0xc8, - 0xfd, 0x83, 0x07, 0xc8, 0xfd, 0x4f, 0xc1, 0x10, 0xfb, 0xa1, 0x56, 0x85, 0x9a, 0xa1, 0x55, 0x5e, - 0x8c, 0x25, 0x3c, 0xbd, 0x88, 0x86, 0x0b, 0x2e, 0xa2, 0xa7, 0x61, 0xbc, 0xe6, 0x90, 0xad, 0xc0, - 0x5f, 0xf6, 0xdd, 0x76, 0xe0, 0xf9, 0x31, 0x9a, 0x81, 0x0a, 0x3b, 0x4f, 0xf8, 0x7e, 0xaf, 0x50, - 0x0a, 0xb8, 0x42, 0x65, 0x77, 0xfb, 0x4f, 0x4a, 0x30, 0x56, 0x23, 0x2d, 0x12, 0x13, 0xae, 0xf7, - 0x44, 0x68, 0x05, 0xd0, 0x46, 0xe8, 0x34, 0x49, 0x9d, 0x84, 0x5e, 0xe0, 0x36, 0x48, 0x33, 0xf0, - 0xd9, 0xdd, 0x15, 0x3d, 0x20, 0x4f, 0xed, 0xed, 0xce, 0xa1, 0x4b, 0x5d, 0x50, 0x9c, 0x51, 0x03, - 0xb9, 0x30, 0xd6, 0x0e, 0x89, 0x61, 0x37, 0xb4, 0xf2, 0x45, 0x8d, 0xba, 0x5e, 0x85, 0x4b, 0xc3, - 0x46, 0x11, 0x36, 0x89, 0xa2, 0x4f, 0xc1, 0x64, 0x10, 0xb6, 0x37, 0x1d, 0xbf, 0x46, 0xda, 0xc4, - 0x77, 0xa9, 0x0a, 0x20, 0xac, 0x1d, 0xd3, 0x7b, 0xbb, 0x73, 0x93, 0x37, 0x52, 0x30, 0xdc, 0x85, - 0x8d, 0x5e, 0x87, 0xa9, 0x76, 0x18, 0xb4, 0x9d, 0x0d, 0xb6, 0x64, 0x84, 0xb4, 0xc2, 0x79, 0xd3, - 0xb9, 0xbd, 0xdd, 0xb9, 0xa9, 0x7a, 0x1a, 0xb8, 0xbf, 0x3b, 0x77, 0x82, 0x0d, 0x19, 0x2d, 0x49, - 0x80, 0xb8, 0x9b, 0x8c, 0xfd, 0x2e, 0x9c, 0xac, 0x05, 0xf7, 0xfc, 0x7b, 0x4e, 0xe8, 0x2e, 0xd4, - 0x57, 0x35, 0xe3, 0xc4, 0x6b, 0x52, 0xf9, 0xe5, 0x77, 0x82, 0x39, 0x27, 0x9b, 0x46, 0x83, 0xab, - 0x1d, 0x2b, 0x5e, 0x8b, 0xf4, 0x30, 0x87, 0xfc, 0xe3, 0x92, 0xd1, 0x66, 0x82, 0xaf, 0xee, 0x2e, - 0xac, 0x9e, 0x77, 0x17, 0x9f, 0x81, 0xe1, 0x75, 0x8f, 0xb4, 0x5c, 0x4c, 0xd6, 0xc5, 0x6c, 0x5d, - 0x28, 0x72, 0xb9, 0xb3, 0x42, 0xeb, 0x48, 0xeb, 0x18, 0x57, 0xa2, 0x57, 0x04, 0x19, 0xac, 0x08, - 0xa2, 0x0e, 0x4c, 0x4a, 0x3d, 0x4c, 0x42, 0xc5, 0x66, 0x7f, 0xae, 0x98, 0x9a, 0x67, 0x36, 0xc3, - 0xa6, 0x17, 0xa7, 0x08, 0xe2, 0xae, 0x26, 0xa8, 0xfe, 0xbc, 0x45, 0x8f, 0xba, 0x0a, 0x5b, 0xfa, - 0x4c, 0x7f, 0x66, 0xa6, 0x00, 0x56, 0x6a, 0xff, 0xa6, 0x05, 0x0f, 0x75, 0x8d, 0x96, 0xb0, 0x93, - 0x1c, 0xd9, 0x1c, 0xa5, 0x8d, 0x15, 0xa5, 0x7c, 0x63, 0x85, 0xfd, 0x5b, 0x16, 0x4c, 0x2f, 0x6f, - 0xb5, 0xe3, 0x9d, 0x9a, 0x67, 0xde, 0xb9, 0xbc, 0x08, 0x83, 0x5b, 0xc4, 0xf5, 0x3a, 0x5b, 0x62, - 0x5e, 0xe7, 0xe4, 0xc1, 0x70, 0x8d, 0x95, 0xee, 0xef, 0xce, 0x8d, 0x35, 0xe2, 0x20, 0x74, 0x36, - 0x08, 0x2f, 0xc0, 0x02, 0x9d, 0x5d, 0x29, 0x79, 0xef, 0x91, 0xab, 0xde, 0x96, 0x27, 0xaf, 0xf2, - 0x0e, 0x34, 0xf2, 0xcd, 0xcb, 0xa1, 0x9d, 0x7f, 0xb5, 0xe3, 0xf8, 0xb1, 0x17, 0xef, 0x98, 0xf2, - 0x32, 0x23, 0x84, 0x13, 0x9a, 0xf6, 0x8f, 0x2c, 0x98, 0x90, 0x1c, 0x68, 0xc1, 0x75, 0x43, 0x12, - 0x45, 0x68, 0x16, 0x4a, 0x5e, 0x5b, 0xf4, 0x14, 0x44, 0xed, 0xd2, 0x6a, 0x1d, 0x97, 0xbc, 0x36, - 0x7a, 0x1d, 0xaa, 0xfc, 0x2e, 0x30, 0x59, 0x7e, 0x7d, 0xde, 0x2d, 0x32, 0xed, 0x73, 0x4d, 0xd2, - 0xc0, 0x09, 0x39, 0x29, 0x87, 0xb3, 0xb3, 0xad, 0x6c, 0xde, 0x4c, 0x5d, 0x16, 0xe5, 0x58, 0x61, - 0xa0, 0xb3, 0x30, 0xec, 0x07, 0x2e, 0xbf, 0xae, 0xe5, 0x9c, 0x80, 0x2d, 0xea, 0xeb, 0xa2, 0x0c, - 0x2b, 0xa8, 0xfd, 0x45, 0x0b, 0x46, 0xe5, 0x37, 0x16, 0x54, 0x09, 0xe8, 0x36, 0x4c, 0xd4, 0x81, - 0x64, 0x1b, 0x52, 0x91, 0x9e, 0x41, 0x0c, 0x49, 0xbe, 0xdc, 0x8f, 0x24, 0x6f, 0xff, 0x76, 0x09, - 0xc6, 0x65, 0x77, 0x1a, 0x9d, 0x3b, 0x11, 0xa1, 0x82, 0x4e, 0xd5, 0xe1, 0x83, 0x4f, 0xe4, 0x4a, - 0x7e, 0x36, 0x4f, 0xdb, 0x33, 0xe6, 0x2c, 0x99, 0xe5, 0x05, 0x49, 0x07, 0x27, 0x24, 0xd1, 0x36, - 0x4c, 0xf9, 0x41, 0xcc, 0x0e, 0x50, 0x05, 0x2f, 0x76, 0x97, 0x92, 0x6e, 0xe7, 0x61, 0xd1, 0xce, - 0xd4, 0xf5, 0x34, 0x3d, 0xdc, 0xdd, 0x04, 0xba, 0x21, 0xad, 0x58, 0x65, 0xd6, 0xd6, 0xd3, 0xc5, - 0xda, 0xea, 0x6d, 0xc4, 0xb2, 0x7f, 0xdf, 0x82, 0xaa, 0x44, 0x3b, 0x8e, 0x4b, 0xb5, 0xdb, 0x30, - 0x14, 0xb1, 0x29, 0x92, 0xc3, 0x75, 0xae, 0xd8, 0x27, 0xf0, 0x79, 0x4d, 0xa4, 0x06, 0xfe, 0x3f, - 0xc2, 0x92, 0x1a, 0x33, 0xe7, 0xab, 0x0f, 0xf9, 0xc0, 0x99, 0xf3, 0x55, 0xcf, 0x7a, 0xdf, 0x9d, - 0x8d, 0x19, 0xf6, 0x06, 0x2a, 0xfa, 0xb6, 0x43, 0xb2, 0xee, 0xdd, 0x4f, 0x8b, 0xbe, 0x75, 0x56, - 0x8a, 0x05, 0x14, 0xad, 0xc3, 0x68, 0x53, 0x1a, 0xbc, 0x13, 0x16, 0xf2, 0xd1, 0x82, 0xb7, 0x0b, - 0xea, 0xa2, 0x8a, 0xfb, 0x4b, 0x2d, 0x69, 0x94, 0xb0, 0x41, 0x97, 0xf2, 0xa9, 0xe4, 0x2e, 0xbe, - 0x5c, 0xd0, 0x34, 0x14, 0x92, 0x38, 0x69, 0xa1, 0xe7, 0x35, 0xbc, 0xfd, 0x55, 0x0b, 0x06, 0xb9, - 0x85, 0xb4, 0x98, 0x99, 0x59, 0xbb, 0x82, 0x4b, 0xc6, 0xf3, 0x16, 0x2d, 0x14, 0x37, 0x72, 0xe8, - 0x36, 0x54, 0xd9, 0x0f, 0x66, 0xed, 0x29, 0x17, 0x71, 0x1e, 0xe3, 0xed, 0xeb, 0x5d, 0xbd, 0x25, - 0x09, 0xe0, 0x84, 0x96, 0xfd, 0x9d, 0x32, 0x65, 0x7d, 0x09, 0xaa, 0x21, 0x3d, 0x58, 0xc7, 0x21, - 0x3d, 0x94, 0x8e, 0x5e, 0x7a, 0x78, 0x17, 0x26, 0x9a, 0xda, 0x15, 0x60, 0x32, 0xe3, 0x17, 0x0b, - 0x2e, 0x2b, 0xed, 0xde, 0x90, 0x5b, 0x04, 0x97, 0x4c, 0x72, 0x38, 0x4d, 0x1f, 0x11, 0x18, 0xe5, - 0xeb, 0x41, 0xb4, 0x57, 0x61, 0xed, 0x9d, 0x2f, 0xb2, 0xc2, 0xf4, 0xc6, 0xd8, 0x2a, 0x6e, 0x68, - 0x84, 0xb0, 0x41, 0xd6, 0xfe, 0xf5, 0x01, 0x18, 0x58, 0xde, 0x26, 0x7e, 0x7c, 0x0c, 0xac, 0x6e, - 0x0b, 0xc6, 0x3d, 0x7f, 0x3b, 0x68, 0x6d, 0x13, 0x97, 0xc3, 0x0f, 0x77, 0xbc, 0x9f, 0x12, 0x8d, - 0x8c, 0xaf, 0x1a, 0xc4, 0x70, 0x8a, 0xf8, 0x51, 0xd8, 0x22, 0x5e, 0x85, 0x41, 0xbe, 0x32, 0x84, - 0x21, 0x22, 0xe7, 0xc6, 0x80, 0x0d, 0xac, 0xd8, 0x41, 0x89, 0xc5, 0x84, 0x5f, 0x56, 0x08, 0x42, - 0xe8, 0x1d, 0x18, 0x5f, 0xf7, 0xc2, 0x28, 0x5e, 0xf3, 0xb6, 0xa8, 0x0e, 0xb9, 0xd5, 0x3e, 0x84, - 0x15, 0x42, 0x8d, 0xc8, 0x8a, 0x41, 0x09, 0xa7, 0x28, 0xa3, 0x0d, 0x18, 0xa3, 0x4a, 0x70, 0xd2, - 0xd4, 0x50, 0xdf, 0x4d, 0x29, 0x23, 0xe4, 0x55, 0x9d, 0x10, 0x36, 0xe9, 0x52, 0x96, 0xd4, 0x64, - 0x4a, 0xf3, 0x30, 0x93, 0x6e, 0x14, 0x4b, 0xe2, 0xda, 0x32, 0x87, 0x51, 0xce, 0xc6, 0x7c, 0x71, - 0xaa, 0x26, 0x67, 0x4b, 0x3c, 0x6e, 0xec, 0xaf, 0xd3, 0xb3, 0x98, 0x8e, 0xe1, 0x31, 0x1c, 0x5f, - 0x97, 0xcd, 0xe3, 0xeb, 0xf1, 0x02, 0x33, 0xdb, 0xe3, 0xe8, 0x7a, 0x1b, 0x46, 0xb4, 0x89, 0x47, - 0xe7, 0xa1, 0xda, 0x94, 0xee, 0x22, 0x82, 0x8b, 0x2b, 0x51, 0x4a, 0xf9, 0x91, 0xe0, 0x04, 0x87, - 0x8e, 0x0b, 0x15, 0x41, 0xd3, 0xce, 0x65, 0x54, 0x40, 0xc5, 0x0c, 0x62, 0x3f, 0x07, 0xb0, 0x7c, - 0x9f, 0x34, 0x17, 0xb8, 0x12, 0xa9, 0xdd, 0x20, 0x5a, 0xbd, 0x6f, 0x10, 0xed, 0xaf, 0x59, 0x30, - 0xbe, 0xb2, 0x64, 0x28, 0x0d, 0xf3, 0x00, 0x5c, 0x36, 0xbe, 0x7d, 0xfb, 0xba, 0xb4, 0x90, 0x73, - 0x33, 0xa6, 0x2a, 0xc5, 0x1a, 0x06, 0x7a, 0x18, 0xca, 0xad, 0x8e, 0x2f, 0x44, 0xd6, 0xa1, 0xbd, - 0xdd, 0xb9, 0xf2, 0xd5, 0x8e, 0x8f, 0x69, 0x99, 0xe6, 0xc5, 0x55, 0x2e, 0xec, 0xc5, 0x95, 0xef, - 0x02, 0xfd, 0xe5, 0x32, 0x4c, 0xae, 0xb4, 0xc8, 0x7d, 0xa3, 0xd7, 0x4f, 0xc2, 0xa0, 0x1b, 0x7a, - 0xdb, 0x24, 0x4c, 0x0b, 0x02, 0x35, 0x56, 0x8a, 0x05, 0xb4, 0xb0, 0x63, 0xd9, 0x5b, 0xdd, 0x07, - 0xf9, 0xd1, 0x39, 0xd5, 0xe5, 0x7e, 0x33, 0x5a, 0x87, 0x21, 0x7e, 0xe3, 0x1c, 0xcd, 0x0c, 0xb0, - 0xa5, 0xf8, 0xf2, 0xc1, 0x9d, 0x49, 0x8f, 0xcf, 0xbc, 0xb0, 0xe0, 0x70, 0x97, 0x1e, 0xc5, 0xcb, - 0x44, 0x29, 0x96, 0xc4, 0x67, 0x3f, 0x01, 0xa3, 0x3a, 0x66, 0x5f, 0xbe, 0x3d, 0x7f, 0xd5, 0x82, - 0x13, 0x2b, 0xad, 0xa0, 0x79, 0x37, 0xe5, 0xf9, 0xf7, 0x02, 0x8c, 0xd0, 0xcd, 0x14, 0x19, 0x6e, - 0xb1, 0x86, 0xcb, 0xb0, 0x00, 0x61, 0x1d, 0x4f, 0xab, 0x76, 0xf3, 0xe6, 0x6a, 0x2d, 0xcb, 0xd3, - 0x58, 0x80, 0xb0, 0x8e, 0x67, 0xff, 0xa1, 0x05, 0x8f, 0x5e, 0x5a, 0x5a, 0xae, 0x93, 0x30, 0xf2, - 0xa2, 0x98, 0xf8, 0x71, 0x97, 0xb3, 0x33, 0x95, 0x19, 0x5d, 0xad, 0x2b, 0x89, 0xcc, 0x58, 0x63, - 0xbd, 0x10, 0xd0, 0x0f, 0x8a, 0xc7, 0xff, 0x57, 0x2d, 0x38, 0x71, 0xc9, 0x8b, 0x31, 0x69, 0x07, - 0x69, 0x67, 0xe3, 0x90, 0xb4, 0x83, 0xc8, 0x8b, 0x83, 0x70, 0x27, 0xed, 0x6c, 0x8c, 0x15, 0x04, - 0x6b, 0x58, 0xbc, 0xe5, 0x6d, 0x2f, 0xa2, 0x3d, 0x2d, 0x99, 0xaa, 0x2e, 0x16, 0xe5, 0x58, 0x61, - 0xd0, 0x0f, 0x73, 0xbd, 0x90, 0x89, 0x0c, 0x3b, 0x62, 0x07, 0xab, 0x0f, 0xab, 0x49, 0x00, 0x4e, - 0x70, 0xec, 0xbf, 0x6b, 0xc1, 0xc9, 0x4b, 0xad, 0x4e, 0x14, 0x93, 0x70, 0x3d, 0x32, 0x3a, 0xfb, - 0x1c, 0x54, 0x89, 0x14, 0xee, 0x45, 0x5f, 0xd5, 0xa1, 0xa1, 0xa4, 0x7e, 0xee, 0xe9, 0xac, 0xf0, - 0x0a, 0x38, 0xd4, 0xf6, 0xe7, 0xfe, 0xf9, 0xbb, 0x25, 0x18, 0xbb, 0xbc, 0xb6, 0x56, 0xbf, 0x44, - 0x62, 0xc1, 0x25, 0xf3, 0xcd, 0x5e, 0x58, 0xd3, 0xc8, 0x0f, 0x12, 0x7e, 0x3a, 0xb1, 0xd7, 0x9a, - 0xe7, 0xd1, 0x28, 0xf3, 0xab, 0x7e, 0x7c, 0x23, 0x6c, 0xc4, 0xa1, 0xe7, 0x6f, 0x64, 0xea, 0xf0, - 0x92, 0x97, 0x97, 0x7b, 0xf1, 0x72, 0xf4, 0x1c, 0x0c, 0xb2, 0x70, 0x18, 0x29, 0x7c, 0x7c, 0x58, - 0xc9, 0x09, 0xac, 0x74, 0x7f, 0x77, 0xae, 0x7a, 0x13, 0xaf, 0xf2, 0x3f, 0x58, 0xa0, 0xa2, 0xb7, - 0x60, 0x64, 0x33, 0x8e, 0xdb, 0x97, 0x89, 0xe3, 0x92, 0x50, 0xf2, 0x89, 0xb3, 0x07, 0xf3, 0x09, - 0x3a, 0x1c, 0xbc, 0x42, 0xb2, 0xb5, 0x92, 0xb2, 0x08, 0xeb, 0x14, 0xed, 0x06, 0x40, 0x02, 0x7b, - 0x40, 0x3a, 0x88, 0xfd, 0xcb, 0x25, 0x18, 0xba, 0xec, 0xf8, 0x6e, 0x8b, 0x84, 0x68, 0x05, 0x2a, - 0xe4, 0x3e, 0x69, 0x8a, 0x83, 0x3c, 0xa7, 0xeb, 0xc9, 0x61, 0xc7, 0x2d, 0x77, 0xf4, 0x3f, 0x66, - 0xf5, 0x11, 0x86, 0x21, 0xda, 0xef, 0x4b, 0xca, 0x0f, 0xfd, 0x99, 0xfc, 0x51, 0x50, 0x8b, 0x82, - 0x9f, 0x94, 0xa2, 0x08, 0x4b, 0x42, 0xcc, 0x02, 0xd5, 0x6c, 0x37, 0x28, 0x7b, 0x8b, 0x8b, 0x69, - 0x76, 0x6b, 0x4b, 0x75, 0x8e, 0x2e, 0xe8, 0x72, 0x0b, 0x94, 0x2c, 0xc4, 0x09, 0x39, 0x7b, 0x0d, - 0xaa, 0x74, 0xf2, 0x17, 0x5a, 0x9e, 0x73, 0xb0, 0x19, 0xec, 0x19, 0xa8, 0x4a, 0x43, 0x54, 0x24, - 0x9c, 0xda, 0x19, 0x55, 0x69, 0xa7, 0x8a, 0x70, 0x02, 0xb7, 0x5f, 0x82, 0x69, 0x76, 0x8f, 0xec, - 0xc4, 0x9b, 0xc6, 0x5e, 0xcc, 0x5d, 0xf4, 0xf6, 0x37, 0x2a, 0x30, 0xb5, 0xda, 0x58, 0x6a, 0x98, - 0x36, 0xcf, 0x97, 0x60, 0x94, 0x1f, 0xfb, 0x74, 0x29, 0x3b, 0x2d, 0x51, 0x5f, 0xdd, 0x7d, 0xac, - 0x69, 0x30, 0x6c, 0x60, 0xa2, 0x47, 0xa1, 0xec, 0xbd, 0xeb, 0xa7, 0xbd, 0x11, 0x57, 0x5f, 0xbd, - 0x8e, 0x69, 0x39, 0x05, 0x53, 0x09, 0x82, 0xb3, 0x4e, 0x05, 0x56, 0x52, 0xc4, 0x2b, 0x30, 0xee, - 0x45, 0xcd, 0xc8, 0x5b, 0xf5, 0x29, 0x5f, 0x71, 0x9a, 0x72, 0x53, 0x24, 0x22, 0x3f, 0xed, 0xaa, - 0x82, 0xe2, 0x14, 0xb6, 0xc6, 0xc7, 0x07, 0x0a, 0x4b, 0x21, 0xb9, 0x6e, 0xee, 0x54, 0xc0, 0x6a, - 0xb3, 0xaf, 0x8b, 0x98, 0x6f, 0x93, 0x10, 0xb0, 0xf8, 0x07, 0x47, 0x58, 0xc2, 0xd0, 0x25, 0x98, - 0x6a, 0x6e, 0x3a, 0xed, 0x85, 0x4e, 0xbc, 0x59, 0xf3, 0xa2, 0x66, 0xb0, 0x4d, 0xc2, 0x1d, 0x26, - 0x00, 0x0f, 0x27, 0x36, 0x2d, 0x05, 0x58, 0xba, 0xbc, 0x50, 0xa7, 0x98, 0xb8, 0xbb, 0x8e, 0x29, - 0x90, 0xc0, 0x11, 0x08, 0x24, 0x0b, 0x30, 0x21, 0x5b, 0x6d, 0x90, 0x88, 0x1d, 0x11, 0x23, 0xac, - 0x9f, 0x2a, 0xc0, 0x48, 0x14, 0xab, 0x5e, 0xa6, 0xf1, 0xed, 0x77, 0xa0, 0xaa, 0x7c, 0xf1, 0xa4, - 0x0b, 0xaa, 0xd5, 0xc3, 0x05, 0x35, 0x9f, 0xb9, 0x4b, 0xeb, 0x7c, 0x39, 0xd3, 0x3a, 0xff, 0x4f, - 0x2d, 0x48, 0x9c, 0x89, 0x10, 0x86, 0x6a, 0x3b, 0x60, 0x37, 0x79, 0xa1, 0xbc, 0x32, 0x7f, 0x22, - 0x67, 0xcf, 0x73, 0x9e, 0xc3, 0x07, 0xa4, 0x2e, 0xeb, 0xe2, 0x84, 0x0c, 0xba, 0x0a, 0x43, 0xed, - 0x90, 0x34, 0x62, 0x16, 0x3f, 0xd2, 0x07, 0x45, 0xbe, 0x10, 0x78, 0x4d, 0x2c, 0x49, 0xd8, 0xff, - 0xd2, 0x02, 0xe0, 0x66, 0x70, 0xc7, 0xdf, 0x20, 0xc7, 0xa0, 0x58, 0x5f, 0x87, 0x4a, 0xd4, 0x26, - 0xcd, 0x62, 0x77, 0xb1, 0x49, 0xcf, 0x1a, 0x6d, 0xd2, 0x4c, 0xa6, 0x83, 0xfe, 0xc3, 0x8c, 0x8e, - 0xfd, 0x6d, 0x80, 0xf1, 0x04, 0x8d, 0x2a, 0x37, 0xe8, 0x59, 0x23, 0x70, 0xe2, 0xe1, 0x54, 0xe0, - 0x44, 0x95, 0x61, 0x6b, 0xb1, 0x12, 0x31, 0x94, 0xb7, 0x9c, 0xfb, 0x42, 0x97, 0x7a, 0xa1, 0x68, - 0x87, 0x68, 0x4b, 0xf3, 0xd7, 0x9c, 0xfb, 0x5c, 0x74, 0x7d, 0x46, 0x2e, 0xa4, 0x6b, 0xce, 0xfd, - 0x7d, 0x7e, 0xe3, 0xca, 0xb8, 0x13, 0x55, 0xde, 0x3e, 0xfb, 0x67, 0xc9, 0x7f, 0x76, 0x0c, 0xd1, - 0xe6, 0x58, 0xab, 0x9e, 0x2f, 0x4c, 0xc1, 0x7d, 0xb6, 0xea, 0xf9, 0xe9, 0x56, 0x3d, 0xbf, 0x40, - 0xab, 0x1e, 0xf3, 0x30, 0x1e, 0x12, 0x77, 0x34, 0xcc, 0x3d, 0x73, 0xe4, 0xe2, 0xc7, 0xfb, 0x6a, - 0x5a, 0x5c, 0xf6, 0xf0, 0xe6, 0xcf, 0x4b, 0x79, 0x5d, 0x94, 0xe6, 0x76, 0x41, 0x36, 0x8d, 0xfe, - 0x9e, 0x05, 0xe3, 0xe2, 0x37, 0x26, 0xef, 0x76, 0x48, 0x14, 0x0b, 0xb9, 0xe0, 0x53, 0x87, 0xe9, - 0x8d, 0x20, 0xc1, 0x3b, 0xf5, 0x31, 0xc9, 0x7e, 0x4d, 0x60, 0x6e, 0xdf, 0x52, 0xfd, 0x41, 0xdf, - 0xb6, 0x60, 0x7a, 0xcb, 0xb9, 0xcf, 0x5b, 0xe4, 0x65, 0xd8, 0x89, 0xbd, 0x40, 0xb8, 0xa0, 0xae, - 0xf4, 0xbb, 0x4e, 0xba, 0x08, 0xf1, 0xee, 0x4a, 0xef, 0xb2, 0xe9, 0x2c, 0x94, 0xdc, 0x4e, 0x67, - 0xf6, 0x70, 0x76, 0x1d, 0x86, 0xe5, 0xc2, 0xcc, 0xd0, 0x94, 0x6a, 0xba, 0xf8, 0xd3, 0xf7, 0x05, - 0x9a, 0xa6, 0x59, 0xb1, 0x76, 0xc4, 0x52, 0x3c, 0xd2, 0x76, 0xde, 0x81, 0x51, 0x7d, 0xdd, 0x1d, - 0x69, 0x5b, 0xef, 0xc2, 0x89, 0x8c, 0x55, 0x75, 0xa4, 0x4d, 0xde, 0x83, 0x87, 0x7b, 0xae, 0x8f, - 0xa3, 0x6c, 0xd8, 0xfe, 0x5d, 0x4b, 0x67, 0x9d, 0xc7, 0x60, 0xb7, 0xba, 0x66, 0xda, 0xad, 0xce, - 0x16, 0xdd, 0x43, 0x3d, 0x8c, 0x57, 0xeb, 0x7a, 0xf7, 0xe9, 0x91, 0x80, 0xd6, 0x60, 0xb0, 0x45, - 0x4b, 0xe4, 0xb5, 0xe1, 0xb9, 0x7e, 0x76, 0x69, 0x22, 0x81, 0xb1, 0xf2, 0x08, 0x0b, 0x5a, 0xf6, - 0xb7, 0x2d, 0xa8, 0xfc, 0x25, 0x86, 0x75, 0x75, 0x91, 0x16, 0xa9, 0x09, 0xe6, 0xb1, 0x73, 0x6f, - 0xf9, 0x7e, 0x4c, 0xfc, 0x88, 0x89, 0xf1, 0x99, 0x43, 0xf4, 0x7f, 0x4a, 0x30, 0x42, 0x9b, 0x92, - 0x9e, 0x32, 0x2f, 0xc3, 0x58, 0xcb, 0xb9, 0x43, 0x5a, 0xd2, 0xe6, 0x9e, 0x56, 0x7a, 0xaf, 0xea, - 0x40, 0x6c, 0xe2, 0xd2, 0xca, 0xeb, 0xfa, 0x95, 0x84, 0x10, 0x92, 0x54, 0x65, 0xe3, 0xbe, 0x02, - 0x9b, 0xb8, 0x54, 0xeb, 0xba, 0xe7, 0xc4, 0xcd, 0x4d, 0xa1, 0x10, 0xab, 0xee, 0xde, 0xa6, 0x85, - 0x98, 0xc3, 0xa8, 0xb0, 0x27, 0x57, 0xec, 0x2d, 0x12, 0x32, 0x61, 0x8f, 0x0b, 0xd5, 0x4a, 0xd8, - 0xc3, 0x26, 0x18, 0xa7, 0xf1, 0xd1, 0x27, 0x60, 0x9c, 0x0e, 0x4e, 0xd0, 0x89, 0xa5, 0x1f, 0xd0, - 0x00, 0xf3, 0x03, 0x62, 0x6e, 0xe4, 0x6b, 0x06, 0x04, 0xa7, 0x30, 0x51, 0x1d, 0xa6, 0x3d, 0xbf, - 0xd9, 0xea, 0xb8, 0xe4, 0xa6, 0xef, 0xf9, 0x5e, 0xec, 0x39, 0x2d, 0xef, 0x3d, 0xe2, 0x0a, 0xb1, - 0x5b, 0xb9, 0x6c, 0xad, 0x66, 0xe0, 0xe0, 0xcc, 0x9a, 0xf6, 0x5b, 0x70, 0xe2, 0x6a, 0xe0, 0xb8, - 0x8b, 0x4e, 0xcb, 0xf1, 0x9b, 0x24, 0x5c, 0xf5, 0x37, 0x72, 0x7d, 0x0a, 0xf4, 0x7b, 0xff, 0x52, - 0xde, 0xbd, 0xbf, 0x1d, 0x02, 0xd2, 0x1b, 0x10, 0x3e, 0x71, 0x6f, 0xc0, 0x90, 0xc7, 0x9b, 0x12, - 0x1b, 0xe1, 0x42, 0x9e, 0x4c, 0xde, 0xd5, 0x47, 0xcd, 0xc7, 0x8b, 0x17, 0x60, 0x49, 0x92, 0x6a, - 0x70, 0x59, 0x42, 0x7c, 0xbe, 0xea, 0x6d, 0xbf, 0x00, 0x53, 0xac, 0x66, 0x9f, 0x8a, 0xdf, 0x5f, - 0xb3, 0x60, 0xe2, 0x7a, 0x2a, 0x00, 0xfa, 0x49, 0x18, 0x8c, 0x48, 0x98, 0x61, 0x59, 0x6d, 0xb0, - 0x52, 0x2c, 0xa0, 0x0f, 0xdc, 0x5a, 0xf3, 0x6b, 0x25, 0xa8, 0x32, 0xa7, 0xec, 0x36, 0x55, 0xe2, - 0x8e, 0x5e, 0x5e, 0xbe, 0x66, 0xc8, 0xcb, 0x39, 0x16, 0x03, 0xd5, 0xb1, 0x5e, 0xe2, 0x32, 0xba, - 0xa9, 0x02, 0x83, 0x0b, 0x19, 0x0b, 0x12, 0x82, 0x3c, 0x78, 0x74, 0xdc, 0x8c, 0x23, 0x96, 0x41, - 0xc3, 0xec, 0x02, 0x5f, 0xe1, 0x7e, 0xe0, 0x2e, 0xf0, 0x55, 0xcf, 0x7a, 0x70, 0xc9, 0xba, 0xd6, - 0x79, 0x76, 0x8e, 0xfc, 0x1c, 0x73, 0xb5, 0x65, 0x7b, 0x58, 0xc5, 0xd7, 0xcf, 0x09, 0xd7, 0x59, - 0x51, 0xba, 0xcf, 0x18, 0x9e, 0xf8, 0xc7, 0xd3, 0x27, 0x24, 0x55, 0xec, 0xcb, 0x30, 0x91, 0x1a, - 0x3a, 0xf4, 0x02, 0x0c, 0xb4, 0x37, 0x9d, 0x88, 0xa4, 0x9c, 0x9e, 0x06, 0xea, 0xb4, 0x70, 0x7f, - 0x77, 0x6e, 0x5c, 0x55, 0x60, 0x25, 0x98, 0x63, 0xdb, 0x9f, 0x2b, 0x41, 0xe5, 0x7a, 0xe0, 0x1e, - 0xc7, 0x52, 0xbb, 0x6c, 0x2c, 0xb5, 0x27, 0xf3, 0xf3, 0xb5, 0xf4, 0x5c, 0x65, 0xf5, 0xd4, 0x2a, - 0x3b, 0x5b, 0x80, 0xd6, 0xc1, 0x0b, 0x6c, 0x0b, 0x46, 0x58, 0x3e, 0x18, 0xe1, 0x94, 0xf5, 0x9c, - 0xa1, 0xe2, 0xcd, 0xa5, 0x54, 0xbc, 0x09, 0x0d, 0x55, 0x53, 0xf4, 0x9e, 0x82, 0x21, 0xe1, 0x04, - 0x94, 0x76, 0x34, 0x16, 0xb8, 0x58, 0xc2, 0xed, 0x7f, 0x51, 0x06, 0x23, 0xff, 0x0c, 0xfa, 0x7d, - 0x0b, 0xe6, 0x43, 0x1e, 0xb4, 0xe5, 0xd6, 0x3a, 0xa1, 0xe7, 0x6f, 0x34, 0x9a, 0x9b, 0xc4, 0xed, - 0xb4, 0x3c, 0x7f, 0x63, 0x75, 0xc3, 0x0f, 0x54, 0xf1, 0xf2, 0x7d, 0xd2, 0xec, 0x30, 0x9b, 0x7b, - 0xe1, 0xb4, 0x37, 0xea, 0x02, 0xfc, 0xe2, 0xde, 0xee, 0xdc, 0x3c, 0xee, 0xab, 0x15, 0xdc, 0x67, - 0xaf, 0xd0, 0x0f, 0x2d, 0x38, 0xcf, 0x33, 0xb0, 0x14, 0xff, 0x92, 0x42, 0xaa, 0x71, 0x5d, 0x12, - 0x4d, 0xc8, 0xad, 0x91, 0x70, 0x6b, 0xf1, 0x45, 0x31, 0xc8, 0xe7, 0xeb, 0xfd, 0xb5, 0x8a, 0xfb, - 0xed, 0xa6, 0xfd, 0xaf, 0xcb, 0x30, 0x46, 0xc7, 0x33, 0x49, 0xa1, 0xf0, 0x82, 0xb1, 0x4c, 0x1e, - 0x4b, 0x2d, 0x93, 0x29, 0x03, 0xf9, 0xc1, 0x64, 0x4f, 0x88, 0x60, 0xaa, 0xe5, 0x44, 0xf1, 0x65, + 0x02, 0x02, 0x27, 0x80, 0x02, 0x03, 0x71, 0x94, 0xc4, 0xf9, 0x50, 0x04, 0x7d, 0x18, 0x96, 0x13, + 0xc4, 0x91, 0x1c, 0x39, 0x48, 0x1c, 0x01, 0x46, 0x62, 0x05, 0x86, 0xd7, 0xd6, 0x0a, 0xf1, 0x9f, + 0x00, 0xf9, 0x91, 0xfc, 0xdb, 0x7c, 0x20, 0xa8, 0xcf, 0xae, 0xea, 0xe9, 0xd9, 0xee, 0x59, 0xde, + 0xae, 0x29, 0x21, 0xff, 0x66, 0xde, 0x7b, 0xf5, 0xaa, 0xba, 0x3e, 0x5e, 0xbd, 0x7a, 0xf5, 0xde, + 0x2b, 0x38, 0x77, 0xf7, 0xa5, 0x68, 0xde, 0x0b, 0xce, 0xdf, 0xed, 0xdc, 0x21, 0xa1, 0x4f, 0x62, + 0x12, 0x9d, 0x6f, 0xdf, 0xdd, 0x38, 0xef, 0xb4, 0xbd, 0xf3, 0xdb, 0x17, 0xce, 0x6f, 0x10, 0x9f, + 0x84, 0x4e, 0x4c, 0xdc, 0xf9, 0x76, 0x18, 0xc4, 0x01, 0x7a, 0x84, 0x53, 0xcf, 0x27, 0xd4, 0xf3, + 0xed, 0xbb, 0x1b, 0xf3, 0x4e, 0xdb, 0x9b, 0xdf, 0xbe, 0x30, 0xfb, 0xec, 0x86, 0x17, 0x6f, 0x76, + 0xee, 0xcc, 0x37, 0x83, 0xad, 0xf3, 0x1b, 0xc1, 0x46, 0x70, 0x9e, 0x15, 0xba, 0xd3, 0x59, 0x67, + 0xff, 0xd8, 0x1f, 0xf6, 0x8b, 0x33, 0x9b, 0x7d, 0x5e, 0x54, 0xed, 0xb4, 0xbd, 0x2d, 0xa7, 0xb9, + 0xe9, 0xf9, 0x24, 0xdc, 0x51, 0x95, 0x87, 0x24, 0x0a, 0x3a, 0x61, 0x93, 0xa4, 0x9b, 0x70, 0x60, + 0xa9, 0xe8, 0xfc, 0x16, 0x89, 0x9d, 0x8c, 0x86, 0xcf, 0x9e, 0xef, 0x55, 0x2a, 0xec, 0xf8, 0xb1, + 0xb7, 0xd5, 0x5d, 0xcd, 0xc7, 0xf2, 0x0a, 0x44, 0xcd, 0x4d, 0xb2, 0xe5, 0x74, 0x95, 0x7b, 0xae, + 0x57, 0xb9, 0x4e, 0xec, 0xb5, 0xce, 0x7b, 0x7e, 0x1c, 0xc5, 0x61, 0xba, 0x90, 0xfd, 0xc7, 0x16, + 0x9c, 0x59, 0xb8, 0xdd, 0x58, 0x6e, 0x39, 0x51, 0xec, 0x35, 0x17, 0x5b, 0x41, 0xf3, 0x6e, 0x23, + 0x0e, 0x42, 0x72, 0x2b, 0x68, 0x75, 0xb6, 0x48, 0x83, 0x75, 0x04, 0x3a, 0x07, 0xc3, 0xdb, 0xec, + 0xff, 0x6a, 0x6d, 0xc6, 0x3a, 0x63, 0x9d, 0xad, 0x2e, 0x4e, 0x7e, 0x7f, 0x77, 0xee, 0x43, 0x7b, + 0xbb, 0x73, 0xc3, 0xb7, 0x04, 0x1c, 0x2b, 0x0a, 0xf4, 0x24, 0x0c, 0xae, 0x47, 0x6b, 0x3b, 0x6d, + 0x32, 0x53, 0x62, 0xb4, 0xe3, 0x82, 0x76, 0x70, 0xa5, 0x41, 0xa1, 0x58, 0x60, 0xd1, 0x79, 0xa8, + 0xb6, 0x9d, 0x30, 0xf6, 0x62, 0x2f, 0xf0, 0x67, 0xca, 0x67, 0xac, 0xb3, 0x03, 0x8b, 0x53, 0x82, + 0xb4, 0x5a, 0x97, 0x08, 0x9c, 0xd0, 0xd0, 0x66, 0x84, 0xc4, 0x71, 0x6f, 0xf8, 0xad, 0x9d, 0x99, + 0xca, 0x19, 0xeb, 0xec, 0x70, 0xd2, 0x0c, 0x2c, 0xe0, 0x58, 0x51, 0xd8, 0xdf, 0x2e, 0xc1, 0xf0, + 0xc2, 0xfa, 0xba, 0xe7, 0x7b, 0xf1, 0x0e, 0x7a, 0x1b, 0x46, 0xfd, 0xc0, 0x25, 0xf2, 0x3f, 0xfb, + 0x8a, 0x91, 0x8b, 0x4f, 0xcf, 0x1f, 0x34, 0xa9, 0xe6, 0xaf, 0x6b, 0x25, 0x16, 0x27, 0xf7, 0x76, + 0xe7, 0x46, 0x75, 0x08, 0x36, 0x38, 0xa2, 0x37, 0x60, 0xa4, 0x1d, 0xb8, 0xaa, 0x82, 0x12, 0xab, + 0xe0, 0xa9, 0x83, 0x2b, 0xa8, 0x27, 0x05, 0x16, 0x27, 0xf6, 0x76, 0xe7, 0x46, 0x34, 0x00, 0xd6, + 0xd9, 0xa1, 0x16, 0x4c, 0xd0, 0xbf, 0x7e, 0xec, 0xa9, 0x1a, 0xca, 0xac, 0x86, 0x67, 0xf3, 0x6b, + 0xd0, 0x0a, 0x2d, 0x9e, 0xd8, 0xdb, 0x9d, 0x9b, 0x48, 0x01, 0x71, 0x9a, 0xb5, 0xfd, 0x1e, 0x8c, + 0x2f, 0xc4, 0xb1, 0xd3, 0xdc, 0x24, 0x2e, 0x1f, 0x5f, 0xf4, 0x3c, 0x54, 0x7c, 0x67, 0x8b, 0x88, + 0xd1, 0x3f, 0x23, 0xba, 0xbd, 0x72, 0xdd, 0xd9, 0x22, 0xfb, 0xbb, 0x73, 0x93, 0x37, 0x7d, 0xef, + 0xdd, 0x8e, 0x98, 0x33, 0x14, 0x86, 0x19, 0x35, 0xba, 0x08, 0xe0, 0x92, 0x6d, 0xaf, 0x49, 0xea, + 0x4e, 0xbc, 0x29, 0x66, 0x03, 0x12, 0x65, 0xa1, 0xa6, 0x30, 0x58, 0xa3, 0xb2, 0x3f, 0x6b, 0x41, + 0x75, 0x61, 0x3b, 0xf0, 0xdc, 0x7a, 0xe0, 0x46, 0xa8, 0x03, 0x13, 0xed, 0x90, 0xac, 0x93, 0x50, + 0x81, 0x66, 0xac, 0x33, 0xe5, 0xb3, 0x23, 0x17, 0x2f, 0xe6, 0x7c, 0xb7, 0x59, 0x68, 0xd9, 0x8f, + 0xc3, 0x9d, 0xc5, 0x87, 0x44, 0xd5, 0x13, 0x29, 0x2c, 0x4e, 0xd7, 0x61, 0x7f, 0xb7, 0x04, 0x27, + 0x17, 0xde, 0xeb, 0x84, 0xa4, 0xe6, 0x45, 0x77, 0xd3, 0x4b, 0xc1, 0xf5, 0xa2, 0xbb, 0xd7, 0x93, + 0xce, 0x50, 0x73, 0xb0, 0x26, 0xe0, 0x58, 0x51, 0xa0, 0x67, 0x61, 0x88, 0xfe, 0xbe, 0x89, 0x57, + 0xc5, 0xd7, 0x9f, 0x10, 0xc4, 0x23, 0x35, 0x27, 0x76, 0x6a, 0x1c, 0x85, 0x25, 0x0d, 0xba, 0x06, + 0x23, 0x4d, 0xb6, 0x72, 0x37, 0xae, 0x05, 0x2e, 0x61, 0x23, 0x5c, 0x5d, 0x7c, 0x86, 0x92, 0x2f, + 0x25, 0xe0, 0xfd, 0xdd, 0xb9, 0x19, 0xde, 0x36, 0xc1, 0x42, 0xc3, 0x61, 0xbd, 0x3c, 0xb2, 0xd5, + 0x42, 0xac, 0x30, 0x4e, 0x90, 0xb1, 0x08, 0xcf, 0x6a, 0x6b, 0x6a, 0x80, 0xad, 0xa9, 0xd1, 0xec, + 0xf5, 0x84, 0x2e, 0x40, 0xe5, 0xae, 0xe7, 0xbb, 0x33, 0x83, 0x8c, 0xd7, 0xa3, 0x74, 0xf8, 0xaf, + 0x78, 0xbe, 0xbb, 0xbf, 0x3b, 0x37, 0x65, 0x34, 0x87, 0x02, 0x31, 0x23, 0xb5, 0xff, 0x91, 0x25, + 0xba, 0x71, 0xc5, 0x6b, 0x99, 0x12, 0xe5, 0x22, 0x40, 0x44, 0x9a, 0x21, 0x89, 0xb5, 0x8e, 0x54, + 0x33, 0xa3, 0xa1, 0x30, 0x58, 0xa3, 0xa2, 0xf2, 0x22, 0xda, 0x74, 0x42, 0x36, 0xc1, 0x44, 0x77, + 0x2a, 0x79, 0xd1, 0x90, 0x08, 0x9c, 0xd0, 0x18, 0xf2, 0xa2, 0x9c, 0x2b, 0x2f, 0x7e, 0xcf, 0x82, + 0xa1, 0x45, 0xcf, 0x77, 0x3d, 0x7f, 0x03, 0xbd, 0x0d, 0xc3, 0x54, 0x9c, 0xbb, 0x4e, 0xec, 0x08, + 0x51, 0xf1, 0x51, 0x39, 0xdf, 0x74, 0xe9, 0x2a, 0x67, 0x5c, 0x34, 0x4f, 0xa9, 0xe9, 0xbc, 0xbb, + 0x71, 0xe7, 0x1d, 0xd2, 0x8c, 0xaf, 0x91, 0xd8, 0x49, 0x3e, 0x27, 0x81, 0x61, 0xc5, 0x15, 0xdd, + 0x84, 0xc1, 0xd8, 0x09, 0x37, 0x48, 0x2c, 0x24, 0x45, 0xce, 0x3a, 0xe6, 0x3c, 0x30, 0x9d, 0xa5, + 0xc4, 0x6f, 0x92, 0x44, 0xa6, 0xae, 0x31, 0x26, 0x58, 0x30, 0xb3, 0x9b, 0x30, 0xba, 0xe4, 0xb4, + 0x9d, 0x3b, 0x5e, 0xcb, 0x8b, 0x3d, 0x12, 0xa1, 0x9f, 0x81, 0xb2, 0xe3, 0xba, 0x6c, 0xcd, 0x54, + 0x17, 0x4f, 0xee, 0xed, 0xce, 0x95, 0x17, 0x5c, 0x3a, 0x64, 0xa0, 0xa8, 0x76, 0x30, 0xa5, 0x40, + 0x4f, 0x43, 0xc5, 0x0d, 0x83, 0xf6, 0x4c, 0x89, 0x51, 0x9e, 0xa2, 0xa3, 0x5b, 0x0b, 0x83, 0x76, + 0x8a, 0x94, 0xd1, 0xd8, 0xdf, 0x2b, 0x01, 0x5a, 0x22, 0xed, 0xcd, 0x95, 0x86, 0x31, 0xa6, 0x67, + 0x61, 0x78, 0x2b, 0xf0, 0xbd, 0x38, 0x08, 0x23, 0x51, 0x21, 0x9b, 0x4a, 0xd7, 0x04, 0x0c, 0x2b, + 0x2c, 0x3a, 0x03, 0x95, 0x76, 0x22, 0x11, 0x46, 0xa5, 0x34, 0x61, 0xb2, 0x80, 0x61, 0x28, 0x45, + 0x27, 0x22, 0xa1, 0x58, 0x02, 0x8a, 0xe2, 0x66, 0x44, 0x42, 0xcc, 0x30, 0xc9, 0x0c, 0xa2, 0x73, + 0x4b, 0x4c, 0xf0, 0xd4, 0x0c, 0xa2, 0x18, 0xac, 0x51, 0xa1, 0xb7, 0xa0, 0xca, 0xff, 0x61, 0xb2, + 0xce, 0x66, 0x7b, 0xae, 0x1c, 0xb9, 0x1a, 0x34, 0x9d, 0x56, 0xba, 0xf3, 0xc7, 0xd8, 0x8c, 0x93, + 0x8c, 0x70, 0xc2, 0xd3, 0x98, 0x71, 0x83, 0xb9, 0x33, 0xee, 0x6f, 0x5b, 0x80, 0x96, 0x3c, 0xdf, + 0x25, 0xe1, 0x31, 0xec, 0xb6, 0xfd, 0x2d, 0x86, 0x3f, 0xa1, 0x4d, 0x0b, 0xb6, 0xda, 0x81, 0x4f, + 0xfc, 0x78, 0x29, 0xf0, 0x5d, 0xbe, 0x03, 0x7f, 0x02, 0x2a, 0x31, 0xad, 0x8a, 0x37, 0xeb, 0x49, + 0x39, 0x2c, 0xb4, 0x82, 0xfd, 0xdd, 0xb9, 0x53, 0xdd, 0x25, 0x58, 0x13, 0x58, 0x19, 0xf4, 0x71, + 0x18, 0x8c, 0x62, 0x27, 0xee, 0x44, 0xa2, 0xa1, 0x8f, 0xc9, 0x86, 0x36, 0x18, 0x74, 0x7f, 0x77, + 0x6e, 0x42, 0x15, 0xe3, 0x20, 0x2c, 0x0a, 0xa0, 0xa7, 0x60, 0x68, 0x8b, 0x44, 0x91, 0xb3, 0x21, + 0x65, 0xe2, 0x84, 0x28, 0x3b, 0x74, 0x8d, 0x83, 0xb1, 0xc4, 0xa3, 0xc7, 0x61, 0x80, 0x84, 0x61, + 0x10, 0x8a, 0x19, 0x31, 0x26, 0x08, 0x07, 0x96, 0x29, 0x10, 0x73, 0x9c, 0xfd, 0x5f, 0x2c, 0x98, + 0x50, 0x6d, 0xe5, 0x75, 0x1d, 0xc3, 0x92, 0x77, 0x01, 0x9a, 0xf2, 0x03, 0x23, 0xb6, 0xd0, 0xb4, + 0x3a, 0xb2, 0xa7, 0x5f, 0x77, 0x87, 0x26, 0x75, 0x28, 0x50, 0x84, 0x35, 0xbe, 0xf6, 0xbf, 0xb5, + 0xe0, 0x44, 0xea, 0xdb, 0xae, 0x7a, 0x51, 0x8c, 0xde, 0xe8, 0xfa, 0xbe, 0xf9, 0x62, 0xdf, 0x47, + 0x4b, 0xb3, 0xaf, 0x53, 0xf3, 0x45, 0x42, 0xb4, 0x6f, 0xc3, 0x30, 0xe0, 0xc5, 0x64, 0x4b, 0x7e, + 0xd6, 0xb3, 0x05, 0x3f, 0x8b, 0xb7, 0x2f, 0x19, 0xa5, 0x55, 0xca, 0x03, 0x73, 0x56, 0xf6, 0xff, + 0xb2, 0xa0, 0xba, 0x14, 0xf8, 0xeb, 0xde, 0xc6, 0x35, 0xa7, 0x7d, 0x0c, 0xe3, 0xd3, 0x80, 0x0a, + 0xe3, 0xce, 0x3f, 0xe1, 0x42, 0xde, 0x27, 0x88, 0x86, 0xcd, 0xd3, 0x7d, 0x8f, 0xeb, 0x17, 0x4a, + 0x4c, 0x51, 0x10, 0x66, 0xcc, 0x66, 0x5f, 0x84, 0xaa, 0x22, 0x40, 0x93, 0x50, 0xbe, 0x4b, 0xb8, + 0xf2, 0x59, 0xc5, 0xf4, 0x27, 0x9a, 0x86, 0x81, 0x6d, 0xa7, 0xd5, 0x11, 0x8b, 0x17, 0xf3, 0x3f, + 0x9f, 0x28, 0xbd, 0x64, 0xd9, 0xdf, 0x63, 0x2b, 0x50, 0x54, 0xb2, 0xec, 0x6f, 0x0b, 0xe1, 0xf0, + 0x39, 0x0b, 0xa6, 0x5b, 0x19, 0x42, 0x49, 0xf4, 0xc9, 0x61, 0xc4, 0xd9, 0x23, 0xa2, 0xd9, 0xd3, + 0x59, 0x58, 0x9c, 0x59, 0x1b, 0x95, 0xf5, 0x41, 0x9b, 0x4e, 0x38, 0xa7, 0xc5, 0x9a, 0x2e, 0xd4, + 0x86, 0x1b, 0x02, 0x86, 0x15, 0xd6, 0xfe, 0x0b, 0x0b, 0xa6, 0xd5, 0x77, 0x5c, 0x21, 0x3b, 0x0d, + 0xd2, 0x22, 0xcd, 0x38, 0x08, 0x3f, 0x28, 0x5f, 0xf2, 0x28, 0x1f, 0x13, 0x2e, 0x93, 0x46, 0x04, + 0x83, 0xf2, 0x15, 0xb2, 0xc3, 0x07, 0x48, 0xff, 0xd0, 0xf2, 0x81, 0x1f, 0xfa, 0x3b, 0x16, 0x8c, + 0xa9, 0x0f, 0x3d, 0x86, 0x25, 0x77, 0xd5, 0x5c, 0x72, 0x3f, 0x53, 0x70, 0xbe, 0xf6, 0x58, 0x6c, + 0x7f, 0xab, 0x44, 0xc5, 0x86, 0xa0, 0xa9, 0x87, 0x01, 0xed, 0x24, 0x2a, 0xf1, 0x3f, 0x20, 0xa3, + 0xd4, 0xdf, 0xc7, 0x5e, 0x21, 0x3b, 0x6b, 0x01, 0xd5, 0x26, 0xb2, 0x3f, 0xd6, 0x18, 0xd4, 0xca, + 0x81, 0x83, 0xfa, 0x07, 0x25, 0x38, 0xa9, 0xba, 0xc5, 0xd8, 0xa5, 0x7f, 0x2a, 0x3b, 0xe6, 0x02, + 0x8c, 0xb8, 0x64, 0xdd, 0xe9, 0xb4, 0x62, 0x75, 0x00, 0x19, 0xe0, 0x27, 0xd3, 0x5a, 0x02, 0xc6, + 0x3a, 0x4d, 0x1f, 0x7d, 0xf9, 0x95, 0x11, 0x26, 0xcf, 0x63, 0x87, 0xce, 0x7a, 0xaa, 0xe1, 0x69, + 0x27, 0xca, 0x51, 0xfd, 0x44, 0x29, 0x4e, 0x8f, 0x8f, 0xc3, 0x80, 0xb7, 0x45, 0xf7, 0xfc, 0x92, + 0xb9, 0x95, 0xaf, 0x52, 0x20, 0xe6, 0x38, 0xf4, 0x04, 0x0c, 0x35, 0x83, 0xad, 0x2d, 0xc7, 0x77, + 0x67, 0xca, 0x4c, 0xe7, 0x1c, 0xa1, 0x6a, 0xc1, 0x12, 0x07, 0x61, 0x89, 0x43, 0x8f, 0x40, 0xc5, + 0x09, 0x37, 0xa2, 0x99, 0x0a, 0xa3, 0x19, 0xa6, 0x35, 0x2d, 0x84, 0x1b, 0x11, 0x66, 0x50, 0xaa, + 0x4b, 0xde, 0x0b, 0xc2, 0xbb, 0x9e, 0xbf, 0x51, 0xf3, 0x42, 0xa6, 0x18, 0x6a, 0xba, 0xe4, 0x6d, + 0x85, 0xc1, 0x1a, 0x15, 0xaa, 0xc3, 0x40, 0x3b, 0x08, 0xe3, 0x68, 0x66, 0x90, 0x75, 0xfc, 0x33, + 0xb9, 0xcb, 0x8f, 0x7f, 0x77, 0x3d, 0x08, 0xe3, 0xe4, 0x53, 0xe8, 0xbf, 0x08, 0x73, 0x46, 0x68, + 0x09, 0xca, 0xc4, 0xdf, 0x9e, 0x19, 0x62, 0xfc, 0x3e, 0x72, 0x30, 0xbf, 0x65, 0x7f, 0xfb, 0x96, + 0x13, 0x26, 0xf2, 0x6a, 0xd9, 0xdf, 0xc6, 0xb4, 0x34, 0x6a, 0x42, 0x55, 0xda, 0xaf, 0xa2, 0x99, + 0xe1, 0x22, 0x53, 0x11, 0x0b, 0x72, 0x4c, 0xde, 0xed, 0x78, 0x21, 0xd9, 0x22, 0x7e, 0x1c, 0x25, + 0x07, 0x2b, 0x89, 0x8d, 0x70, 0xc2, 0x17, 0x35, 0x61, 0x94, 0xeb, 0x9f, 0xd7, 0x82, 0x8e, 0x1f, + 0x47, 0x33, 0x55, 0xd6, 0xe4, 0x1c, 0x63, 0xc7, 0xad, 0xa4, 0xc4, 0xe2, 0xb4, 0x60, 0x3f, 0xaa, + 0x01, 0x23, 0x6c, 0x30, 0x45, 0x6f, 0xc0, 0x58, 0xcb, 0xdb, 0x26, 0x3e, 0x89, 0xa2, 0x7a, 0x18, + 0xdc, 0x21, 0x33, 0xc0, 0xbe, 0xe6, 0xf1, 0xbc, 0x83, 0x7f, 0x70, 0x87, 0x2c, 0x4e, 0xed, 0xed, + 0xce, 0x8d, 0x5d, 0xd5, 0x4b, 0x63, 0x93, 0x19, 0x7a, 0x0b, 0xc6, 0xa9, 0xb2, 0xeb, 0x25, 0xec, + 0x47, 0x8a, 0xb3, 0x47, 0x7b, 0xbb, 0x73, 0xe3, 0xd8, 0x28, 0x8e, 0x53, 0xec, 0xd0, 0x1a, 0x54, + 0x5b, 0xde, 0x3a, 0x69, 0xee, 0x34, 0x5b, 0x64, 0x66, 0x94, 0xf1, 0xce, 0x59, 0x9c, 0x57, 0x25, + 0x39, 0x3f, 0x60, 0xa8, 0xbf, 0x38, 0x61, 0x84, 0x6e, 0xc1, 0xa9, 0x98, 0x84, 0x5b, 0x9e, 0xef, + 0xd0, 0x45, 0x25, 0xb4, 0x5f, 0x66, 0x5d, 0x19, 0x63, 0xb3, 0xf6, 0xb4, 0xe8, 0xd8, 0x53, 0x6b, + 0x99, 0x54, 0xb8, 0x47, 0x69, 0x74, 0x03, 0x26, 0xd8, 0x7a, 0xaa, 0x77, 0x5a, 0xad, 0x7a, 0xd0, + 0xf2, 0x9a, 0x3b, 0x33, 0xe3, 0x8c, 0xe1, 0x13, 0xd2, 0x66, 0xb2, 0x6a, 0xa2, 0xe9, 0xc1, 0x30, + 0xf9, 0x87, 0xd3, 0xa5, 0x51, 0x0b, 0x26, 0x22, 0xd2, 0xec, 0x84, 0x5e, 0xbc, 0x43, 0xe7, 0x3e, + 0xb9, 0x1f, 0xcf, 0x4c, 0x14, 0x39, 0xe8, 0x36, 0xcc, 0x42, 0xdc, 0x60, 0x95, 0x02, 0xe2, 0x34, + 0x6b, 0x2a, 0x2a, 0xa2, 0xd8, 0xf5, 0xfc, 0x99, 0x49, 0x26, 0x81, 0xd4, 0xfa, 0x6a, 0x50, 0x20, + 0xe6, 0x38, 0x66, 0x3f, 0xa0, 0x3f, 0x6e, 0x50, 0x29, 0x3d, 0xc5, 0x08, 0x13, 0xfb, 0x81, 0x44, + 0xe0, 0x84, 0x86, 0xaa, 0x06, 0x71, 0xbc, 0x33, 0x83, 0x18, 0xa9, 0x5a, 0x6a, 0x6b, 0x6b, 0x9f, + 0xc6, 0x14, 0x8e, 0x6e, 0xc1, 0x10, 0xf1, 0xb7, 0x57, 0xc2, 0x60, 0x6b, 0xe6, 0x44, 0x11, 0x19, + 0xb0, 0xcc, 0x89, 0xf9, 0xfe, 0x91, 0x1c, 0x61, 0x04, 0x18, 0x4b, 0x66, 0xe8, 0x3e, 0xcc, 0x64, + 0x8c, 0x12, 0x1f, 0x94, 0x69, 0x36, 0x28, 0x9f, 0x14, 0x65, 0x67, 0xd6, 0x7a, 0xd0, 0xed, 0x1f, + 0x80, 0xc3, 0x3d, 0xb9, 0xdb, 0x77, 0x60, 0x5c, 0x09, 0x2a, 0x36, 0xde, 0x68, 0x0e, 0x06, 0xa8, + 0x2c, 0x96, 0x07, 0xfa, 0x2a, 0xed, 0x54, 0x2a, 0xa2, 0x23, 0xcc, 0xe1, 0xac, 0x53, 0xbd, 0xf7, + 0xc8, 0xe2, 0x4e, 0x4c, 0xf8, 0xc1, 0xae, 0xac, 0x75, 0xaa, 0x44, 0xe0, 0x84, 0xc6, 0xfe, 0xbf, + 0x5c, 0x4d, 0x4a, 0xa4, 0x61, 0x81, 0x9d, 0xe0, 0x1c, 0x0c, 0x6f, 0x06, 0x51, 0x4c, 0xa9, 0x59, + 0x1d, 0x03, 0x89, 0x62, 0x74, 0x59, 0xc0, 0xb1, 0xa2, 0x40, 0x2f, 0xc3, 0x58, 0x53, 0xaf, 0x40, + 0x6c, 0x63, 0x27, 0x45, 0x11, 0xb3, 0x76, 0x6c, 0xd2, 0xa2, 0x97, 0x60, 0x98, 0x19, 0xc6, 0x9b, + 0x41, 0x4b, 0x1c, 0x21, 0xe5, 0xae, 0x3c, 0x5c, 0x17, 0xf0, 0x7d, 0xed, 0x37, 0x56, 0xd4, 0xf4, + 0x20, 0x4e, 0x9b, 0xb0, 0x5a, 0x17, 0x1b, 0x88, 0x3a, 0x88, 0x5f, 0x66, 0x50, 0x2c, 0xb0, 0xf6, + 0x3f, 0x2f, 0x69, 0xbd, 0x4c, 0x0f, 0x40, 0x04, 0xbd, 0x0e, 0x43, 0xf7, 0x1c, 0x2f, 0xf6, 0xfc, + 0x0d, 0xa1, 0x3d, 0x3c, 0x57, 0x70, 0x37, 0x61, 0xc5, 0x6f, 0xf3, 0xa2, 0x7c, 0xe7, 0x13, 0x7f, + 0xb0, 0x64, 0x48, 0x79, 0x87, 0x1d, 0xdf, 0xa7, 0xbc, 0x4b, 0xfd, 0xf3, 0xc6, 0xbc, 0x28, 0xe7, + 0x2d, 0xfe, 0x60, 0xc9, 0x10, 0xad, 0x03, 0xc8, 0xb9, 0x44, 0x5c, 0x61, 0x90, 0xfe, 0x58, 0x3f, + 0xec, 0xd7, 0x54, 0xe9, 0xc5, 0x71, 0xba, 0xd7, 0x26, 0xff, 0xb1, 0xc6, 0xd9, 0x8e, 0x99, 0x12, + 0xd6, 0xdd, 0x2c, 0xf4, 0x19, 0xba, 0xa4, 0x9d, 0x30, 0x26, 0xee, 0x42, 0x9c, 0xb6, 0xe9, 0x1f, + 0xac, 0x62, 0xaf, 0x79, 0x5b, 0x44, 0x5f, 0xfe, 0x82, 0x09, 0x4e, 0xf8, 0xd9, 0xdf, 0x2a, 0xc3, + 0x4c, 0xaf, 0xe6, 0xd2, 0x29, 0x49, 0xee, 0x7b, 0xf1, 0x12, 0x55, 0x93, 0x2c, 0x73, 0x4a, 0x2e, + 0x0b, 0x38, 0x56, 0x14, 0x74, 0x6e, 0x44, 0xde, 0x86, 0x3c, 0x2c, 0x0d, 0x24, 0x73, 0xa3, 0xc1, + 0xa0, 0x58, 0x60, 0x29, 0x5d, 0x48, 0x9c, 0x48, 0xdc, 0x87, 0x68, 0x73, 0x08, 0x33, 0x28, 0x16, + 0x58, 0xdd, 0x20, 0x52, 0xc9, 0x31, 0x88, 0x18, 0x5d, 0x34, 0xf0, 0x60, 0xbb, 0x08, 0xbd, 0x09, + 0xb0, 0xee, 0xf9, 0x5e, 0xb4, 0xc9, 0xb8, 0x0f, 0xf6, 0xcd, 0x5d, 0x29, 0x59, 0x2b, 0x8a, 0x0b, + 0xd6, 0x38, 0xa2, 0x17, 0x60, 0x44, 0x2d, 0xcf, 0xd5, 0xda, 0xcc, 0x90, 0x69, 0x43, 0x4f, 0x64, + 0x55, 0x0d, 0xeb, 0x74, 0xf6, 0x3b, 0xe9, 0xf9, 0x22, 0x56, 0x85, 0xd6, 0xbf, 0x56, 0xd1, 0xfe, + 0x2d, 0x1d, 0xdc, 0xbf, 0xf6, 0x7f, 0x2e, 0xc3, 0x84, 0x51, 0x59, 0x27, 0x2a, 0x20, 0xd1, 0x5e, + 0xa5, 0x1b, 0x96, 0x13, 0x13, 0xb1, 0x26, 0xcf, 0xf5, 0xb3, 0x68, 0xf4, 0xed, 0x8d, 0xae, 0x05, + 0xce, 0x09, 0x6d, 0x42, 0xb5, 0xe5, 0x44, 0xcc, 0xa4, 0x42, 0xc4, 0x5a, 0xec, 0x8f, 0x6d, 0x72, + 0xfc, 0x70, 0xa2, 0x58, 0xdb, 0x3d, 0x78, 0x2d, 0x09, 0x73, 0xba, 0xdb, 0x52, 0x65, 0x47, 0x5e, + 0xc2, 0xa9, 0xe6, 0x50, 0x8d, 0x68, 0x07, 0x73, 0x1c, 0x7a, 0x09, 0x46, 0x43, 0xc2, 0x66, 0xca, + 0x12, 0xd5, 0xe7, 0xd8, 0xd4, 0x1b, 0x48, 0x14, 0x3f, 0xac, 0xe1, 0xb0, 0x41, 0x99, 0xe8, 0xfd, + 0x83, 0x07, 0xe8, 0xfd, 0x4f, 0xc1, 0x10, 0xfb, 0xa1, 0x66, 0x85, 0x1a, 0xa1, 0x55, 0x0e, 0xc6, + 0x12, 0x9f, 0x9e, 0x44, 0xc3, 0x05, 0x27, 0xd1, 0xd3, 0x30, 0x5e, 0x73, 0xc8, 0x56, 0xe0, 0x2f, + 0xfb, 0x6e, 0x3b, 0xf0, 0xfc, 0x18, 0xcd, 0x40, 0x85, 0xed, 0x27, 0x7c, 0xbd, 0x57, 0x28, 0x07, + 0x5c, 0xa1, 0xba, 0xbb, 0xfd, 0x27, 0x25, 0x18, 0xab, 0x91, 0x16, 0x89, 0x09, 0x3f, 0xf7, 0x44, + 0x68, 0x05, 0xd0, 0x46, 0xe8, 0x34, 0x49, 0x9d, 0x84, 0x5e, 0xe0, 0x36, 0x48, 0x33, 0xf0, 0xd9, + 0xdd, 0x15, 0xdd, 0x20, 0x4f, 0xed, 0xed, 0xce, 0xa1, 0x4b, 0x5d, 0x58, 0x9c, 0x51, 0x02, 0xb9, + 0x30, 0xd6, 0x0e, 0x89, 0x61, 0x37, 0xb4, 0xf2, 0x55, 0x8d, 0xba, 0x5e, 0x84, 0x6b, 0xc3, 0x06, + 0x08, 0x9b, 0x4c, 0xd1, 0xa7, 0x60, 0x32, 0x08, 0xdb, 0x9b, 0x8e, 0x5f, 0x23, 0x6d, 0xe2, 0xbb, + 0xf4, 0x08, 0x20, 0xac, 0x1d, 0xd3, 0x7b, 0xbb, 0x73, 0x93, 0x37, 0x52, 0x38, 0xdc, 0x45, 0x8d, + 0x5e, 0x87, 0xa9, 0x76, 0x18, 0xb4, 0x9d, 0x0d, 0x36, 0x65, 0x84, 0xb6, 0xc2, 0x65, 0xd3, 0xb9, + 0xbd, 0xdd, 0xb9, 0xa9, 0x7a, 0x1a, 0xb9, 0xbf, 0x3b, 0x77, 0x82, 0x75, 0x19, 0x85, 0x24, 0x48, + 0xdc, 0xcd, 0xc6, 0x7e, 0x17, 0x4e, 0xd6, 0x82, 0x7b, 0xfe, 0x3d, 0x27, 0x74, 0x17, 0xea, 0xab, + 0x9a, 0x71, 0xe2, 0x35, 0x79, 0xf8, 0xe5, 0x77, 0x82, 0x39, 0x3b, 0x9b, 0xc6, 0x83, 0x1f, 0x3b, + 0x56, 0xbc, 0x16, 0xe9, 0x61, 0x0e, 0xf9, 0xc7, 0x25, 0xa3, 0xce, 0x84, 0x5e, 0xdd, 0x5d, 0x58, + 0x3d, 0xef, 0x2e, 0x3e, 0x03, 0xc3, 0xeb, 0x1e, 0x69, 0xb9, 0x98, 0xac, 0x8b, 0xd1, 0xba, 0x50, + 0xe4, 0x72, 0x67, 0x85, 0x96, 0x91, 0xd6, 0x31, 0x7e, 0x88, 0x5e, 0x11, 0x6c, 0xb0, 0x62, 0x88, + 0x3a, 0x30, 0x29, 0xcf, 0x61, 0x12, 0x2b, 0x16, 0xfb, 0x73, 0xc5, 0x8e, 0x79, 0x66, 0x35, 0x6c, + 0x78, 0x71, 0x8a, 0x21, 0xee, 0xaa, 0x82, 0x9e, 0x9f, 0xb7, 0xe8, 0x56, 0x57, 0x61, 0x53, 0x9f, + 0x9d, 0x9f, 0x99, 0x29, 0x80, 0x41, 0xed, 0xdf, 0xb4, 0xe0, 0xa1, 0xae, 0xde, 0x12, 0x76, 0x92, + 0x23, 0x1b, 0xa3, 0xb4, 0xb1, 0xa2, 0x94, 0x6f, 0xac, 0xb0, 0x7f, 0xcb, 0x82, 0xe9, 0xe5, 0xad, + 0x76, 0xbc, 0x53, 0xf3, 0xcc, 0x3b, 0x97, 0x17, 0x61, 0x70, 0x8b, 0xb8, 0x5e, 0x67, 0x4b, 0x8c, + 0xeb, 0x9c, 0xdc, 0x18, 0xae, 0x31, 0xe8, 0xfe, 0xee, 0xdc, 0x58, 0x23, 0x0e, 0x42, 0x67, 0x83, + 0x70, 0x00, 0x16, 0xe4, 0x6c, 0x7b, 0xf5, 0xde, 0x23, 0x57, 0xbd, 0x2d, 0x4f, 0x5e, 0xe5, 0x1d, + 0x68, 0xe4, 0x9b, 0x97, 0x5d, 0x3b, 0xff, 0x6a, 0xc7, 0xf1, 0x63, 0x2f, 0xde, 0x11, 0xd7, 0x49, + 0x92, 0x09, 0x4e, 0xf8, 0xd9, 0x3f, 0xb2, 0x60, 0x42, 0x4a, 0x9f, 0x05, 0xd7, 0x0d, 0x49, 0x14, + 0xa1, 0x59, 0x28, 0x79, 0x6d, 0xd1, 0x4a, 0x10, 0xad, 0x2c, 0xad, 0xd6, 0x71, 0xc9, 0x6b, 0xa3, + 0xd7, 0xa1, 0xca, 0xef, 0x01, 0x93, 0xa9, 0xd7, 0xe7, 0xbd, 0x22, 0x6b, 0xcb, 0x9a, 0xe4, 0x81, + 0x13, 0x76, 0x52, 0x07, 0x67, 0xfb, 0x5a, 0xd9, 0xbc, 0x95, 0xba, 0x2c, 0xe0, 0x58, 0x51, 0xa0, + 0xb3, 0x30, 0xec, 0x07, 0x2e, 0xbf, 0xaa, 0xe5, 0x52, 0x80, 0x4d, 0xe8, 0xeb, 0x02, 0x86, 0x15, + 0xd6, 0xfe, 0xa2, 0x05, 0xa3, 0xf2, 0x1b, 0x0b, 0x1e, 0x07, 0xe8, 0x12, 0x4c, 0x8e, 0x02, 0xc9, + 0x12, 0xa4, 0xea, 0x3c, 0xc3, 0x18, 0x5a, 0x7c, 0xb9, 0x1f, 0x2d, 0xde, 0xfe, 0xed, 0x12, 0x8c, + 0xcb, 0xe6, 0x34, 0x3a, 0x77, 0x22, 0x42, 0x95, 0x9c, 0xaa, 0xc3, 0x3b, 0x9f, 0xc8, 0x59, 0xfc, + 0x6c, 0xde, 0x49, 0xcf, 0x18, 0xb3, 0x44, 0x89, 0x5a, 0x90, 0x7c, 0x70, 0xc2, 0x12, 0x6d, 0xc3, + 0x94, 0x1f, 0xc4, 0x6c, 0xf3, 0x54, 0xf8, 0x62, 0xf7, 0x28, 0xe9, 0x7a, 0x1e, 0x16, 0xf5, 0x4c, + 0x5d, 0x4f, 0xf3, 0xc3, 0xdd, 0x55, 0xa0, 0x1b, 0xd2, 0x82, 0x55, 0x66, 0x75, 0x3d, 0x5d, 0xac, + 0xae, 0xde, 0x06, 0x2c, 0xfb, 0xf7, 0x2d, 0xa8, 0x4a, 0xb2, 0xe3, 0xb8, 0x50, 0xbb, 0x0d, 0x43, + 0x11, 0x1b, 0x22, 0xd9, 0x5d, 0xe7, 0x8a, 0x7d, 0x02, 0x1f, 0xd7, 0x44, 0x63, 0xe0, 0xff, 0x23, + 0x2c, 0xb9, 0x31, 0x53, 0xbe, 0xfa, 0x90, 0x0f, 0x9c, 0x29, 0x5f, 0xb5, 0xac, 0xf7, 0xbd, 0xd9, + 0x98, 0x61, 0x6b, 0xa0, 0x6a, 0x6f, 0x3b, 0x24, 0xeb, 0xde, 0xfd, 0xb4, 0xda, 0x5b, 0x67, 0x50, + 0x2c, 0xb0, 0x68, 0x1d, 0x46, 0x9b, 0xd2, 0xd8, 0x9d, 0x88, 0x90, 0x8f, 0x16, 0xbc, 0x59, 0x50, + 0x97, 0x54, 0xdc, 0x57, 0x6a, 0x49, 0xe3, 0x84, 0x0d, 0xbe, 0x54, 0x4e, 0x25, 0xf7, 0xf0, 0xe5, + 0x82, 0x66, 0xa1, 0x90, 0xc4, 0x49, 0x0d, 0x3d, 0xaf, 0xe0, 0xed, 0xaf, 0x5a, 0x30, 0xc8, 0xad, + 0xa3, 0xc5, 0x4c, 0xcc, 0xda, 0xf5, 0x5b, 0xd2, 0x9f, 0xb7, 0x28, 0x50, 0xdc, 0xc6, 0xa1, 0xdb, + 0x50, 0x65, 0x3f, 0x98, 0xa5, 0xa7, 0x5c, 0xc4, 0x71, 0x8c, 0xd7, 0xaf, 0x37, 0xf5, 0x96, 0x64, + 0x80, 0x13, 0x5e, 0xf6, 0x77, 0xca, 0x54, 0xf4, 0x25, 0xa4, 0x86, 0xe6, 0x60, 0x1d, 0x87, 0xe6, + 0x50, 0x3a, 0x7a, 0xcd, 0xe1, 0x5d, 0x98, 0x68, 0x6a, 0xd7, 0x7f, 0xc9, 0x88, 0x5f, 0x2c, 0x38, + 0xad, 0xb4, 0x3b, 0x43, 0x6e, 0x0d, 0x5c, 0x32, 0xd9, 0xe1, 0x34, 0x7f, 0x44, 0x60, 0x94, 0xcf, + 0x07, 0x51, 0x5f, 0x85, 0xd5, 0x77, 0xbe, 0xc8, 0x0c, 0xd3, 0x2b, 0x63, 0xb3, 0xb8, 0xa1, 0x31, + 0xc2, 0x06, 0x5b, 0xfb, 0xd7, 0x07, 0x60, 0x60, 0x79, 0x9b, 0xf8, 0xf1, 0x31, 0x88, 0xba, 0x2d, + 0x18, 0xf7, 0xfc, 0xed, 0xa0, 0xb5, 0x4d, 0x5c, 0x8e, 0x3f, 0xdc, 0xf6, 0x7e, 0x4a, 0x54, 0x32, + 0xbe, 0x6a, 0x30, 0xc3, 0x29, 0xe6, 0x47, 0x61, 0x87, 0x78, 0x15, 0x06, 0xf9, 0xcc, 0x10, 0x46, + 0x88, 0x9c, 0xdb, 0x02, 0xd6, 0xb1, 0x62, 0x05, 0x25, 0xd6, 0x12, 0x7e, 0x51, 0x21, 0x18, 0xa1, + 0x77, 0x60, 0x7c, 0xdd, 0x0b, 0xa3, 0x78, 0xcd, 0xdb, 0xa2, 0xe7, 0xc7, 0xad, 0xf6, 0x21, 0x2c, + 0x10, 0xaa, 0x47, 0x56, 0x0c, 0x4e, 0x38, 0xc5, 0x19, 0x6d, 0xc0, 0x18, 0x3d, 0x00, 0x27, 0x55, + 0x0d, 0xf5, 0x5d, 0x95, 0x32, 0x40, 0x5e, 0xd5, 0x19, 0x61, 0x93, 0x2f, 0x15, 0x49, 0x4d, 0x76, + 0x60, 0x1e, 0x66, 0xda, 0x8d, 0x12, 0x49, 0xfc, 0xa4, 0xcc, 0x71, 0x54, 0xb2, 0x31, 0x3f, 0x9c, + 0xaa, 0x29, 0xd9, 0x12, 0x6f, 0x1b, 0xfb, 0xeb, 0x74, 0x2f, 0xa6, 0x7d, 0x78, 0x0c, 0xdb, 0xd7, + 0x65, 0x73, 0xfb, 0x7a, 0xbc, 0xc0, 0xc8, 0xf6, 0xd8, 0xba, 0xde, 0x86, 0x11, 0x6d, 0xe0, 0xd1, + 0x79, 0xa8, 0x36, 0xa5, 0xab, 0x88, 0x90, 0xe2, 0x4a, 0x95, 0x52, 0x3e, 0x24, 0x38, 0xa1, 0xa1, + 0xfd, 0x42, 0x55, 0xd0, 0xb4, 0x63, 0x19, 0x55, 0x50, 0x31, 0xc3, 0xd8, 0xcf, 0x01, 0x2c, 0xdf, + 0x27, 0xcd, 0x05, 0x7e, 0x80, 0xd4, 0x6e, 0x0f, 0xad, 0xde, 0xb7, 0x87, 0xf6, 0xd7, 0x2c, 0x18, + 0x5f, 0x59, 0x32, 0x0e, 0x0c, 0xf3, 0x00, 0x5c, 0x37, 0xbe, 0x7d, 0xfb, 0xba, 0xb4, 0x8e, 0x73, + 0x13, 0xa6, 0x82, 0x62, 0x8d, 0x02, 0x3d, 0x0c, 0xe5, 0x56, 0xc7, 0x17, 0x2a, 0xeb, 0xd0, 0xde, + 0xee, 0x5c, 0xf9, 0x6a, 0xc7, 0xc7, 0x14, 0xa6, 0x79, 0x70, 0x95, 0x0b, 0x7b, 0x70, 0xe5, 0xbb, + 0x3f, 0x7f, 0xb9, 0x0c, 0x93, 0x2b, 0x2d, 0x72, 0xdf, 0x68, 0xf5, 0x93, 0x30, 0xe8, 0x86, 0xde, + 0x36, 0x09, 0xd3, 0x8a, 0x40, 0x8d, 0x41, 0xb1, 0xc0, 0x16, 0x76, 0x2a, 0x7b, 0xab, 0x7b, 0x23, + 0x3f, 0x3a, 0x87, 0xba, 0xdc, 0x6f, 0x46, 0xeb, 0x30, 0xc4, 0x6f, 0x9b, 0xa3, 0x99, 0x01, 0x36, + 0x15, 0x5f, 0x3e, 0xb8, 0x31, 0xe9, 0xfe, 0x99, 0x17, 0xd6, 0x1b, 0xee, 0xce, 0xa3, 0x64, 0x99, + 0x80, 0x62, 0xc9, 0x7c, 0xf6, 0x13, 0x30, 0xaa, 0x53, 0xf6, 0xe5, 0xd7, 0xf3, 0x57, 0x2d, 0x38, + 0xb1, 0xd2, 0x0a, 0x9a, 0x77, 0x53, 0x5e, 0x7f, 0x2f, 0xc0, 0x08, 0x5d, 0x4c, 0x91, 0xe1, 0x12, + 0x6b, 0xb8, 0x0b, 0x0b, 0x14, 0xd6, 0xe9, 0xb4, 0x62, 0x37, 0x6f, 0xae, 0xd6, 0xb2, 0xbc, 0x8c, + 0x05, 0x0a, 0xeb, 0x74, 0xf6, 0x1f, 0x5a, 0xf0, 0xe8, 0xa5, 0xa5, 0xe5, 0x3a, 0x09, 0x23, 0x2f, + 0x8a, 0x89, 0x1f, 0x77, 0x39, 0x3a, 0x53, 0x9d, 0xd1, 0xd5, 0x9a, 0x92, 0xe8, 0x8c, 0x35, 0xd6, + 0x0a, 0x81, 0xfd, 0xa0, 0x78, 0xfb, 0x7f, 0xd5, 0x82, 0x13, 0x97, 0xbc, 0x18, 0x93, 0x76, 0x90, + 0x76, 0x34, 0x0e, 0x49, 0x3b, 0x88, 0xbc, 0x38, 0x08, 0x77, 0xd2, 0x8e, 0xc6, 0x58, 0x61, 0xb0, + 0x46, 0xc5, 0x6b, 0xde, 0xf6, 0x22, 0xda, 0xd2, 0x92, 0x79, 0xd4, 0xc5, 0x02, 0x8e, 0x15, 0x05, + 0xfd, 0x30, 0xd7, 0x0b, 0x99, 0xca, 0xb0, 0x23, 0x56, 0xb0, 0xfa, 0xb0, 0x9a, 0x44, 0xe0, 0x84, + 0xc6, 0xfe, 0xbb, 0x16, 0x9c, 0xbc, 0xd4, 0xea, 0x44, 0x31, 0x09, 0xd7, 0x23, 0xa3, 0xb1, 0xcf, + 0x41, 0x95, 0x48, 0xe5, 0x5e, 0xb4, 0x55, 0x6d, 0x1a, 0x4a, 0xeb, 0xe7, 0x5e, 0xce, 0x8a, 0xae, + 0x80, 0x33, 0x6d, 0x7f, 0xae, 0x9f, 0xbf, 0x5b, 0x82, 0xb1, 0xcb, 0x6b, 0x6b, 0xf5, 0x4b, 0x24, + 0x16, 0x52, 0x32, 0xdf, 0xe4, 0x85, 0xb5, 0x13, 0xf9, 0x41, 0xca, 0x4f, 0x27, 0xf6, 0x5a, 0xf3, + 0x3c, 0x12, 0x65, 0x7e, 0xd5, 0x8f, 0x6f, 0x84, 0x8d, 0x38, 0xf4, 0xfc, 0x8d, 0xcc, 0x33, 0xbc, + 0x94, 0xe5, 0xe5, 0x5e, 0xb2, 0x1c, 0x3d, 0x07, 0x83, 0x2c, 0x14, 0x46, 0x2a, 0x1f, 0x1f, 0x56, + 0x7a, 0x02, 0x83, 0xee, 0xef, 0xce, 0x55, 0x6f, 0xe2, 0x55, 0xfe, 0x07, 0x0b, 0x52, 0xf4, 0x16, + 0x8c, 0x6c, 0xc6, 0x71, 0xfb, 0x32, 0x71, 0x5c, 0x12, 0x4a, 0x39, 0x71, 0xf6, 0x60, 0x39, 0x41, + 0xbb, 0x83, 0x17, 0x48, 0x96, 0x56, 0x02, 0x8b, 0xb0, 0xce, 0xd1, 0x6e, 0x00, 0x24, 0xb8, 0x07, + 0x74, 0x06, 0xb1, 0x7f, 0xb9, 0x04, 0x43, 0x97, 0x1d, 0xdf, 0x6d, 0x91, 0x10, 0xad, 0x40, 0x85, + 0xdc, 0x27, 0x4d, 0xb1, 0x91, 0xe7, 0x34, 0x3d, 0xd9, 0xec, 0xb8, 0xd5, 0x8e, 0xfe, 0xc7, 0xac, + 0x3c, 0xc2, 0x30, 0x44, 0xdb, 0x7d, 0x49, 0xf9, 0xa0, 0x3f, 0x93, 0xdf, 0x0b, 0x6a, 0x52, 0xf0, + 0x9d, 0x52, 0x80, 0xb0, 0x64, 0xc4, 0x2c, 0x50, 0xcd, 0x76, 0x83, 0x8a, 0xb7, 0xb8, 0xd8, 0xc9, + 0x6e, 0x6d, 0xa9, 0xce, 0xc9, 0x05, 0x5f, 0x6e, 0x81, 0x92, 0x40, 0x9c, 0xb0, 0xb3, 0xd7, 0xa0, + 0x4a, 0x07, 0x7f, 0xa1, 0xe5, 0x39, 0x07, 0x9b, 0xc1, 0x9e, 0x81, 0xaa, 0x34, 0x44, 0x45, 0xc2, + 0xa1, 0x9d, 0x71, 0x95, 0x76, 0xaa, 0x08, 0x27, 0x78, 0xfb, 0x25, 0x98, 0x66, 0x77, 0xc8, 0x4e, + 0xbc, 0x69, 0xac, 0xc5, 0xdc, 0x49, 0x6f, 0x7f, 0xa3, 0x02, 0x53, 0xab, 0x8d, 0xa5, 0x86, 0x69, + 0xef, 0x7c, 0x09, 0x46, 0xf9, 0xb6, 0x4f, 0xa7, 0xb2, 0xd3, 0x12, 0xe5, 0xd5, 0xbd, 0xc7, 0x9a, + 0x86, 0xc3, 0x06, 0x25, 0x7a, 0x14, 0xca, 0xde, 0xbb, 0x7e, 0xda, 0x13, 0x71, 0xf5, 0xd5, 0xeb, + 0x98, 0xc2, 0x29, 0x9a, 0x6a, 0x10, 0x5c, 0x74, 0x2a, 0xb4, 0xd2, 0x22, 0x5e, 0x81, 0x71, 0x2f, + 0x6a, 0x46, 0xde, 0xaa, 0x4f, 0xe5, 0x8a, 0xd3, 0x94, 0x8b, 0x22, 0x51, 0xf9, 0x69, 0x53, 0x15, + 0x16, 0xa7, 0xa8, 0x35, 0x39, 0x3e, 0x50, 0x58, 0x0b, 0xc9, 0x75, 0x71, 0xa7, 0x0a, 0x56, 0x9b, + 0x7d, 0x5d, 0xc4, 0xfc, 0x9a, 0x84, 0x82, 0xc5, 0x3f, 0x38, 0xc2, 0x12, 0x87, 0x2e, 0xc1, 0x54, + 0x73, 0xd3, 0x69, 0x2f, 0x74, 0xe2, 0xcd, 0x9a, 0x17, 0x35, 0x83, 0x6d, 0x12, 0xee, 0x30, 0x05, + 0x78, 0x38, 0xb1, 0x69, 0x29, 0xc4, 0xd2, 0xe5, 0x85, 0x3a, 0xa5, 0xc4, 0xdd, 0x65, 0x4c, 0x85, + 0x04, 0x8e, 0x40, 0x21, 0x59, 0x80, 0x09, 0x59, 0x6b, 0x83, 0x44, 0x6c, 0x8b, 0x18, 0x61, 0xed, + 0x54, 0xc1, 0x45, 0x02, 0xac, 0x5a, 0x99, 0xa6, 0xb7, 0xdf, 0x81, 0xaa, 0xf2, 0xc3, 0x93, 0xee, + 0xa7, 0x56, 0x0f, 0xf7, 0xd3, 0x7c, 0xe1, 0x2e, 0x2d, 0xf3, 0xe5, 0x4c, 0xcb, 0xfc, 0x3f, 0xb1, + 0x20, 0x71, 0x24, 0x42, 0x18, 0xaa, 0xed, 0x80, 0xdd, 0xe2, 0x85, 0xf2, 0xba, 0xfc, 0x89, 0x9c, + 0x35, 0xcf, 0x65, 0x0e, 0xef, 0x90, 0xba, 0x2c, 0x8b, 0x13, 0x36, 0xe8, 0x2a, 0x0c, 0xb5, 0x43, + 0xd2, 0x88, 0x59, 0xec, 0x48, 0x1f, 0x1c, 0xf9, 0x44, 0xe0, 0x25, 0xb1, 0x64, 0x61, 0xff, 0x4b, + 0x0b, 0x80, 0x9b, 0xc1, 0x1d, 0x7f, 0x83, 0x1c, 0xc3, 0xc1, 0xfa, 0x3a, 0x54, 0xa2, 0x36, 0x69, + 0x16, 0xbb, 0x87, 0x4d, 0x5a, 0xd6, 0x68, 0x93, 0x66, 0x32, 0x1c, 0xf4, 0x1f, 0x66, 0x7c, 0xec, + 0x6f, 0x03, 0x8c, 0x27, 0x64, 0xf4, 0x70, 0x83, 0x9e, 0x35, 0x82, 0x26, 0x1e, 0x4e, 0x05, 0x4d, + 0x54, 0x19, 0xb5, 0x16, 0x27, 0x11, 0x43, 0x79, 0xcb, 0xb9, 0x2f, 0xce, 0x52, 0x2f, 0x14, 0x6d, + 0x10, 0xad, 0x69, 0xfe, 0x9a, 0x73, 0x9f, 0xab, 0xae, 0xcf, 0xc8, 0x89, 0x74, 0xcd, 0xb9, 0xbf, + 0xcf, 0x6f, 0x5b, 0x99, 0x74, 0xa2, 0x87, 0xb7, 0xcf, 0xfe, 0x59, 0xf2, 0x9f, 0x6d, 0x43, 0xb4, + 0x3a, 0x56, 0xab, 0xe7, 0x0b, 0x53, 0x70, 0x9f, 0xb5, 0x7a, 0x7e, 0xba, 0x56, 0xcf, 0x2f, 0x50, + 0xab, 0xc7, 0xbc, 0x8b, 0x87, 0xc4, 0xfd, 0x0c, 0x73, 0xcd, 0x1c, 0xb9, 0xf8, 0xf1, 0xbe, 0xaa, + 0x16, 0x17, 0x3d, 0xbc, 0xfa, 0xf3, 0x52, 0x5f, 0x17, 0xd0, 0xdc, 0x26, 0xc8, 0xaa, 0xd1, 0xdf, + 0xb3, 0x60, 0x5c, 0xfc, 0xc6, 0xe4, 0xdd, 0x0e, 0x89, 0x62, 0xa1, 0x17, 0x7c, 0xea, 0x30, 0xad, + 0x11, 0x2c, 0x78, 0xa3, 0x3e, 0x26, 0xc5, 0xaf, 0x89, 0xcc, 0x6d, 0x5b, 0xaa, 0x3d, 0xe8, 0xdb, + 0x16, 0x4c, 0x6f, 0x39, 0xf7, 0x79, 0x8d, 0x1c, 0x86, 0x9d, 0xd8, 0x0b, 0x84, 0xfb, 0xe9, 0x4a, + 0xbf, 0xf3, 0xa4, 0x8b, 0x11, 0x6f, 0xae, 0xf4, 0x2c, 0x9b, 0xce, 0x22, 0xc9, 0x6d, 0x74, 0x66, + 0x0b, 0x67, 0xd7, 0x61, 0x58, 0x4e, 0xcc, 0x8c, 0x93, 0x52, 0x4d, 0x57, 0x7f, 0xfa, 0xbe, 0x3c, + 0xd3, 0x4e, 0x56, 0xac, 0x1e, 0x31, 0x15, 0x8f, 0xb4, 0x9e, 0x77, 0x60, 0x54, 0x9f, 0x77, 0x47, + 0x5a, 0xd7, 0xbb, 0x70, 0x22, 0x63, 0x56, 0x1d, 0x69, 0x95, 0xf7, 0xe0, 0xe1, 0x9e, 0xf3, 0xe3, + 0x28, 0x2b, 0xb6, 0x7f, 0xd7, 0xd2, 0x45, 0xe7, 0x31, 0xd8, 0xad, 0xae, 0x99, 0x76, 0xab, 0xb3, + 0x45, 0xd7, 0x50, 0x0f, 0xe3, 0xd5, 0xba, 0xde, 0x7c, 0xba, 0x25, 0xa0, 0x35, 0x18, 0x6c, 0x51, + 0x88, 0xbc, 0x36, 0x3c, 0xd7, 0xcf, 0x2a, 0x4d, 0x34, 0x30, 0x06, 0x8f, 0xb0, 0xe0, 0x65, 0x7f, + 0xdb, 0x82, 0xca, 0x5f, 0x62, 0x48, 0x57, 0x17, 0x6b, 0x91, 0x96, 0x60, 0x1e, 0x3b, 0xf7, 0x96, + 0xef, 0xc7, 0xc4, 0x8f, 0x98, 0x1a, 0x9f, 0xd9, 0x45, 0xff, 0xa7, 0x04, 0x23, 0xb4, 0x2a, 0xe9, + 0x25, 0xf3, 0x32, 0x8c, 0xb5, 0x9c, 0x3b, 0xa4, 0x25, 0x6d, 0xee, 0xe9, 0x43, 0xef, 0x55, 0x1d, + 0x89, 0x4d, 0x5a, 0x5a, 0x78, 0x5d, 0xbf, 0x92, 0x10, 0x4a, 0x92, 0x2a, 0x6c, 0xdc, 0x57, 0x60, + 0x93, 0x96, 0x9e, 0xba, 0xee, 0x39, 0x71, 0x73, 0x53, 0x1c, 0x88, 0x55, 0x73, 0x6f, 0x53, 0x20, + 0xe6, 0x38, 0xaa, 0xec, 0xc9, 0x19, 0x7b, 0x8b, 0x84, 0x4c, 0xd9, 0xe3, 0x4a, 0xb5, 0x52, 0xf6, + 0xb0, 0x89, 0xc6, 0x69, 0x7a, 0xf4, 0x09, 0x18, 0xa7, 0x9d, 0x13, 0x74, 0x62, 0xe9, 0x03, 0x34, + 0xc0, 0x7c, 0x80, 0x98, 0x0b, 0xf9, 0x9a, 0x81, 0xc1, 0x29, 0x4a, 0x54, 0x87, 0x69, 0xcf, 0x6f, + 0xb6, 0x3a, 0x2e, 0xb9, 0xe9, 0x7b, 0xbe, 0x17, 0x7b, 0x4e, 0xcb, 0x7b, 0x8f, 0xb8, 0x42, 0xed, + 0x56, 0xee, 0x5a, 0xab, 0x19, 0x34, 0x38, 0xb3, 0xa4, 0xfd, 0x16, 0x9c, 0xb8, 0x1a, 0x38, 0xee, + 0xa2, 0xd3, 0x72, 0xfc, 0x26, 0x09, 0x57, 0xfd, 0x8d, 0x5c, 0x9f, 0x02, 0xfd, 0xde, 0xbf, 0x94, + 0x77, 0xef, 0x6f, 0x87, 0x80, 0xf4, 0x0a, 0x84, 0x3f, 0xdc, 0x1b, 0x30, 0xe4, 0xf1, 0xaa, 0xc4, + 0x42, 0xb8, 0x90, 0xa7, 0x93, 0x77, 0xb5, 0x51, 0xf3, 0xef, 0xe2, 0x00, 0x2c, 0x59, 0xd2, 0x13, + 0x5c, 0x96, 0x12, 0x9f, 0x7f, 0xf4, 0xb6, 0x5f, 0x80, 0x29, 0x56, 0xb2, 0xcf, 0x83, 0xdf, 0x5f, + 0xb3, 0x60, 0xe2, 0x7a, 0x2a, 0xf8, 0xf9, 0x49, 0x18, 0x8c, 0x48, 0x98, 0x61, 0x59, 0x6d, 0x30, + 0x28, 0x16, 0xd8, 0x07, 0x6e, 0xad, 0xf9, 0xb5, 0x12, 0x54, 0x99, 0x43, 0x76, 0x9b, 0x1e, 0xe2, + 0x8e, 0x5e, 0x5f, 0xbe, 0x66, 0xe8, 0xcb, 0x39, 0x16, 0x03, 0xd5, 0xb0, 0x5e, 0xea, 0x32, 0xba, + 0xa9, 0x82, 0x82, 0x0b, 0x19, 0x0b, 0x12, 0x86, 0x3c, 0x70, 0x74, 0xdc, 0x8c, 0x21, 0x96, 0x01, + 0xc3, 0xec, 0x02, 0x5f, 0xd1, 0x7e, 0xe0, 0x2e, 0xf0, 0x55, 0xcb, 0x7a, 0x48, 0xc9, 0xba, 0xd6, + 0x78, 0xb6, 0x8f, 0xfc, 0x1c, 0x73, 0xb3, 0x65, 0x6b, 0x58, 0xc5, 0xd6, 0xcf, 0x09, 0xb7, 0x59, + 0x01, 0xdd, 0x67, 0x02, 0x4f, 0xfc, 0xe3, 0xa9, 0x13, 0x92, 0x22, 0xf6, 0x65, 0x98, 0x48, 0x75, + 0x1d, 0x7a, 0x01, 0x06, 0xda, 0x9b, 0x4e, 0x44, 0x52, 0x0e, 0x4f, 0x03, 0x75, 0x0a, 0xdc, 0xdf, + 0x9d, 0x1b, 0x57, 0x05, 0x18, 0x04, 0x73, 0x6a, 0xfb, 0x73, 0x25, 0xa8, 0x5c, 0x0f, 0xdc, 0xe3, + 0x98, 0x6a, 0x97, 0x8d, 0xa9, 0xf6, 0x64, 0x7e, 0xae, 0x96, 0x9e, 0xb3, 0xac, 0x9e, 0x9a, 0x65, + 0x67, 0x0b, 0xf0, 0x3a, 0x78, 0x82, 0x6d, 0xc1, 0x08, 0xcb, 0x05, 0x23, 0x9c, 0xb2, 0x9e, 0x33, + 0x8e, 0x78, 0x73, 0xa9, 0x23, 0xde, 0x84, 0x46, 0xaa, 0x1d, 0xf4, 0x9e, 0x82, 0x21, 0xe1, 0x04, + 0x94, 0x76, 0x32, 0x16, 0xb4, 0x58, 0xe2, 0xed, 0x7f, 0x51, 0x06, 0x23, 0xf7, 0x0c, 0xfa, 0x7d, + 0x0b, 0xe6, 0x43, 0x1e, 0xb0, 0xe5, 0xd6, 0x3a, 0xa1, 0xe7, 0x6f, 0x34, 0x9a, 0x9b, 0xc4, 0xed, + 0xb4, 0x3c, 0x7f, 0x63, 0x75, 0xc3, 0x0f, 0x14, 0x78, 0xf9, 0x3e, 0x69, 0x76, 0x98, 0xcd, 0xbd, + 0x70, 0xca, 0x1b, 0x75, 0x01, 0x7e, 0x71, 0x6f, 0x77, 0x6e, 0x1e, 0xf7, 0x55, 0x0b, 0xee, 0xb3, + 0x55, 0xe8, 0x87, 0x16, 0x9c, 0xe7, 0xd9, 0x57, 0x8a, 0x7f, 0x49, 0xa1, 0xa3, 0x71, 0x5d, 0x32, + 0x4d, 0xd8, 0xad, 0x91, 0x70, 0x6b, 0xf1, 0x45, 0xd1, 0xc9, 0xe7, 0xeb, 0xfd, 0xd5, 0x8a, 0xfb, + 0x6d, 0xa6, 0xfd, 0xaf, 0xcb, 0x30, 0x46, 0xfb, 0x33, 0x49, 0x9f, 0xf0, 0x82, 0x31, 0x4d, 0x1e, + 0x4b, 0x4d, 0x93, 0x29, 0x83, 0xf8, 0xc1, 0x64, 0x4e, 0x88, 0x60, 0xaa, 0xe5, 0x44, 0xf1, 0x65, 0xe2, 0x84, 0xf1, 0x1d, 0xe2, 0xb0, 0x7b, 0xe6, 0xb4, 0x0f, 0x4b, 0x81, 0xab, 0x6b, 0x65, 0x84, - 0xbb, 0x9a, 0x26, 0x86, 0xbb, 0xe9, 0xa3, 0x6d, 0x40, 0xec, 0x4e, 0x3b, 0x74, 0xfc, 0x88, 0x7f, - 0x8b, 0x27, 0x6c, 0xf4, 0xfd, 0xb5, 0x3a, 0x2b, 0x5a, 0x45, 0x57, 0xbb, 0xa8, 0xe1, 0x8c, 0x16, - 0x34, 0xaf, 0x85, 0x81, 0xa2, 0x5e, 0x0b, 0x83, 0x39, 0x1e, 0xfe, 0xbf, 0x62, 0xc1, 0x09, 0x3a, - 0x2d, 0xa6, 0x37, 0x78, 0x84, 0x02, 0x98, 0xa0, 0xcb, 0xae, 0x45, 0x62, 0x59, 0x26, 0xf6, 0x57, - 0x8e, 0x88, 0x6f, 0xd2, 0x49, 0xe4, 0xc8, 0x2b, 0x26, 0x31, 0x9c, 0xa6, 0x6e, 0x7f, 0xcd, 0x02, - 0xe6, 0x3d, 0x79, 0x0c, 0x87, 0xd9, 0x25, 0xf3, 0x30, 0xb3, 0xf3, 0x39, 0x46, 0x8f, 0x73, 0xec, - 0x79, 0x98, 0xa4, 0xd0, 0x7a, 0x18, 0xdc, 0xdf, 0x91, 0x12, 0x7f, 0xbe, 0x74, 0xf5, 0x2b, 0x25, - 0xbe, 0x6d, 0x54, 0xf4, 0x29, 0xfa, 0xbc, 0x05, 0xc3, 0x4d, 0xa7, 0xed, 0x34, 0x79, 0xf6, 0xae, - 0x02, 0x66, 0x22, 0xa3, 0xfe, 0xfc, 0x92, 0xa8, 0xcb, 0x4d, 0x1c, 0x1f, 0x95, 0x9f, 0x2e, 0x8b, - 0x73, 0xcd, 0x1a, 0xaa, 0xf1, 0xd9, 0xbb, 0x30, 0x66, 0x10, 0x3b, 0x52, 0x7d, 0xf8, 0xf3, 0x16, - 0x67, 0xfa, 0x4a, 0x67, 0xb9, 0x07, 0x53, 0xbe, 0xf6, 0x9f, 0xb2, 0x33, 0x29, 0x50, 0xcf, 0x17, - 0x67, 0xeb, 0x8c, 0x0b, 0x6a, 0x9e, 0xa2, 0x29, 0x82, 0xb8, 0xbb, 0x0d, 0xfb, 0x37, 0x2c, 0x78, - 0x48, 0x47, 0xd4, 0xc2, 0x85, 0xf3, 0x0c, 0xd8, 0x35, 0x18, 0x0e, 0xda, 0x24, 0x74, 0x12, 0xfd, - 0xec, 0xac, 0x1c, 0xff, 0x1b, 0xa2, 0x7c, 0x7f, 0x77, 0x6e, 0x5a, 0xa7, 0x2e, 0xcb, 0xb1, 0xaa, - 0x89, 0x6c, 0x18, 0x64, 0xe3, 0x12, 0x89, 0x40, 0x6f, 0x96, 0xcd, 0x8a, 0x5d, 0x90, 0x45, 0x58, - 0x40, 0xec, 0xbf, 0x69, 0xf1, 0xe5, 0xa6, 0x77, 0x1d, 0xfd, 0x02, 0x4c, 0x6e, 0x51, 0x55, 0x6e, - 0xf9, 0x7e, 0x3b, 0xe4, 0xe6, 0x77, 0x39, 0x62, 0x2f, 0x14, 0x1f, 0x31, 0xed, 0x73, 0x17, 0x67, - 0x44, 0xef, 0x27, 0xaf, 0xa5, 0xc8, 0xe2, 0xae, 0x86, 0xec, 0x7f, 0x50, 0xe2, 0x7b, 0x96, 0xc9, - 0x70, 0x4f, 0xc1, 0x50, 0x3b, 0x70, 0x97, 0x56, 0x6b, 0x58, 0x8c, 0x95, 0x62, 0x3a, 0x75, 0x5e, - 0x8c, 0x25, 0x1c, 0x5d, 0x04, 0x20, 0xf7, 0x63, 0x12, 0xfa, 0x4e, 0x4b, 0x5d, 0xe9, 0x2b, 0x51, - 0x69, 0x59, 0x41, 0xb0, 0x86, 0x45, 0xeb, 0xb4, 0xc3, 0x60, 0xdb, 0x73, 0x59, 0x9c, 0x4b, 0xd9, - 0xac, 0x53, 0x57, 0x10, 0xac, 0x61, 0x51, 0x05, 0xba, 0xe3, 0x47, 0xfc, 0x18, 0x73, 0xee, 0x88, - 0x4c, 0x4a, 0xc3, 0x89, 0x02, 0x7d, 0x53, 0x07, 0x62, 0x13, 0x17, 0x5d, 0x81, 0xc1, 0xd8, 0x61, - 0x17, 0xd5, 0x03, 0x45, 0xbc, 0x7e, 0xd6, 0x28, 0xae, 0x9e, 0xba, 0x8a, 0x56, 0xc5, 0x82, 0x84, - 0xfd, 0x9f, 0xaa, 0x00, 0x89, 0xd4, 0x85, 0x3e, 0xd7, 0xbd, 0xe1, 0x3f, 0x56, 0x54, 0x64, 0x7b, - 0x70, 0xbb, 0x1d, 0x7d, 0xc9, 0x82, 0x11, 0xa7, 0xd5, 0x0a, 0x9a, 0x4e, 0xcc, 0x86, 0xa7, 0x54, - 0x94, 0xf5, 0x88, 0x9e, 0x2c, 0x24, 0x75, 0x79, 0x67, 0x9e, 0x93, 0x97, 0xc7, 0x1a, 0x24, 0xb7, - 0x3f, 0x7a, 0x17, 0xd0, 0x47, 0xa5, 0xd4, 0xce, 0x67, 0x78, 0x36, 0x2d, 0xb5, 0x57, 0x19, 0xc3, - 0xd5, 0x04, 0x76, 0xf4, 0x96, 0x91, 0x79, 0xa8, 0x52, 0x24, 0x58, 0xd9, 0x90, 0x43, 0xf2, 0x92, - 0x0e, 0xa1, 0xd7, 0x75, 0xf7, 0xf8, 0x81, 0x22, 0xd9, 0x00, 0x34, 0x71, 0x38, 0xc7, 0x35, 0x3e, - 0x86, 0x09, 0xd7, 0x3c, 0x79, 0x85, 0x8b, 0xdf, 0x85, 0xfc, 0x16, 0x52, 0x47, 0x76, 0x72, 0xd6, - 0xa6, 0x00, 0x38, 0xdd, 0x04, 0x7a, 0x9d, 0x07, 0x2f, 0xac, 0xfa, 0xeb, 0x81, 0x70, 0xf3, 0x3b, - 0x57, 0x60, 0xce, 0x77, 0xa2, 0x98, 0x6c, 0xd1, 0x3a, 0xc9, 0xe1, 0x7a, 0x5d, 0x50, 0xc1, 0x8a, - 0x1e, 0x5a, 0x83, 0x41, 0x16, 0x9b, 0x16, 0xcd, 0x0c, 0x17, 0x31, 0x09, 0x9a, 0x21, 0xd9, 0xc9, - 0xfe, 0x61, 0x7f, 0x23, 0x2c, 0x68, 0xa1, 0xcb, 0x32, 0x29, 0x43, 0xb4, 0xea, 0xdf, 0x8c, 0x08, - 0x4b, 0xca, 0x50, 0x5d, 0xfc, 0x48, 0x92, 0x65, 0x81, 0x97, 0x67, 0xa6, 0x6b, 0x34, 0x6a, 0x52, - 0xc1, 0x46, 0xfc, 0x97, 0x59, 0x20, 0x67, 0xa0, 0x48, 0x47, 0xcd, 0x9c, 0x91, 0xc9, 0x60, 0xdf, - 0x32, 0x89, 0xe1, 0x34, 0xf5, 0x63, 0x3d, 0x52, 0x67, 0x7d, 0x98, 0x4c, 0x6f, 0xca, 0x23, 0x3d, - 0xc2, 0x7f, 0x5c, 0x81, 0x71, 0x73, 0x71, 0xa0, 0xf3, 0x50, 0x15, 0x44, 0x54, 0x8a, 0x37, 0xb5, - 0x07, 0xae, 0x49, 0x00, 0x4e, 0x70, 0x58, 0xb2, 0x3b, 0x56, 0x5d, 0x73, 0xf0, 0x4a, 0x92, 0xdd, - 0x29, 0x08, 0xd6, 0xb0, 0xa8, 0x24, 0x7c, 0x27, 0x08, 0x62, 0x75, 0x12, 0xa8, 0x75, 0xb3, 0xc8, - 0x4a, 0xb1, 0x80, 0xd2, 0x13, 0xe0, 0x2e, 0x9d, 0xcc, 0x96, 0x69, 0xde, 0x54, 0x27, 0xc0, 0x15, - 0x1d, 0x88, 0x4d, 0x5c, 0x7a, 0xa2, 0x05, 0x11, 0x5b, 0x88, 0x42, 0xde, 0x4e, 0x1c, 0xe6, 0x1a, - 0x3c, 0x5e, 0x53, 0xc2, 0xd1, 0xa7, 0xe1, 0x21, 0x15, 0x5e, 0x89, 0xb9, 0xb9, 0x58, 0xb6, 0x38, - 0x68, 0xa8, 0xcc, 0x0f, 0x2d, 0x65, 0xa3, 0xe1, 0x5e, 0xf5, 0xd1, 0x2b, 0x30, 0x2e, 0x64, 0x65, - 0x49, 0x71, 0xc8, 0xf4, 0x7b, 0xb8, 0x62, 0x40, 0x71, 0x0a, 0x1b, 0xd5, 0x60, 0x92, 0x96, 0x30, - 0x21, 0x55, 0x52, 0xe0, 0x61, 0xa2, 0xea, 0xa8, 0xbf, 0x92, 0x82, 0xe3, 0xae, 0x1a, 0x68, 0x01, - 0x26, 0xb8, 0xb0, 0x42, 0x15, 0x43, 0x36, 0x0f, 0xc2, 0x37, 0x57, 0x6d, 0x84, 0x1b, 0x26, 0x18, - 0xa7, 0xf1, 0xd1, 0x4b, 0x30, 0xea, 0x84, 0xcd, 0x4d, 0x2f, 0x26, 0xcd, 0xb8, 0x13, 0xf2, 0x94, - 0x27, 0x9a, 0xe3, 0xc8, 0x82, 0x06, 0xc3, 0x06, 0xa6, 0xfd, 0x1e, 0x9c, 0xc8, 0x08, 0x04, 0xa0, - 0x0b, 0xc7, 0x69, 0x7b, 0xf2, 0x9b, 0x52, 0xae, 0x6f, 0x0b, 0xf5, 0x55, 0xf9, 0x35, 0x1a, 0x16, - 0x5d, 0x9d, 0xcc, 0x4e, 0xae, 0x25, 0x6d, 0x55, 0xab, 0x73, 0x45, 0x02, 0x70, 0x82, 0x63, 0xff, - 0x29, 0x80, 0x66, 0xbd, 0x29, 0xe0, 0xee, 0xf4, 0x12, 0x8c, 0xca, 0x3c, 0xc4, 0x5a, 0x32, 0x4f, - 0xf5, 0x99, 0x97, 0x34, 0x18, 0x36, 0x30, 0x69, 0xdf, 0x7c, 0x69, 0x93, 0x4a, 0x3b, 0xda, 0x29, - 0x63, 0x15, 0x4e, 0x70, 0xd0, 0x39, 0x18, 0x8e, 0x48, 0x6b, 0xfd, 0xaa, 0xe7, 0xdf, 0x15, 0x0b, - 0x5b, 0x71, 0xe6, 0x86, 0x28, 0xc7, 0x0a, 0x03, 0x2d, 0x42, 0xb9, 0xe3, 0xb9, 0x62, 0x29, 0x4b, - 0xb1, 0xa1, 0x7c, 0x73, 0xb5, 0xb6, 0xbf, 0x3b, 0xf7, 0x58, 0xaf, 0xf4, 0xca, 0x54, 0x3f, 0x8f, - 0xe6, 0xe9, 0xf6, 0xa3, 0x95, 0xb3, 0x2e, 0x0c, 0x06, 0xfb, 0xbc, 0x30, 0xb8, 0x08, 0x20, 0xbe, - 0x5a, 0xae, 0xe5, 0x72, 0x32, 0x6b, 0x97, 0x14, 0x04, 0x6b, 0x58, 0x54, 0xcb, 0x6f, 0x86, 0xc4, - 0x91, 0x8a, 0x30, 0x77, 0x50, 0x1f, 0x3e, 0xbc, 0x96, 0xbf, 0x94, 0x26, 0x86, 0xbb, 0xe9, 0xa3, - 0x00, 0xa6, 0x5c, 0x11, 0xc3, 0x9b, 0x34, 0x5a, 0xed, 0xdf, 0x2b, 0x9e, 0xf9, 0xf6, 0xa4, 0x09, - 0xe1, 0x6e, 0xda, 0xe8, 0x4d, 0x98, 0x95, 0x85, 0xdd, 0x01, 0xd4, 0x6c, 0xbb, 0x94, 0x17, 0x4f, - 0xef, 0xed, 0xce, 0xcd, 0xd6, 0x7a, 0x62, 0xe1, 0x03, 0x28, 0xa0, 0x37, 0x60, 0x90, 0x5d, 0x30, - 0x45, 0x33, 0x23, 0xec, 0xc4, 0x7b, 0xbe, 0x48, 0x6c, 0x05, 0x5d, 0xf5, 0xf3, 0xec, 0x9a, 0x4a, - 0x78, 0x0d, 0x27, 0xb7, 0x76, 0xac, 0x10, 0x0b, 0x9a, 0xa8, 0x0d, 0x23, 0x8e, 0xef, 0x07, 0xb1, - 0xc3, 0x05, 0xb1, 0xd1, 0x22, 0xb2, 0xa4, 0xd6, 0xc4, 0x42, 0x52, 0x97, 0xb7, 0xa3, 0x1c, 0x11, - 0x35, 0x08, 0xd6, 0x9b, 0x40, 0xf7, 0x60, 0x22, 0xb8, 0x47, 0x19, 0xa6, 0xbc, 0x11, 0x89, 0x66, - 0xc6, 0xcc, 0x0f, 0xcb, 0x31, 0xd4, 0x1a, 0x95, 0x35, 0x4e, 0x66, 0x12, 0xc5, 0xe9, 0x56, 0xd0, - 0xbc, 0x61, 0xae, 0x1e, 0x4f, 0x7c, 0xe3, 0x13, 0x73, 0xb5, 0x6e, 0x9d, 0x66, 0x41, 0xfa, 0xdc, - 0x1f, 0x96, 0x71, 0x84, 0x89, 0x54, 0x90, 0x7e, 0x02, 0xc2, 0x3a, 0x1e, 0xda, 0x84, 0xd1, 0xe4, - 0x6e, 0x2b, 0x8c, 0x58, 0xfe, 0x1f, 0xcd, 0xdd, 0xeb, 0xe0, 0x8f, 0x5b, 0xd5, 0x6a, 0xf2, 0x48, - 0x1f, 0xbd, 0x04, 0x1b, 0x94, 0x67, 0x3f, 0x0e, 0x23, 0xda, 0x14, 0xf7, 0xe3, 0xee, 0x3d, 0xfb, - 0x0a, 0x4c, 0xa6, 0xa7, 0xae, 0x2f, 0x77, 0xf1, 0xff, 0x51, 0x82, 0x89, 0x8c, 0x8b, 0x2d, 0x96, - 0x8d, 0x39, 0xc5, 0x64, 0x93, 0xe4, 0xcb, 0x26, 0xab, 0x2c, 0x15, 0x60, 0x95, 0x92, 0x6f, 0x97, - 0x7b, 0xf2, 0x6d, 0xc1, 0x1e, 0x2b, 0xef, 0x87, 0x3d, 0x9a, 0x27, 0xd2, 0x40, 0xa1, 0x13, 0xe9, - 0x01, 0xb0, 0x54, 0xe3, 0x50, 0x1b, 0x2a, 0x70, 0xa8, 0x7d, 0xb5, 0x04, 0x93, 0x89, 0x6b, 0xbc, - 0x48, 0x83, 0x7e, 0xf4, 0x17, 0x1e, 0x6b, 0xc6, 0x85, 0x47, 0x5e, 0x96, 0xf3, 0x54, 0xff, 0x7a, - 0x5e, 0x7e, 0xbc, 0x91, 0xba, 0xfc, 0x78, 0xbe, 0x4f, 0xba, 0x07, 0x5f, 0x84, 0x7c, 0xab, 0x04, - 0x27, 0xd3, 0x55, 0x96, 0x5a, 0x8e, 0xb7, 0x75, 0x0c, 0xe3, 0xf5, 0x69, 0x63, 0xbc, 0x5e, 0xec, - 0xef, 0xbb, 0x58, 0x27, 0x7b, 0x0e, 0x9a, 0x93, 0x1a, 0xb4, 0x8f, 0x1f, 0x86, 0xf8, 0xc1, 0x23, - 0xf7, 0x47, 0x16, 0x3c, 0x9c, 0x59, 0xef, 0x18, 0x4c, 0xbc, 0xaf, 0x99, 0x26, 0xde, 0xe7, 0x0e, + 0xbb, 0x9a, 0x66, 0x86, 0xbb, 0xf9, 0xa3, 0x6d, 0x40, 0xec, 0x4e, 0x3b, 0x74, 0xfc, 0x88, 0x7f, + 0x8b, 0x27, 0x6c, 0xf4, 0xfd, 0xd5, 0x3a, 0x2b, 0x6a, 0x45, 0x57, 0xbb, 0xb8, 0xe1, 0x8c, 0x1a, + 0x34, 0xaf, 0x85, 0x81, 0xa2, 0x5e, 0x0b, 0x83, 0x39, 0xde, 0xfd, 0xbf, 0x62, 0xc1, 0x09, 0x3a, + 0x2c, 0xa6, 0x27, 0x78, 0x84, 0x02, 0x98, 0xa0, 0xd3, 0xae, 0x45, 0x62, 0x09, 0x13, 0xeb, 0x2b, + 0x47, 0xc5, 0x37, 0xf9, 0x24, 0x7a, 0xe4, 0x15, 0x93, 0x19, 0x4e, 0x73, 0xb7, 0xbf, 0x66, 0x01, + 0xf3, 0x9e, 0x3c, 0x86, 0xcd, 0xec, 0x92, 0xb9, 0x99, 0xd9, 0xf9, 0x12, 0xa3, 0xc7, 0x3e, 0xf6, + 0x3c, 0x4c, 0x52, 0x6c, 0x3d, 0x0c, 0xee, 0xef, 0x48, 0x8d, 0x3f, 0x5f, 0xbb, 0xfa, 0x95, 0x12, + 0x5f, 0x36, 0x2a, 0xf2, 0x14, 0x7d, 0xde, 0x82, 0xe1, 0xa6, 0xd3, 0x76, 0x9a, 0x3c, 0x73, 0x57, + 0x01, 0x33, 0x91, 0x51, 0x7e, 0x7e, 0x49, 0x94, 0xe5, 0x26, 0x8e, 0x8f, 0xca, 0x4f, 0x97, 0xe0, + 0x5c, 0xb3, 0x86, 0xaa, 0x7c, 0xf6, 0x2e, 0x8c, 0x19, 0xcc, 0x8e, 0xf4, 0x3c, 0xfc, 0x79, 0x8b, + 0x0b, 0x7d, 0x75, 0x66, 0xb9, 0x07, 0x53, 0xbe, 0xf6, 0x9f, 0x8a, 0x33, 0xa9, 0x50, 0xcf, 0x17, + 0x17, 0xeb, 0x4c, 0x0a, 0x6a, 0x9e, 0xa2, 0x29, 0x86, 0xb8, 0xbb, 0x0e, 0xfb, 0x37, 0x2c, 0x78, + 0x48, 0x27, 0xd4, 0x42, 0x85, 0xf3, 0x0c, 0xd8, 0x35, 0x18, 0x0e, 0xda, 0x24, 0x74, 0x92, 0xf3, + 0xd9, 0x59, 0xd9, 0xff, 0x37, 0x04, 0x7c, 0x7f, 0x77, 0x6e, 0x5a, 0xe7, 0x2e, 0xe1, 0x58, 0x95, + 0x44, 0x36, 0x0c, 0xb2, 0x7e, 0x89, 0x44, 0x90, 0x37, 0xcb, 0x64, 0xc5, 0x2e, 0xc8, 0x22, 0x2c, + 0x30, 0xf6, 0xdf, 0xb4, 0xf8, 0x74, 0xd3, 0x9b, 0x8e, 0x7e, 0x01, 0x26, 0xb7, 0xe8, 0x51, 0x6e, + 0xf9, 0x7e, 0x3b, 0xe4, 0xe6, 0x77, 0xd9, 0x63, 0x2f, 0x14, 0xef, 0x31, 0xed, 0x73, 0x17, 0x67, + 0x44, 0xeb, 0x27, 0xaf, 0xa5, 0xd8, 0xe2, 0xae, 0x8a, 0xec, 0x7f, 0x50, 0xe2, 0x6b, 0x96, 0xe9, + 0x70, 0x4f, 0xc1, 0x50, 0x3b, 0x70, 0x97, 0x56, 0x6b, 0x58, 0xf4, 0x95, 0x12, 0x3a, 0x75, 0x0e, + 0xc6, 0x12, 0x8f, 0x2e, 0x02, 0x90, 0xfb, 0x31, 0x09, 0x7d, 0xa7, 0xa5, 0xae, 0xf4, 0x95, 0xaa, + 0xb4, 0xac, 0x30, 0x58, 0xa3, 0xa2, 0x65, 0xda, 0x61, 0xb0, 0xed, 0xb9, 0x2c, 0xc6, 0xa5, 0x6c, + 0x96, 0xa9, 0x2b, 0x0c, 0xd6, 0xa8, 0xe8, 0x01, 0xba, 0xe3, 0x47, 0x7c, 0x1b, 0x73, 0xee, 0x88, + 0x2c, 0x4a, 0xc3, 0xc9, 0x01, 0xfa, 0xa6, 0x8e, 0xc4, 0x26, 0x2d, 0xba, 0x02, 0x83, 0xb1, 0xc3, + 0x2e, 0xaa, 0x07, 0x8a, 0x78, 0xfd, 0xac, 0x51, 0x5a, 0x3d, 0x6d, 0x15, 0x2d, 0x8a, 0x05, 0x0b, + 0xfb, 0x3f, 0x55, 0x01, 0x12, 0xad, 0x0b, 0x7d, 0xae, 0x7b, 0xc1, 0x7f, 0xac, 0xa8, 0xca, 0xf6, + 0xe0, 0x56, 0x3b, 0xfa, 0x92, 0x05, 0x23, 0x4e, 0xab, 0x15, 0x34, 0x9d, 0x98, 0x75, 0x4f, 0xa9, + 0xa8, 0xe8, 0x11, 0x2d, 0x59, 0x48, 0xca, 0xf2, 0xc6, 0x3c, 0x27, 0x2f, 0x8f, 0x35, 0x4c, 0x6e, + 0x7b, 0xf4, 0x26, 0xa0, 0x8f, 0x4a, 0xad, 0x9d, 0x8f, 0xf0, 0x6c, 0x5a, 0x6b, 0xaf, 0x32, 0x81, + 0xab, 0x29, 0xec, 0xe8, 0x2d, 0x23, 0xeb, 0x50, 0xa5, 0x48, 0xa0, 0xb2, 0xa1, 0x87, 0xe4, 0x25, + 0x1c, 0x42, 0xaf, 0xeb, 0xee, 0xf1, 0x03, 0x45, 0x32, 0x01, 0x68, 0xea, 0x70, 0x8e, 0x6b, 0x7c, + 0x0c, 0x13, 0xae, 0xb9, 0xf3, 0x0a, 0x17, 0xbf, 0x0b, 0xf9, 0x35, 0xa4, 0xb6, 0xec, 0x64, 0xaf, + 0x4d, 0x21, 0x70, 0xba, 0x0a, 0xf4, 0x3a, 0x0f, 0x5e, 0x58, 0xf5, 0xd7, 0x03, 0xe1, 0xe6, 0x77, + 0xae, 0xc0, 0x98, 0xef, 0x44, 0x31, 0xd9, 0xa2, 0x65, 0x92, 0xcd, 0xf5, 0xba, 0xe0, 0x82, 0x15, + 0x3f, 0xb4, 0x06, 0x83, 0x2c, 0x2e, 0x2d, 0x9a, 0x19, 0x2e, 0x62, 0x12, 0x34, 0xc3, 0xb1, 0x93, + 0xf5, 0xc3, 0xfe, 0x46, 0x58, 0xf0, 0x42, 0x97, 0x65, 0x42, 0x86, 0x68, 0xd5, 0xbf, 0x19, 0x11, + 0x96, 0x90, 0xa1, 0xba, 0xf8, 0x91, 0x24, 0xc3, 0x02, 0x87, 0x67, 0xa6, 0x6a, 0x34, 0x4a, 0x52, + 0xc5, 0x46, 0xfc, 0x97, 0x19, 0x20, 0x67, 0xa0, 0x48, 0x43, 0xcd, 0x7c, 0x91, 0x49, 0x67, 0xdf, + 0x32, 0x99, 0xe1, 0x34, 0xf7, 0x63, 0xdd, 0x52, 0x67, 0x7d, 0x98, 0x4c, 0x2f, 0xca, 0x23, 0xdd, + 0xc2, 0x7f, 0x5c, 0x81, 0x71, 0x73, 0x72, 0xa0, 0xf3, 0x50, 0x15, 0x4c, 0x54, 0x7a, 0x37, 0xb5, + 0x06, 0xae, 0x49, 0x04, 0x4e, 0x68, 0x58, 0xa2, 0x3b, 0x56, 0x5c, 0x73, 0xf0, 0x4a, 0x12, 0xdd, + 0x29, 0x0c, 0xd6, 0xa8, 0xa8, 0x26, 0x7c, 0x27, 0x08, 0x62, 0xb5, 0x13, 0xa8, 0x79, 0xb3, 0xc8, + 0xa0, 0x58, 0x60, 0xe9, 0x0e, 0x70, 0x97, 0x0e, 0x66, 0xcb, 0x34, 0x6f, 0xaa, 0x1d, 0xe0, 0x8a, + 0x8e, 0xc4, 0x26, 0x2d, 0xdd, 0xd1, 0x82, 0x88, 0x4d, 0x44, 0xa1, 0x6f, 0x27, 0x0e, 0x73, 0x0d, + 0x1e, 0xab, 0x29, 0xf1, 0xe8, 0xd3, 0xf0, 0x90, 0x0a, 0xad, 0xc4, 0xdc, 0x5c, 0x2c, 0x6b, 0x1c, + 0x34, 0x8e, 0xcc, 0x0f, 0x2d, 0x65, 0x93, 0xe1, 0x5e, 0xe5, 0xd1, 0x2b, 0x30, 0x2e, 0x74, 0x65, + 0xc9, 0x71, 0xc8, 0xf4, 0x7b, 0xb8, 0x62, 0x60, 0x71, 0x8a, 0x1a, 0xd5, 0x60, 0x92, 0x42, 0x98, + 0x92, 0x2a, 0x39, 0xf0, 0x10, 0x51, 0xb5, 0xd5, 0x5f, 0x49, 0xe1, 0x71, 0x57, 0x09, 0xb4, 0x00, + 0x13, 0x5c, 0x59, 0xa1, 0x07, 0x43, 0x36, 0x0e, 0xc2, 0x37, 0x57, 0x2d, 0x84, 0x1b, 0x26, 0x1a, + 0xa7, 0xe9, 0xd1, 0x4b, 0x30, 0xea, 0x84, 0xcd, 0x4d, 0x2f, 0x26, 0xcd, 0xb8, 0x13, 0xf2, 0x74, + 0x27, 0x9a, 0xe3, 0xc8, 0x82, 0x86, 0xc3, 0x06, 0xa5, 0xfd, 0x1e, 0x9c, 0xc8, 0x08, 0x04, 0xa0, + 0x13, 0xc7, 0x69, 0x7b, 0xf2, 0x9b, 0x52, 0xae, 0x6f, 0x0b, 0xf5, 0x55, 0xf9, 0x35, 0x1a, 0x15, + 0x9d, 0x9d, 0xcc, 0x4e, 0xae, 0x25, 0x6c, 0x55, 0xb3, 0x73, 0x45, 0x22, 0x70, 0x42, 0x63, 0xff, + 0x29, 0x80, 0x66, 0xbd, 0x29, 0xe0, 0xee, 0xf4, 0x12, 0x8c, 0xca, 0x1c, 0xc4, 0x5a, 0x22, 0x4f, + 0xf5, 0x99, 0x97, 0x34, 0x1c, 0x36, 0x28, 0x69, 0xdb, 0x7c, 0x69, 0x93, 0x4a, 0x3b, 0xda, 0x29, + 0x63, 0x15, 0x4e, 0x68, 0xd0, 0x39, 0x18, 0x8e, 0x48, 0x6b, 0xfd, 0xaa, 0xe7, 0xdf, 0x15, 0x13, + 0x5b, 0x49, 0xe6, 0x86, 0x80, 0x63, 0x45, 0x81, 0x16, 0xa1, 0xdc, 0xf1, 0x5c, 0x31, 0x95, 0xa5, + 0xda, 0x50, 0xbe, 0xb9, 0x5a, 0xdb, 0xdf, 0x9d, 0x7b, 0xac, 0x57, 0x6a, 0x65, 0x7a, 0x3e, 0x8f, + 0xe6, 0xe9, 0xf2, 0xa3, 0x85, 0xb3, 0x2e, 0x0c, 0x06, 0xfb, 0xbc, 0x30, 0xb8, 0x08, 0x20, 0xbe, + 0x5a, 0xce, 0xe5, 0x72, 0x32, 0x6a, 0x97, 0x14, 0x06, 0x6b, 0x54, 0xf4, 0x94, 0xdf, 0x0c, 0x89, + 0x23, 0x0f, 0xc2, 0xdc, 0x41, 0x7d, 0xf8, 0xf0, 0xa7, 0xfc, 0xa5, 0x34, 0x33, 0xdc, 0xcd, 0x1f, + 0x05, 0x30, 0xe5, 0x8a, 0xf8, 0xdd, 0xa4, 0xd2, 0x6a, 0xff, 0x5e, 0xf1, 0xcc, 0xb7, 0x27, 0xcd, + 0x08, 0x77, 0xf3, 0x46, 0x6f, 0xc2, 0xac, 0x04, 0x76, 0x07, 0x4f, 0xb3, 0xe5, 0x52, 0x5e, 0x3c, + 0xbd, 0xb7, 0x3b, 0x37, 0x5b, 0xeb, 0x49, 0x85, 0x0f, 0xe0, 0x80, 0xde, 0x80, 0x41, 0x76, 0xc1, + 0x14, 0xcd, 0x8c, 0xb0, 0x1d, 0xef, 0xf9, 0x22, 0xb1, 0x15, 0x74, 0xd6, 0xcf, 0xb3, 0x6b, 0x2a, + 0xe1, 0x35, 0x9c, 0xdc, 0xda, 0x31, 0x20, 0x16, 0x3c, 0x51, 0x1b, 0x46, 0x1c, 0xdf, 0x0f, 0x62, + 0x87, 0x2b, 0x62, 0xa3, 0x45, 0x74, 0x49, 0xad, 0x8a, 0x85, 0xa4, 0x2c, 0xaf, 0x47, 0x39, 0x22, + 0x6a, 0x18, 0xac, 0x57, 0x81, 0xee, 0xc1, 0x44, 0x70, 0x8f, 0x0a, 0x4c, 0x79, 0x23, 0x12, 0xcd, + 0x8c, 0x99, 0x1f, 0x96, 0x63, 0xa8, 0x35, 0x0a, 0x6b, 0x92, 0xcc, 0x64, 0x8a, 0xd3, 0xb5, 0xa0, + 0x79, 0xc3, 0x5c, 0x3d, 0x9e, 0xf8, 0xc6, 0x27, 0xe6, 0x6a, 0xdd, 0x3a, 0xcd, 0x02, 0xf4, 0xb9, + 0x3f, 0x2c, 0x93, 0x08, 0x13, 0xa9, 0x00, 0xfd, 0x04, 0x85, 0x75, 0x3a, 0xb4, 0x09, 0xa3, 0xc9, + 0xdd, 0x56, 0x18, 0xb1, 0xdc, 0x3f, 0x9a, 0xbb, 0xd7, 0xc1, 0x1f, 0xb7, 0xaa, 0x95, 0xe4, 0x91, + 0x3e, 0x3a, 0x04, 0x1b, 0x9c, 0x67, 0x3f, 0x0e, 0x23, 0xda, 0x10, 0xf7, 0xe3, 0xee, 0x3d, 0xfb, + 0x0a, 0x4c, 0xa6, 0x87, 0xae, 0x2f, 0x77, 0xf1, 0xff, 0x51, 0x82, 0x89, 0x8c, 0x8b, 0x2d, 0x96, + 0x89, 0x39, 0x25, 0x64, 0x93, 0xc4, 0xcb, 0xa6, 0xa8, 0x2c, 0x15, 0x10, 0x95, 0x52, 0x6e, 0x97, + 0x7b, 0xca, 0x6d, 0x21, 0x1e, 0x2b, 0xef, 0x47, 0x3c, 0x9a, 0x3b, 0xd2, 0x40, 0xa1, 0x1d, 0xe9, + 0x01, 0x88, 0x54, 0x63, 0x53, 0x1b, 0x2a, 0xb0, 0xa9, 0x7d, 0xb5, 0x04, 0x93, 0x89, 0x6b, 0xbc, + 0x48, 0x81, 0x7e, 0xf4, 0x17, 0x1e, 0x6b, 0xc6, 0x85, 0x47, 0x5e, 0x86, 0xf3, 0x54, 0xfb, 0x7a, + 0x5e, 0x7e, 0xbc, 0x91, 0xba, 0xfc, 0x78, 0xbe, 0x4f, 0xbe, 0x07, 0x5f, 0x84, 0x7c, 0xab, 0x04, + 0x27, 0xd3, 0x45, 0x96, 0x5a, 0x8e, 0xb7, 0x75, 0x0c, 0xfd, 0xf5, 0x69, 0xa3, 0xbf, 0x5e, 0xec, + 0xef, 0xbb, 0x58, 0x23, 0x7b, 0x76, 0x9a, 0x93, 0xea, 0xb4, 0x8f, 0x1f, 0x86, 0xf9, 0xc1, 0x3d, + 0xf7, 0x47, 0x16, 0x3c, 0x9c, 0x59, 0xee, 0x18, 0x4c, 0xbc, 0xaf, 0x99, 0x26, 0xde, 0xe7, 0x0e, 0xf1, 0x75, 0x3d, 0x6c, 0xbe, 0xbf, 0x59, 0xee, 0xf1, 0x55, 0xcc, 0x08, 0x76, 0x03, 0x46, 0x9c, - 0x66, 0x93, 0x44, 0xd1, 0xb5, 0xc0, 0x55, 0x89, 0xc5, 0x9e, 0x65, 0xa7, 0x58, 0x52, 0xbc, 0xbf, - 0x3b, 0x37, 0x9b, 0x26, 0x91, 0x80, 0xb1, 0x4e, 0xc1, 0x4c, 0x79, 0x58, 0x3a, 0xa2, 0x94, 0x87, - 0x17, 0x01, 0xb6, 0x95, 0xbe, 0x9c, 0xb6, 0xad, 0x69, 0x9a, 0xb4, 0x86, 0x85, 0xfe, 0x0a, 0x93, - 0x3d, 0xb9, 0x5f, 0x4a, 0xc5, 0x8c, 0xb2, 0xcd, 0x99, 0x3f, 0xdd, 0xc7, 0x85, 0x07, 0xf3, 0x2a, - 0x3b, 0xa4, 0x22, 0x89, 0x3e, 0x05, 0x93, 0x11, 0xcf, 0x49, 0xb1, 0xd4, 0x72, 0x22, 0x16, 0x13, - 0x22, 0xf8, 0x29, 0x8b, 0xcb, 0x6d, 0xa4, 0x60, 0xb8, 0x0b, 0xdb, 0xfe, 0x66, 0x19, 0x3e, 0x7c, - 0xc0, 0xb2, 0x45, 0x0b, 0xe6, 0xfd, 0xf0, 0x33, 0x69, 0x4b, 0xd3, 0x6c, 0x66, 0x65, 0xc3, 0xf4, - 0x94, 0x9a, 0xed, 0xd2, 0xfb, 0x9e, 0xed, 0x2f, 0xeb, 0x76, 0x41, 0xee, 0xaa, 0x7a, 0xe9, 0xd0, - 0x1b, 0xf3, 0x27, 0xf5, 0x5a, 0xe0, 0xb3, 0x16, 0x3c, 0x96, 0xf9, 0x59, 0x86, 0x3f, 0xca, 0x79, - 0xa8, 0x36, 0x69, 0xa1, 0x16, 0xc1, 0x95, 0x84, 0x4e, 0x4a, 0x00, 0x4e, 0x70, 0x0c, 0xb7, 0x93, - 0x52, 0xae, 0xdb, 0xc9, 0x1f, 0x58, 0x30, 0x9d, 0xee, 0xc4, 0x31, 0xf0, 0xad, 0x86, 0xc9, 0xb7, - 0xe6, 0xfb, 0x9b, 0xfc, 0x1e, 0x2c, 0xeb, 0xab, 0x93, 0x70, 0xaa, 0xeb, 0xd4, 0xe3, 0xa3, 0xf8, - 0x4b, 0x16, 0x4c, 0x6d, 0x30, 0x3d, 0x41, 0x0b, 0x93, 0x13, 0xdf, 0x95, 0x13, 0x5b, 0x78, 0x60, - 0x74, 0x1d, 0xd7, 0x7a, 0xba, 0x50, 0x70, 0x77, 0x63, 0xe8, 0x8b, 0x16, 0x4c, 0x3b, 0xf7, 0xa2, - 0xae, 0x47, 0x7a, 0xc4, 0x42, 0x7a, 0x25, 0xc7, 0x2c, 0x97, 0xf3, 0xbc, 0xcf, 0xe2, 0xcc, 0xde, - 0xee, 0xdc, 0x74, 0x16, 0x16, 0xce, 0x6c, 0x95, 0xce, 0xef, 0xa6, 0x08, 0x97, 0x29, 0x16, 0xf0, - 0x99, 0x15, 0x5c, 0xc3, 0xd9, 0x9a, 0x84, 0x60, 0x45, 0x11, 0xbd, 0x0d, 0xd5, 0x0d, 0x19, 0x19, - 0x97, 0x66, 0x9b, 0x3d, 0x86, 0x39, 0x2b, 0x90, 0x8e, 0x87, 0x2b, 0x28, 0x10, 0x4e, 0x88, 0xa2, - 0xcb, 0x50, 0xf6, 0xd7, 0x23, 0x11, 0x83, 0x9e, 0xe7, 0x6d, 0x64, 0xfa, 0x78, 0xf1, 0xb0, 0xdd, - 0xeb, 0x2b, 0x0d, 0x4c, 0x49, 0x50, 0x4a, 0xe1, 0x1d, 0x57, 0xd8, 0xa3, 0x73, 0x28, 0xe1, 0xc5, - 0x5a, 0x37, 0x25, 0xbc, 0x58, 0xc3, 0x94, 0x04, 0xaa, 0xc3, 0x00, 0x0b, 0xc6, 0x11, 0xc6, 0xe6, - 0x9c, 0x44, 0x05, 0x5d, 0x21, 0x47, 0x3c, 0x33, 0x27, 0x2b, 0xc6, 0x9c, 0x10, 0x5a, 0x83, 0xc1, - 0x26, 0x7b, 0x5c, 0x42, 0x58, 0x01, 0xf2, 0x52, 0x78, 0x74, 0x3d, 0x44, 0xc1, 0x6f, 0xd8, 0x78, - 0x39, 0x16, 0xb4, 0x18, 0x55, 0xd2, 0xde, 0x5c, 0x8f, 0x84, 0x9a, 0x9f, 0x47, 0xb5, 0xeb, 0x99, - 0x10, 0x41, 0x95, 0x95, 0x63, 0x41, 0x0b, 0xd5, 0xa0, 0xb4, 0xde, 0x14, 0xb1, 0x3a, 0x39, 0x46, + 0x66, 0x93, 0x44, 0xd1, 0xb5, 0xc0, 0x55, 0x49, 0xc5, 0x9e, 0x65, 0xbb, 0x58, 0x02, 0xde, 0xdf, + 0x9d, 0x9b, 0x4d, 0xb3, 0x48, 0xd0, 0x58, 0xe7, 0x60, 0xa6, 0x3b, 0x2c, 0x1d, 0x51, 0xba, 0xc3, + 0x8b, 0x00, 0xdb, 0xea, 0xbc, 0x9c, 0xb6, 0xad, 0x69, 0x27, 0x69, 0x8d, 0x0a, 0xfd, 0x15, 0xa6, + 0x7b, 0x72, 0xbf, 0x94, 0x8a, 0x19, 0x65, 0x9b, 0x33, 0x7e, 0xba, 0x8f, 0x0b, 0x0f, 0xe6, 0x55, + 0x76, 0x48, 0xc5, 0x12, 0x7d, 0x0a, 0x26, 0x23, 0x9e, 0x8f, 0x62, 0xa9, 0xe5, 0x44, 0x2c, 0x26, + 0x44, 0xc8, 0x53, 0x16, 0x97, 0xdb, 0x48, 0xe1, 0x70, 0x17, 0xb5, 0xfd, 0xcd, 0x32, 0x7c, 0xf8, + 0x80, 0x69, 0x8b, 0x16, 0xcc, 0xfb, 0xe1, 0x67, 0xd2, 0x96, 0xa6, 0xd9, 0xcc, 0xc2, 0x86, 0xe9, + 0x29, 0x35, 0xda, 0xa5, 0xf7, 0x3d, 0xda, 0x5f, 0xd6, 0xed, 0x82, 0xdc, 0x55, 0xf5, 0xd2, 0xa1, + 0x17, 0xe6, 0x4f, 0xea, 0xb5, 0xc0, 0x67, 0x2d, 0x78, 0x2c, 0xf3, 0xb3, 0x0c, 0x7f, 0x94, 0xf3, + 0x50, 0x6d, 0x52, 0xa0, 0x16, 0xc1, 0x95, 0x84, 0x4e, 0x4a, 0x04, 0x4e, 0x68, 0x0c, 0xb7, 0x93, + 0x52, 0xae, 0xdb, 0xc9, 0x1f, 0x58, 0x30, 0x9d, 0x6e, 0xc4, 0x31, 0xc8, 0xad, 0x86, 0x29, 0xb7, + 0xe6, 0xfb, 0x1b, 0xfc, 0x1e, 0x22, 0xeb, 0xab, 0x93, 0x70, 0xaa, 0x6b, 0xd7, 0xe3, 0xbd, 0xf8, + 0x4b, 0x16, 0x4c, 0x6d, 0xb0, 0x73, 0x82, 0x16, 0x26, 0x27, 0xbe, 0x2b, 0x27, 0xb6, 0xf0, 0xc0, + 0xe8, 0x3a, 0x7e, 0xea, 0xe9, 0x22, 0xc1, 0xdd, 0x95, 0xa1, 0x2f, 0x5a, 0x30, 0xed, 0xdc, 0x8b, + 0xba, 0x1e, 0xe8, 0x11, 0x13, 0xe9, 0x95, 0x1c, 0xb3, 0x5c, 0xce, 0xd3, 0x3e, 0x8b, 0x33, 0x7b, + 0xbb, 0x73, 0xd3, 0x59, 0x54, 0x38, 0xb3, 0x56, 0x3a, 0xbe, 0x9b, 0x22, 0x5c, 0xa6, 0x58, 0xc0, + 0x67, 0x56, 0x70, 0x0d, 0x17, 0x6b, 0x12, 0x83, 0x15, 0x47, 0xf4, 0x36, 0x54, 0x37, 0x64, 0x64, + 0x5c, 0x5a, 0x6c, 0xf6, 0xe8, 0xe6, 0xac, 0x40, 0x3a, 0x1e, 0xae, 0xa0, 0x50, 0x38, 0x61, 0x8a, + 0x2e, 0x43, 0xd9, 0x5f, 0x8f, 0x44, 0x0c, 0x7a, 0x9e, 0xb7, 0x91, 0xe9, 0xe3, 0xc5, 0xc3, 0x76, + 0xaf, 0xaf, 0x34, 0x30, 0x65, 0x41, 0x39, 0x85, 0x77, 0x5c, 0x61, 0x8f, 0xce, 0xe1, 0x84, 0x17, + 0x6b, 0xdd, 0x9c, 0xf0, 0x62, 0x0d, 0x53, 0x16, 0xa8, 0x0e, 0x03, 0x2c, 0x18, 0x47, 0x18, 0x9b, + 0x73, 0x12, 0x15, 0x74, 0x85, 0x1c, 0xf1, 0xac, 0x9c, 0x0c, 0x8c, 0x39, 0x23, 0xb4, 0x06, 0x83, + 0x4d, 0xf6, 0xb0, 0x84, 0xb0, 0x02, 0xe4, 0xa5, 0xf0, 0xe8, 0x7a, 0x84, 0x82, 0xdf, 0xb0, 0x71, + 0x38, 0x16, 0xbc, 0x18, 0x57, 0xd2, 0xde, 0x5c, 0x8f, 0xc4, 0x31, 0x3f, 0x8f, 0x6b, 0xd7, 0x13, + 0x21, 0x82, 0x2b, 0x83, 0x63, 0xc1, 0x0b, 0xd5, 0xa0, 0xb4, 0xde, 0x14, 0xb1, 0x3a, 0x39, 0x46, 0x66, 0x33, 0x06, 0x7b, 0x71, 0x70, 0x6f, 0x77, 0xae, 0xb4, 0xb2, 0x84, 0x4b, 0xeb, 0x4d, 0xf4, - 0x1a, 0x0c, 0xad, 0xf3, 0xa8, 0x5a, 0x91, 0xcc, 0xf7, 0x42, 0x5e, 0xe8, 0x6f, 0x57, 0x08, 0x2e, - 0x0f, 0x49, 0x11, 0x00, 0x2c, 0xc9, 0xb1, 0x3c, 0x87, 0x2a, 0x4e, 0x58, 0x64, 0xf3, 0x9d, 0xef, - 0x2f, 0xae, 0x58, 0x68, 0xbf, 0xaa, 0x14, 0x6b, 0x14, 0xe9, 0x9a, 0x77, 0xe4, 0x3b, 0x39, 0x2c, - 0x93, 0x6f, 0xee, 0x9a, 0xcf, 0x7c, 0x56, 0x87, 0xaf, 0x79, 0x05, 0xc2, 0x09, 0x51, 0xd4, 0x81, - 0xb1, 0xed, 0xa8, 0xbd, 0x49, 0xe4, 0xd6, 0x67, 0xe9, 0x7d, 0x47, 0x2e, 0x7e, 0x32, 0x27, 0x67, - 0xb3, 0xa8, 0xe2, 0x85, 0x71, 0xc7, 0x69, 0x75, 0x71, 0x30, 0x96, 0x58, 0xee, 0x96, 0x4e, 0x16, - 0x9b, 0xad, 0xd0, 0x29, 0x79, 0xb7, 0x13, 0xdc, 0xd9, 0x89, 0x89, 0x48, 0xff, 0x9b, 0x33, 0x25, - 0xaf, 0x72, 0xe4, 0xee, 0x29, 0x11, 0x00, 0x2c, 0xc9, 0xa9, 0x21, 0x63, 0xdc, 0x78, 0xb2, 0xf0, - 0x90, 0x75, 0x7d, 0x43, 0x32, 0x64, 0x8c, 0xfb, 0x26, 0x44, 0x19, 0xd7, 0x6d, 0x6f, 0x06, 0x71, - 0xe0, 0xa7, 0x78, 0xff, 0x54, 0x11, 0xae, 0x5b, 0xcf, 0xa8, 0xd9, 0xcd, 0x75, 0xb3, 0xb0, 0x70, - 0x66, 0xab, 0xc8, 0x87, 0xf1, 0x76, 0x10, 0xc6, 0xf7, 0x82, 0x50, 0xae, 0x43, 0x54, 0x48, 0x47, - 0x34, 0xea, 0x88, 0xb6, 0x99, 0xe7, 0xb1, 0x09, 0xc1, 0x29, 0xea, 0x74, 0xea, 0xa2, 0xa6, 0xd3, - 0x22, 0xab, 0x37, 0x66, 0x4e, 0x14, 0x99, 0xba, 0x06, 0x47, 0xee, 0x9e, 0x3a, 0x01, 0xc0, 0x92, - 0x1c, 0xe5, 0x75, 0x2c, 0x97, 0x3d, 0xcb, 0x66, 0x9c, 0xcb, 0xeb, 0xba, 0xbc, 0x73, 0x39, 0xaf, - 0x63, 0xc5, 0x98, 0x13, 0x42, 0xef, 0x40, 0x55, 0x08, 0xb7, 0x41, 0x34, 0x73, 0x92, 0x51, 0xfd, - 0xd9, 0x9c, 0xde, 0x72, 0xf4, 0x1b, 0x8d, 0xec, 0x53, 0x5f, 0x44, 0xff, 0x49, 0x24, 0x9c, 0x90, - 0xb7, 0x7f, 0x63, 0xb0, 0x5b, 0xec, 0x61, 0x8a, 0xcd, 0xdf, 0xe8, 0xbe, 0xb1, 0xfe, 0x54, 0xff, - 0xfa, 0xfb, 0x03, 0xbc, 0xbb, 0xfe, 0xa2, 0x05, 0xa7, 0xda, 0x99, 0x9f, 0x27, 0x04, 0x87, 0x7e, - 0xcd, 0x00, 0x7c, 0x68, 0x54, 0x8e, 0xf1, 0x6c, 0x38, 0xee, 0xd1, 0x66, 0x5a, 0x15, 0x28, 0xbf, - 0x6f, 0x55, 0xe0, 0x36, 0x0c, 0x33, 0xd9, 0x35, 0xc9, 0xef, 0xd3, 0x67, 0x2a, 0x1c, 0x26, 0x82, - 0x2c, 0x09, 0x12, 0x58, 0x11, 0xa3, 0x03, 0xf7, 0x68, 0xfa, 0x23, 0x30, 0x61, 0x60, 0x91, 0xd9, - 0x92, 0xeb, 0x59, 0x2b, 0x62, 0x24, 0x1e, 0xad, 0x1f, 0x84, 0xbc, 0x9f, 0x87, 0x80, 0x0f, 0x6e, - 0x0c, 0xd5, 0x32, 0x14, 0xbd, 0x41, 0xf3, 0x7a, 0x2a, 0x5f, 0xd9, 0x3b, 0x5e, 0x05, 0xe5, 0x1f, - 0x5a, 0x19, 0xf2, 0x34, 0x57, 0x2a, 0x3f, 0x69, 0x2a, 0x95, 0x4f, 0xa6, 0x95, 0xca, 0x2e, 0x53, - 0x92, 0xa1, 0x4f, 0x16, 0xcf, 0xcc, 0x5b, 0x34, 0x81, 0x91, 0xdd, 0x82, 0x33, 0x79, 0xcc, 0x9a, - 0xb9, 0xac, 0xb9, 0xea, 0xb2, 0x36, 0x71, 0x59, 0x73, 0x57, 0x6b, 0x98, 0x41, 0x8a, 0xe6, 0xc0, - 0xb0, 0x7f, 0xb9, 0x04, 0xe5, 0x7a, 0xe0, 0x1e, 0x83, 0x69, 0xec, 0x92, 0x61, 0x1a, 0x7b, 0x22, - 0xf7, 0xa1, 0xc8, 0x9e, 0x86, 0xb0, 0x1b, 0x29, 0x43, 0xd8, 0xcf, 0xe4, 0x93, 0x3a, 0xd8, 0xec, - 0xf5, 0xed, 0x32, 0xe8, 0x4f, 0x5d, 0xa2, 0xff, 0x70, 0x18, 0x4f, 0xe6, 0x72, 0xb1, 0xd7, 0x2f, - 0x45, 0x1b, 0xcc, 0xe3, 0x4d, 0x06, 0x62, 0xfe, 0xc4, 0x3a, 0x34, 0xdf, 0x26, 0xde, 0xc6, 0x66, - 0x4c, 0xdc, 0xf4, 0x87, 0x1d, 0x9f, 0x43, 0xf3, 0x5f, 0x58, 0x30, 0x91, 0x6a, 0x1d, 0xb5, 0xb2, - 0x22, 0xb8, 0x0e, 0x69, 0xec, 0x9a, 0xca, 0x0d, 0xf9, 0x9a, 0x07, 0x50, 0x77, 0x16, 0xd2, 0xa0, - 0xc4, 0x64, 0x6b, 0x75, 0xa9, 0x11, 0x61, 0x0d, 0x03, 0xbd, 0x00, 0x23, 0x71, 0xd0, 0x0e, 0x5a, - 0xc1, 0xc6, 0xce, 0x15, 0x22, 0xb3, 0xb3, 0xa8, 0x9b, 0xa5, 0xb5, 0x04, 0x84, 0x75, 0x3c, 0xfb, - 0x3b, 0x65, 0x48, 0x3f, 0x94, 0xfa, 0xff, 0xd7, 0xe9, 0x4f, 0xce, 0x3a, 0xfd, 0x63, 0x0b, 0x26, - 0x69, 0xeb, 0xcc, 0xc5, 0x48, 0x3a, 0x1e, 0xab, 0x67, 0x42, 0xac, 0x03, 0x9e, 0x09, 0x79, 0x92, - 0x72, 0x3b, 0x37, 0xe8, 0xc4, 0xc2, 0x04, 0xa6, 0x31, 0x31, 0x5a, 0x8a, 0x05, 0x54, 0xe0, 0x91, - 0x30, 0x14, 0x11, 0x5a, 0x3a, 0x1e, 0x09, 0x43, 0x2c, 0xa0, 0xf2, 0x15, 0x91, 0x4a, 0x8f, 0x57, - 0x44, 0x58, 0x7e, 0x33, 0xe1, 0xd6, 0x22, 0xc4, 0x0a, 0x2d, 0xbf, 0x99, 0xf4, 0x77, 0x49, 0x70, - 0xec, 0xaf, 0x97, 0x61, 0xb4, 0x1e, 0xb8, 0x49, 0x44, 0xc1, 0xf3, 0x46, 0x44, 0xc1, 0x99, 0x54, - 0x44, 0xc1, 0xa4, 0x8e, 0xfb, 0x60, 0x02, 0x0a, 0x44, 0x1e, 0x3c, 0xf6, 0xce, 0xcd, 0x21, 0x83, - 0x09, 0x8c, 0x3c, 0x78, 0x8a, 0x10, 0x36, 0xe9, 0xfe, 0x34, 0x05, 0x11, 0xfc, 0x6f, 0x0b, 0xc6, - 0xeb, 0x81, 0x4b, 0x17, 0xe8, 0x4f, 0xd3, 0x6a, 0xd4, 0xb3, 0xe7, 0x0d, 0x1e, 0x90, 0x3d, 0xef, - 0x9f, 0x5b, 0x30, 0x54, 0x0f, 0xdc, 0x63, 0x30, 0x0f, 0xaf, 0x98, 0xe6, 0xe1, 0xc7, 0x72, 0x39, - 0x6f, 0x0f, 0x8b, 0xf0, 0x37, 0xcb, 0x30, 0x46, 0x7b, 0x1c, 0x6c, 0xc8, 0xf9, 0x32, 0xc6, 0xc6, - 0x2a, 0x30, 0x36, 0x54, 0x24, 0x0c, 0x5a, 0xad, 0xe0, 0x5e, 0x7a, 0xee, 0x56, 0x58, 0x29, 0x16, - 0x50, 0x74, 0x0e, 0x86, 0xdb, 0x21, 0xd9, 0xf6, 0x82, 0x4e, 0x94, 0x8e, 0xf6, 0xac, 0x8b, 0x72, - 0xac, 0x30, 0xd0, 0xf3, 0x30, 0x1a, 0x79, 0x7e, 0x93, 0x48, 0xa7, 0x97, 0x0a, 0x73, 0x7a, 0xe1, - 0x89, 0x4a, 0xb5, 0x72, 0x6c, 0x60, 0xa1, 0xdb, 0x50, 0x65, 0xff, 0xd9, 0x0e, 0xea, 0xff, 0x19, - 0x10, 0xae, 0x0e, 0x4b, 0x02, 0x38, 0xa1, 0x85, 0x2e, 0x02, 0xc4, 0xd2, 0x3d, 0x27, 0x12, 0x61, - 0xc9, 0x4a, 0x2e, 0x55, 0x8e, 0x3b, 0x11, 0xd6, 0xb0, 0xd0, 0x33, 0x50, 0x8d, 0x1d, 0xaf, 0x75, - 0xd5, 0xf3, 0x49, 0x24, 0xdc, 0x9b, 0x44, 0xd2, 0x71, 0x51, 0x88, 0x13, 0x38, 0x3d, 0xef, 0x59, - 0xd0, 0x3b, 0x7f, 0x62, 0x68, 0x98, 0x61, 0xb3, 0xf3, 0xfe, 0xaa, 0x2a, 0xc5, 0x1a, 0x86, 0xfd, - 0x12, 0x9c, 0xac, 0x07, 0x6e, 0x3d, 0x08, 0xe3, 0x95, 0x20, 0xbc, 0xe7, 0x84, 0xae, 0x9c, 0xbf, - 0x39, 0x99, 0xeb, 0x9a, 0x9e, 0xc9, 0x03, 0xdc, 0x8a, 0x60, 0xe4, 0xae, 0x7e, 0x8e, 0x9d, 0xf8, - 0x7d, 0x86, 0xaa, 0xfc, 0xa0, 0x04, 0xa8, 0xce, 0x1c, 0x88, 0x8c, 0x17, 0xa9, 0x36, 0x61, 0x3c, - 0x22, 0x57, 0x3d, 0xbf, 0x73, 0x5f, 0x90, 0x2a, 0x16, 0x1b, 0xd4, 0x58, 0xd6, 0xeb, 0x70, 0x3b, - 0x8d, 0x59, 0x86, 0x53, 0x74, 0xe9, 0x60, 0x86, 0x1d, 0x7f, 0x21, 0xba, 0x19, 0x91, 0x50, 0xbc, - 0xc0, 0xc4, 0x06, 0x13, 0xcb, 0x42, 0x9c, 0xc0, 0xe9, 0xe2, 0x61, 0x7f, 0xae, 0x07, 0x3e, 0x0e, - 0x82, 0x58, 0x2e, 0x37, 0xf6, 0x22, 0x87, 0x56, 0x8e, 0x0d, 0x2c, 0xb4, 0x02, 0x28, 0xea, 0xb4, - 0xdb, 0x2d, 0x76, 0x53, 0xea, 0xb4, 0x2e, 0x85, 0x41, 0xa7, 0xcd, 0xfd, 0xc8, 0xc5, 0x63, 0x16, - 0x8d, 0x2e, 0x28, 0xce, 0xa8, 0x41, 0x99, 0xc5, 0x7a, 0xc4, 0x7e, 0x8b, 0x08, 0x78, 0x6e, 0x6d, - 0x6d, 0xb0, 0x22, 0x2c, 0x61, 0xf6, 0x2f, 0xb2, 0x03, 0x8e, 0x3d, 0x8d, 0x13, 0x77, 0x42, 0x82, - 0xb6, 0x60, 0xac, 0xcd, 0x0e, 0xb1, 0x38, 0x0c, 0x5a, 0x2d, 0x22, 0xe5, 0xcb, 0xc3, 0xb9, 0x30, - 0xf1, 0xc7, 0x30, 0x74, 0x72, 0xd8, 0xa4, 0x6e, 0xff, 0xb7, 0x71, 0xc6, 0xab, 0xc4, 0x65, 0xf5, - 0x90, 0x70, 0x56, 0x16, 0x92, 0xdc, 0x47, 0x8a, 0x3c, 0x72, 0x97, 0x9c, 0x03, 0xc2, 0xf5, 0x19, - 0x4b, 0x2a, 0xe8, 0x33, 0xcc, 0x15, 0x9f, 0x33, 0x88, 0xe2, 0x4f, 0x77, 0x72, 0x7c, 0xc3, 0x0d, - 0x5f, 0x90, 0xc0, 0x1a, 0x39, 0x74, 0x15, 0xc6, 0xc4, 0x4b, 0x2a, 0xc2, 0x4c, 0x51, 0x36, 0x54, - 0xec, 0x31, 0xac, 0x03, 0xf7, 0xd3, 0x05, 0xd8, 0xac, 0x8c, 0x36, 0xe0, 0x51, 0xed, 0xa5, 0xb0, - 0x0c, 0x77, 0x3b, 0xce, 0x79, 0x1e, 0xdb, 0xdb, 0x9d, 0x7b, 0x74, 0xed, 0x20, 0x44, 0x7c, 0x30, - 0x1d, 0x74, 0x03, 0x4e, 0x3a, 0xcd, 0xd8, 0xdb, 0x26, 0x35, 0xe2, 0xb8, 0x2d, 0xcf, 0x27, 0x66, - 0x9a, 0x84, 0x87, 0xf7, 0x76, 0xe7, 0x4e, 0x2e, 0x64, 0x21, 0xe0, 0xec, 0x7a, 0xe8, 0x93, 0x50, - 0x75, 0xfd, 0x48, 0x8c, 0xc1, 0xa0, 0xf1, 0x30, 0x5e, 0xb5, 0x76, 0xbd, 0xa1, 0xbe, 0x3f, 0xf9, - 0x83, 0x93, 0x0a, 0xe8, 0x5d, 0x18, 0xd5, 0xc3, 0x9f, 0xc4, 0x83, 0x8c, 0x2f, 0x16, 0xd2, 0x9f, - 0x8d, 0x98, 0x21, 0x6e, 0xc1, 0x53, 0x6e, 0xad, 0x46, 0x38, 0x91, 0xd1, 0x04, 0xfa, 0x79, 0x40, - 0x11, 0x09, 0xb7, 0xbd, 0x26, 0x59, 0x68, 0xb2, 0xec, 0xbe, 0xcc, 0xc6, 0x33, 0x6c, 0xc4, 0x77, - 0xa0, 0x46, 0x17, 0x06, 0xce, 0xa8, 0x85, 0x2e, 0x53, 0xce, 0xa3, 0x97, 0x0a, 0x2f, 0x64, 0x29, - 0x18, 0xce, 0xd4, 0x48, 0x3b, 0x24, 0x4d, 0x27, 0x26, 0xae, 0x49, 0x11, 0xa7, 0xea, 0xd1, 0x73, - 0x49, 0x3d, 0xe0, 0x00, 0xa6, 0xef, 0x6c, 0xf7, 0x23, 0x0e, 0x54, 0xcf, 0xda, 0x0c, 0xa2, 0xf8, - 0x3a, 0x89, 0xef, 0x05, 0xe1, 0x5d, 0x91, 0x11, 0x2d, 0x49, 0x95, 0x98, 0x80, 0xb0, 0x8e, 0x47, - 0x65, 0x28, 0x76, 0xf5, 0xb7, 0x5a, 0x63, 0xf7, 0x2a, 0xc3, 0xc9, 0xde, 0xb9, 0xcc, 0x8b, 0xb1, - 0x84, 0x4b, 0xd4, 0xd5, 0xfa, 0x12, 0xbb, 0x23, 0x49, 0xa1, 0xae, 0xd6, 0x97, 0xb0, 0x84, 0xa3, - 0xa0, 0xfb, 0xf9, 0xc1, 0xf1, 0x22, 0xf7, 0x55, 0xdd, 0x9c, 0xbc, 0xe0, 0x0b, 0x84, 0xf7, 0x61, - 0x52, 0x3d, 0x81, 0xc8, 0x93, 0xc6, 0x45, 0x33, 0x13, 0x6c, 0xe1, 0x1c, 0x26, 0xf7, 0x9c, 0xb2, - 0xeb, 0xad, 0xa6, 0x68, 0xe2, 0xae, 0x56, 0x8c, 0xe4, 0x1c, 0x93, 0xb9, 0x8f, 0x72, 0x9c, 0x87, - 0x6a, 0xd4, 0xb9, 0xe3, 0x06, 0x5b, 0x8e, 0xe7, 0xb3, 0x8b, 0x0c, 0x4d, 0x88, 0x69, 0x48, 0x00, - 0x4e, 0x70, 0x50, 0x1d, 0x86, 0x1d, 0xa1, 0xc2, 0x89, 0x0b, 0x87, 0x9c, 0x28, 0x7c, 0xa9, 0xf0, - 0x71, 0xeb, 0xaa, 0xfc, 0x87, 0x15, 0x15, 0xf4, 0x32, 0x8c, 0x89, 0x20, 0x32, 0xe1, 0xec, 0x79, - 0xc2, 0x0c, 0x38, 0x68, 0xe8, 0x40, 0x6c, 0xe2, 0xa2, 0x0d, 0x18, 0xa7, 0x54, 0x12, 0x06, 0x38, - 0x33, 0xdd, 0x1f, 0x0f, 0xd5, 0xd2, 0x9f, 0xeb, 0x64, 0x70, 0x8a, 0x2c, 0x72, 0xe1, 0x11, 0xa7, - 0x13, 0x07, 0x5b, 0x74, 0x27, 0x98, 0xfb, 0x64, 0x2d, 0xb8, 0x4b, 0x7c, 0x76, 0xcb, 0x30, 0xbc, - 0x78, 0x66, 0x6f, 0x77, 0xee, 0x91, 0x85, 0x03, 0xf0, 0xf0, 0x81, 0x54, 0xd0, 0x5b, 0x30, 0x12, - 0x07, 0x2d, 0xe1, 0xc3, 0x1d, 0xcd, 0x9c, 0x2a, 0x92, 0x84, 0x68, 0x4d, 0x55, 0xd0, 0xcd, 0x18, - 0x8a, 0x08, 0xd6, 0x29, 0xa2, 0x37, 0xf9, 0xae, 0x64, 0x09, 0x33, 0x49, 0x34, 0xf3, 0x50, 0x91, - 0xc1, 0x52, 0x19, 0x36, 0xcd, 0xed, 0x2b, 0x68, 0x60, 0x9d, 0xe0, 0xec, 0xcf, 0xc1, 0x54, 0x17, - 0xcb, 0xeb, 0xcb, 0xb9, 0xf5, 0x3f, 0x0e, 0x40, 0x55, 0x59, 0x0c, 0xd1, 0x79, 0xd3, 0x38, 0xfc, - 0x70, 0xda, 0x38, 0x3c, 0x4c, 0x05, 0x34, 0xdd, 0x1e, 0xfc, 0x66, 0xc6, 0xa3, 0xfa, 0x4f, 0xe7, - 0xee, 0xf1, 0xe2, 0x91, 0x6d, 0x9a, 0x8a, 0x57, 0x2e, 0x6c, 0x6f, 0xae, 0x1c, 0xa8, 0x35, 0x16, - 0x7c, 0x28, 0x92, 0xea, 0x87, 0xed, 0xc0, 0x5d, 0xad, 0xa7, 0xdf, 0x41, 0xab, 0xd3, 0x42, 0xcc, - 0x61, 0x4c, 0xae, 0xa7, 0x67, 0x36, 0x93, 0xeb, 0x87, 0x0e, 0x29, 0xd7, 0x4b, 0x02, 0x38, 0xa1, - 0x85, 0xb6, 0x61, 0xaa, 0x69, 0x3e, 0x6b, 0xa7, 0xe2, 0xd5, 0x9e, 0xed, 0xe3, 0x59, 0xb9, 0x8e, - 0xf6, 0x22, 0xcd, 0x52, 0x9a, 0x1e, 0xee, 0x6e, 0x02, 0xbd, 0x0c, 0xc3, 0xef, 0x06, 0x11, 0xbb, - 0xb6, 0x10, 0x07, 0x97, 0x8c, 0x0b, 0x1a, 0x7e, 0xf5, 0x46, 0x83, 0x95, 0xef, 0xef, 0xce, 0x8d, - 0xd4, 0x03, 0x57, 0xfe, 0xc5, 0xaa, 0x02, 0xfa, 0xac, 0x05, 0x27, 0x8d, 0x7d, 0xac, 0x7a, 0x0e, - 0x87, 0xe9, 0xf9, 0xa3, 0xa2, 0xe5, 0x93, 0xab, 0x59, 0x34, 0x71, 0x76, 0x53, 0xf6, 0x77, 0xb9, - 0x89, 0x54, 0x18, 0x4d, 0x48, 0xd4, 0x69, 0x1d, 0xc7, 0xeb, 0x10, 0x37, 0x0c, 0x7b, 0xce, 0x03, - 0x30, 0xd2, 0xff, 0x7b, 0x8b, 0x19, 0xe9, 0xd7, 0xc8, 0x56, 0xbb, 0xe5, 0xc4, 0xc7, 0xe1, 0xfb, - 0xfc, 0x19, 0x18, 0x8e, 0x45, 0x6b, 0xc5, 0x9e, 0xb6, 0xd0, 0xba, 0xc7, 0x2e, 0x2f, 0xd4, 0xc1, - 0x27, 0x4b, 0xb1, 0x22, 0x68, 0xff, 0x2b, 0x3e, 0x2b, 0x12, 0x72, 0x0c, 0x96, 0x88, 0xeb, 0xa6, - 0x25, 0xe2, 0xa9, 0xc2, 0xdf, 0xd2, 0xc3, 0x22, 0xf1, 0x1d, 0xf3, 0x0b, 0x98, 0x7e, 0xf2, 0x93, - 0x73, 0x8b, 0x64, 0xff, 0xba, 0x05, 0xd3, 0x59, 0xce, 0x08, 0x54, 0x80, 0xe1, 0xda, 0x91, 0xba, - 0x5f, 0x53, 0xa3, 0x7a, 0x4b, 0x94, 0x63, 0x85, 0x51, 0x38, 0xd7, 0x7c, 0x7f, 0x29, 0xb4, 0x6e, - 0x80, 0xf9, 0x40, 0x22, 0x7a, 0x85, 0x87, 0x3a, 0x58, 0xea, 0x05, 0xc3, 0xfe, 0xc2, 0x1c, 0xec, - 0x6f, 0x94, 0x60, 0x9a, 0x1b, 0xb9, 0x17, 0xb6, 0x03, 0xcf, 0xad, 0x07, 0xae, 0x08, 0xfc, 0x70, - 0x61, 0xb4, 0xad, 0x29, 0xb7, 0xc5, 0x52, 0xf2, 0xe8, 0xea, 0x70, 0xa2, 0x50, 0xe8, 0xa5, 0xd8, - 0xa0, 0x4a, 0x5b, 0x21, 0xdb, 0x5e, 0x53, 0xd9, 0x4c, 0x4b, 0x7d, 0x9f, 0x0c, 0xaa, 0x95, 0x65, - 0x8d, 0x0e, 0x36, 0xa8, 0x1e, 0xc1, 0x13, 0x31, 0xf6, 0xdf, 0xb7, 0xe0, 0xa1, 0x1e, 0x69, 0x7b, - 0x68, 0x73, 0xf7, 0xd8, 0xc5, 0x82, 0x78, 0x81, 0x53, 0x35, 0xc7, 0xaf, 0x1b, 0xb0, 0x80, 0xa2, - 0x3b, 0x00, 0xfc, 0xba, 0x80, 0xca, 0xd2, 0xe9, 0xbb, 0xec, 0x82, 0xc9, 0x31, 0xb4, 0xbc, 0x09, - 0x92, 0x12, 0xd6, 0xa8, 0xda, 0x5f, 0x2b, 0xc3, 0x00, 0x7f, 0xe8, 0xbd, 0x0e, 0x43, 0x9b, 0x3c, - 0x9f, 0x71, 0x7f, 0xe9, 0x94, 0x13, 0xe5, 0x85, 0x17, 0x60, 0x49, 0x06, 0x5d, 0x83, 0x13, 0x22, - 0xf4, 0xa8, 0x46, 0x5a, 0xce, 0x8e, 0xd4, 0x86, 0xf9, 0xbb, 0x21, 0x32, 0xc1, 0xfd, 0x89, 0xd5, - 0x6e, 0x14, 0x9c, 0x55, 0x0f, 0xbd, 0xd2, 0x95, 0x7e, 0x90, 0xe7, 0x89, 0x56, 0x92, 0x70, 0x4e, - 0x0a, 0xc2, 0x97, 0x61, 0xac, 0xdd, 0xa5, 0xf7, 0x6b, 0xef, 0x69, 0x9b, 0xba, 0xbe, 0x89, 0xcb, - 0x7c, 0x17, 0x3a, 0xcc, 0x67, 0x63, 0x6d, 0x33, 0x24, 0xd1, 0x66, 0xd0, 0x72, 0xc5, 0x53, 0xb0, - 0x89, 0xef, 0x42, 0x0a, 0x8e, 0xbb, 0x6a, 0x50, 0x2a, 0xeb, 0x8e, 0xd7, 0xea, 0x84, 0x24, 0xa1, - 0x32, 0x68, 0x52, 0x59, 0x49, 0xc1, 0x71, 0x57, 0x0d, 0xba, 0xb6, 0x4e, 0x8a, 0xd7, 0x43, 0x65, - 0x90, 0xba, 0x60, 0x41, 0x9f, 0x86, 0x21, 0x19, 0x40, 0x50, 0x28, 0x97, 0x8a, 0x70, 0x4c, 0x50, - 0x2f, 0x91, 0x6a, 0xef, 0xc8, 0x89, 0xd0, 0x01, 0x49, 0xef, 0x30, 0xaf, 0x54, 0xfe, 0xb9, 0x05, - 0x27, 0x32, 0x1c, 0xe1, 0x38, 0x4b, 0xdb, 0xf0, 0xa2, 0x58, 0xbd, 0x62, 0xa1, 0xb1, 0x34, 0x5e, - 0x8e, 0x15, 0x06, 0xdd, 0x2d, 0x9c, 0x69, 0xa6, 0x19, 0xa5, 0x70, 0x31, 0x11, 0xd0, 0xfe, 0x18, - 0x25, 0x3a, 0x03, 0x95, 0x4e, 0x44, 0x42, 0xf9, 0xa0, 0xa3, 0xe4, 0xf3, 0xcc, 0xce, 0xc8, 0x20, - 0x54, 0x6c, 0xdd, 0x50, 0x26, 0x3e, 0x4d, 0x6c, 0xe5, 0x46, 0x3e, 0x0e, 0xb3, 0xbf, 0x5c, 0x86, - 0x89, 0x94, 0x43, 0x2c, 0xed, 0xc8, 0x56, 0xe0, 0x7b, 0x71, 0xa0, 0xf2, 0xdb, 0xf1, 0x37, 0xe4, - 0x48, 0x7b, 0xf3, 0x9a, 0x28, 0xc7, 0x0a, 0x03, 0x3d, 0x29, 0x5f, 0x09, 0x4e, 0xbf, 0xce, 0xb1, - 0x58, 0x33, 0x1e, 0x0a, 0x2e, 0xfa, 0xb2, 0xce, 0xe3, 0x50, 0x69, 0x07, 0xea, 0xd1, 0x77, 0x35, - 0x9f, 0x78, 0xb1, 0x56, 0x0f, 0x82, 0x16, 0x66, 0x40, 0xf4, 0x84, 0xf8, 0xfa, 0xd4, 0xcd, 0x08, - 0x76, 0xdc, 0x20, 0xd2, 0x86, 0xe0, 0x29, 0x18, 0xba, 0x4b, 0x76, 0x42, 0xcf, 0xdf, 0x48, 0xdf, - 0x0b, 0x5d, 0xe1, 0xc5, 0x58, 0xc2, 0xcd, 0x64, 0xf5, 0x43, 0x47, 0xfc, 0x7a, 0xce, 0x70, 0xee, - 0x39, 0xf8, 0x4d, 0x0b, 0x26, 0x58, 0xf6, 0x59, 0x91, 0x22, 0xc1, 0x0b, 0xfc, 0x63, 0x90, 0x31, - 0x1e, 0x87, 0x81, 0x90, 0x36, 0x9a, 0x7e, 0xfe, 0x82, 0xf5, 0x04, 0x73, 0x18, 0x7a, 0x04, 0x2a, - 0xac, 0x0b, 0x74, 0x1a, 0x47, 0x79, 0x92, 0xfb, 0x9a, 0x13, 0x3b, 0x98, 0x95, 0xb2, 0x18, 0x34, - 0x4c, 0xda, 0x2d, 0x8f, 0x77, 0x3a, 0x31, 0xe7, 0x7e, 0xd0, 0x62, 0xd0, 0x32, 0x3b, 0xf9, 0xa0, - 0x62, 0xd0, 0xb2, 0x89, 0x1f, 0x2c, 0xe7, 0xff, 0xf7, 0x12, 0x9c, 0xce, 0xac, 0x97, 0xdc, 0x30, - 0xaf, 0x18, 0x37, 0xcc, 0x17, 0x53, 0x37, 0xcc, 0xf6, 0xc1, 0xb5, 0x1f, 0xcc, 0x9d, 0x73, 0xf6, - 0x55, 0x70, 0xf9, 0x18, 0xaf, 0x82, 0x2b, 0x45, 0x45, 0x9c, 0x81, 0x1c, 0x11, 0xe7, 0x8f, 0x2c, - 0x78, 0x38, 0x73, 0xc8, 0x3e, 0x70, 0x41, 0x7f, 0x99, 0xbd, 0xec, 0xa1, 0x9d, 0xfc, 0x5a, 0xb9, - 0xc7, 0x57, 0x31, 0x3d, 0xe5, 0x2c, 0xe5, 0x42, 0x0c, 0x18, 0x09, 0xe1, 0x6d, 0x94, 0x73, 0x20, - 0x5e, 0x86, 0x15, 0x14, 0x45, 0x5a, 0xd0, 0x1c, 0xef, 0xe4, 0xf2, 0x21, 0x37, 0xd4, 0xbc, 0x69, - 0x87, 0xd7, 0xf3, 0x3e, 0xa4, 0x43, 0xe9, 0x6e, 0x6b, 0x9a, 0x67, 0xf9, 0x30, 0x9a, 0xe7, 0x68, - 0xb6, 0xd6, 0x89, 0x16, 0x60, 0x62, 0xcb, 0xf3, 0xd9, 0xa3, 0xbb, 0xa6, 0xf4, 0xa4, 0x22, 0x97, - 0xaf, 0x99, 0x60, 0x9c, 0xc6, 0x9f, 0x7d, 0x19, 0xc6, 0x0e, 0x6f, 0x5d, 0xfb, 0x51, 0x19, 0x3e, - 0x7c, 0x00, 0x53, 0xe0, 0xa7, 0x83, 0x31, 0x2f, 0xda, 0xe9, 0xd0, 0x35, 0x37, 0x75, 0x98, 0x5e, - 0xef, 0xb4, 0x5a, 0x3b, 0xcc, 0x3f, 0x8b, 0xb8, 0x12, 0x43, 0x08, 0x35, 0x2a, 0x19, 0xf5, 0x4a, - 0x06, 0x0e, 0xce, 0xac, 0x89, 0x7e, 0x1e, 0x50, 0x70, 0x87, 0xa5, 0x45, 0x76, 0x93, 0xbc, 0x16, - 0x6c, 0x0a, 0xca, 0xc9, 0x56, 0xbd, 0xd1, 0x85, 0x81, 0x33, 0x6a, 0x51, 0x39, 0x95, 0x9e, 0x63, - 0x3b, 0xaa, 0x5b, 0x29, 0x39, 0x15, 0xeb, 0x40, 0x6c, 0xe2, 0xa2, 0x4b, 0x30, 0xe5, 0x6c, 0x3b, - 0x1e, 0x4f, 0x73, 0x26, 0x09, 0x70, 0x41, 0x55, 0xd9, 0xaf, 0x16, 0xd2, 0x08, 0xb8, 0xbb, 0x0e, - 0x6a, 0x1b, 0x06, 0x49, 0xfe, 0x32, 0xc3, 0x27, 0x0f, 0xb1, 0x82, 0x0b, 0x9b, 0x28, 0xed, 0x3f, - 0xb5, 0xe8, 0xd1, 0x97, 0xf1, 0x3e, 0x2b, 0x1d, 0x11, 0x65, 0x60, 0xd3, 0x82, 0x00, 0xd5, 0x88, - 0x2c, 0xe9, 0x40, 0x6c, 0xe2, 0xf2, 0xa5, 0x11, 0x25, 0xee, 0xe2, 0x86, 0xb4, 0x29, 0xe2, 0x67, - 0x15, 0x06, 0x95, 0xa0, 0x5d, 0x6f, 0xdb, 0x8b, 0x82, 0x50, 0x6c, 0xa0, 0x7e, 0x5f, 0x41, 0x57, - 0xfc, 0xb2, 0xc6, 0xc9, 0x60, 0x49, 0xcf, 0xfe, 0x4a, 0x09, 0xc6, 0x64, 0x8b, 0xaf, 0x76, 0x82, - 0xd8, 0x39, 0x86, 0x23, 0xfd, 0x55, 0xe3, 0x48, 0x3f, 0x5f, 0x2c, 0x9c, 0x98, 0x75, 0xae, 0xe7, - 0x51, 0xfe, 0xe9, 0xd4, 0x51, 0x7e, 0xa1, 0x1f, 0xa2, 0x07, 0x1f, 0xe1, 0xff, 0xc6, 0x82, 0x29, - 0x03, 0xff, 0x18, 0x4e, 0x92, 0xba, 0x79, 0x92, 0x3c, 0xd3, 0xc7, 0xd7, 0xf4, 0x38, 0x41, 0xbe, - 0x5e, 0x4a, 0x7d, 0x05, 0x3b, 0x39, 0x7e, 0x01, 0x2a, 0x9b, 0x4e, 0xe8, 0x16, 0xcb, 0xf9, 0xd9, - 0x55, 0x7d, 0xfe, 0xb2, 0x13, 0xba, 0x9c, 0xff, 0x9f, 0x53, 0xaf, 0xc7, 0x39, 0xa1, 0x9b, 0x1b, - 0x45, 0xc1, 0x1a, 0x45, 0x2f, 0xc1, 0x60, 0xd4, 0x0c, 0xda, 0xca, 0xcf, 0xf4, 0x0c, 0x7f, 0x59, - 0x8e, 0x96, 0xec, 0xef, 0xce, 0x21, 0xb3, 0x39, 0x5a, 0x8c, 0x05, 0xfe, 0xec, 0x06, 0x54, 0x55, - 0xd3, 0x47, 0xea, 0x69, 0xff, 0x5f, 0xcb, 0x70, 0x22, 0x63, 0xad, 0xa0, 0x5f, 0x34, 0xc6, 0xed, - 0xe5, 0xbe, 0x17, 0xdb, 0xfb, 0x1c, 0xb9, 0x5f, 0x64, 0x9a, 0x92, 0x2b, 0x56, 0xc7, 0x21, 0x9a, - 0xbf, 0x19, 0x91, 0x74, 0xf3, 0xb4, 0x28, 0xbf, 0x79, 0xda, 0xec, 0xb1, 0x0d, 0x3f, 0x6d, 0x48, - 0xf5, 0xf4, 0x48, 0xe7, 0xf9, 0x0b, 0x15, 0x98, 0xce, 0xca, 0x5b, 0x80, 0x7e, 0xc5, 0x4a, 0xbd, - 0x30, 0xf2, 0x4a, 0xff, 0xc9, 0x0f, 0xf8, 0xb3, 0x23, 0x22, 0xab, 0xd0, 0xbc, 0xf9, 0xe6, 0x48, - 0xee, 0x88, 0x8b, 0xd6, 0x59, 0xfc, 0x53, 0xc8, 0x5f, 0x8b, 0x91, 0x5c, 0xe1, 0x53, 0x87, 0xe8, - 0x8a, 0x78, 0x70, 0x26, 0x4a, 0xc5, 0x3f, 0xc9, 0xe2, 0xfc, 0xf8, 0x27, 0xd9, 0x87, 0x59, 0x0f, - 0x46, 0xb4, 0xef, 0x3a, 0xd2, 0x65, 0x70, 0x97, 0x1e, 0x51, 0x5a, 0xbf, 0x8f, 0x74, 0x29, 0xfc, - 0x1d, 0x0b, 0x52, 0x4e, 0x61, 0xca, 0x2c, 0x63, 0xf5, 0x34, 0xcb, 0x9c, 0x81, 0x4a, 0x18, 0xb4, - 0x48, 0xfa, 0xd1, 0x09, 0x1c, 0xb4, 0x08, 0x66, 0x10, 0xf5, 0xa0, 0x74, 0xb9, 0xd7, 0x83, 0xd2, - 0x54, 0x4f, 0x6f, 0x91, 0x6d, 0x22, 0x8d, 0x24, 0x8a, 0x8d, 0x5f, 0xa5, 0x85, 0x98, 0xc3, 0xec, - 0xdf, 0xa9, 0xc0, 0x89, 0x8c, 0x58, 0x40, 0xaa, 0x21, 0x6d, 0x38, 0x31, 0xb9, 0xe7, 0xec, 0xa4, - 0x93, 0xdf, 0x5e, 0xe2, 0xc5, 0x58, 0xc2, 0x99, 0x33, 0x2b, 0x4f, 0xa0, 0x97, 0x32, 0x5d, 0x89, - 0xbc, 0x79, 0x02, 0x7a, 0xf4, 0x4f, 0x0f, 0x5f, 0x04, 0x88, 0xa2, 0xd6, 0xb2, 0x4f, 0x25, 0x3c, - 0x57, 0x38, 0xcd, 0x26, 0x79, 0x17, 0x1b, 0x57, 0x05, 0x04, 0x6b, 0x58, 0xa8, 0x06, 0x93, 0xed, - 0x30, 0x88, 0xb9, 0x61, 0xb0, 0xc6, 0x1d, 0x2d, 0x06, 0xcc, 0x68, 0xad, 0x7a, 0x0a, 0x8e, 0xbb, - 0x6a, 0xa0, 0x17, 0x60, 0x44, 0x44, 0x70, 0xd5, 0x83, 0xa0, 0x25, 0xcc, 0x48, 0xea, 0x3a, 0xbe, - 0x91, 0x80, 0xb0, 0x8e, 0xa7, 0x55, 0x63, 0xd6, 0xc6, 0xa1, 0xcc, 0x6a, 0xdc, 0xe2, 0xa8, 0xe1, - 0xa5, 0xb2, 0x9b, 0x0c, 0x17, 0xca, 0x6e, 0x92, 0x18, 0xd6, 0xaa, 0x85, 0x2f, 0x62, 0x20, 0xd7, - 0x00, 0xf5, 0x87, 0x65, 0x18, 0xe4, 0x53, 0x71, 0x0c, 0x52, 0x5e, 0x5d, 0x98, 0x94, 0x0a, 0x65, - 0x92, 0xe0, 0xbd, 0x9a, 0xaf, 0x39, 0xb1, 0xc3, 0x59, 0x93, 0xda, 0x21, 0x89, 0x19, 0x0a, 0xcd, - 0x1b, 0x7b, 0x68, 0x36, 0x65, 0x29, 0x01, 0x4e, 0x43, 0xdb, 0x51, 0x9b, 0x00, 0x11, 0x7b, 0xfe, - 0x96, 0xd2, 0x10, 0x99, 0x79, 0x9f, 0x2f, 0xd4, 0x8f, 0x86, 0xaa, 0xc6, 0x7b, 0x93, 0x2c, 0x4b, - 0x05, 0xc0, 0x1a, 0xed, 0xd9, 0x17, 0xa1, 0xaa, 0x90, 0xf3, 0x54, 0xc8, 0x51, 0x9d, 0xb5, 0xfd, - 0x2c, 0x4c, 0xa4, 0xda, 0xea, 0x4b, 0x03, 0xfd, 0x3d, 0x0b, 0x26, 0x78, 0x97, 0x97, 0xfd, 0x6d, - 0xc1, 0x0a, 0x3e, 0x67, 0xc1, 0x74, 0x2b, 0x63, 0x27, 0x8a, 0x69, 0x3e, 0xcc, 0x1e, 0x56, 0xca, - 0x67, 0x16, 0x14, 0x67, 0xb6, 0x86, 0xce, 0xc2, 0x30, 0x7f, 0xcd, 0xdb, 0x69, 0x09, 0x0f, 0xed, - 0x51, 0x9e, 0x93, 0x9c, 0x97, 0x61, 0x05, 0xb5, 0x7f, 0x6c, 0xc1, 0x14, 0xff, 0x88, 0x2b, 0x64, - 0x47, 0xa9, 0x57, 0x1f, 0x90, 0xcf, 0x10, 0xd9, 0xd7, 0x4b, 0x3d, 0xb2, 0xaf, 0xeb, 0x5f, 0x59, - 0x3e, 0xf0, 0x2b, 0xbf, 0x61, 0x81, 0x58, 0xa1, 0xc7, 0xa0, 0x3f, 0xac, 0x9a, 0xfa, 0xc3, 0x47, - 0x8a, 0x2c, 0xfa, 0x1e, 0x8a, 0xc3, 0xaf, 0x96, 0x60, 0x92, 0x23, 0x24, 0x37, 0x32, 0x1f, 0x94, - 0xc9, 0xe9, 0xef, 0x55, 0x20, 0xf5, 0x26, 0x6c, 0xf6, 0x97, 0x1a, 0x73, 0x59, 0x39, 0x70, 0x2e, - 0xff, 0xa7, 0x05, 0x88, 0x8f, 0x49, 0xfa, 0x29, 0x74, 0x7e, 0xba, 0x69, 0xe6, 0x80, 0x84, 0x73, - 0x28, 0x08, 0xd6, 0xb0, 0x1e, 0xf0, 0x27, 0xa4, 0xee, 0xc3, 0xca, 0xf9, 0xf7, 0x61, 0x7d, 0x7c, - 0xf5, 0x77, 0xcb, 0x90, 0x76, 0xd5, 0x44, 0x6f, 0xc3, 0x68, 0xd3, 0x69, 0x3b, 0x77, 0xbc, 0x96, - 0x17, 0x7b, 0x24, 0x2a, 0x76, 0xe1, 0xbe, 0xa4, 0xd5, 0x10, 0xd7, 0x50, 0x5a, 0x09, 0x36, 0x28, - 0xa2, 0x79, 0x80, 0x76, 0xe8, 0x6d, 0x7b, 0x2d, 0xb2, 0xc1, 0x34, 0x1e, 0x16, 0xeb, 0xc1, 0xef, - 0x8e, 0x65, 0x29, 0xd6, 0x30, 0x32, 0x62, 0x03, 0xca, 0xc7, 0x11, 0x1b, 0x50, 0xe9, 0x33, 0x36, - 0x60, 0xa0, 0x50, 0x6c, 0x00, 0x86, 0x53, 0xf2, 0xf0, 0xa6, 0xff, 0x57, 0xbc, 0x16, 0x11, 0xb2, - 0x1b, 0x8f, 0x05, 0x99, 0xdd, 0xdb, 0x9d, 0x3b, 0x85, 0x33, 0x31, 0x70, 0x8f, 0x9a, 0x76, 0x07, - 0x4e, 0x34, 0x48, 0x28, 0x9f, 0xb1, 0x53, 0x7b, 0xe9, 0x4d, 0xa8, 0x86, 0xa9, 0x6d, 0xdc, 0x67, - 0xc0, 0xbf, 0x96, 0xe3, 0x4d, 0x6e, 0xdb, 0x84, 0xa4, 0xfd, 0xd7, 0x4b, 0x30, 0x24, 0x9c, 0x34, - 0x8f, 0x41, 0xf8, 0xb8, 0x62, 0x98, 0x98, 0x9e, 0xca, 0xe3, 0x7f, 0xac, 0x5b, 0x3d, 0x8d, 0x4b, - 0x8d, 0x94, 0x71, 0xe9, 0x99, 0x62, 0xe4, 0x0e, 0x36, 0x2b, 0xfd, 0x93, 0x32, 0x8c, 0x9b, 0x4e, - 0xab, 0xc7, 0x30, 0x2c, 0xaf, 0xc1, 0x50, 0x24, 0xfc, 0xa7, 0x4b, 0x45, 0x7c, 0xf6, 0xd2, 0x53, - 0x9c, 0xdc, 0xc4, 0x0b, 0x8f, 0x69, 0x49, 0x2e, 0xd3, 0x45, 0xbb, 0x7c, 0x2c, 0x2e, 0xda, 0x79, - 0xbe, 0xc4, 0x95, 0x07, 0xe1, 0x4b, 0x6c, 0x7f, 0x8f, 0xb1, 0x7c, 0xbd, 0xfc, 0x18, 0x8e, 0xf1, - 0x57, 0xcd, 0xc3, 0xe1, 0x5c, 0xa1, 0x75, 0x27, 0xba, 0xd7, 0xe3, 0x38, 0xff, 0x96, 0x05, 0x23, - 0x02, 0xf1, 0x18, 0x3e, 0xe0, 0xe7, 0xcd, 0x0f, 0x78, 0xa2, 0xd0, 0x07, 0xf4, 0xe8, 0xf9, 0x57, - 0x4a, 0xaa, 0xe7, 0xf5, 0x20, 0x8c, 0x0b, 0x65, 0x42, 0x1f, 0xa6, 0xaa, 0x5f, 0xd0, 0x0c, 0x5a, - 0x42, 0x80, 0x7b, 0x24, 0x09, 0xfd, 0xe3, 0xe5, 0xfb, 0xda, 0x6f, 0xac, 0xb0, 0x59, 0x64, 0x5a, - 0x10, 0xc6, 0xe2, 0x00, 0x4d, 0x22, 0xd3, 0x82, 0x30, 0xc6, 0x0c, 0x82, 0x5c, 0x80, 0xd8, 0x09, - 0x37, 0x48, 0x4c, 0xcb, 0x44, 0xd4, 0x6c, 0xef, 0xdd, 0xda, 0x89, 0xbd, 0xd6, 0xbc, 0xe7, 0xc7, - 0x51, 0x1c, 0xce, 0xaf, 0xfa, 0xf1, 0x8d, 0x90, 0x0b, 0xfd, 0x5a, 0x2c, 0x9f, 0xa2, 0x85, 0x35, - 0xba, 0x32, 0x48, 0x84, 0xb5, 0x31, 0x60, 0xde, 0x20, 0x5d, 0x17, 0xe5, 0x58, 0x61, 0xd8, 0x2f, - 0x32, 0xce, 0xce, 0x06, 0xa8, 0xbf, 0x30, 0xbb, 0x2f, 0x0c, 0xa9, 0xa1, 0x65, 0x66, 0xe1, 0xeb, - 0x7a, 0x30, 0x5f, 0x51, 0xf6, 0x49, 0xbb, 0xa0, 0xfb, 0x51, 0x27, 0xb1, 0x7f, 0x88, 0x74, 0x5d, - 0x3b, 0xbe, 0x58, 0x98, 0x23, 0xf7, 0x71, 0xd1, 0xc8, 0x52, 0x32, 0xb2, 0x3c, 0x74, 0xab, 0xf5, - 0x74, 0xfe, 0xfa, 0x25, 0x09, 0xc0, 0x09, 0x0e, 0x3a, 0x2f, 0x14, 0x4a, 0x6e, 0x71, 0xf9, 0x70, - 0x4a, 0xa1, 0x94, 0x43, 0xa2, 0x69, 0x94, 0x17, 0x60, 0x44, 0x3d, 0x09, 0x54, 0xe7, 0x8f, 0xb1, - 0x54, 0xb9, 0x7c, 0xb5, 0x9c, 0x14, 0x63, 0x1d, 0x07, 0xad, 0xc1, 0x44, 0xc4, 0xdf, 0x2b, 0x92, - 0xd1, 0x1a, 0xc2, 0x70, 0xf0, 0xb4, 0xbc, 0xa4, 0x6c, 0x98, 0xe0, 0x7d, 0x56, 0xc4, 0xb7, 0xb2, - 0x8c, 0xef, 0x48, 0x93, 0x40, 0xaf, 0xc0, 0x78, 0x4b, 0x7f, 0xc3, 0xb5, 0x2e, 0xec, 0x0a, 0xca, - 0xed, 0xcc, 0x78, 0xe1, 0xb5, 0x8e, 0x53, 0xd8, 0xe8, 0x35, 0x98, 0xd1, 0x4b, 0x44, 0x72, 0x21, - 0xc7, 0xdf, 0x20, 0x91, 0x78, 0xdb, 0xe4, 0x91, 0xbd, 0xdd, 0xb9, 0x99, 0xab, 0x3d, 0x70, 0x70, - 0xcf, 0xda, 0xe8, 0x25, 0x18, 0x95, 0x9f, 0xaf, 0xc5, 0x36, 0x25, 0x0e, 0x8f, 0x1a, 0x0c, 0x1b, - 0x98, 0xe8, 0x1e, 0x9c, 0x94, 0xff, 0xd7, 0x42, 0x67, 0x7d, 0xdd, 0x6b, 0x8a, 0x20, 0xb3, 0x11, - 0x46, 0x62, 0x41, 0xfa, 0x8b, 0x2f, 0x67, 0x21, 0xed, 0xef, 0xce, 0x9d, 0x11, 0xa3, 0x96, 0x09, - 0x67, 0x93, 0x98, 0x4d, 0x1f, 0x5d, 0x83, 0x13, 0x9b, 0xc4, 0x69, 0xc5, 0x9b, 0x4b, 0x9b, 0xa4, - 0x79, 0x57, 0x6e, 0x2c, 0x16, 0x31, 0xa5, 0xb9, 0x04, 0x5e, 0xee, 0x46, 0xc1, 0x59, 0xf5, 0xde, - 0xdf, 0x9d, 0xf2, 0x2f, 0xd0, 0xca, 0x9a, 0xfc, 0x80, 0xde, 0x81, 0x51, 0x7d, 0xac, 0xd3, 0x82, - 0x41, 0xfe, 0xfb, 0xbe, 0x42, 0x0e, 0x51, 0x33, 0xa0, 0xc3, 0xb0, 0x41, 0xdb, 0xfe, 0x77, 0x25, - 0x98, 0xcb, 0xc9, 0xdd, 0x95, 0xb2, 0x66, 0x59, 0x85, 0xac, 0x59, 0x0b, 0xf2, 0xcd, 0x9b, 0xeb, - 0xa9, 0x9c, 0xe9, 0xa9, 0x57, 0x6c, 0x92, 0xcc, 0xe9, 0x69, 0xfc, 0xc2, 0x9e, 0x66, 0xba, 0x41, - 0xac, 0x92, 0xeb, 0x70, 0xf7, 0xba, 0x6e, 0xe3, 0x1c, 0x38, 0x8c, 0xd0, 0xdb, 0xd3, 0xbc, 0x69, - 0x7f, 0xaf, 0x04, 0x27, 0xd5, 0x60, 0xfe, 0xf4, 0x0e, 0xe1, 0x5b, 0xdd, 0x43, 0xf8, 0x40, 0xcd, - 0xc4, 0xf6, 0x0d, 0x18, 0x6c, 0xec, 0x44, 0xcd, 0xb8, 0x55, 0xe0, 0xc4, 0x7f, 0xdc, 0xd8, 0x57, - 0xc9, 0x69, 0xc4, 0x5e, 0xb2, 0x13, 0xdb, 0xcc, 0xfe, 0xbc, 0x05, 0x13, 0x6b, 0x4b, 0xf5, 0x46, - 0xd0, 0xbc, 0x4b, 0xe2, 0x05, 0x6e, 0xd0, 0xc0, 0xe2, 0xc0, 0xb7, 0x0e, 0x79, 0x90, 0x67, 0x89, - 0x08, 0x67, 0xa0, 0xb2, 0x19, 0x44, 0x71, 0xfa, 0x52, 0xe0, 0x72, 0x10, 0xc5, 0x98, 0x41, 0xec, - 0x3f, 0xb3, 0x60, 0x80, 0x3d, 0xd4, 0x96, 0xf7, 0xc8, 0x5f, 0x91, 0xef, 0x42, 0x2f, 0xc0, 0x20, - 0x59, 0x5f, 0x27, 0xcd, 0x58, 0xcc, 0xaf, 0x0c, 0xb0, 0x19, 0x5c, 0x66, 0xa5, 0xf4, 0x44, 0x63, - 0x8d, 0xf1, 0xbf, 0x58, 0x20, 0xa3, 0xcf, 0x40, 0x35, 0xf6, 0xb6, 0xc8, 0x82, 0xeb, 0x0a, 0x2b, - 0x7c, 0x7f, 0x3e, 0x5f, 0xea, 0x84, 0x5d, 0x93, 0x44, 0x70, 0x42, 0xcf, 0xfe, 0x52, 0x09, 0x20, - 0x09, 0x9f, 0xcb, 0xfb, 0xcc, 0xc5, 0xae, 0xb7, 0x0c, 0x9f, 0xcc, 0x78, 0xcb, 0x10, 0x25, 0x04, - 0x33, 0x5e, 0x32, 0x54, 0x43, 0x55, 0x2e, 0x34, 0x54, 0x95, 0x7e, 0x86, 0x6a, 0x09, 0xa6, 0x92, - 0xf0, 0x3f, 0x33, 0x8e, 0x9a, 0xe5, 0x1b, 0x5e, 0x4b, 0x03, 0x71, 0x37, 0xbe, 0xfd, 0x25, 0x0b, - 0x84, 0x97, 0x70, 0x81, 0x05, 0xed, 0xca, 0x77, 0xc7, 0x8c, 0xd4, 0x82, 0x4f, 0x17, 0x71, 0xa0, - 0x16, 0x09, 0x05, 0x15, 0xdf, 0x37, 0xd2, 0x08, 0x1a, 0x54, 0xed, 0xdf, 0xb6, 0x60, 0x84, 0x83, - 0xaf, 0x31, 0x45, 0x34, 0xbf, 0x5f, 0x7d, 0x25, 0xb3, 0x66, 0x4f, 0x72, 0x51, 0xc2, 0x2a, 0xa9, - 0xb1, 0xfe, 0x24, 0x97, 0x04, 0xe0, 0x04, 0x07, 0x3d, 0x05, 0x43, 0x51, 0xe7, 0x0e, 0x43, 0x4f, - 0xb9, 0x0c, 0x37, 0x78, 0x31, 0x96, 0x70, 0xfb, 0x9f, 0x95, 0x60, 0x32, 0xed, 0x31, 0x8e, 0x30, - 0x0c, 0x72, 0x06, 0x92, 0xd6, 0x69, 0x0e, 0x32, 0x80, 0x6a, 0x1e, 0xe7, 0xc0, 0x1f, 0x96, 0x67, - 0x2c, 0x48, 0x50, 0x42, 0xeb, 0x30, 0xe2, 0x06, 0xf7, 0xfc, 0x7b, 0x4e, 0xe8, 0x2e, 0xd4, 0x57, - 0xc5, 0x4c, 0xe4, 0xf8, 0xf8, 0xd5, 0x92, 0x0a, 0xba, 0x3f, 0x3b, 0x33, 0xc8, 0x25, 0x20, 0xac, - 0x13, 0x46, 0x6f, 0xb2, 0x4c, 0x28, 0xeb, 0xde, 0xc6, 0x35, 0xa7, 0x5d, 0xcc, 0x9b, 0x65, 0x49, - 0xa2, 0x6b, 0x6d, 0x8c, 0x89, 0xc4, 0x29, 0x1c, 0x80, 0x13, 0x92, 0xf6, 0xaf, 0x9e, 0x04, 0x63, - 0x2d, 0x18, 0x19, 0xa7, 0xad, 0x07, 0x9e, 0x71, 0xfa, 0x0d, 0x18, 0x26, 0x5b, 0xed, 0x78, 0xa7, - 0xe6, 0x85, 0xc5, 0xde, 0x0f, 0x58, 0x16, 0xd8, 0xdd, 0xd4, 0x25, 0x04, 0x2b, 0x8a, 0x3d, 0xf2, - 0x87, 0x97, 0x3f, 0x10, 0xf9, 0xc3, 0x2b, 0x7f, 0x29, 0xf9, 0xc3, 0x5f, 0x83, 0xa1, 0x0d, 0x2f, - 0xc6, 0xa4, 0x1d, 0x88, 0xd3, 0x38, 0x67, 0xf1, 0x5c, 0xe2, 0xc8, 0xdd, 0x99, 0x65, 0x05, 0x00, - 0x4b, 0x72, 0x68, 0x4d, 0x6d, 0xaa, 0xc1, 0x22, 0x32, 0x68, 0xb7, 0x81, 0x3c, 0x73, 0x5b, 0x89, - 0x7c, 0xe1, 0x43, 0xef, 0x3f, 0x5f, 0xb8, 0xca, 0xf2, 0x3d, 0xfc, 0xa0, 0xb2, 0x7c, 0x1b, 0xd9, - 0xd2, 0xab, 0x47, 0x91, 0x2d, 0xfd, 0x4b, 0x16, 0x9c, 0x6c, 0x67, 0xbd, 0x35, 0x20, 0xf2, 0x75, - 0xff, 0xdc, 0x21, 0x5e, 0x5f, 0x30, 0x9a, 0x66, 0xf9, 0x3d, 0x32, 0xd1, 0x70, 0x76, 0xc3, 0x32, - 0xed, 0xfa, 0xc8, 0xfb, 0x4f, 0xbb, 0x7e, 0xd4, 0x89, 0xbd, 0x93, 0x24, 0xec, 0x63, 0x47, 0x92, - 0x84, 0x7d, 0xfc, 0x01, 0x26, 0x61, 0xd7, 0xd2, 0xa7, 0x4f, 0x3c, 0xd8, 0xf4, 0xe9, 0x9b, 0xe6, - 0xb9, 0xc4, 0xb3, 0x75, 0xbf, 0x50, 0xf8, 0x5c, 0x32, 0x5a, 0x38, 0xf8, 0x64, 0xe2, 0x89, 0xe4, - 0xa7, 0xde, 0x67, 0x22, 0x79, 0x23, 0x1d, 0x3b, 0x3a, 0x8a, 0x74, 0xec, 0x6f, 0xeb, 0x27, 0xe8, - 0x89, 0x22, 0x2d, 0xa8, 0x83, 0xb2, 0xbb, 0x85, 0xac, 0x33, 0xb4, 0x3b, 0xe1, 0xfb, 0xf4, 0x71, - 0x27, 0x7c, 0x3f, 0x79, 0x84, 0x09, 0xdf, 0x4f, 0x1d, 0x6b, 0xc2, 0xf7, 0x87, 0x3e, 0x20, 0x09, - 0xdf, 0x67, 0x8e, 0x2b, 0xe1, 0xfb, 0xc3, 0x0f, 0x36, 0xe1, 0xfb, 0xdb, 0x50, 0x6d, 0xcb, 0xb8, - 0xcb, 0x99, 0xd9, 0x22, 0x53, 0x97, 0x19, 0xa6, 0xc9, 0xa7, 0x4e, 0x81, 0x70, 0x42, 0x94, 0xb6, - 0x90, 0x24, 0x80, 0xff, 0x70, 0x91, 0x16, 0x32, 0xed, 0x1e, 0x07, 0xa4, 0x7d, 0xff, 0x42, 0x09, - 0x4e, 0x1f, 0xbc, 0x3b, 0x12, 0xa3, 0x49, 0x3d, 0xb1, 0x65, 0xa7, 0x8c, 0x26, 0x4c, 0xf2, 0xd4, - 0xb0, 0x0a, 0x87, 0xb3, 0x5f, 0x82, 0x29, 0xe5, 0xe7, 0xd5, 0xf2, 0x9a, 0x3b, 0xda, 0x33, 0x54, - 0x2a, 0x3e, 0xa1, 0x91, 0x46, 0xc0, 0xdd, 0x75, 0xd0, 0x02, 0x4c, 0x18, 0x85, 0xab, 0x35, 0xa1, - 0xbf, 0x28, 0x2b, 0x4d, 0xc3, 0x04, 0xe3, 0x34, 0xbe, 0xfd, 0x75, 0x0b, 0x1e, 0xea, 0x91, 0xe1, - 0xb5, 0x70, 0x8c, 0x76, 0x1b, 0x26, 0xda, 0x66, 0xd5, 0xc2, 0x29, 0x1f, 0x8c, 0x8c, 0xb2, 0xaa, - 0xd7, 0x29, 0x00, 0x4e, 0x93, 0x5f, 0x3c, 0xfb, 0xfd, 0x1f, 0x9d, 0xfe, 0xd0, 0x0f, 0x7e, 0x74, - 0xfa, 0x43, 0x3f, 0xfc, 0xd1, 0xe9, 0x0f, 0xfd, 0xd2, 0xde, 0x69, 0xeb, 0xfb, 0x7b, 0xa7, 0xad, - 0x1f, 0xec, 0x9d, 0xb6, 0x7e, 0xb8, 0x77, 0xda, 0xfa, 0xf3, 0xbd, 0xd3, 0xd6, 0x97, 0x7e, 0x7c, - 0xfa, 0x43, 0xaf, 0x97, 0xb6, 0x2f, 0xfc, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0xe5, 0xd7, - 0x49, 0x99, 0xd0, 0x00, 0x00, + 0x1a, 0x0c, 0xad, 0xf3, 0xa8, 0x5a, 0x91, 0xc8, 0xf7, 0x42, 0x5e, 0xe8, 0x6f, 0x57, 0x08, 0x2e, + 0x0f, 0x49, 0x11, 0x08, 0x2c, 0xd9, 0xb1, 0x1c, 0x87, 0x2a, 0x4e, 0x58, 0x64, 0xf2, 0x9d, 0xef, + 0x2f, 0xae, 0x58, 0x9c, 0x7e, 0x15, 0x14, 0x6b, 0x1c, 0xe9, 0x9c, 0x77, 0xe4, 0x1b, 0x39, 0x2c, + 0x8b, 0x6f, 0xee, 0x9c, 0xcf, 0x7c, 0x52, 0x87, 0xcf, 0x79, 0x85, 0xc2, 0x09, 0x53, 0xd4, 0x81, + 0xb1, 0xed, 0xa8, 0xbd, 0x49, 0xe4, 0xd2, 0x67, 0xa9, 0x7d, 0x47, 0x2e, 0x7e, 0x32, 0x27, 0x5f, + 0xb3, 0x28, 0xe2, 0x85, 0x71, 0xc7, 0x69, 0x75, 0x49, 0x30, 0x96, 0x54, 0xee, 0x96, 0xce, 0x16, + 0x9b, 0xb5, 0xd0, 0x21, 0x79, 0xb7, 0x13, 0xdc, 0xd9, 0x89, 0x89, 0x48, 0xfd, 0x9b, 0x33, 0x24, + 0xaf, 0x72, 0xe2, 0xee, 0x21, 0x11, 0x08, 0x2c, 0xd9, 0xa9, 0x2e, 0x63, 0xd2, 0x78, 0xb2, 0x70, + 0x97, 0x75, 0x7d, 0x43, 0xd2, 0x65, 0x4c, 0xfa, 0x26, 0x4c, 0x99, 0xd4, 0x6d, 0x6f, 0x06, 0x71, + 0xe0, 0xa7, 0x64, 0xff, 0x54, 0x11, 0xa9, 0x5b, 0xcf, 0x28, 0xd9, 0x2d, 0x75, 0xb3, 0xa8, 0x70, + 0x66, 0xad, 0xc8, 0x87, 0xf1, 0x76, 0x10, 0xc6, 0xf7, 0x82, 0x50, 0xce, 0x43, 0x54, 0xe8, 0x8c, + 0x68, 0x94, 0x11, 0x75, 0x33, 0xcf, 0x63, 0x13, 0x83, 0x53, 0xdc, 0xe9, 0xd0, 0x45, 0x4d, 0xa7, + 0x45, 0x56, 0x6f, 0xcc, 0x9c, 0x28, 0x32, 0x74, 0x0d, 0x4e, 0xdc, 0x3d, 0x74, 0x02, 0x81, 0x25, + 0x3b, 0x2a, 0xeb, 0x58, 0x1e, 0x7b, 0x96, 0xc9, 0x38, 0x57, 0xd6, 0x75, 0x79, 0xe7, 0x72, 0x59, + 0xc7, 0xc0, 0x98, 0x33, 0x42, 0xef, 0x40, 0x55, 0x28, 0xb7, 0x41, 0x34, 0x73, 0x92, 0x71, 0xfd, + 0xd9, 0x9c, 0xd6, 0x72, 0xf2, 0x1b, 0x8d, 0xec, 0x5d, 0x5f, 0x44, 0xff, 0x49, 0x22, 0x9c, 0xb0, + 0xb7, 0x7f, 0x63, 0xb0, 0x5b, 0xed, 0x61, 0x07, 0x9b, 0xbf, 0xd1, 0x7d, 0x63, 0xfd, 0xa9, 0xfe, + 0xcf, 0xef, 0x0f, 0xf0, 0xee, 0xfa, 0x8b, 0x16, 0x9c, 0x6a, 0x67, 0x7e, 0x9e, 0x50, 0x1c, 0xfa, + 0x35, 0x03, 0xf0, 0xae, 0x51, 0xf9, 0xc5, 0xb3, 0xf1, 0xb8, 0x47, 0x9d, 0xe9, 0xa3, 0x40, 0xf9, + 0x7d, 0x1f, 0x05, 0x6e, 0xc3, 0x30, 0xd3, 0x5d, 0x93, 0xfc, 0x3e, 0x7d, 0xa6, 0xc2, 0x61, 0x2a, + 0xc8, 0x92, 0x60, 0x81, 0x15, 0x33, 0xda, 0x71, 0x8f, 0xa6, 0x3f, 0x02, 0x13, 0x86, 0x16, 0x59, + 0x2d, 0xf9, 0x39, 0x6b, 0x45, 0xf4, 0xc4, 0xa3, 0xf5, 0x83, 0x88, 0xf7, 0xf3, 0x08, 0xf0, 0xc1, + 0x95, 0xa1, 0x5a, 0xc6, 0x41, 0x6f, 0xd0, 0xbc, 0x9e, 0xca, 0x3f, 0xec, 0x1d, 0xef, 0x01, 0xe5, + 0x1f, 0x5a, 0x19, 0xfa, 0x34, 0x3f, 0x54, 0x7e, 0xd2, 0x3c, 0x54, 0x3e, 0x99, 0x3e, 0x54, 0x76, + 0x99, 0x92, 0x8c, 0xf3, 0x64, 0xf1, 0xac, 0xbc, 0x45, 0x13, 0x18, 0xd9, 0x2d, 0x38, 0x93, 0x27, + 0xac, 0x99, 0xcb, 0x9a, 0xab, 0x2e, 0x6b, 0x13, 0x97, 0x35, 0x77, 0xb5, 0x86, 0x19, 0xa6, 0x68, + 0x0e, 0x0c, 0xfb, 0x97, 0x4b, 0x50, 0xae, 0x07, 0xee, 0x31, 0x98, 0xc6, 0x2e, 0x19, 0xa6, 0xb1, + 0x27, 0x72, 0x1f, 0x89, 0xec, 0x69, 0x08, 0xbb, 0x91, 0x32, 0x84, 0xfd, 0x4c, 0x3e, 0xab, 0x83, + 0xcd, 0x5e, 0xdf, 0x2e, 0x83, 0xfe, 0xcc, 0x25, 0xfa, 0x0f, 0x87, 0xf1, 0x64, 0x2e, 0x17, 0x7b, + 0xf9, 0x52, 0xd4, 0xc1, 0x3c, 0xde, 0x64, 0x20, 0xe6, 0x4f, 0xac, 0x43, 0xf3, 0x6d, 0xe2, 0x6d, + 0x6c, 0xc6, 0xc4, 0x4d, 0x7f, 0xd8, 0xf1, 0x39, 0x34, 0xff, 0x85, 0x05, 0x13, 0xa9, 0xda, 0x51, + 0x2b, 0x2b, 0x82, 0xeb, 0x90, 0xc6, 0xae, 0xa9, 0xdc, 0x90, 0xaf, 0x79, 0x00, 0x75, 0x67, 0x21, + 0x0d, 0x4a, 0x4c, 0xb7, 0x56, 0x97, 0x1a, 0x11, 0xd6, 0x28, 0xd0, 0x0b, 0x30, 0x12, 0x07, 0xed, + 0xa0, 0x15, 0x6c, 0xec, 0x5c, 0x21, 0x32, 0x3b, 0x8b, 0xba, 0x59, 0x5a, 0x4b, 0x50, 0x58, 0xa7, + 0xb3, 0xbf, 0x53, 0x86, 0xf4, 0x23, 0xa9, 0xff, 0x7f, 0x9e, 0xfe, 0xe4, 0xcc, 0xd3, 0x3f, 0xb6, + 0x60, 0x92, 0xd6, 0xce, 0x5c, 0x8c, 0xa4, 0xe3, 0xb1, 0x7a, 0x22, 0xc4, 0x3a, 0xe0, 0x89, 0x90, + 0x27, 0xa9, 0xb4, 0x73, 0x83, 0x4e, 0x2c, 0x4c, 0x60, 0x9a, 0x10, 0xa3, 0x50, 0x2c, 0xb0, 0x82, + 0x8e, 0x84, 0xa1, 0x88, 0xd0, 0xd2, 0xe9, 0x48, 0x18, 0x62, 0x81, 0x95, 0x2f, 0x88, 0x54, 0x7a, + 0xbc, 0x20, 0xc2, 0xf2, 0x9b, 0x09, 0xb7, 0x16, 0xa1, 0x56, 0x68, 0xf9, 0xcd, 0xa4, 0xbf, 0x4b, + 0x42, 0x63, 0x7f, 0xbd, 0x0c, 0xa3, 0xf5, 0xc0, 0x4d, 0x22, 0x0a, 0x9e, 0x37, 0x22, 0x0a, 0xce, + 0xa4, 0x22, 0x0a, 0x26, 0x75, 0xda, 0x07, 0x13, 0x50, 0x20, 0xf2, 0xe0, 0xb1, 0x37, 0x6e, 0x0e, + 0x19, 0x4c, 0x60, 0xe4, 0xc1, 0x53, 0x8c, 0xb0, 0xc9, 0xf7, 0xa7, 0x29, 0x88, 0xe0, 0x7f, 0x5b, + 0x30, 0x5e, 0x0f, 0x5c, 0x3a, 0x41, 0x7f, 0x9a, 0x66, 0xa3, 0x9e, 0x3d, 0x6f, 0xf0, 0x80, 0xec, + 0x79, 0xff, 0xcc, 0x82, 0xa1, 0x7a, 0xe0, 0x1e, 0x83, 0x79, 0x78, 0xc5, 0x34, 0x0f, 0x3f, 0x96, + 0x2b, 0x79, 0x7b, 0x58, 0x84, 0xbf, 0x59, 0x86, 0x31, 0xda, 0xe2, 0x60, 0x43, 0x8e, 0x97, 0xd1, + 0x37, 0x56, 0x81, 0xbe, 0xa1, 0x2a, 0x61, 0xd0, 0x6a, 0x05, 0xf7, 0xd2, 0x63, 0xb7, 0xc2, 0xa0, + 0x58, 0x60, 0xd1, 0x39, 0x18, 0x6e, 0x87, 0x64, 0xdb, 0x0b, 0x3a, 0x51, 0x3a, 0xda, 0xb3, 0x2e, + 0xe0, 0x58, 0x51, 0xa0, 0xe7, 0x61, 0x34, 0xf2, 0xfc, 0x26, 0x91, 0x4e, 0x2f, 0x15, 0xe6, 0xf4, + 0xc2, 0x13, 0x95, 0x6a, 0x70, 0x6c, 0x50, 0xa1, 0xdb, 0x50, 0x65, 0xff, 0xd9, 0x0a, 0xea, 0xff, + 0x09, 0x10, 0x91, 0x9f, 0x5c, 0x30, 0xc0, 0x09, 0x2f, 0x74, 0x11, 0x20, 0x96, 0xee, 0x39, 0x91, + 0x08, 0x4b, 0x56, 0x7a, 0xa9, 0x72, 0xdc, 0x89, 0xb0, 0x46, 0x85, 0x9e, 0x81, 0x6a, 0xec, 0x78, + 0xad, 0xab, 0x9e, 0x4f, 0x22, 0xe1, 0xde, 0x24, 0x92, 0x8e, 0x0b, 0x20, 0x4e, 0xf0, 0x74, 0xbf, + 0x67, 0x41, 0xef, 0xfc, 0x79, 0xa1, 0x61, 0x46, 0xcd, 0xf6, 0xfb, 0xab, 0x0a, 0x8a, 0x35, 0x0a, + 0xfb, 0x25, 0x38, 0x59, 0x0f, 0xdc, 0x7a, 0x10, 0xc6, 0x2b, 0x41, 0x78, 0xcf, 0x09, 0x5d, 0x39, + 0x7e, 0x73, 0x32, 0xd7, 0x35, 0xdd, 0x93, 0x07, 0xb8, 0x15, 0xc1, 0xc8, 0x5d, 0xfd, 0x1c, 0xdb, + 0xf1, 0xfb, 0x0c, 0x55, 0xf9, 0x41, 0x09, 0x50, 0x9d, 0x39, 0x10, 0x19, 0xaf, 0x51, 0x6d, 0xc2, + 0x78, 0x44, 0xae, 0x7a, 0x7e, 0xe7, 0xbe, 0x60, 0x55, 0x2c, 0x36, 0xa8, 0xb1, 0xac, 0x97, 0xe1, + 0x76, 0x1a, 0x13, 0x86, 0x53, 0x7c, 0x69, 0x67, 0x86, 0x1d, 0x7f, 0x21, 0xba, 0x19, 0x91, 0x50, + 0xbc, 0xbe, 0xc4, 0x3a, 0x13, 0x4b, 0x20, 0x4e, 0xf0, 0x74, 0xf2, 0xb0, 0x3f, 0xd7, 0x03, 0x1f, + 0x07, 0x41, 0x2c, 0xa7, 0x1b, 0x7b, 0x8d, 0x43, 0x83, 0x63, 0x83, 0x0a, 0xad, 0x00, 0x8a, 0x3a, + 0xed, 0x76, 0x8b, 0xdd, 0x94, 0x3a, 0xad, 0x4b, 0x61, 0xd0, 0x69, 0x73, 0x3f, 0x72, 0xf1, 0x90, + 0x45, 0xa3, 0x0b, 0x8b, 0x33, 0x4a, 0x50, 0x61, 0xb1, 0x1e, 0xb1, 0xdf, 0x22, 0x02, 0x9e, 0x5b, + 0x5b, 0x1b, 0x0c, 0x84, 0x25, 0xce, 0xfe, 0x45, 0xb6, 0xc1, 0xb1, 0x67, 0x71, 0xe2, 0x4e, 0x48, + 0xd0, 0x16, 0x8c, 0xb5, 0xd9, 0x26, 0x16, 0x87, 0x41, 0xab, 0x45, 0xa4, 0x7e, 0x79, 0x38, 0x17, + 0x26, 0xfe, 0x10, 0x86, 0xce, 0x0e, 0x9b, 0xdc, 0xed, 0xff, 0x36, 0xce, 0x64, 0x95, 0xb8, 0xac, + 0x1e, 0x12, 0xce, 0xca, 0x42, 0x93, 0xfb, 0x48, 0x91, 0x07, 0xee, 0x92, 0x7d, 0x40, 0xb8, 0x3e, + 0x63, 0xc9, 0x05, 0x7d, 0x86, 0xb9, 0xe2, 0x73, 0x01, 0x51, 0xfc, 0xd9, 0x4e, 0x4e, 0x6f, 0xb8, + 0xe1, 0x0b, 0x16, 0x58, 0x63, 0x87, 0xae, 0xc2, 0x98, 0x78, 0x45, 0x45, 0x98, 0x29, 0xca, 0xc6, + 0x11, 0x7b, 0x0c, 0xeb, 0xc8, 0xfd, 0x34, 0x00, 0x9b, 0x85, 0xd1, 0x06, 0x3c, 0xaa, 0xbd, 0x12, + 0x96, 0xe1, 0x6e, 0xc7, 0x25, 0xcf, 0x63, 0x7b, 0xbb, 0x73, 0x8f, 0xae, 0x1d, 0x44, 0x88, 0x0f, + 0xe6, 0x83, 0x6e, 0xc0, 0x49, 0xa7, 0x19, 0x7b, 0xdb, 0xa4, 0x46, 0x1c, 0xb7, 0xe5, 0xf9, 0xc4, + 0x4c, 0x93, 0xf0, 0xf0, 0xde, 0xee, 0xdc, 0xc9, 0x85, 0x2c, 0x02, 0x9c, 0x5d, 0x0e, 0x7d, 0x12, + 0xaa, 0xae, 0x1f, 0x89, 0x3e, 0x18, 0x34, 0x1e, 0xc5, 0xab, 0xd6, 0xae, 0x37, 0xd4, 0xf7, 0x27, + 0x7f, 0x70, 0x52, 0x00, 0xbd, 0x0b, 0xa3, 0x7a, 0xf8, 0x93, 0x78, 0x8c, 0xf1, 0xc5, 0x42, 0xe7, + 0x67, 0x23, 0x66, 0x88, 0x5b, 0xf0, 0x94, 0x5b, 0xab, 0x11, 0x4e, 0x64, 0x54, 0x81, 0x7e, 0x1e, + 0x50, 0x44, 0xc2, 0x6d, 0xaf, 0x49, 0x16, 0x9a, 0x2c, 0xbb, 0x2f, 0xb3, 0xf1, 0x0c, 0x1b, 0xf1, + 0x1d, 0xa8, 0xd1, 0x45, 0x81, 0x33, 0x4a, 0xa1, 0xcb, 0x54, 0xf2, 0xe8, 0x50, 0xe1, 0x85, 0x2c, + 0x15, 0xc3, 0x99, 0x1a, 0x69, 0x87, 0xa4, 0xe9, 0xc4, 0xc4, 0x35, 0x39, 0xe2, 0x54, 0x39, 0xba, + 0x2f, 0xa9, 0x07, 0x1c, 0xc0, 0xf4, 0x9d, 0xed, 0x7e, 0xc4, 0x81, 0x9e, 0xb3, 0x36, 0x83, 0x28, + 0xbe, 0x4e, 0xe2, 0x7b, 0x41, 0x78, 0x57, 0x64, 0x44, 0x4b, 0x52, 0x25, 0x26, 0x28, 0xac, 0xd3, + 0x51, 0x1d, 0x8a, 0x5d, 0xfd, 0xad, 0xd6, 0xd8, 0xbd, 0xca, 0x70, 0xb2, 0x76, 0x2e, 0x73, 0x30, + 0x96, 0x78, 0x49, 0xba, 0x5a, 0x5f, 0x62, 0x77, 0x24, 0x29, 0xd2, 0xd5, 0xfa, 0x12, 0x96, 0x78, + 0x14, 0x74, 0x3f, 0x3d, 0x38, 0x5e, 0xe4, 0xbe, 0xaa, 0x5b, 0x92, 0x17, 0x7c, 0x7d, 0xf0, 0x3e, + 0x4c, 0xaa, 0xe7, 0x0f, 0x79, 0xd2, 0xb8, 0x68, 0x66, 0x82, 0x4d, 0x9c, 0xc3, 0xe4, 0x9e, 0x53, + 0x76, 0xbd, 0xd5, 0x14, 0x4f, 0xdc, 0x55, 0x8b, 0x91, 0x9c, 0x63, 0x32, 0xf7, 0x51, 0x8e, 0xf3, + 0x50, 0x8d, 0x3a, 0x77, 0xdc, 0x60, 0xcb, 0xf1, 0x7c, 0x76, 0x91, 0xa1, 0x29, 0x31, 0x0d, 0x89, + 0xc0, 0x09, 0x0d, 0xaa, 0xc3, 0xb0, 0x23, 0x8e, 0x70, 0xe2, 0xc2, 0x21, 0x27, 0x0a, 0x5f, 0x1e, + 0xf8, 0xb8, 0x75, 0x55, 0xfe, 0xc3, 0x8a, 0x0b, 0x7a, 0x19, 0xc6, 0x44, 0x10, 0x99, 0x70, 0xf6, + 0x3c, 0x61, 0x06, 0x1c, 0x34, 0x74, 0x24, 0x36, 0x69, 0xd1, 0x06, 0x8c, 0x53, 0x2e, 0x89, 0x00, + 0x9c, 0x99, 0xee, 0x4f, 0x86, 0x6a, 0xe9, 0xcf, 0x75, 0x36, 0x38, 0xc5, 0x16, 0xb9, 0xf0, 0x88, + 0xd3, 0x89, 0x83, 0x2d, 0xba, 0x12, 0xcc, 0x75, 0xb2, 0x16, 0xdc, 0x25, 0x3e, 0xbb, 0x65, 0x18, + 0x5e, 0x3c, 0xb3, 0xb7, 0x3b, 0xf7, 0xc8, 0xc2, 0x01, 0x74, 0xf8, 0x40, 0x2e, 0xe8, 0x2d, 0x18, + 0x89, 0x83, 0x96, 0xf0, 0xe1, 0x8e, 0x66, 0x4e, 0x15, 0x49, 0x42, 0xb4, 0xa6, 0x0a, 0xe8, 0x66, + 0x0c, 0xc5, 0x04, 0xeb, 0x1c, 0xd1, 0x9b, 0x7c, 0x55, 0xb2, 0x84, 0x99, 0x24, 0x9a, 0x79, 0xa8, + 0x48, 0x67, 0xa9, 0x0c, 0x9b, 0xe6, 0xf2, 0x15, 0x3c, 0xb0, 0xce, 0x70, 0xf6, 0xe7, 0x60, 0xaa, + 0x4b, 0xe4, 0xf5, 0xe5, 0xdc, 0xfa, 0x1f, 0x07, 0xa0, 0xaa, 0x2c, 0x86, 0xe8, 0xbc, 0x69, 0x1c, + 0x7e, 0x38, 0x6d, 0x1c, 0x1e, 0xa6, 0x0a, 0x9a, 0x6e, 0x0f, 0x7e, 0x33, 0xe3, 0x41, 0xfd, 0xa7, + 0x73, 0xd7, 0x78, 0xf1, 0xc8, 0x36, 0xed, 0x88, 0x57, 0x2e, 0x6c, 0x6f, 0xae, 0x1c, 0x78, 0x6a, + 0x2c, 0xf8, 0x48, 0x24, 0x3d, 0x1f, 0xb6, 0x03, 0x77, 0xb5, 0x9e, 0x7e, 0x03, 0xad, 0x4e, 0x81, + 0x98, 0xe3, 0x98, 0x5e, 0x4f, 0xf7, 0x6c, 0xa6, 0xd7, 0x0f, 0x1d, 0x52, 0xaf, 0x97, 0x0c, 0x70, + 0xc2, 0x0b, 0x6d, 0xc3, 0x54, 0xd3, 0x7c, 0xd2, 0x4e, 0xc5, 0xab, 0x3d, 0xdb, 0xc7, 0x93, 0x72, + 0x1d, 0xed, 0x45, 0x9a, 0xa5, 0x34, 0x3f, 0xdc, 0x5d, 0x05, 0x7a, 0x19, 0x86, 0xdf, 0x0d, 0x22, + 0x76, 0x6d, 0x21, 0x36, 0x2e, 0x19, 0x17, 0x34, 0xfc, 0xea, 0x8d, 0x06, 0x83, 0xef, 0xef, 0xce, + 0x8d, 0xd4, 0x03, 0x57, 0xfe, 0xc5, 0xaa, 0x00, 0xfa, 0xac, 0x05, 0x27, 0x8d, 0x75, 0xac, 0x5a, + 0x0e, 0x87, 0x69, 0xf9, 0xa3, 0xa2, 0xe6, 0x93, 0xab, 0x59, 0x3c, 0x71, 0x76, 0x55, 0xf6, 0x77, + 0xb9, 0x89, 0x54, 0x18, 0x4d, 0x48, 0xd4, 0x69, 0x1d, 0xc7, 0xeb, 0x10, 0x37, 0x0c, 0x7b, 0xce, + 0x03, 0x30, 0xd2, 0xff, 0x7b, 0x8b, 0x19, 0xe9, 0xd7, 0xc8, 0x56, 0xbb, 0xe5, 0xc4, 0xc7, 0xe1, + 0xfb, 0xfc, 0x19, 0x18, 0x8e, 0x45, 0x6d, 0xc5, 0x9e, 0xb6, 0xd0, 0x9a, 0xc7, 0x2e, 0x2f, 0xd4, + 0xc6, 0x27, 0xa1, 0x58, 0x31, 0xb4, 0xff, 0x15, 0x1f, 0x15, 0x89, 0x39, 0x06, 0x4b, 0xc4, 0x75, + 0xd3, 0x12, 0xf1, 0x54, 0xe1, 0x6f, 0xe9, 0x61, 0x91, 0xf8, 0x8e, 0xf9, 0x05, 0xec, 0x7c, 0xf2, + 0x93, 0x73, 0x8b, 0x64, 0xff, 0xba, 0x05, 0xd3, 0x59, 0xce, 0x08, 0x54, 0x81, 0xe1, 0xa7, 0x23, + 0x75, 0xbf, 0xa6, 0x7a, 0xf5, 0x96, 0x80, 0x63, 0x45, 0x51, 0x38, 0xd7, 0x7c, 0x7f, 0x29, 0xb4, + 0x6e, 0x80, 0xf9, 0x38, 0x22, 0x7a, 0x85, 0x87, 0x3a, 0x58, 0xea, 0xf5, 0xc2, 0xfe, 0xc2, 0x1c, + 0xec, 0x6f, 0x94, 0x60, 0x9a, 0x1b, 0xb9, 0x17, 0xb6, 0x03, 0xcf, 0xad, 0x07, 0xae, 0x08, 0xfc, + 0x70, 0x61, 0xb4, 0xad, 0x1d, 0x6e, 0x8b, 0xa5, 0xe4, 0xd1, 0x8f, 0xc3, 0xc9, 0x81, 0x42, 0x87, + 0x62, 0x83, 0x2b, 0xad, 0x85, 0x6c, 0x7b, 0x4d, 0x65, 0x33, 0x2d, 0xf5, 0xbd, 0x33, 0xa8, 0x5a, + 0x96, 0x35, 0x3e, 0xd8, 0xe0, 0x7a, 0x04, 0x4f, 0xc4, 0xd8, 0x7f, 0xdf, 0x82, 0x87, 0x7a, 0xa4, + 0xed, 0xa1, 0xd5, 0xdd, 0x63, 0x17, 0x0b, 0xe2, 0xf5, 0x4d, 0x55, 0x1d, 0xbf, 0x6e, 0xc0, 0x02, + 0x8b, 0xee, 0x00, 0xf0, 0xeb, 0x02, 0xaa, 0x4b, 0xa7, 0xef, 0xb2, 0x0b, 0x26, 0xc7, 0xd0, 0xf2, + 0x26, 0x48, 0x4e, 0x58, 0xe3, 0x6a, 0x7f, 0xad, 0x0c, 0x03, 0xfc, 0x91, 0xf7, 0x3a, 0x0c, 0x6d, + 0xf2, 0x7c, 0xc6, 0xfd, 0xa5, 0x53, 0x4e, 0x0e, 0x2f, 0x1c, 0x80, 0x25, 0x1b, 0x74, 0x0d, 0x4e, + 0x88, 0xd0, 0xa3, 0x1a, 0x69, 0x39, 0x3b, 0xf2, 0x34, 0xcc, 0xdf, 0x0d, 0x91, 0x09, 0xee, 0x4f, + 0xac, 0x76, 0x93, 0xe0, 0xac, 0x72, 0xe8, 0x95, 0xae, 0xf4, 0x83, 0x3c, 0x4f, 0xb4, 0xd2, 0x84, + 0x73, 0x52, 0x10, 0xbe, 0x0c, 0x63, 0xed, 0xae, 0x73, 0xbf, 0xf6, 0x96, 0xb6, 0x79, 0xd6, 0x37, + 0x69, 0x99, 0xef, 0x42, 0x87, 0xf9, 0x6c, 0xac, 0x6d, 0x86, 0x24, 0xda, 0x0c, 0x5a, 0xae, 0x78, + 0x06, 0x36, 0xf1, 0x5d, 0x48, 0xe1, 0x71, 0x57, 0x09, 0xca, 0x65, 0xdd, 0xf1, 0x5a, 0x9d, 0x90, + 0x24, 0x5c, 0x06, 0x4d, 0x2e, 0x2b, 0x29, 0x3c, 0xee, 0x2a, 0x41, 0xe7, 0xd6, 0x49, 0xf1, 0x72, + 0xa8, 0x0c, 0x52, 0x17, 0x22, 0xe8, 0xd3, 0x30, 0x24, 0x03, 0x08, 0x0a, 0xe5, 0x52, 0x11, 0x8e, + 0x09, 0xea, 0x15, 0x52, 0xed, 0x1d, 0x39, 0x11, 0x3a, 0x20, 0xf9, 0x1d, 0xe6, 0x85, 0xca, 0x3f, + 0xb7, 0xe0, 0x44, 0x86, 0x23, 0x1c, 0x17, 0x69, 0x1b, 0x5e, 0x14, 0xab, 0x57, 0x2c, 0x34, 0x91, + 0xc6, 0xe1, 0x58, 0x51, 0xd0, 0xd5, 0xc2, 0x85, 0x66, 0x5a, 0x50, 0x0a, 0x17, 0x13, 0x81, 0xed, + 0x4f, 0x50, 0xa2, 0x33, 0x50, 0xe9, 0x44, 0x24, 0x94, 0x0f, 0x3a, 0x4a, 0x39, 0xcf, 0xec, 0x8c, + 0x0c, 0x43, 0xd5, 0xd6, 0x0d, 0x65, 0xe2, 0xd3, 0xd4, 0x56, 0x6e, 0xe4, 0xe3, 0x38, 0xfb, 0xcb, + 0x65, 0x98, 0x48, 0x39, 0xc4, 0xd2, 0x86, 0x6c, 0x05, 0xbe, 0x17, 0x07, 0x2a, 0xbf, 0x1d, 0x7f, + 0x43, 0x8e, 0xb4, 0x37, 0xaf, 0x09, 0x38, 0x56, 0x14, 0xe8, 0x49, 0xf9, 0x42, 0x70, 0xfa, 0x75, + 0x8e, 0xc5, 0x9a, 0xf1, 0x48, 0x70, 0xd1, 0x97, 0x75, 0x1e, 0x87, 0x4a, 0x3b, 0x50, 0x0f, 0xbe, + 0xab, 0xf1, 0xc4, 0x8b, 0xb5, 0x7a, 0x10, 0xb4, 0x30, 0x43, 0xa2, 0x27, 0xc4, 0xd7, 0xa7, 0x6e, + 0x46, 0xb0, 0xe3, 0x06, 0x91, 0xd6, 0x05, 0x4f, 0xc1, 0xd0, 0x5d, 0xb2, 0x13, 0x7a, 0xfe, 0x46, + 0xfa, 0x5e, 0xe8, 0x0a, 0x07, 0x63, 0x89, 0x37, 0x93, 0xd5, 0x0f, 0x1d, 0xf1, 0xeb, 0x39, 0xc3, + 0xb9, 0xfb, 0xe0, 0x37, 0x2d, 0x98, 0x60, 0xd9, 0x67, 0x45, 0x8a, 0x04, 0x2f, 0xf0, 0x8f, 0x41, + 0xc7, 0x78, 0x1c, 0x06, 0x42, 0x5a, 0x69, 0xfa, 0xf9, 0x0b, 0xd6, 0x12, 0xcc, 0x71, 0xe8, 0x11, + 0xa8, 0xb0, 0x26, 0xd0, 0x61, 0x1c, 0xe5, 0x49, 0xee, 0x6b, 0x4e, 0xec, 0x60, 0x06, 0x65, 0x31, + 0x68, 0x98, 0xb4, 0x5b, 0x1e, 0x6f, 0x74, 0x62, 0xce, 0xfd, 0xa0, 0xc5, 0xa0, 0x65, 0x36, 0xf2, + 0x41, 0xc5, 0xa0, 0x65, 0x33, 0x3f, 0x58, 0xcf, 0xff, 0xef, 0x25, 0x38, 0x9d, 0x59, 0x2e, 0xb9, + 0x61, 0x5e, 0x31, 0x6e, 0x98, 0x2f, 0xa6, 0x6e, 0x98, 0xed, 0x83, 0x4b, 0x3f, 0x98, 0x3b, 0xe7, + 0xec, 0xab, 0xe0, 0xf2, 0x31, 0x5e, 0x05, 0x57, 0x8a, 0xaa, 0x38, 0x03, 0x39, 0x2a, 0xce, 0x1f, + 0x59, 0xf0, 0x70, 0x66, 0x97, 0x7d, 0xe0, 0x82, 0xfe, 0x32, 0x5b, 0xd9, 0xe3, 0x74, 0xf2, 0x6b, + 0xe5, 0x1e, 0x5f, 0xc5, 0xce, 0x29, 0x67, 0xa9, 0x14, 0x62, 0xc8, 0x48, 0x28, 0x6f, 0xa3, 0x5c, + 0x02, 0x71, 0x18, 0x56, 0x58, 0x14, 0x69, 0x41, 0x73, 0xbc, 0x91, 0xcb, 0x87, 0x5c, 0x50, 0xf3, + 0xa6, 0x1d, 0x5e, 0xcf, 0xfb, 0x90, 0x0e, 0xa5, 0xbb, 0xad, 0x9d, 0x3c, 0xcb, 0x87, 0x39, 0x79, + 0x8e, 0x66, 0x9f, 0x3a, 0xd1, 0x02, 0x4c, 0x6c, 0x79, 0x3e, 0x7b, 0x74, 0xd7, 0xd4, 0x9e, 0x54, + 0xe4, 0xf2, 0x35, 0x13, 0x8d, 0xd3, 0xf4, 0xb3, 0x2f, 0xc3, 0xd8, 0xe1, 0xad, 0x6b, 0x3f, 0x2a, + 0xc3, 0x87, 0x0f, 0x10, 0x0a, 0x7c, 0x77, 0x30, 0xc6, 0x45, 0xdb, 0x1d, 0xba, 0xc6, 0xa6, 0x0e, + 0xd3, 0xeb, 0x9d, 0x56, 0x6b, 0x87, 0xf9, 0x67, 0x11, 0x57, 0x52, 0x08, 0xa5, 0x46, 0x25, 0xa3, + 0x5e, 0xc9, 0xa0, 0xc1, 0x99, 0x25, 0xd1, 0xcf, 0x03, 0x0a, 0xee, 0xb0, 0xb4, 0xc8, 0x6e, 0x92, + 0xd7, 0x82, 0x0d, 0x41, 0x39, 0x59, 0xaa, 0x37, 0xba, 0x28, 0x70, 0x46, 0x29, 0xaa, 0xa7, 0xd2, + 0x7d, 0x6c, 0x47, 0x35, 0x2b, 0xa5, 0xa7, 0x62, 0x1d, 0x89, 0x4d, 0x5a, 0x74, 0x09, 0xa6, 0x9c, + 0x6d, 0xc7, 0xe3, 0x69, 0xce, 0x24, 0x03, 0xae, 0xa8, 0x2a, 0xfb, 0xd5, 0x42, 0x9a, 0x00, 0x77, + 0x97, 0x41, 0x6d, 0xc3, 0x20, 0xc9, 0x5f, 0x66, 0xf8, 0xe4, 0x21, 0x66, 0x70, 0x61, 0x13, 0xa5, + 0xfd, 0xa7, 0x16, 0xdd, 0xfa, 0x32, 0xde, 0x67, 0xa5, 0x3d, 0xa2, 0x0c, 0x6c, 0x5a, 0x10, 0xa0, + 0xea, 0x91, 0x25, 0x1d, 0x89, 0x4d, 0x5a, 0x3e, 0x35, 0xa2, 0xc4, 0x5d, 0xdc, 0xd0, 0x36, 0x45, + 0xfc, 0xac, 0xa2, 0xa0, 0x1a, 0xb4, 0xeb, 0x6d, 0x7b, 0x51, 0x10, 0x8a, 0x05, 0xd4, 0xef, 0x0b, + 0xe8, 0x4a, 0x5e, 0xd6, 0x38, 0x1b, 0x2c, 0xf9, 0xd9, 0x5f, 0x29, 0xc1, 0x98, 0xac, 0xf1, 0xd5, + 0x4e, 0x10, 0x3b, 0xc7, 0xb0, 0xa5, 0xbf, 0x6a, 0x6c, 0xe9, 0xe7, 0x8b, 0x85, 0x13, 0xb3, 0xc6, + 0xf5, 0xdc, 0xca, 0x3f, 0x9d, 0xda, 0xca, 0x2f, 0xf4, 0xc3, 0xf4, 0xe0, 0x2d, 0xfc, 0xdf, 0x58, + 0x30, 0x65, 0xd0, 0x1f, 0xc3, 0x4e, 0x52, 0x37, 0x77, 0x92, 0x67, 0xfa, 0xf8, 0x9a, 0x1e, 0x3b, + 0xc8, 0xd7, 0x4b, 0xa9, 0xaf, 0x60, 0x3b, 0xc7, 0x2f, 0x40, 0x65, 0xd3, 0x09, 0xdd, 0x62, 0x39, + 0x3f, 0xbb, 0x8a, 0xcf, 0x5f, 0x76, 0x42, 0x97, 0xcb, 0xff, 0x73, 0xea, 0xf5, 0x38, 0x27, 0x74, + 0x73, 0xa3, 0x28, 0x58, 0xa5, 0xe8, 0x25, 0x18, 0x8c, 0x9a, 0x41, 0x5b, 0xf9, 0x99, 0x9e, 0xe1, + 0x2f, 0xcb, 0x51, 0xc8, 0xfe, 0xee, 0x1c, 0x32, 0xab, 0xa3, 0x60, 0x2c, 0xe8, 0x67, 0x37, 0xa0, + 0xaa, 0xaa, 0x3e, 0x52, 0x4f, 0xfb, 0xff, 0x5a, 0x86, 0x13, 0x19, 0x73, 0x05, 0xfd, 0xa2, 0xd1, + 0x6f, 0x2f, 0xf7, 0x3d, 0xd9, 0xde, 0x67, 0xcf, 0xfd, 0x22, 0x3b, 0x29, 0xb9, 0x62, 0x76, 0x1c, + 0xa2, 0xfa, 0x9b, 0x11, 0x49, 0x57, 0x4f, 0x41, 0xf9, 0xd5, 0xd3, 0x6a, 0x8f, 0xad, 0xfb, 0x69, + 0x45, 0xaa, 0xa5, 0x47, 0x3a, 0xce, 0x5f, 0xa8, 0xc0, 0x74, 0x56, 0xde, 0x02, 0xf4, 0x2b, 0x56, + 0xea, 0x85, 0x91, 0x57, 0xfa, 0x4f, 0x7e, 0xc0, 0x9f, 0x1d, 0x11, 0x59, 0x85, 0xe6, 0xcd, 0x37, + 0x47, 0x72, 0x7b, 0x5c, 0xd4, 0xce, 0xe2, 0x9f, 0x42, 0xfe, 0x5a, 0x8c, 0x94, 0x0a, 0x9f, 0x3a, + 0x44, 0x53, 0xc4, 0x83, 0x33, 0x51, 0x2a, 0xfe, 0x49, 0x82, 0xf3, 0xe3, 0x9f, 0x64, 0x1b, 0x66, + 0x3d, 0x18, 0xd1, 0xbe, 0xeb, 0x48, 0xa7, 0xc1, 0x5d, 0xba, 0x45, 0x69, 0xed, 0x3e, 0xd2, 0xa9, + 0xf0, 0x77, 0x2c, 0x48, 0x39, 0x85, 0x29, 0xb3, 0x8c, 0xd5, 0xd3, 0x2c, 0x73, 0x06, 0x2a, 0x61, + 0xd0, 0x22, 0xe9, 0x47, 0x27, 0x70, 0xd0, 0x22, 0x98, 0x61, 0xd4, 0x83, 0xd2, 0xe5, 0x5e, 0x0f, + 0x4a, 0xd3, 0x73, 0x7a, 0x8b, 0x6c, 0x13, 0x69, 0x24, 0x51, 0x62, 0xfc, 0x2a, 0x05, 0x62, 0x8e, + 0xb3, 0x7f, 0xa7, 0x02, 0x27, 0x32, 0x62, 0x01, 0xe9, 0x09, 0x69, 0xc3, 0x89, 0xc9, 0x3d, 0x67, + 0x27, 0x9d, 0xfc, 0xf6, 0x12, 0x07, 0x63, 0x89, 0x67, 0xce, 0xac, 0x3c, 0x81, 0x5e, 0xca, 0x74, + 0x25, 0xf2, 0xe6, 0x09, 0xec, 0xd1, 0x3f, 0x3d, 0x7c, 0x11, 0x20, 0x8a, 0x5a, 0xcb, 0x3e, 0xd5, + 0xf0, 0x5c, 0xe1, 0x34, 0x9b, 0xe4, 0x5d, 0x6c, 0x5c, 0x15, 0x18, 0xac, 0x51, 0xa1, 0x1a, 0x4c, + 0xb6, 0xc3, 0x20, 0xe6, 0x86, 0xc1, 0x1a, 0x77, 0xb4, 0x18, 0x30, 0xa3, 0xb5, 0xea, 0x29, 0x3c, + 0xee, 0x2a, 0x81, 0x5e, 0x80, 0x11, 0x11, 0xc1, 0x55, 0x0f, 0x82, 0x96, 0x30, 0x23, 0xa9, 0xeb, + 0xf8, 0x46, 0x82, 0xc2, 0x3a, 0x9d, 0x56, 0x8c, 0x59, 0x1b, 0x87, 0x32, 0x8b, 0x71, 0x8b, 0xa3, + 0x46, 0x97, 0xca, 0x6e, 0x32, 0x5c, 0x28, 0xbb, 0x49, 0x62, 0x58, 0xab, 0x16, 0xbe, 0x88, 0x81, + 0x5c, 0x03, 0xd4, 0x1f, 0x96, 0x61, 0x90, 0x0f, 0xc5, 0x31, 0x68, 0x79, 0x75, 0x61, 0x52, 0x2a, + 0x94, 0x49, 0x82, 0xb7, 0x6a, 0xbe, 0xe6, 0xc4, 0x0e, 0x17, 0x4d, 0x6a, 0x85, 0x24, 0x66, 0x28, + 0x34, 0x6f, 0xac, 0xa1, 0xd9, 0x94, 0xa5, 0x04, 0x38, 0x0f, 0x6d, 0x45, 0x6d, 0x02, 0x44, 0xec, + 0xf9, 0x5b, 0xca, 0x43, 0x64, 0xe6, 0x7d, 0xbe, 0x50, 0x3b, 0x1a, 0xaa, 0x18, 0x6f, 0x4d, 0x32, + 0x2d, 0x15, 0x02, 0x6b, 0xbc, 0x67, 0x5f, 0x84, 0xaa, 0x22, 0xce, 0x3b, 0x42, 0x8e, 0xea, 0xa2, + 0xed, 0x67, 0x61, 0x22, 0x55, 0x57, 0x5f, 0x27, 0xd0, 0xdf, 0xb3, 0x60, 0x82, 0x37, 0x79, 0xd9, + 0xdf, 0x16, 0xa2, 0xe0, 0x73, 0x16, 0x4c, 0xb7, 0x32, 0x56, 0xa2, 0x18, 0xe6, 0xc3, 0xac, 0x61, + 0x75, 0xf8, 0xcc, 0xc2, 0xe2, 0xcc, 0xda, 0xd0, 0x59, 0x18, 0xe6, 0xaf, 0x79, 0x3b, 0x2d, 0xe1, + 0xa1, 0x3d, 0xca, 0x73, 0x92, 0x73, 0x18, 0x56, 0x58, 0xfb, 0xc7, 0x16, 0x4c, 0xf1, 0x8f, 0xb8, + 0x42, 0x76, 0xd4, 0xf1, 0xea, 0x03, 0xf2, 0x19, 0x22, 0xfb, 0x7a, 0xa9, 0x47, 0xf6, 0x75, 0xfd, + 0x2b, 0xcb, 0x07, 0x7e, 0xe5, 0x37, 0x2c, 0x10, 0x33, 0xf4, 0x18, 0xce, 0x0f, 0xab, 0xe6, 0xf9, + 0xe1, 0x23, 0x45, 0x26, 0x7d, 0x8f, 0x83, 0xc3, 0xaf, 0x96, 0x60, 0x92, 0x13, 0x24, 0x37, 0x32, + 0x1f, 0x94, 0xc1, 0xe9, 0xef, 0x55, 0x20, 0xf5, 0x26, 0x6c, 0xf6, 0x97, 0x1a, 0x63, 0x59, 0x39, + 0x70, 0x2c, 0xff, 0xa7, 0x05, 0x88, 0xf7, 0x49, 0xfa, 0x29, 0x74, 0xbe, 0xbb, 0x69, 0xe6, 0x80, + 0x44, 0x72, 0x28, 0x0c, 0xd6, 0xa8, 0x1e, 0xf0, 0x27, 0xa4, 0xee, 0xc3, 0xca, 0xf9, 0xf7, 0x61, + 0x7d, 0x7c, 0xf5, 0x77, 0xcb, 0x90, 0x76, 0xd5, 0x44, 0x6f, 0xc3, 0x68, 0xd3, 0x69, 0x3b, 0x77, + 0xbc, 0x96, 0x17, 0x7b, 0x24, 0x2a, 0x76, 0xe1, 0xbe, 0xa4, 0x95, 0x10, 0xd7, 0x50, 0x1a, 0x04, + 0x1b, 0x1c, 0xd1, 0x3c, 0x40, 0x3b, 0xf4, 0xb6, 0xbd, 0x16, 0xd9, 0x60, 0x27, 0x1e, 0x16, 0xeb, + 0xc1, 0xef, 0x8e, 0x25, 0x14, 0x6b, 0x14, 0x19, 0xb1, 0x01, 0xe5, 0xe3, 0x88, 0x0d, 0xa8, 0xf4, + 0x19, 0x1b, 0x30, 0x50, 0x28, 0x36, 0x00, 0xc3, 0x29, 0xb9, 0x79, 0xd3, 0xff, 0x2b, 0x5e, 0x8b, + 0x08, 0xdd, 0x8d, 0xc7, 0x82, 0xcc, 0xee, 0xed, 0xce, 0x9d, 0xc2, 0x99, 0x14, 0xb8, 0x47, 0x49, + 0xbb, 0x03, 0x27, 0x1a, 0x24, 0x94, 0xcf, 0xd8, 0xa9, 0xb5, 0xf4, 0x26, 0x54, 0xc3, 0xd4, 0x32, + 0xee, 0x33, 0xe0, 0x5f, 0xcb, 0xf1, 0x26, 0x97, 0x6d, 0xc2, 0xd2, 0xfe, 0xeb, 0x25, 0x18, 0x12, + 0x4e, 0x9a, 0xc7, 0xa0, 0x7c, 0x5c, 0x31, 0x4c, 0x4c, 0x4f, 0xe5, 0xc9, 0x3f, 0xd6, 0xac, 0x9e, + 0xc6, 0xa5, 0x46, 0xca, 0xb8, 0xf4, 0x4c, 0x31, 0x76, 0x07, 0x9b, 0x95, 0x7e, 0xab, 0x0c, 0xe3, + 0xa6, 0xd3, 0xea, 0x31, 0x74, 0xcb, 0x6b, 0x30, 0x14, 0x09, 0xff, 0xe9, 0x52, 0x11, 0x9f, 0xbd, + 0xf4, 0x10, 0x27, 0x37, 0xf1, 0xc2, 0x63, 0x5a, 0xb2, 0xcb, 0x74, 0xd1, 0x2e, 0x1f, 0x8b, 0x8b, + 0x76, 0x9e, 0x2f, 0x71, 0xe5, 0x41, 0xf8, 0x12, 0xdb, 0xdf, 0x63, 0x22, 0x5f, 0x87, 0x1f, 0xc3, + 0x36, 0xfe, 0xaa, 0xb9, 0x39, 0x9c, 0x2b, 0x34, 0xef, 0x44, 0xf3, 0x7a, 0x6c, 0xe7, 0xdf, 0xb2, + 0x60, 0x44, 0x10, 0x1e, 0xc3, 0x07, 0xfc, 0xbc, 0xf9, 0x01, 0x4f, 0x14, 0xfa, 0x80, 0x1e, 0x2d, + 0xff, 0x4a, 0x49, 0xb5, 0xbc, 0x1e, 0x84, 0x71, 0xa1, 0x4c, 0xe8, 0xc3, 0xf4, 0xe8, 0x17, 0x34, + 0x83, 0x96, 0x50, 0xe0, 0x1e, 0x49, 0x42, 0xff, 0x38, 0x7c, 0x5f, 0xfb, 0x8d, 0x15, 0x35, 0x8b, + 0x4c, 0x0b, 0xc2, 0x58, 0x6c, 0xa0, 0x49, 0x64, 0x5a, 0x10, 0xc6, 0x98, 0x61, 0x90, 0x0b, 0x10, + 0x3b, 0xe1, 0x06, 0x89, 0x29, 0x4c, 0x44, 0xcd, 0xf6, 0x5e, 0xad, 0x9d, 0xd8, 0x6b, 0xcd, 0x7b, + 0x7e, 0x1c, 0xc5, 0xe1, 0xfc, 0xaa, 0x1f, 0xdf, 0x08, 0xb9, 0xd2, 0xaf, 0xc5, 0xf2, 0x29, 0x5e, + 0x58, 0xe3, 0x2b, 0x83, 0x44, 0x58, 0x1d, 0x03, 0xe6, 0x0d, 0xd2, 0x75, 0x01, 0xc7, 0x8a, 0xc2, + 0x7e, 0x91, 0x49, 0x76, 0xd6, 0x41, 0xfd, 0x85, 0xd9, 0x7d, 0x61, 0x48, 0x75, 0x2d, 0x33, 0x0b, + 0x5f, 0xd7, 0x83, 0xf9, 0x8a, 0x8a, 0x4f, 0xda, 0x04, 0xdd, 0x8f, 0x3a, 0x89, 0xfd, 0x43, 0xa4, + 0xeb, 0xda, 0xf1, 0xc5, 0xc2, 0x12, 0xb9, 0x8f, 0x8b, 0x46, 0x96, 0x92, 0x91, 0xe5, 0xa1, 0x5b, + 0xad, 0xa7, 0xf3, 0xd7, 0x2f, 0x49, 0x04, 0x4e, 0x68, 0xd0, 0x79, 0x71, 0xa0, 0xe4, 0x16, 0x97, + 0x0f, 0xa7, 0x0e, 0x94, 0xb2, 0x4b, 0xb4, 0x13, 0xe5, 0x05, 0x18, 0x51, 0x4f, 0x02, 0xd5, 0xf9, + 0x63, 0x2c, 0x55, 0xae, 0x5f, 0x2d, 0x27, 0x60, 0xac, 0xd3, 0xa0, 0x35, 0x98, 0x88, 0xf8, 0x7b, + 0x45, 0x32, 0x5a, 0x43, 0x18, 0x0e, 0x9e, 0x96, 0x97, 0x94, 0x0d, 0x13, 0xbd, 0xcf, 0x40, 0x7c, + 0x29, 0xcb, 0xf8, 0x8e, 0x34, 0x0b, 0xf4, 0x0a, 0x8c, 0xb7, 0xf4, 0x37, 0x5c, 0xeb, 0xc2, 0xae, + 0xa0, 0xdc, 0xce, 0x8c, 0x17, 0x5e, 0xeb, 0x38, 0x45, 0x8d, 0x5e, 0x83, 0x19, 0x1d, 0x22, 0x92, + 0x0b, 0x39, 0xfe, 0x06, 0x89, 0xc4, 0xdb, 0x26, 0x8f, 0xec, 0xed, 0xce, 0xcd, 0x5c, 0xed, 0x41, + 0x83, 0x7b, 0x96, 0x46, 0x2f, 0xc1, 0xa8, 0xfc, 0x7c, 0x2d, 0xb6, 0x29, 0x71, 0x78, 0xd4, 0x70, + 0xd8, 0xa0, 0x44, 0xf7, 0xe0, 0xa4, 0xfc, 0xbf, 0x16, 0x3a, 0xeb, 0xeb, 0x5e, 0x53, 0x04, 0x99, + 0x8d, 0x30, 0x16, 0x0b, 0xd2, 0x5f, 0x7c, 0x39, 0x8b, 0x68, 0x7f, 0x77, 0xee, 0x8c, 0xe8, 0xb5, + 0x4c, 0x3c, 0x1b, 0xc4, 0x6c, 0xfe, 0xe8, 0x1a, 0x9c, 0xd8, 0x24, 0x4e, 0x2b, 0xde, 0x5c, 0xda, + 0x24, 0xcd, 0xbb, 0x72, 0x61, 0xb1, 0x88, 0x29, 0xcd, 0x25, 0xf0, 0x72, 0x37, 0x09, 0xce, 0x2a, + 0xf7, 0xfe, 0xee, 0x94, 0x7f, 0x81, 0x16, 0xd6, 0xf4, 0x07, 0xf4, 0x0e, 0x8c, 0xea, 0x7d, 0x9d, + 0x56, 0x0c, 0xf2, 0xdf, 0xf7, 0x15, 0x7a, 0x88, 0x1a, 0x01, 0x1d, 0x87, 0x0d, 0xde, 0xf6, 0xbf, + 0x2b, 0xc1, 0x5c, 0x4e, 0xee, 0xae, 0x94, 0x35, 0xcb, 0x2a, 0x64, 0xcd, 0x5a, 0x90, 0x6f, 0xde, + 0x5c, 0x4f, 0xe5, 0x4c, 0x4f, 0xbd, 0x62, 0x93, 0x64, 0x4e, 0x4f, 0xd3, 0x17, 0xf6, 0x34, 0xd3, + 0x0d, 0x62, 0x95, 0x5c, 0x87, 0xbb, 0xd7, 0x75, 0x1b, 0xe7, 0xc0, 0x61, 0x94, 0xde, 0x9e, 0xe6, + 0x4d, 0xfb, 0x7b, 0x25, 0x38, 0xa9, 0x3a, 0xf3, 0xa7, 0xb7, 0x0b, 0xdf, 0xea, 0xee, 0xc2, 0x07, + 0x6a, 0x26, 0xb6, 0x6f, 0xc0, 0x60, 0x63, 0x27, 0x6a, 0xc6, 0xad, 0x02, 0x3b, 0xfe, 0xe3, 0xc6, + 0xba, 0x4a, 0x76, 0x23, 0xf6, 0x92, 0x9d, 0x58, 0x66, 0xf6, 0xe7, 0x2d, 0x98, 0x58, 0x5b, 0xaa, + 0x37, 0x82, 0xe6, 0x5d, 0x12, 0x2f, 0x70, 0x83, 0x06, 0x16, 0x1b, 0xbe, 0x75, 0xc8, 0x8d, 0x3c, + 0x4b, 0x45, 0x38, 0x03, 0x95, 0xcd, 0x20, 0x8a, 0xd3, 0x97, 0x02, 0x97, 0x83, 0x28, 0xc6, 0x0c, + 0x63, 0xff, 0x99, 0x05, 0x03, 0xec, 0xa1, 0xb6, 0xbc, 0x47, 0xfe, 0x8a, 0x7c, 0x17, 0x7a, 0x01, + 0x06, 0xc9, 0xfa, 0x3a, 0x69, 0xc6, 0x62, 0x7c, 0x65, 0x80, 0xcd, 0xe0, 0x32, 0x83, 0xd2, 0x1d, + 0x8d, 0x55, 0xc6, 0xff, 0x62, 0x41, 0x8c, 0x3e, 0x03, 0xd5, 0xd8, 0xdb, 0x22, 0x0b, 0xae, 0x2b, + 0xac, 0xf0, 0xfd, 0xf9, 0x7c, 0xa9, 0x1d, 0x76, 0x4d, 0x32, 0xc1, 0x09, 0x3f, 0xfb, 0x4b, 0x25, + 0x80, 0x24, 0x7c, 0x2e, 0xef, 0x33, 0x17, 0xbb, 0xde, 0x32, 0x7c, 0x32, 0xe3, 0x2d, 0x43, 0x94, + 0x30, 0xcc, 0x78, 0xc9, 0x50, 0x75, 0x55, 0xb9, 0x50, 0x57, 0x55, 0xfa, 0xe9, 0xaa, 0x25, 0x98, + 0x4a, 0xc2, 0xff, 0xcc, 0x38, 0x6a, 0x96, 0x6f, 0x78, 0x2d, 0x8d, 0xc4, 0xdd, 0xf4, 0xf6, 0x97, + 0x2c, 0x10, 0x5e, 0xc2, 0x05, 0x26, 0xb4, 0x2b, 0xdf, 0x1d, 0x33, 0x52, 0x0b, 0x3e, 0x5d, 0xc4, + 0x81, 0x5a, 0x24, 0x14, 0x54, 0x72, 0xdf, 0x48, 0x23, 0x68, 0x70, 0xb5, 0x7f, 0xdb, 0x82, 0x11, + 0x8e, 0xbe, 0xc6, 0x0e, 0xa2, 0xf9, 0xed, 0xea, 0x2b, 0x99, 0x35, 0x7b, 0x92, 0x8b, 0x32, 0x56, + 0x49, 0x8d, 0xf5, 0x27, 0xb9, 0x24, 0x02, 0x27, 0x34, 0xe8, 0x29, 0x18, 0x8a, 0x3a, 0x77, 0x18, + 0x79, 0xca, 0x65, 0xb8, 0xc1, 0xc1, 0x58, 0xe2, 0xed, 0x7f, 0x5a, 0x82, 0xc9, 0xb4, 0xc7, 0x38, + 0xc2, 0x30, 0xc8, 0x05, 0x48, 0xfa, 0x4c, 0x73, 0x90, 0x01, 0x54, 0xf3, 0x38, 0x07, 0xfe, 0xb0, + 0x3c, 0x13, 0x41, 0x82, 0x13, 0x5a, 0x87, 0x11, 0x37, 0xb8, 0xe7, 0xdf, 0x73, 0x42, 0x77, 0xa1, + 0xbe, 0x2a, 0x46, 0x22, 0xc7, 0xc7, 0xaf, 0x96, 0x14, 0xd0, 0xfd, 0xd9, 0x99, 0x41, 0x2e, 0x41, + 0x61, 0x9d, 0x31, 0x7a, 0x93, 0x65, 0x42, 0x59, 0xf7, 0x36, 0xae, 0x39, 0xed, 0x62, 0xde, 0x2c, + 0x4b, 0x92, 0x5c, 0xab, 0x63, 0x4c, 0x24, 0x4e, 0xe1, 0x08, 0x9c, 0xb0, 0xb4, 0x7f, 0xf5, 0x24, + 0x18, 0x73, 0xc1, 0xc8, 0x38, 0x6d, 0x3d, 0xf0, 0x8c, 0xd3, 0x6f, 0xc0, 0x30, 0xd9, 0x6a, 0xc7, + 0x3b, 0x35, 0x2f, 0x2c, 0xf6, 0x7e, 0xc0, 0xb2, 0xa0, 0xee, 0xe6, 0x2e, 0x31, 0x58, 0x71, 0xec, + 0x91, 0x3f, 0xbc, 0xfc, 0x81, 0xc8, 0x1f, 0x5e, 0xf9, 0x4b, 0xc9, 0x1f, 0xfe, 0x1a, 0x0c, 0x6d, + 0x78, 0x31, 0x26, 0xed, 0x40, 0xec, 0xc6, 0x39, 0x93, 0xe7, 0x12, 0x27, 0xee, 0xce, 0x2c, 0x2b, + 0x10, 0x58, 0xb2, 0x43, 0x6b, 0x6a, 0x51, 0x0d, 0x16, 0xd1, 0x41, 0xbb, 0x0d, 0xe4, 0x99, 0xcb, + 0x4a, 0xe4, 0x0b, 0x1f, 0x7a, 0xff, 0xf9, 0xc2, 0x55, 0x96, 0xef, 0xe1, 0x07, 0x95, 0xe5, 0xdb, + 0xc8, 0x96, 0x5e, 0x3d, 0x8a, 0x6c, 0xe9, 0x5f, 0xb2, 0xe0, 0x64, 0x3b, 0xeb, 0xad, 0x01, 0x91, + 0xaf, 0xfb, 0xe7, 0x0e, 0xf1, 0xfa, 0x82, 0x51, 0x35, 0xcb, 0xef, 0x91, 0x49, 0x86, 0xb3, 0x2b, + 0x96, 0x69, 0xd7, 0x47, 0xde, 0x7f, 0xda, 0xf5, 0xa3, 0x4e, 0xec, 0x9d, 0x24, 0x61, 0x1f, 0x3b, + 0x92, 0x24, 0xec, 0xe3, 0x0f, 0x30, 0x09, 0xbb, 0x96, 0x3e, 0x7d, 0xe2, 0xc1, 0xa6, 0x4f, 0xdf, + 0x34, 0xf7, 0x25, 0x9e, 0xad, 0xfb, 0x85, 0xc2, 0xfb, 0x92, 0x51, 0xc3, 0xc1, 0x3b, 0x13, 0x4f, + 0x24, 0x3f, 0xf5, 0x3e, 0x13, 0xc9, 0x1b, 0xe9, 0xd8, 0xd1, 0x51, 0xa4, 0x63, 0x7f, 0x5b, 0xdf, + 0x41, 0x4f, 0x14, 0xa9, 0x41, 0x6d, 0x94, 0xdd, 0x35, 0x64, 0xed, 0xa1, 0xdd, 0x09, 0xdf, 0xa7, + 0x8f, 0x3b, 0xe1, 0xfb, 0xc9, 0x23, 0x4c, 0xf8, 0x7e, 0xea, 0x58, 0x13, 0xbe, 0x3f, 0xf4, 0x01, + 0x49, 0xf8, 0x3e, 0x73, 0x5c, 0x09, 0xdf, 0x1f, 0x7e, 0xb0, 0x09, 0xdf, 0xdf, 0x86, 0x6a, 0x5b, + 0xc6, 0x5d, 0xce, 0xcc, 0x16, 0x19, 0xba, 0xcc, 0x30, 0x4d, 0x3e, 0x74, 0x0a, 0x85, 0x13, 0xa6, + 0xb4, 0x86, 0x24, 0x01, 0xfc, 0x87, 0x8b, 0xd4, 0x90, 0x69, 0xf7, 0x38, 0x20, 0xed, 0xfb, 0x17, + 0x4a, 0x70, 0xfa, 0xe0, 0xd5, 0x91, 0x18, 0x4d, 0xea, 0x89, 0x2d, 0x3b, 0x65, 0x34, 0x61, 0x9a, + 0xa7, 0x46, 0x55, 0x38, 0x9c, 0xfd, 0x12, 0x4c, 0x29, 0x3f, 0xaf, 0x96, 0xd7, 0xdc, 0xd1, 0x9e, + 0xa1, 0x52, 0xf1, 0x09, 0x8d, 0x34, 0x01, 0xee, 0x2e, 0x83, 0x16, 0x60, 0xc2, 0x00, 0xae, 0xd6, + 0xc4, 0xf9, 0x45, 0x59, 0x69, 0x1a, 0x26, 0x1a, 0xa7, 0xe9, 0xed, 0xaf, 0x5b, 0xf0, 0x50, 0x8f, + 0x0c, 0xaf, 0x85, 0x63, 0xb4, 0xdb, 0x30, 0xd1, 0x36, 0x8b, 0x16, 0x4e, 0xf9, 0x60, 0x64, 0x94, + 0x55, 0xad, 0x4e, 0x21, 0x70, 0x9a, 0xfd, 0xe2, 0xd9, 0xef, 0xff, 0xe8, 0xf4, 0x87, 0x7e, 0xf0, + 0xa3, 0xd3, 0x1f, 0xfa, 0xe1, 0x8f, 0x4e, 0x7f, 0xe8, 0x97, 0xf6, 0x4e, 0x5b, 0xdf, 0xdf, 0x3b, + 0x6d, 0xfd, 0x60, 0xef, 0xb4, 0xf5, 0xc3, 0xbd, 0xd3, 0xd6, 0x9f, 0xef, 0x9d, 0xb6, 0xbe, 0xf4, + 0xe3, 0xd3, 0x1f, 0x7a, 0xbd, 0xb4, 0x7d, 0xe1, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x1c, + 0xd0, 0x1f, 0x95, 0xd0, 0x00, 0x00, } diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/types.generated.go b/vendor/k8s.io/kubernetes/pkg/api/v1/types.generated.go index 9bd5aa8456..e289f199bb 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/types.generated.go +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/types.generated.go @@ -11488,7 +11488,7 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { _, _, _ = yysep2, yyq2, yy2arr2 const yyr2 bool = false yyq2[0] = x.Medium != "" - yyq2[1] = true + yyq2[1] = x.SizeLimit != nil var yynn2 int if yyr2 || yy2arr2 { r.EncodeArrayStart(2) @@ -11520,15 +11520,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { if yyr2 || yy2arr2 { z.EncSendContainerState(codecSelfer_containerArrayElem1234) if yyq2[1] { - yy7 := &x.SizeLimit - yym8 := z.EncBinary() - _ = yym8 - if false { - } else if z.HasExtensions() && z.EncExt(yy7) { - } else if !yym8 && z.IsJSONHandle() { - z.EncJSONMarshal(yy7) + if x.SizeLimit == nil { + r.EncodeNil() } else { - z.EncFallback(yy7) + yym7 := z.EncBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.EncExt(x.SizeLimit) { + } else if !yym7 && z.IsJSONHandle() { + z.EncJSONMarshal(x.SizeLimit) + } else { + z.EncFallback(x.SizeLimit) + } } } else { r.EncodeNil() @@ -11538,15 +11541,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { z.EncSendContainerState(codecSelfer_containerMapKey1234) r.EncodeString(codecSelferC_UTF81234, string("sizeLimit")) z.EncSendContainerState(codecSelfer_containerMapValue1234) - yy9 := &x.SizeLimit - yym10 := z.EncBinary() - _ = yym10 - if false { - } else if z.HasExtensions() && z.EncExt(yy9) { - } else if !yym10 && z.IsJSONHandle() { - z.EncJSONMarshal(yy9) + if x.SizeLimit == nil { + r.EncodeNil() } else { - z.EncFallback(yy9) + yym8 := z.EncBinary() + _ = yym8 + if false { + } else if z.HasExtensions() && z.EncExt(x.SizeLimit) { + } else if !yym8 && z.IsJSONHandle() { + z.EncJSONMarshal(x.SizeLimit) + } else { + z.EncFallback(x.SizeLimit) + } } } } @@ -11620,17 +11626,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decode } case "sizeLimit": if r.TryDecodeAsNil() { - x.SizeLimit = pkg3_resource.Quantity{} + if x.SizeLimit != nil { + x.SizeLimit = nil + } } else { - yyv5 := &x.SizeLimit + if x.SizeLimit == nil { + x.SizeLimit = new(pkg3_resource.Quantity) + } yym6 := z.DecBinary() _ = yym6 if false { - } else if z.HasExtensions() && z.DecExt(yyv5) { + } else if z.HasExtensions() && z.DecExt(x.SizeLimit) { } else if !yym6 && z.IsJSONHandle() { - z.DecJSONUnmarshal(yyv5) + z.DecJSONUnmarshal(x.SizeLimit) } else { - z.DecFallback(yyv5, false) + z.DecFallback(x.SizeLimit, false) } } default: @@ -11676,17 +11686,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco } z.DecSendContainerState(codecSelfer_containerArrayElem1234) if r.TryDecodeAsNil() { - x.SizeLimit = pkg3_resource.Quantity{} + if x.SizeLimit != nil { + x.SizeLimit = nil + } } else { - yyv9 := &x.SizeLimit + if x.SizeLimit == nil { + x.SizeLimit = new(pkg3_resource.Quantity) + } yym10 := z.DecBinary() _ = yym10 if false { - } else if z.HasExtensions() && z.DecExt(yyv9) { + } else if z.HasExtensions() && z.DecExt(x.SizeLimit) { } else if !yym10 && z.IsJSONHandle() { - z.DecJSONUnmarshal(yyv9) + z.DecJSONUnmarshal(x.SizeLimit) } else { - z.DecFallback(yyv9, false) + z.DecFallback(x.SizeLimit, false) } } for { diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/types.go b/vendor/k8s.io/kubernetes/pkg/api/v1/types.go index cdb0088c46..940f0e3254 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/types.go +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/types.go @@ -700,7 +700,7 @@ type EmptyDirVolumeSource struct { // The default is nil which means that the limit is undefined. // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir // +optional - SizeLimit resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"` + SizeLimit *resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"` } // Represents a Glusterfs mount that lasts the lifetime of a pod. diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.conversion.go index 9897d4710a..4492a06379 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.conversion.go +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.conversion.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + resource "k8s.io/apimachinery/pkg/api/resource" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" @@ -1240,7 +1241,7 @@ func Convert_api_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *api.D func autoConvert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVolumeSource, out *api.EmptyDirVolumeSource, s conversion.Scope) error { out.Medium = api.StorageMedium(in.Medium) - out.SizeLimit = in.SizeLimit + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) return nil } @@ -1251,7 +1252,7 @@ func Convert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVol func autoConvert_api_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *api.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error { out.Medium = StorageMedium(in.Medium) - out.SizeLimit = in.SizeLimit + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) return nil } diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.deepcopy.go index b909d9b332..18cd4311e8 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/kubernetes/pkg/api/v1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + resource "k8s.io/apimachinery/pkg/api/resource" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" @@ -858,7 +859,11 @@ func DeepCopy_v1_EmptyDirVolumeSource(in interface{}, out interface{}, c *conver in := in.(*EmptyDirVolumeSource) out := out.(*EmptyDirVolumeSource) *out = *in - out.SizeLimit = in.SizeLimit.DeepCopy() + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + *out = new(resource.Quantity) + **out = (*in).DeepCopy() + } return nil } } diff --git a/vendor/k8s.io/kubernetes/pkg/api/validation/validation.go b/vendor/k8s.io/kubernetes/pkg/api/validation/validation.go index b8c09113ce..859313b347 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/validation/validation.go +++ b/vendor/k8s.io/kubernetes/pkg/api/validation/validation.go @@ -399,10 +399,13 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E if source.EmptyDir != nil { numVolumes++ if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) { - unsetSizeLimit := resource.Quantity{} - if unsetSizeLimit.Cmp(source.EmptyDir.SizeLimit) != 0 { + if source.EmptyDir.SizeLimit != nil && source.EmptyDir.SizeLimit.Cmp(resource.Quantity{}) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("emptyDir").Child("sizeLimit"), "SizeLimit field disabled by feature-gate for EmptyDir volumes")) } + } else { + if source.EmptyDir.SizeLimit != nil && source.EmptyDir.SizeLimit.Cmp(resource.Quantity{}) < 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("emptyDir").Child("sizeLimit"), "SizeLimit field must be a valid resource quantity")) + } } } if source.HostPath != nil { @@ -3353,6 +3356,16 @@ func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "podCIDR"), "node updates may not change podCIDR except from \"\" to valid")) } } + + // Allow controller manager updating provider ID when not set + if len(oldNode.Spec.ProviderID) == 0 { + oldNode.Spec.ProviderID = node.Spec.ProviderID + } else { + if oldNode.Spec.ProviderID != node.Spec.ProviderID { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "providerID"), "node updates may not change providerID except from \"\" to valid")) + } + } + // TODO: move reset function to its own location // Ignore metadata changes now that they have been tested oldNode.ObjectMeta = node.ObjectMeta diff --git a/vendor/k8s.io/kubernetes/pkg/api/validation/validation_test.go b/vendor/k8s.io/kubernetes/pkg/api/validation/validation_test.go index 559cef8833..114973bf7e 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/validation/validation_test.go +++ b/vendor/k8s.io/kubernetes/pkg/api/validation/validation_test.go @@ -2418,7 +2418,7 @@ func TestValidateVolumes(t *testing.T) { func TestAlphaLocalStorageCapacityIsolation(t *testing.T) { testCases := []api.VolumeSource{ - {EmptyDir: &api.EmptyDirVolumeSource{SizeLimit: *resource.NewQuantity(int64(5), resource.BinarySI)}}, + {EmptyDir: &api.EmptyDirVolumeSource{SizeLimit: resource.NewQuantity(int64(5), resource.BinarySI)}}, } // Enable alpha feature LocalStorageCapacityIsolation err := utilfeature.DefaultFeatureGate.Set("LocalStorageCapacityIsolation=true") @@ -7813,6 +7813,33 @@ func TestValidateNodeUpdate(t *testing.T) { }, }, }, false}, + {api.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-provider-id-when-not-set", + }, + }, api.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-provider-id-when-not-set", + }, + Spec: api.NodeSpec{ + ProviderID: "provider:///new", + }, + }, true}, + {api.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-provider-id-when-set", + }, + Spec: api.NodeSpec{ + ProviderID: "provider:///old", + }, + }, api.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "update-provider-id-when-set", + }, + Spec: api.NodeSpec{ + ProviderID: "provider:///new", + }, + }, false}, } for i, test := range tests { test.oldNode.ObjectMeta.ResourceVersion = "1" diff --git a/vendor/k8s.io/kubernetes/pkg/api/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/api/zz_generated.deepcopy.go index cc111561b7..0aa95e1071 100644 --- a/vendor/k8s.io/kubernetes/pkg/api/zz_generated.deepcopy.go +++ b/vendor/k8s.io/kubernetes/pkg/api/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package api import ( + resource "k8s.io/apimachinery/pkg/api/resource" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" fields "k8s.io/apimachinery/pkg/fields" @@ -860,7 +861,11 @@ func DeepCopy_api_EmptyDirVolumeSource(in interface{}, out interface{}, c *conve in := in.(*EmptyDirVolumeSource) out := out.(*EmptyDirVolumeSource) *out = *in - out.SizeLimit = in.SizeLimit.DeepCopy() + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + *out = new(resource.Quantity) + **out = (*in).DeepCopy() + } return nil } } diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.pb.go b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.pb.go index a210900969..65e4b91934 100644 --- a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.pb.go +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.pb.go @@ -3314,89 +3314,88 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 1331 bytes of a gzipped FileDescriptorProto + // 1323 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0x5b, 0x6f, 0x1b, 0x45, - 0x1b, 0xce, 0x3a, 0x4e, 0x9a, 0x6f, 0x9c, 0x26, 0xfd, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56, - 0x08, 0xb5, 0x08, 0x76, 0xa9, 0x29, 0x88, 0x0a, 0x01, 0x8a, 0xcd, 0xa1, 0x15, 0x71, 0x0f, 0xd3, - 0x50, 0x21, 0x40, 0x82, 0xc9, 0x7a, 0xea, 0x0c, 0xf1, 0x1e, 0xb4, 0x33, 0xb6, 0x48, 0xa5, 0x4a, - 0xdc, 0x70, 0x87, 0x04, 0x37, 0xfc, 0x04, 0x24, 0xfe, 0x01, 0xd7, 0x20, 0x21, 0xf5, 0xb2, 0x97, - 0xe5, 0xc6, 0xa2, 0xee, 0x1d, 0x3f, 0x21, 0x12, 0x07, 0xcd, 0x61, 0x4f, 0x5e, 0x6f, 0x1a, 0x87, - 0xb4, 0x82, 0x3b, 0x7b, 0xe6, 0x7d, 0x9f, 0xe7, 0x3d, 0x3c, 0xf3, 0xce, 0x2c, 0x78, 0x6b, 0xfb, - 0x35, 0x66, 0x51, 0xdf, 0xde, 0xee, 0x6f, 0x92, 0xd0, 0x23, 0x9c, 0x30, 0x3b, 0xd8, 0xee, 0xda, - 0x38, 0xa0, 0xcc, 0xc6, 0x7d, 0xee, 0x33, 0x07, 0xf7, 0xa8, 0xd7, 0xb5, 0x07, 0x0d, 0xdc, 0x0b, - 0xb6, 0xf0, 0x05, 0xbb, 0x4b, 0x3c, 0x12, 0x62, 0x4e, 0x3a, 0x56, 0x10, 0xfa, 0xdc, 0x87, 0xb6, - 0x02, 0xb0, 0x12, 0x00, 0x2b, 0xd8, 0xee, 0x5a, 0x02, 0xc0, 0x4a, 0x01, 0x58, 0x11, 0xc0, 0xca, - 0x8b, 0x5d, 0xca, 0xb7, 0xfa, 0x9b, 0x96, 0xe3, 0xbb, 0x76, 0xd7, 0xef, 0xfa, 0xb6, 0xc4, 0xd9, - 0xec, 0xdf, 0x96, 0xff, 0xe4, 0x1f, 0xf9, 0x4b, 0xe1, 0xaf, 0x5c, 0xd4, 0x01, 0xe2, 0x80, 0xba, - 0xd8, 0xd9, 0xa2, 0x1e, 0x09, 0x77, 0xa2, 0x10, 0xed, 0x90, 0x30, 0xbf, 0x1f, 0x3a, 0x64, 0x3c, - 0xaa, 0x3d, 0xbd, 0x98, 0xed, 0x12, 0x8e, 0xed, 0x41, 0x2e, 0x97, 0x15, 0xbb, 0xc8, 0x2b, 0xec, - 0x7b, 0x9c, 0xba, 0x79, 0x9a, 0x57, 0x1f, 0xe7, 0xc0, 0x9c, 0x2d, 0xe2, 0xe2, 0x9c, 0xdf, 0xcb, - 0x45, 0x7e, 0x7d, 0x4e, 0x7b, 0x36, 0xf5, 0x38, 0xe3, 0x61, 0xce, 0xe9, 0x85, 0xc2, 0x56, 0x4d, - 0xca, 0xe5, 0xd2, 0x7e, 0x1b, 0x9b, 0x73, 0x35, 0xbf, 0x33, 0xc0, 0x99, 0x56, 0xe8, 0x33, 0x76, - 0x8b, 0x84, 0x8c, 0xfa, 0xde, 0xb5, 0xcd, 0xcf, 0x89, 0xc3, 0x11, 0xb9, 0x4d, 0x42, 0xe2, 0x39, - 0x04, 0xae, 0x82, 0xf2, 0x36, 0xf5, 0x3a, 0x55, 0x63, 0xd5, 0x38, 0xf7, 0xbf, 0xe6, 0xe2, 0xbd, - 0x61, 0x7d, 0x66, 0x34, 0xac, 0x97, 0xdf, 0xa7, 0x5e, 0x07, 0xc9, 0x1d, 0x61, 0xe1, 0x61, 0x97, - 0x54, 0x4b, 0x59, 0x8b, 0xab, 0xd8, 0x25, 0x48, 0xee, 0xc0, 0x06, 0x00, 0x38, 0xa0, 0x9a, 0xa0, - 0x3a, 0x2b, 0xed, 0xa0, 0xb6, 0x03, 0x6b, 0xd7, 0xaf, 0xe8, 0x1d, 0x94, 0xb2, 0x32, 0x1f, 0x95, - 0xc0, 0xa9, 0xcb, 0x7e, 0x48, 0xef, 0xf8, 0x1e, 0xc7, 0xbd, 0xeb, 0x7e, 0x67, 0x4d, 0xe7, 0x41, - 0x42, 0xf8, 0x19, 0x58, 0x10, 0x5d, 0xed, 0x60, 0x8e, 0x65, 0x5c, 0x95, 0xc6, 0x4b, 0x96, 0x56, - 0x66, 0xba, 0xc8, 0x89, 0x36, 0x85, 0xb5, 0x35, 0xb8, 0x60, 0xa9, 0xe4, 0xda, 0x84, 0xe3, 0x84, - 0x3f, 0x59, 0x43, 0x31, 0x2a, 0xf4, 0x40, 0x99, 0x05, 0xc4, 0x91, 0x39, 0x55, 0x1a, 0xeb, 0xd6, - 0x94, 0xba, 0xb7, 0x0a, 0x22, 0xbf, 0x19, 0x10, 0x27, 0xa9, 0x90, 0xf8, 0x87, 0x24, 0x0f, 0x1c, - 0x80, 0x79, 0xc6, 0x31, 0xef, 0x33, 0x59, 0x9d, 0x4a, 0xe3, 0xea, 0xa1, 0x31, 0x4a, 0xd4, 0xe6, - 0x92, 0xe6, 0x9c, 0x57, 0xff, 0x91, 0x66, 0x33, 0xbf, 0x99, 0x05, 0xab, 0x05, 0x9e, 0x2d, 0xdf, - 0xeb, 0x50, 0x4e, 0x7d, 0x0f, 0x5e, 0x06, 0x65, 0xbe, 0x13, 0x10, 0x2d, 0x81, 0x8b, 0x51, 0xf8, - 0x1b, 0x3b, 0x01, 0xd9, 0x1d, 0xd6, 0x9f, 0x7d, 0x9c, 0xbf, 0xb0, 0x43, 0x12, 0x01, 0xde, 0x8a, - 0xd3, 0x54, 0x62, 0x79, 0x33, 0x1b, 0xd6, 0xee, 0xb0, 0xbe, 0xa7, 0xee, 0xad, 0x18, 0x33, 0x9b, - 0x06, 0x1c, 0x00, 0xd8, 0xc3, 0x8c, 0x6f, 0x84, 0xd8, 0x63, 0x8a, 0x93, 0xba, 0x44, 0x97, 0xf2, - 0xf9, 0xfd, 0x49, 0x43, 0x78, 0x34, 0x57, 0x74, 0x3c, 0x70, 0x3d, 0x87, 0x86, 0x26, 0x30, 0xc0, - 0xe7, 0xc0, 0x7c, 0x48, 0x30, 0xf3, 0xbd, 0x6a, 0x59, 0xe6, 0x13, 0x97, 0x19, 0xc9, 0x55, 0xa4, - 0x77, 0xe1, 0x79, 0x70, 0xc4, 0x25, 0x8c, 0xe1, 0x2e, 0xa9, 0xce, 0x49, 0xc3, 0x65, 0x6d, 0x78, - 0xa4, 0xad, 0x96, 0x51, 0xb4, 0x6f, 0xfe, 0x6e, 0x80, 0x33, 0x05, 0x15, 0x5d, 0xa7, 0x8c, 0xc3, - 0x4f, 0x72, 0xda, 0xb7, 0xf6, 0x97, 0xa0, 0xf0, 0x96, 0xca, 0x3f, 0xa6, 0xb9, 0x17, 0xa2, 0x95, - 0x94, 0xee, 0x5d, 0x30, 0x47, 0x39, 0x71, 0x45, 0x7f, 0x66, 0xcf, 0x55, 0x1a, 0x97, 0x0f, 0x4b, - 0x86, 0xcd, 0xa3, 0x9a, 0x74, 0xee, 0x8a, 0x80, 0x47, 0x8a, 0xc5, 0xfc, 0xb3, 0x54, 0x98, 0xac, - 0x38, 0x1c, 0xf0, 0x6b, 0x03, 0x2c, 0xc9, 0xbf, 0x1b, 0x38, 0xec, 0x12, 0x31, 0x95, 0x74, 0xce, - 0xd3, 0x9f, 0xc8, 0x3d, 0x66, 0x5c, 0xf3, 0xa4, 0x0e, 0x6e, 0xe9, 0x66, 0x86, 0x0b, 0x8d, 0x71, - 0xc3, 0x0b, 0xa0, 0xe2, 0x52, 0x0f, 0x91, 0xa0, 0x47, 0x1d, 0xac, 0x34, 0x3c, 0xd7, 0x5c, 0x1e, - 0x0d, 0xeb, 0x95, 0x76, 0xb2, 0x8c, 0xd2, 0x36, 0xf0, 0x15, 0x50, 0x71, 0xf1, 0x17, 0xb1, 0xcb, - 0xac, 0x74, 0x39, 0xae, 0xf9, 0x2a, 0xed, 0x64, 0x0b, 0xa5, 0xed, 0xe0, 0x6d, 0x21, 0x18, 0x1e, - 0x52, 0x87, 0x55, 0xcb, 0xb2, 0x13, 0xaf, 0x4f, 0x9d, 0x70, 0x5b, 0xfa, 0xcb, 0x89, 0x93, 0x52, - 0x9b, 0xc4, 0x44, 0x11, 0xb8, 0xf9, 0x6b, 0x19, 0x9c, 0xdd, 0x73, 0x72, 0xc0, 0x77, 0x01, 0xf4, - 0x37, 0x19, 0x09, 0x07, 0xa4, 0xf3, 0x9e, 0xba, 0x3a, 0xc4, 0x0c, 0x17, 0x5d, 0x98, 0x6d, 0x9e, - 0x14, 0x47, 0xe5, 0x5a, 0x6e, 0x17, 0x4d, 0xf0, 0x80, 0x0e, 0x38, 0x2a, 0x0e, 0x90, 0xaa, 0x30, - 0xd5, 0xd7, 0xc5, 0x74, 0xa7, 0xf3, 0xff, 0xa3, 0x61, 0xfd, 0xe8, 0x7a, 0x1a, 0x04, 0x65, 0x31, - 0xe1, 0x1a, 0x58, 0x76, 0xfa, 0x61, 0x48, 0x3c, 0x3e, 0x56, 0xf1, 0x53, 0xba, 0x02, 0xcb, 0xad, - 0xec, 0x36, 0x1a, 0xb7, 0x17, 0x10, 0x1d, 0xc2, 0x68, 0x48, 0x3a, 0x31, 0x44, 0x39, 0x0b, 0xf1, - 0x76, 0x76, 0x1b, 0x8d, 0xdb, 0xc3, 0xbb, 0x60, 0x49, 0xa3, 0xea, 0x7a, 0x57, 0xe7, 0x64, 0x0f, - 0xdf, 0x38, 0x68, 0x0f, 0xd5, 0x0c, 0x8f, 0x55, 0xda, 0xca, 0x80, 0xa3, 0x31, 0x32, 0xf8, 0x95, - 0x01, 0x80, 0x13, 0x0d, 0x4a, 0x56, 0x9d, 0x97, 0xdc, 0x37, 0x0e, 0xeb, 0x24, 0xc7, 0x23, 0x38, - 0xb9, 0x41, 0xe3, 0x25, 0x86, 0x52, 0xc4, 0xe6, 0x1f, 0x25, 0x00, 0x12, 0x11, 0xc2, 0x8b, 0x99, - 0x5b, 0x64, 0x75, 0xec, 0x16, 0x39, 0xa6, 0x2d, 0xe5, 0x0b, 0x2f, 0x75, 0x63, 0x74, 0xc1, 0xbc, - 0x2f, 0x4f, 0xab, 0xd6, 0x4b, 0x6b, 0xea, 0x3c, 0xe2, 0xfb, 0x3d, 0x86, 0x6f, 0x02, 0x31, 0xa2, - 0xf5, 0x10, 0xd0, 0xf0, 0xf0, 0x53, 0x50, 0x0e, 0xfc, 0x4e, 0x74, 0xff, 0xae, 0x4d, 0x4d, 0x73, - 0xdd, 0xef, 0xb0, 0x0c, 0xc9, 0x82, 0xc8, 0x4e, 0xac, 0x22, 0x09, 0x0c, 0x7d, 0xb0, 0x10, 0xbd, - 0x60, 0xa5, 0xa2, 0x2a, 0x8d, 0x77, 0xa6, 0x26, 0x41, 0x1a, 0x20, 0x43, 0xb4, 0x28, 0x66, 0x79, - 0xb4, 0x83, 0x62, 0x12, 0xf3, 0xaf, 0x12, 0x58, 0x4c, 0x0b, 0xe8, 0xdf, 0xd1, 0x01, 0xa5, 0xe5, - 0x27, 0xdc, 0x01, 0x45, 0xf2, 0x14, 0x3a, 0xa0, 0x88, 0x8a, 0x3a, 0xf0, 0x7d, 0x09, 0xc0, 0xbc, - 0xfc, 0x20, 0x07, 0xf3, 0x5c, 0xde, 0x29, 0x4f, 0xe4, 0x32, 0x8b, 0xdf, 0x20, 0xfa, 0xde, 0xd2, - 0x5c, 0xe2, 0x11, 0xae, 0xa6, 0xfe, 0xd5, 0xe4, 0xb1, 0x1e, 0x1f, 0xe1, 0x76, 0xbc, 0x83, 0x52, - 0x56, 0x90, 0x80, 0x8a, 0xf2, 0xbe, 0x85, 0x7b, 0xfd, 0xe8, 0x41, 0xb5, 0xe7, 0x7b, 0xc3, 0x8a, - 0x92, 0xb7, 0x6e, 0xf4, 0xb1, 0xc7, 0x29, 0xdf, 0x49, 0x6e, 0xbb, 0x8d, 0x04, 0x0a, 0xa5, 0x71, - 0xcd, 0x1f, 0xc6, 0xeb, 0xa4, 0xf4, 0xfa, 0xdf, 0xa9, 0xd3, 0x16, 0x58, 0xd4, 0x43, 0xf8, 0x9f, - 0x14, 0xea, 0x84, 0x66, 0x59, 0x6c, 0xa5, 0xb0, 0x50, 0x06, 0xd9, 0xfc, 0xd9, 0x00, 0xc7, 0xc6, - 0x47, 0xcd, 0x58, 0xc8, 0xc6, 0xbe, 0x42, 0xbe, 0x03, 0xa0, 0x4a, 0x78, 0x6d, 0x40, 0x42, 0xdc, - 0x25, 0x2a, 0xf0, 0xd2, 0x81, 0x02, 0x8f, 0x9f, 0xcd, 0x1b, 0x39, 0x44, 0x34, 0x81, 0xc5, 0xfc, - 0x25, 0x9b, 0x84, 0xea, 0xf6, 0x41, 0x92, 0xb8, 0x0b, 0x8e, 0xeb, 0xea, 0x1c, 0x42, 0x16, 0x67, - 0x34, 0xd9, 0xf1, 0x56, 0x1e, 0x12, 0x4d, 0xe2, 0x31, 0x7f, 0x2c, 0x81, 0x13, 0x93, 0x46, 0x32, - 0x6c, 0xeb, 0x4f, 0x62, 0x95, 0xc5, 0xa5, 0xf4, 0x27, 0xf1, 0xee, 0xb0, 0x7e, 0x7e, 0xcf, 0x6f, - 0x9c, 0x08, 0x30, 0xf5, 0xfd, 0xfc, 0x21, 0xa8, 0x66, 0xaa, 0xf8, 0x01, 0xa7, 0x3d, 0x7a, 0x47, - 0xbd, 0xc4, 0xd4, 0x23, 0xf4, 0x99, 0xd1, 0xb0, 0x5e, 0xdd, 0x28, 0xb0, 0x41, 0x85, 0xde, 0xe2, - 0xc3, 0x69, 0x82, 0x0a, 0x0e, 0x26, 0xdf, 0x93, 0x53, 0x28, 0xe0, 0xa7, 0x7c, 0xe5, 0x94, 0x0a, - 0x0e, 0xb9, 0x72, 0x1f, 0x83, 0xd3, 0xd9, 0xc6, 0xe5, 0x4b, 0x77, 0x76, 0x34, 0xac, 0x9f, 0x6e, - 0x15, 0x19, 0xa1, 0x62, 0xff, 0x22, 0xf5, 0xcd, 0x3e, 0x1d, 0xf5, 0x35, 0xad, 0x7b, 0x0f, 0x6b, - 0x33, 0xf7, 0x1f, 0xd6, 0x66, 0x1e, 0x3c, 0xac, 0xcd, 0x7c, 0x39, 0xaa, 0x19, 0xf7, 0x46, 0x35, - 0xe3, 0xfe, 0xa8, 0x66, 0x3c, 0x18, 0xd5, 0x8c, 0xdf, 0x46, 0x35, 0xe3, 0xdb, 0x47, 0xb5, 0x99, - 0x8f, 0x16, 0xa2, 0x61, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xa9, 0x91, 0xe9, 0xfe, - 0x13, 0x00, 0x00, + 0x14, 0xce, 0x3a, 0x4e, 0x1a, 0xc6, 0x69, 0x52, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56, 0x08, + 0xb5, 0x08, 0x76, 0xa9, 0x29, 0x08, 0x84, 0x00, 0xc5, 0xe6, 0xd2, 0x8a, 0xb8, 0x97, 0x69, 0xa8, + 0x10, 0x20, 0xc1, 0x64, 0x3d, 0x75, 0x86, 0x78, 0x2f, 0xda, 0x19, 0x5b, 0xa4, 0x52, 0x25, 0x5e, + 0x78, 0x43, 0x82, 0x17, 0x7e, 0x02, 0x12, 0xff, 0x80, 0x67, 0x90, 0x90, 0xfa, 0xd8, 0xc7, 0xf2, + 0x62, 0x51, 0xf7, 0x8d, 0x9f, 0x50, 0x89, 0x8b, 0xe6, 0xb2, 0x37, 0xaf, 0xd7, 0xad, 0x43, 0x5a, + 0xc1, 0x9b, 0x3d, 0x73, 0xce, 0xf7, 0x9d, 0xcb, 0x37, 0x67, 0x66, 0xc1, 0xdb, 0xbb, 0xaf, 0x31, + 0x8b, 0xfa, 0xf6, 0x6e, 0x7f, 0x9b, 0x84, 0x1e, 0xe1, 0x84, 0xd9, 0xc1, 0x6e, 0xd7, 0xc6, 0x01, + 0x65, 0x36, 0xee, 0x73, 0x9f, 0x39, 0xb8, 0x47, 0xbd, 0xae, 0x3d, 0x68, 0xe0, 0x5e, 0xb0, 0x83, + 0xcf, 0xd9, 0x5d, 0xe2, 0x91, 0x10, 0x73, 0xd2, 0xb1, 0x82, 0xd0, 0xe7, 0x3e, 0xb4, 0x15, 0x80, + 0x95, 0x00, 0x58, 0xc1, 0x6e, 0xd7, 0x12, 0x00, 0x56, 0x0a, 0xc0, 0x8a, 0x00, 0xd6, 0x5e, 0xec, + 0x52, 0xbe, 0xd3, 0xdf, 0xb6, 0x1c, 0xdf, 0xb5, 0xbb, 0x7e, 0xd7, 0xb7, 0x25, 0xce, 0x76, 0xff, + 0x86, 0xfc, 0x27, 0xff, 0xc8, 0x5f, 0x0a, 0x7f, 0xed, 0xbc, 0x0e, 0x10, 0x07, 0xd4, 0xc5, 0xce, + 0x0e, 0xf5, 0x48, 0xb8, 0x17, 0x85, 0x68, 0x87, 0x84, 0xf9, 0xfd, 0xd0, 0x21, 0xe3, 0x51, 0x4d, + 0xf5, 0x62, 0xb6, 0x4b, 0x38, 0xb6, 0x07, 0xb9, 0x5c, 0xd6, 0xec, 0x22, 0xaf, 0xb0, 0xef, 0x71, + 0xea, 0xe6, 0x69, 0x5e, 0x7d, 0x98, 0x03, 0x73, 0x76, 0x88, 0x8b, 0x73, 0x7e, 0x2f, 0x17, 0xf9, + 0xf5, 0x39, 0xed, 0xd9, 0xd4, 0xe3, 0x8c, 0x87, 0x39, 0xa7, 0x17, 0x0a, 0x5b, 0x35, 0x21, 0x17, + 0xf3, 0x7b, 0x03, 0x9c, 0x6a, 0x85, 0x3e, 0x63, 0xd7, 0x49, 0xc8, 0xa8, 0xef, 0x5d, 0xde, 0xfe, + 0x82, 0x38, 0x1c, 0x91, 0x1b, 0x24, 0x24, 0x9e, 0x43, 0xe0, 0x3a, 0x28, 0xef, 0x52, 0xaf, 0x53, + 0x35, 0xd6, 0x8d, 0x33, 0x4f, 0x35, 0x97, 0x6f, 0x0f, 0xeb, 0x73, 0xa3, 0x61, 0xbd, 0xfc, 0x01, + 0xf5, 0x3a, 0x48, 0xee, 0x08, 0x0b, 0x0f, 0xbb, 0xa4, 0x5a, 0xca, 0x5a, 0x5c, 0xc2, 0x2e, 0x41, + 0x72, 0x07, 0x36, 0x00, 0xc0, 0x01, 0xd5, 0x04, 0xd5, 0x79, 0x69, 0x07, 0xb5, 0x1d, 0xd8, 0xb8, + 0x72, 0x51, 0xef, 0xa0, 0x94, 0x95, 0x79, 0xbf, 0x04, 0x4e, 0x5c, 0xf0, 0x43, 0x7a, 0xd3, 0xf7, + 0x38, 0xee, 0x5d, 0xf1, 0x3b, 0x1b, 0x5a, 0x24, 0x24, 0x84, 0x9f, 0x83, 0x25, 0xd1, 0x9a, 0x0e, + 0xe6, 0x58, 0xc6, 0x55, 0x69, 0xbc, 0x64, 0x69, 0x79, 0xa5, 0x2b, 0x95, 0x08, 0x4c, 0x58, 0x5b, + 0x83, 0x73, 0x96, 0x4a, 0xae, 0x4d, 0x38, 0x4e, 0xf8, 0x93, 0x35, 0x14, 0xa3, 0x42, 0x0f, 0x94, + 0x59, 0x40, 0x1c, 0x99, 0x53, 0xa5, 0xb1, 0x69, 0xcd, 0x28, 0x5e, 0xab, 0x20, 0xf2, 0x6b, 0x01, + 0x71, 0x92, 0x0a, 0x89, 0x7f, 0x48, 0xf2, 0xc0, 0x01, 0x58, 0x64, 0x1c, 0xf3, 0x3e, 0x93, 0xd5, + 0xa9, 0x34, 0x2e, 0x1d, 0x18, 0xa3, 0x44, 0x6d, 0xae, 0x68, 0xce, 0x45, 0xf5, 0x1f, 0x69, 0x36, + 0xf3, 0xdb, 0x79, 0xb0, 0x5e, 0xe0, 0xd9, 0xf2, 0xbd, 0x0e, 0xe5, 0xd4, 0xf7, 0xe0, 0x05, 0x50, + 0xe6, 0x7b, 0x01, 0xd1, 0x12, 0x38, 0x1f, 0x85, 0xbf, 0xb5, 0x17, 0x90, 0x07, 0xc3, 0xfa, 0xb3, + 0x0f, 0xf3, 0x17, 0x76, 0x48, 0x22, 0xc0, 0xeb, 0x71, 0x9a, 0x4a, 0x2c, 0x6f, 0x65, 0xc3, 0x7a, + 0x30, 0xac, 0x4f, 0x15, 0xaf, 0x15, 0x63, 0x66, 0xd3, 0x80, 0x03, 0x00, 0x7b, 0x98, 0xf1, 0xad, + 0x10, 0x7b, 0x4c, 0x71, 0x52, 0x97, 0xe8, 0x52, 0x3e, 0xff, 0x68, 0xd2, 0x10, 0x1e, 0xcd, 0x35, + 0x1d, 0x0f, 0xdc, 0xcc, 0xa1, 0xa1, 0x09, 0x0c, 0xf0, 0x39, 0xb0, 0x18, 0x12, 0xcc, 0x7c, 0xaf, + 0x5a, 0x96, 0xf9, 0xc4, 0x65, 0x46, 0x72, 0x15, 0xe9, 0x5d, 0x78, 0x16, 0x1c, 0x72, 0x09, 0x63, + 0xb8, 0x4b, 0xaa, 0x0b, 0xd2, 0x70, 0x55, 0x1b, 0x1e, 0x6a, 0xab, 0x65, 0x14, 0xed, 0x9b, 0x7f, + 0x18, 0xe0, 0x54, 0x41, 0x45, 0x37, 0x29, 0xe3, 0xf0, 0xd3, 0x9c, 0xf6, 0xad, 0x47, 0x4b, 0x50, + 0x78, 0x4b, 0xe5, 0x1f, 0xd1, 0xdc, 0x4b, 0xd1, 0x4a, 0x4a, 0xf7, 0x2e, 0x58, 0xa0, 0x9c, 0xb8, + 0xa2, 0x3f, 0xf3, 0x67, 0x2a, 0x8d, 0x0b, 0x07, 0x25, 0xc3, 0xe6, 0x61, 0x4d, 0xba, 0x70, 0x51, + 0xc0, 0x23, 0xc5, 0x62, 0xfe, 0x55, 0x2a, 0x4c, 0x56, 0x1c, 0x0e, 0xf8, 0x8d, 0x01, 0x56, 0xe4, + 0xdf, 0x2d, 0x1c, 0x76, 0x89, 0x98, 0x4a, 0x3a, 0xe7, 0xd9, 0x4f, 0xe4, 0x94, 0x19, 0xd7, 0x3c, + 0xae, 0x83, 0x5b, 0xb9, 0x96, 0xe1, 0x42, 0x63, 0xdc, 0xf0, 0x1c, 0xa8, 0xb8, 0xd4, 0x43, 0x24, + 0xe8, 0x51, 0x07, 0x2b, 0x0d, 0x2f, 0x34, 0x57, 0x47, 0xc3, 0x7a, 0xa5, 0x9d, 0x2c, 0xa3, 0xb4, + 0x0d, 0x7c, 0x05, 0x54, 0x5c, 0xfc, 0x65, 0xec, 0x32, 0x2f, 0x5d, 0x8e, 0x6a, 0xbe, 0x4a, 0x3b, + 0xd9, 0x42, 0x69, 0x3b, 0x78, 0x43, 0x08, 0x86, 0x87, 0xd4, 0x61, 0xd5, 0xb2, 0xec, 0xc4, 0x1b, + 0x33, 0x27, 0xdc, 0x96, 0xfe, 0x72, 0xe2, 0xa4, 0xd4, 0x26, 0x31, 0x51, 0x04, 0x6e, 0xfe, 0x56, + 0x06, 0xa7, 0xa7, 0x4e, 0x0e, 0xf8, 0x1e, 0x80, 0xfe, 0x36, 0x23, 0xe1, 0x80, 0x74, 0xde, 0x57, + 0x57, 0x87, 0x98, 0xe1, 0xa2, 0x0b, 0xf3, 0xcd, 0xe3, 0xe2, 0xa8, 0x5c, 0xce, 0xed, 0xa2, 0x09, + 0x1e, 0xd0, 0x01, 0x87, 0xc5, 0x01, 0x52, 0x15, 0xa6, 0xfa, 0xba, 0x98, 0xed, 0x74, 0x3e, 0x3d, + 0x1a, 0xd6, 0x0f, 0x6f, 0xa6, 0x41, 0x50, 0x16, 0x13, 0x6e, 0x80, 0x55, 0xa7, 0x1f, 0x86, 0xc4, + 0xe3, 0x63, 0x15, 0x3f, 0xa1, 0x2b, 0xb0, 0xda, 0xca, 0x6e, 0xa3, 0x71, 0x7b, 0x01, 0xd1, 0x21, + 0x8c, 0x86, 0xa4, 0x13, 0x43, 0x94, 0xb3, 0x10, 0xef, 0x64, 0xb7, 0xd1, 0xb8, 0x3d, 0xbc, 0x05, + 0x56, 0x34, 0xaa, 0xae, 0x77, 0x75, 0x41, 0xf6, 0xf0, 0xcd, 0xfd, 0xf6, 0x50, 0xcd, 0xf0, 0x58, + 0xa5, 0xad, 0x0c, 0x38, 0x1a, 0x23, 0x83, 0x5f, 0x1b, 0x00, 0x38, 0xd1, 0xa0, 0x64, 0xd5, 0x45, + 0xc9, 0x7d, 0xf5, 0xa0, 0x4e, 0x72, 0x3c, 0x82, 0x93, 0x1b, 0x34, 0x5e, 0x62, 0x28, 0x45, 0x6c, + 0xfe, 0x59, 0x02, 0x20, 0x11, 0x21, 0x3c, 0x9f, 0xb9, 0x45, 0xd6, 0xc7, 0x6e, 0x91, 0x23, 0xda, + 0x52, 0x3e, 0xd3, 0x52, 0x37, 0x46, 0x17, 0x2c, 0xfa, 0xf2, 0xb4, 0x6a, 0xbd, 0xb4, 0x66, 0xce, + 0x23, 0xbe, 0xdf, 0x63, 0xf8, 0x26, 0x10, 0x23, 0x5a, 0x0f, 0x01, 0x0d, 0x0f, 0x3f, 0x03, 0xe5, + 0xc0, 0xef, 0x44, 0xf7, 0xef, 0xc6, 0xcc, 0x34, 0x57, 0xfc, 0x0e, 0xcb, 0x90, 0x2c, 0x89, 0xec, + 0xc4, 0x2a, 0x92, 0xc0, 0xd0, 0x07, 0x4b, 0xd1, 0x33, 0x54, 0x2a, 0xaa, 0xd2, 0x78, 0x77, 0x66, + 0x12, 0xa4, 0x01, 0x32, 0x44, 0xcb, 0x62, 0x96, 0x47, 0x3b, 0x28, 0x26, 0x31, 0xff, 0x2e, 0x81, + 0xe5, 0xb4, 0x80, 0xfe, 0x1b, 0x1d, 0x50, 0x5a, 0x7e, 0xcc, 0x1d, 0x50, 0x24, 0x4f, 0xa0, 0x03, + 0x8a, 0xa8, 0xa8, 0x03, 0x3f, 0x94, 0x00, 0xcc, 0xcb, 0x0f, 0x72, 0xb0, 0xc8, 0xe5, 0x9d, 0xf2, + 0x58, 0x2e, 0xb3, 0xf8, 0x0d, 0xa2, 0xef, 0x2d, 0xcd, 0x25, 0x1e, 0xe1, 0x6a, 0xea, 0x5f, 0x4a, + 0x1e, 0xeb, 0xf1, 0x11, 0x6e, 0xc7, 0x3b, 0x28, 0x65, 0x05, 0x09, 0xa8, 0x28, 0xef, 0xeb, 0xb8, + 0xd7, 0x8f, 0x1e, 0x54, 0x53, 0xdf, 0x1b, 0x56, 0x94, 0xbc, 0x75, 0xb5, 0x8f, 0x3d, 0x4e, 0xf9, + 0x5e, 0x72, 0xdb, 0x6d, 0x25, 0x50, 0x28, 0x8d, 0x6b, 0xfe, 0x38, 0x5e, 0x27, 0xa5, 0xd7, 0xff, + 0x4f, 0x9d, 0x76, 0xc0, 0xb2, 0x1e, 0xc2, 0xff, 0xa6, 0x50, 0xc7, 0x34, 0xcb, 0x72, 0x2b, 0x85, + 0x85, 0x32, 0xc8, 0xe6, 0x2f, 0x06, 0x38, 0x32, 0x3e, 0x6a, 0xc6, 0x42, 0x36, 0x1e, 0x29, 0xe4, + 0x9b, 0x00, 0xaa, 0x84, 0x37, 0x06, 0x24, 0xc4, 0x5d, 0xa2, 0x02, 0x2f, 0xed, 0x2b, 0xf0, 0xf8, + 0xd9, 0xbc, 0x95, 0x43, 0x44, 0x13, 0x58, 0xcc, 0x5f, 0xb3, 0x49, 0xa8, 0x6e, 0xef, 0x27, 0x89, + 0x5b, 0xe0, 0xa8, 0xae, 0xce, 0x01, 0x64, 0x71, 0x4a, 0x93, 0x1d, 0x6d, 0xe5, 0x21, 0xd1, 0x24, + 0x1e, 0xf3, 0xa7, 0x12, 0x38, 0x36, 0x69, 0x24, 0xc3, 0xb6, 0xfe, 0x24, 0x56, 0x59, 0xbc, 0x9e, + 0xfe, 0x24, 0x7e, 0x30, 0xac, 0x9f, 0x9d, 0xfa, 0x8d, 0x13, 0x01, 0xa6, 0xbe, 0x9f, 0x3f, 0x02, + 0xd5, 0x4c, 0x15, 0x3f, 0xe4, 0xb4, 0x47, 0x6f, 0xaa, 0x97, 0x98, 0x7a, 0x84, 0x3e, 0x33, 0x1a, + 0xd6, 0xab, 0x5b, 0x05, 0x36, 0xa8, 0xd0, 0x5b, 0x7c, 0x38, 0x4d, 0x50, 0xc1, 0xfe, 0xe4, 0x7b, + 0x7c, 0x06, 0x05, 0xfc, 0x9c, 0xaf, 0x9c, 0x52, 0xc1, 0x01, 0x57, 0xee, 0x13, 0x70, 0x32, 0xdb, + 0xb8, 0x7c, 0xe9, 0x4e, 0x8f, 0x86, 0xf5, 0x93, 0xad, 0x22, 0x23, 0x54, 0xec, 0x5f, 0xa4, 0xbe, + 0xf9, 0x27, 0xa3, 0xbe, 0xa6, 0x75, 0xfb, 0x5e, 0x6d, 0xee, 0xce, 0xbd, 0xda, 0xdc, 0xdd, 0x7b, + 0xb5, 0xb9, 0xaf, 0x46, 0x35, 0xe3, 0xf6, 0xa8, 0x66, 0xdc, 0x19, 0xd5, 0x8c, 0xbb, 0xa3, 0x9a, + 0xf1, 0xfb, 0xa8, 0x66, 0x7c, 0x77, 0xbf, 0x36, 0xf7, 0xf1, 0x52, 0x34, 0x0c, 0xff, 0x09, 0x00, + 0x00, 0xff, 0xff, 0x88, 0x5a, 0x1f, 0xc3, 0xc3, 0x13, 0x00, 0x00, } diff --git a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.proto b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.proto index d51547584f..c2223a1188 100644 --- a/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.proto +++ b/vendor/k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1/generated.proto @@ -27,7 +27,6 @@ import "k8s.io/apimachinery/pkg/runtime/generated.proto"; import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; import "k8s.io/kubernetes/pkg/api/v1/generated.proto"; -import "k8s.io/kubernetes/pkg/apis/autoscaling/v1/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v2alpha1"; diff --git a/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation.go b/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation.go index 528a9bc521..cb0e0506d7 100644 --- a/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation.go +++ b/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation.go @@ -38,7 +38,7 @@ func ValidatePodDisruptionBudgetUpdate(pdb, oldPdb *policy.PodDisruptionBudget) restoreGeneration := pdb.Generation pdb.Generation = oldPdb.Generation - if !reflect.DeepEqual(pdb, oldPdb) { + if !reflect.DeepEqual(pdb.Spec, oldPdb.Spec) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to poddisruptionbudget spec are forbidden.")) } allErrs = append(allErrs, ValidatePodDisruptionBudgetStatus(pdb.Status, field.NewPath("status"))...) diff --git a/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation_test.go b/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation_test.go index a11454374c..c2ba5b61fb 100644 --- a/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation_test.go +++ b/vendor/k8s.io/kubernetes/pkg/apis/policy/validation/validation_test.go @@ -113,3 +113,111 @@ func TestValidatePodDisruptionBudgetStatus(t *testing.T) { } } } + +func TestValidatePodDisruptionBudgetUpdate(t *testing.T) { + c1 := intstr.FromString("10%") + c2 := intstr.FromInt(1) + c3 := intstr.FromInt(2) + oldPdb := &policy.PodDisruptionBudget{} + pdb := &policy.PodDisruptionBudget{} + testCases := []struct { + generations []int64 + name string + specs []policy.PodDisruptionBudgetSpec + status []policy.PodDisruptionBudgetStatus + ok bool + }{ + { + name: "only update status", + generations: []int64{int64(2), int64(3)}, + specs: []policy.PodDisruptionBudgetSpec{ + { + MinAvailable: &c1, + MaxUnavailable: &c2, + }, + { + MinAvailable: &c1, + MaxUnavailable: &c2, + }, + }, + status: []policy.PodDisruptionBudgetStatus{ + { + PodDisruptionsAllowed: 10, + CurrentHealthy: 5, + ExpectedPods: 2, + }, + { + PodDisruptionsAllowed: 8, + CurrentHealthy: 5, + DesiredHealthy: 3, + }, + }, + ok: true, + }, + { + name: "only update pdb spec", + generations: []int64{int64(2), int64(3)}, + specs: []policy.PodDisruptionBudgetSpec{ + { + MaxUnavailable: &c2, + }, + { + MinAvailable: &c1, + MaxUnavailable: &c3, + }, + }, + status: []policy.PodDisruptionBudgetStatus{ + { + PodDisruptionsAllowed: 10, + }, + { + PodDisruptionsAllowed: 10, + }, + }, + ok: false, + }, + { + name: "update spec and status", + generations: []int64{int64(2), int64(3)}, + specs: []policy.PodDisruptionBudgetSpec{ + { + MaxUnavailable: &c2, + }, + { + MinAvailable: &c1, + MaxUnavailable: &c3, + }, + }, + status: []policy.PodDisruptionBudgetStatus{ + { + PodDisruptionsAllowed: 10, + CurrentHealthy: 5, + ExpectedPods: 2, + }, + { + PodDisruptionsAllowed: 8, + CurrentHealthy: 5, + DesiredHealthy: 3, + }, + }, + ok: false, + }, + } + + for i, tc := range testCases { + oldPdb.Spec = tc.specs[0] + oldPdb.Generation = tc.generations[0] + oldPdb.Status = tc.status[0] + + pdb.Spec = tc.specs[1] + pdb.Generation = tc.generations[1] + oldPdb.Status = tc.status[1] + + errs := ValidatePodDisruptionBudgetUpdate(oldPdb, pdb) + if tc.ok && len(errs) > 0 { + t.Errorf("[%d:%s] unexpected errors: %v", i, tc.name, errs) + } else if !tc.ok && len(errs) == 0 { + t.Errorf("[%d:%s] expected errors: %v", i, tc.name, errs) + } + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/aws/aws.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/aws/aws.go index d5e916a924..04e6421bff 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/aws/aws.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/aws/aws.go @@ -2072,6 +2072,11 @@ func isEqualUserGroupPair(l, r *ec2.UserIdGroupPair, compareGroupUserIDs bool) b // Returns true if and only if changes were made // The security group must already exist func (c *Cloud) setSecurityGroupIngress(securityGroupID string, permissions IPPermissionSet) (bool, error) { + // We do not want to make changes to the Global defined SG + if securityGroupID == c.cfg.Global.ElbSecurityGroup { + return false, nil + } + group, err := c.findSecurityGroup(securityGroupID) if err != nil { glog.Warning("Error retrieving security group", err) @@ -2142,6 +2147,11 @@ func (c *Cloud) setSecurityGroupIngress(securityGroupID string, permissions IPPe // Returns true if and only if changes were made // The security group must already exist func (c *Cloud) addSecurityGroupIngress(securityGroupID string, addPermissions []*ec2.IpPermission) (bool, error) { + // We do not want to make changes to the Global defined SG + if securityGroupID == c.cfg.Global.ElbSecurityGroup { + return false, nil + } + group, err := c.findSecurityGroup(securityGroupID) if err != nil { glog.Warningf("Error retrieving security group: %v", err) @@ -2198,6 +2208,11 @@ func (c *Cloud) addSecurityGroupIngress(securityGroupID string, addPermissions [ // Returns true if and only if changes were made // If the security group no longer exists, will return (false, nil) func (c *Cloud) removeSecurityGroupIngress(securityGroupID string, removePermissions []*ec2.IpPermission) (bool, error) { + // We do not want to make changes to the Global defined SG + if securityGroupID == c.cfg.Global.ElbSecurityGroup { + return false, nil + } + group, err := c.findSecurityGroup(securityGroupID) if err != nil { glog.Warningf("Error retrieving security group: %v", err) @@ -2525,7 +2540,7 @@ func getPortSets(annotation string) (ports *portSets) { // buildELBSecurityGroupList returns list of SecurityGroups which should be // attached to ELB created by a service. List always consist of at least -// 1 member which is an SG created for this service. Extra groups can be +// 1 member which is an SG created for this service or a SG from the Global config. Extra groups can be // specified via annotation func (c *Cloud) buildELBSecurityGroupList(serviceName types.NamespacedName, loadBalancerName, annotation string) ([]string, error) { var err error diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/BUILD b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/BUILD index 37e23ace38..2054172ac3 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/BUILD @@ -13,17 +13,18 @@ go_library( srcs = [ "azure.go", "azure_backoff.go", - "azure_blob.go", + "azure_blobDiskController.go", + "azure_controllerCommon.go", "azure_file.go", "azure_instances.go", "azure_loadbalancer.go", + "azure_managedDiskController.go", "azure_routes.go", "azure_storage.go", "azure_storageaccount.go", "azure_util.go", "azure_wrap.go", "azure_zones.go", - "vhd.go", ], tags = ["automanaged"], deps = [ @@ -34,15 +35,18 @@ go_library( "//pkg/version:go_default_library", "//pkg/volume:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/arm/compute:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/arm/disk:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/arm/network:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/arm/storage:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/storage:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/rubiojr/go-vhd/vhd:go_default_library", + "//vendor/golang.org/x/crypto/pkcs12:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure.go index ca2e48b7e6..448f0643f1 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure.go @@ -17,6 +17,8 @@ limitations under the License. package azure import ( + "crypto/rsa" + "crypto/x509" "fmt" "io" "io/ioutil" @@ -28,12 +30,15 @@ import ( "k8s.io/kubernetes/pkg/version" "github.com/Azure/azure-sdk-for-go/arm/compute" + "github.com/Azure/azure-sdk-for-go/arm/disk" "github.com/Azure/azure-sdk-for-go/arm/network" "github.com/Azure/azure-sdk-for-go/arm/storage" "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/azure" "github.com/ghodss/yaml" "github.com/golang/glog" + "golang.org/x/crypto/pkcs12" "k8s.io/apimachinery/pkg/util/wait" ) @@ -63,6 +68,8 @@ type Config struct { Location string `json:"location" yaml:"location"` // The name of the VNet that the cluster is deployed in VnetName string `json:"vnetName" yaml:"vnetName"` + // The name of the resource group that the Vnet is deployed in + VnetResourceGroup string `json:"vnetResourceGroup" yaml:"vnetResourceGroup"` // The name of the subnet that the cluster is deployed in SubnetName string `json:"subnetName" yaml:"subnetName"` // The name of the security group attached to the cluster's subnet @@ -80,6 +87,10 @@ type Config struct { AADClientID string `json:"aadClientId" yaml:"aadClientId"` // The ClientSecret for an AAD application with RBAC access to talk to Azure RM APIs AADClientSecret string `json:"aadClientSecret" yaml:"aadClientSecret"` + // The path of a client certificate for an AAD application with RBAC access to talk to Azure RM APIs + AADClientCertPath string `json:"aadClientCertPath" yaml:"aadClientCertPath"` + // The password of the client certificate for an AAD application with RBAC access to talk to Azure RM APIs + AADClientCertPassword string `json:"aadClientCertPassword" yaml:"aadClientCertPassword"` // Enable exponential backoff to manage resource request retries CloudProviderBackoff bool `json:"cloudProviderBackoff" yaml:"cloudProviderBackoff"` // Backoff retry limit @@ -96,6 +107,12 @@ type Config struct { CloudProviderRateLimitQPS float32 `json:"cloudProviderRateLimitQPS" yaml:"cloudProviderRateLimitQPS"` // Rate limit Bucket Size CloudProviderRateLimitBucket int `json:"cloudProviderRateLimitBucket" yaml:"cloudProviderRateLimitBucket"` + + // Use instance metadata service where possible + UseInstanceMetadata bool `json:"useInstanceMetadata" yaml:"useInstanceMetadata"` + + // Use managed service identity for the virtual machine to access Azure ARM APIs + UseManagedIdentityExtension bool `json:"useManagedIdentityExtension"` } // Cloud holds the config and clients @@ -111,100 +128,149 @@ type Cloud struct { SecurityGroupsClient network.SecurityGroupsClient VirtualMachinesClient compute.VirtualMachinesClient StorageAccountClient storage.AccountsClient + DisksClient disk.DisksClient operationPollRateLimiter flowcontrol.RateLimiter resourceRequestBackoff wait.Backoff + + *BlobDiskController + *ManagedDiskController + *controllerCommon } func init() { cloudprovider.RegisterCloudProvider(CloudProviderName, NewCloud) } -// NewCloud returns a Cloud with initialized clients -func NewCloud(configReader io.Reader) (cloudprovider.Interface, error) { - var az Cloud - - configContents, err := ioutil.ReadAll(configReader) +// decodePkcs12 decodes a PKCS#12 client certificate by extracting the public certificate and +// the private RSA key +func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) { + privateKey, certificate, err := pkcs12.Decode(pkcs, password) if err != nil { - return nil, err + return nil, nil, fmt.Errorf("decoding the PKCS#12 client certificate: %v", err) + } + rsaPrivateKey, isRsaKey := privateKey.(*rsa.PrivateKey) + if !isRsaKey { + return nil, nil, fmt.Errorf("PKCS#12 certificate must contain a RSA private key") } - err = yaml.Unmarshal(configContents, &az) + + return certificate, rsaPrivateKey, nil +} + +// GetServicePrincipalToken creates a new service principal token based on the configuration +func GetServicePrincipalToken(config *Config, env *azure.Environment) (*adal.ServicePrincipalToken, error) { + oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, config.TenantID) if err != nil { - return nil, err + return nil, fmt.Errorf("creating the OAuth config: %v", err) } - if az.Cloud == "" { - az.Environment = azure.PublicCloud - } else { - az.Environment, err = azure.EnvironmentFromName(az.Cloud) + if config.UseManagedIdentityExtension { + glog.V(2).Infoln("azure: using managed identity extension to retrieve access token") + return adal.NewServicePrincipalTokenFromMSI( + *oauthConfig, + env.ServiceManagementEndpoint) + } + + if len(config.AADClientSecret) > 0 { + glog.V(2).Infoln("azure: using client_id+client_secret to retrieve access token") + return adal.NewServicePrincipalToken( + *oauthConfig, + config.AADClientID, + config.AADClientSecret, + env.ServiceManagementEndpoint) + } + + if len(config.AADClientCertPath) > 0 && len(config.AADClientCertPassword) > 0 { + glog.V(2).Infoln("azure: using jwt client_assertion (client_cert+client_private_key) to retrieve access token") + certData, err := ioutil.ReadFile(config.AADClientCertPath) + if err != nil { + return nil, fmt.Errorf("reading the client certificate from file %s: %v", config.AADClientCertPath, err) + } + certificate, privateKey, err := decodePkcs12(certData, config.AADClientCertPassword) if err != nil { - return nil, err + return nil, fmt.Errorf("decoding the client certificate: %v", err) } + return adal.NewServicePrincipalTokenFromCertificate( + *oauthConfig, + config.AADClientID, + certificate, + privateKey, + env.ServiceManagementEndpoint) } - oauthConfig, err := az.Environment.OAuthConfigForTenant(az.TenantID) + return nil, fmt.Errorf("No credentials provided for AAD application %s", config.AADClientID) +} + +// NewCloud returns a Cloud with initialized clients +func NewCloud(configReader io.Reader) (cloudprovider.Interface, error) { + config, env, err := ParseConfig(configReader) if err != nil { return nil, err } + az := Cloud{ + Config: *config, + Environment: *env, + } - servicePrincipalToken, err := azure.NewServicePrincipalToken( - *oauthConfig, - az.AADClientID, - az.AADClientSecret, - az.Environment.ServiceManagementEndpoint) + servicePrincipalToken, err := GetServicePrincipalToken(config, env) if err != nil { return nil, err } az.SubnetsClient = network.NewSubnetsClient(az.SubscriptionID) az.SubnetsClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.SubnetsClient.Authorizer = servicePrincipalToken + az.SubnetsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.SubnetsClient.PollingDelay = 5 * time.Second configureUserAgent(&az.SubnetsClient.Client) az.RouteTablesClient = network.NewRouteTablesClient(az.SubscriptionID) az.RouteTablesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.RouteTablesClient.Authorizer = servicePrincipalToken + az.RouteTablesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.RouteTablesClient.PollingDelay = 5 * time.Second configureUserAgent(&az.RouteTablesClient.Client) az.RoutesClient = network.NewRoutesClient(az.SubscriptionID) az.RoutesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.RoutesClient.Authorizer = servicePrincipalToken + az.RoutesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.RoutesClient.PollingDelay = 5 * time.Second configureUserAgent(&az.RoutesClient.Client) az.InterfacesClient = network.NewInterfacesClient(az.SubscriptionID) az.InterfacesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.InterfacesClient.Authorizer = servicePrincipalToken + az.InterfacesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.InterfacesClient.PollingDelay = 5 * time.Second configureUserAgent(&az.InterfacesClient.Client) az.LoadBalancerClient = network.NewLoadBalancersClient(az.SubscriptionID) az.LoadBalancerClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.LoadBalancerClient.Authorizer = servicePrincipalToken + az.LoadBalancerClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.LoadBalancerClient.PollingDelay = 5 * time.Second configureUserAgent(&az.LoadBalancerClient.Client) az.VirtualMachinesClient = compute.NewVirtualMachinesClient(az.SubscriptionID) az.VirtualMachinesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.VirtualMachinesClient.Authorizer = servicePrincipalToken + az.VirtualMachinesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.VirtualMachinesClient.PollingDelay = 5 * time.Second configureUserAgent(&az.VirtualMachinesClient.Client) az.PublicIPAddressesClient = network.NewPublicIPAddressesClient(az.SubscriptionID) az.PublicIPAddressesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.PublicIPAddressesClient.Authorizer = servicePrincipalToken + az.PublicIPAddressesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.PublicIPAddressesClient.PollingDelay = 5 * time.Second configureUserAgent(&az.PublicIPAddressesClient.Client) az.SecurityGroupsClient = network.NewSecurityGroupsClient(az.SubscriptionID) az.SecurityGroupsClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.SecurityGroupsClient.Authorizer = servicePrincipalToken + az.SecurityGroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) az.SecurityGroupsClient.PollingDelay = 5 * time.Second configureUserAgent(&az.SecurityGroupsClient.Client) az.StorageAccountClient = storage.NewAccountsClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) - az.StorageAccountClient.Authorizer = servicePrincipalToken + az.StorageAccountClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + configureUserAgent(&az.StorageAccountClient.Client) + + az.DisksClient = disk.NewDisksClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) + az.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + configureUserAgent(&az.DisksClient.Client) // Conditionally configure rate limits if az.CloudProviderRateLimit { @@ -254,9 +320,37 @@ func NewCloud(configReader io.Reader) (cloudprovider.Interface, error) { az.CloudProviderBackoffJitter) } + if err := initDiskControllers(&az); err != nil { + return nil, err + } return &az, nil } +// ParseConfig returns a parsed configuration and azure.Environment for an Azure cloudprovider config file +func ParseConfig(configReader io.Reader) (*Config, *azure.Environment, error) { + var config Config + + configContents, err := ioutil.ReadAll(configReader) + if err != nil { + return nil, nil, err + } + err = yaml.Unmarshal(configContents, &config) + if err != nil { + return nil, nil, err + } + + var env azure.Environment + if config.Cloud == "" { + env = azure.PublicCloud + } else { + env, err = azure.EnvironmentFromName(config.Cloud) + if err != nil { + return nil, nil, err + } + } + return &config, &env, nil +} + // Initialize passes a Kubernetes clientBuilder interface to the cloud provider func (az *Cloud) Initialize(clientBuilder controller.ControllerClientBuilder) {} @@ -303,3 +397,42 @@ func configureUserAgent(client *autorest.Client) { k8sVersion := version.Get().GitVersion client.UserAgent = fmt.Sprintf("%s; kubernetes-cloudprovider/%s", client.UserAgent, k8sVersion) } + +func initDiskControllers(az *Cloud) error { + // Common controller contains the function + // needed by both blob disk and managed disk controllers + + common := &controllerCommon{ + aadResourceEndPoint: az.Environment.ServiceManagementEndpoint, + clientID: az.AADClientID, + clientSecret: az.AADClientSecret, + location: az.Location, + storageEndpointSuffix: az.Environment.StorageEndpointSuffix, + managementEndpoint: az.Environment.ResourceManagerEndpoint, + resourceGroup: az.ResourceGroup, + tenantID: az.TenantID, + tokenEndPoint: az.Environment.ActiveDirectoryEndpoint, + subscriptionID: az.SubscriptionID, + cloud: az, + } + + // BlobDiskController: contains the function needed to + // create/attach/detach/delete blob based (unmanaged disks) + blobController, err := newBlobDiskController(common) + if err != nil { + return fmt.Errorf("AzureDisk - failed to init Blob Disk Controller with error (%s)", err.Error()) + } + + // ManagedDiskController: contains the functions needed to + // create/attach/detach/delete managed disks + managedController, err := newManagedDiskController(common) + if err != nil { + return fmt.Errorf("AzureDisk - failed to init Managed Disk Controller with error (%s)", err.Error()) + } + + az.BlobDiskController = blobController + az.ManagedDiskController = managedController + az.controllerCommon = common + + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_backoff.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_backoff.go index 3fca4c4933..839592f303 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_backoff.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_backoff.go @@ -47,8 +47,10 @@ func (az *Cloud) GetVirtualMachineWithRetry(name types.NodeName) (compute.Virtua func (az *Cloud) CreateOrUpdateSGWithRetry(sg network.SecurityGroup) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *sg.Name, sg, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *sg.Name, sg, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -56,8 +58,10 @@ func (az *Cloud) CreateOrUpdateSGWithRetry(sg network.SecurityGroup) error { func (az *Cloud) CreateOrUpdateLBWithRetry(lb network.LoadBalancer) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -65,8 +69,10 @@ func (az *Cloud) CreateOrUpdateLBWithRetry(lb network.LoadBalancer) error { func (az *Cloud) CreateOrUpdatePIPWithRetry(pip network.PublicIPAddress) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.PublicIPAddressesClient.CreateOrUpdate(az.ResourceGroup, *pip.Name, pip, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.PublicIPAddressesClient.CreateOrUpdate(az.ResourceGroup, *pip.Name, pip, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -74,8 +80,10 @@ func (az *Cloud) CreateOrUpdatePIPWithRetry(pip network.PublicIPAddress) error { func (az *Cloud) CreateOrUpdateInterfaceWithRetry(nic network.Interface) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.InterfacesClient.CreateOrUpdate(az.ResourceGroup, *nic.Name, nic, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.InterfacesClient.CreateOrUpdate(az.ResourceGroup, *nic.Name, nic, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -83,7 +91,9 @@ func (az *Cloud) CreateOrUpdateInterfaceWithRetry(nic network.Interface) error { func (az *Cloud) DeletePublicIPWithRetry(pipName string) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.PublicIPAddressesClient.Delete(az.ResourceGroup, pipName, nil) + respChan, errChan := az.PublicIPAddressesClient.Delete(az.ResourceGroup, pipName, nil) + resp := <-respChan + err := <-errChan return processRetryResponse(resp, err) }) } @@ -92,7 +102,9 @@ func (az *Cloud) DeletePublicIPWithRetry(pipName string) error { func (az *Cloud) DeleteLBWithRetry(lbName string) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.LoadBalancerClient.Delete(az.ResourceGroup, lbName, nil) + respChan, errChan := az.LoadBalancerClient.Delete(az.ResourceGroup, lbName, nil) + resp := <-respChan + err := <-errChan return processRetryResponse(resp, err) }) } @@ -101,8 +113,10 @@ func (az *Cloud) DeleteLBWithRetry(lbName string) error { func (az *Cloud) CreateOrUpdateRouteTableWithRetry(routeTable network.RouteTable) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.RouteTablesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, routeTable, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.RouteTablesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, routeTable, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -110,8 +124,10 @@ func (az *Cloud) CreateOrUpdateRouteTableWithRetry(routeTable network.RouteTable func (az *Cloud) CreateOrUpdateRouteWithRetry(route network.Route) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.RoutesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, *route.Name, route, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.RoutesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, *route.Name, route, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } @@ -119,7 +135,9 @@ func (az *Cloud) CreateOrUpdateRouteWithRetry(route network.Route) error { func (az *Cloud) DeleteRouteWithRetry(routeName string) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.RoutesClient.Delete(az.ResourceGroup, az.RouteTableName, routeName, nil) + respChan, errChan := az.RoutesClient.Delete(az.ResourceGroup, az.RouteTableName, routeName, nil) + resp := <-respChan + err := <-errChan return processRetryResponse(resp, err) }) } @@ -128,8 +146,10 @@ func (az *Cloud) DeleteRouteWithRetry(routeName string) error { func (az *Cloud) CreateOrUpdateVMWithRetry(vmName string, newVM compute.VirtualMachine) error { return wait.ExponentialBackoff(az.resourceRequestBackoff, func() (bool, error) { az.operationPollRateLimiter.Accept() - resp, err := az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil) - return processRetryResponse(resp, err) + respChan, errChan := az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil) + resp := <-respChan + err := <-errChan + return processRetryResponse(resp.Response, err) }) } diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blob.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blob.go deleted file mode 100644 index 47d1edd130..0000000000 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blob.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package azure - -import ( - "fmt" - "regexp" - "strings" - - azs "github.com/Azure/azure-sdk-for-go/storage" -) - -const ( - vhdContainerName = "vhds" - useHTTPS = true - blobServiceName = "blob" -) - -// create page blob -func (az *Cloud) createVhdBlob(accountName, accountKey, name string, sizeGB int64, tags map[string]string) (string, string, error) { - blobClient, err := az.getBlobClient(accountName, accountKey) - if err != nil { - return "", "", err - } - size := 1024 * 1024 * 1024 * sizeGB - vhdSize := size + vhdHeaderSize /* header size */ - // Blob name in URL must end with '.vhd' extension. - name = name + ".vhd" - err = blobClient.PutPageBlob(vhdContainerName, name, vhdSize, tags) - if err != nil { - // if container doesn't exist, create one and retry PutPageBlob - detail := err.Error() - if strings.Contains(detail, errContainerNotFound) { - err = blobClient.CreateContainer(vhdContainerName, azs.ContainerAccessTypePrivate) - if err == nil { - err = blobClient.PutPageBlob(vhdContainerName, name, vhdSize, tags) - } - } - } - if err != nil { - return "", "", fmt.Errorf("failed to put page blob: %v", err) - } - - // add VHD signature to the blob - h, err := createVHDHeader(uint64(size)) - if err != nil { - az.deleteVhdBlob(accountName, accountKey, name) - return "", "", fmt.Errorf("failed to create vhd header, err: %v", err) - } - if err = blobClient.PutPage(vhdContainerName, name, size, vhdSize-1, azs.PageWriteTypeUpdate, h[:vhdHeaderSize], nil); err != nil { - az.deleteVhdBlob(accountName, accountKey, name) - return "", "", fmt.Errorf("failed to update vhd header, err: %v", err) - } - - scheme := "http" - if useHTTPS { - scheme = "https" - } - host := fmt.Sprintf("%s://%s.%s.%s", scheme, accountName, blobServiceName, az.Environment.StorageEndpointSuffix) - uri := fmt.Sprintf("%s/%s/%s", host, vhdContainerName, name) - return name, uri, nil - -} - -// delete a vhd blob -func (az *Cloud) deleteVhdBlob(accountName, accountKey, blobName string) error { - blobClient, err := az.getBlobClient(accountName, accountKey) - if err == nil { - return blobClient.DeleteBlob(vhdContainerName, blobName, nil) - } - return err -} - -func (az *Cloud) getBlobClient(accountName, accountKey string) (*azs.BlobStorageClient, error) { - client, err := azs.NewClient(accountName, accountKey, az.Environment.StorageEndpointSuffix, azs.DefaultAPIVersion, useHTTPS) - if err != nil { - return nil, fmt.Errorf("error creating azure client: %v", err) - } - b := client.GetBlobService() - return &b, nil -} - -// get uri https://foo.blob.core.windows.net/vhds/bar.vhd and return foo (account) and bar.vhd (blob name) -func (az *Cloud) getBlobNameAndAccountFromURI(uri string) (string, string, error) { - scheme := "http" - if useHTTPS { - scheme = "https" - } - host := fmt.Sprintf("%s://(.*).%s.%s", scheme, blobServiceName, az.Environment.StorageEndpointSuffix) - reStr := fmt.Sprintf("%s/%s/(.*)", host, vhdContainerName) - re := regexp.MustCompile(reStr) - res := re.FindSubmatch([]byte(uri)) - if len(res) < 3 { - return "", "", fmt.Errorf("invalid vhd URI for regex %s: %s", reStr, uri) - } - return string(res[1]), string(res[2]), nil -} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blobDiskController.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blobDiskController.go new file mode 100644 index 0000000000..037c4941ef --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_blobDiskController.go @@ -0,0 +1,808 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "net/url" + "os" + "regexp" + "sync" + + "strconv" + "strings" + "sync/atomic" + "time" + + storage "github.com/Azure/azure-sdk-for-go/arm/storage" + azstorage "github.com/Azure/azure-sdk-for-go/storage" + "github.com/Azure/go-autorest/autorest/to" + "github.com/golang/glog" + "github.com/rubiojr/go-vhd/vhd" + kwait "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/volume" +) + +const ( + vhdContainerName = "vhds" + useHTTPSForBlobBasedDisk = true + blobServiceName = "blob" +) + +type storageAccountState struct { + name string + saType storage.SkuName + key string + diskCount int32 + isValidating int32 + defaultContainerCreated bool +} + +//BlobDiskController : blob disk controller struct +type BlobDiskController struct { + common *controllerCommon + accounts map[string]*storageAccountState +} + +var defaultContainerName = "" +var storageAccountNamePrefix = "" +var storageAccountNameMatch = "" +var initFlag int64 + +var accountsLock = &sync.Mutex{} + +func newBlobDiskController(common *controllerCommon) (*BlobDiskController, error) { + c := BlobDiskController{common: common} + err := c.init() + + if err != nil { + return nil, err + } + + return &c, nil +} + +// CreateVolume creates a VHD blob in a given storage account, will create the given storage account if it does not exist in current resource group +func (c *BlobDiskController) CreateVolume(name, storageAccount string, storageAccountType storage.SkuName, location string, requestGB int) (string, string, int, error) { + key, err := c.common.cloud.getStorageAccesskey(storageAccount) + if err != nil { + glog.V(2).Infof("azureDisk - no key found for storage account %s in resource group %s, begin to create a new storage account", storageAccount, c.common.resourceGroup) + + cp := storage.AccountCreateParameters{ + Sku: &storage.Sku{Name: storageAccountType}, + Tags: &map[string]*string{"created-by": to.StringPtr("azure-dd")}, + Location: &location} + cancel := make(chan struct{}) + + _, errchan := c.common.cloud.StorageAccountClient.Create(c.common.resourceGroup, storageAccount, cp, cancel) + err = <-errchan + if err != nil { + return "", "", 0, fmt.Errorf(fmt.Sprintf("Create Storage Account %s, error: %s", storageAccount, err)) + } + + key, err = c.common.cloud.getStorageAccesskey(storageAccount) + if err != nil { + return "", "", 0, fmt.Errorf("no key found for storage account %s even after creating a new storage account", storageAccount) + } + + glog.Errorf("no key found for storage account %s in resource group %s", storageAccount, c.common.resourceGroup) + return "", "", 0, err + } + + client, err := azstorage.NewBasicClient(storageAccount, key) + if err != nil { + return "", "", 0, err + } + blobClient := client.GetBlobService() + + container := blobClient.GetContainerReference(vhdContainerName) + _, err = container.CreateIfNotExists(&azstorage.CreateContainerOptions{Access: azstorage.ContainerAccessTypePrivate}) + if err != nil { + return "", "", 0, err + } + + diskName, diskURI, err := c.createVHDBlobDisk(blobClient, storageAccount, name, vhdContainerName, int64(requestGB)) + if err != nil { + return "", "", 0, err + } + + glog.V(4).Infof("azureDisk - created vhd blob uri: %s", diskURI) + return diskName, diskURI, requestGB, err +} + +// DeleteVolume deletes a VHD blob +func (c *BlobDiskController) DeleteVolume(diskURI string) error { + glog.V(4).Infof("azureDisk - begin to delete volume %s", diskURI) + accountName, blob, err := c.common.cloud.getBlobNameAndAccountFromURI(diskURI) + if err != nil { + return fmt.Errorf("failed to parse vhd URI %v", err) + } + key, err := c.common.cloud.getStorageAccesskey(accountName) + if err != nil { + return fmt.Errorf("no key for storage account %s, err %v", accountName, err) + } + err = c.common.cloud.deleteVhdBlob(accountName, key, blob) + if err != nil { + glog.Warningf("azureDisk - failed to delete blob %s err: %v", diskURI, err) + detail := err.Error() + if strings.Contains(detail, errLeaseIDMissing) { + // disk is still being used + // see https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.blob.protocol.bloberrorcodestrings.leaseidmissing.aspx + return volume.NewDeletedVolumeInUseError(fmt.Sprintf("disk %q is still in use while being deleted", diskURI)) + } + return fmt.Errorf("failed to delete vhd %v, account %s, blob %s, err: %v", diskURI, accountName, blob, err) + } + glog.V(4).Infof("azureDisk - blob %s deleted", diskURI) + return nil + +} + +// get diskURI https://foo.blob.core.windows.net/vhds/bar.vhd and return foo (account) and bar.vhd (blob name) +func (c *BlobDiskController) getBlobNameAndAccountFromURI(diskURI string) (string, string, error) { + scheme := "http" + if useHTTPSForBlobBasedDisk { + scheme = "https" + } + host := fmt.Sprintf("%s://(.*).%s.%s", scheme, blobServiceName, c.common.storageEndpointSuffix) + reStr := fmt.Sprintf("%s/%s/(.*)", host, vhdContainerName) + re := regexp.MustCompile(reStr) + res := re.FindSubmatch([]byte(diskURI)) + if len(res) < 3 { + return "", "", fmt.Errorf("invalid vhd URI for regex %s: %s", reStr, diskURI) + } + return string(res[1]), string(res[2]), nil +} + +func (c *BlobDiskController) createVHDBlobDisk(blobClient azstorage.BlobStorageClient, accountName, vhdName, containerName string, sizeGB int64) (string, string, error) { + container := blobClient.GetContainerReference(containerName) + _, err := container.CreateIfNotExists(&azstorage.CreateContainerOptions{Access: azstorage.ContainerAccessTypePrivate}) + if err != nil { + return "", "", err + } + + size := 1024 * 1024 * 1024 * sizeGB + vhdSize := size + vhd.VHD_HEADER_SIZE /* header size */ + // Blob name in URL must end with '.vhd' extension. + vhdName = vhdName + ".vhd" + + tags := make(map[string]string) + tags["createdby"] = "k8sAzureDataDisk" + glog.V(4).Infof("azureDisk - creating page blob %name in container %s account %s", vhdName, containerName, accountName) + + blob := container.GetBlobReference(vhdName) + blob.Properties.ContentLength = vhdSize + blob.Metadata = tags + err = blob.PutPageBlob(nil) + if err != nil { + return "", "", fmt.Errorf("failed to put page blob %s in container %s: %v", vhdName, containerName, err) + } + + // add VHD signature to the blob + h, err := createVHDHeader(uint64(size)) + if err != nil { + blob.DeleteIfExists(nil) + return "", "", fmt.Errorf("failed to create vhd header, err: %v", err) + } + + blobRange := azstorage.BlobRange{ + Start: uint64(size), + End: uint64(vhdSize - 1), + } + if err = blob.WriteRange(blobRange, bytes.NewBuffer(h[:vhd.VHD_HEADER_SIZE]), nil); err != nil { + glog.Infof("azureDisk - failed to put header page for data disk %s in container %s account %s, error was %s\n", + vhdName, containerName, accountName, err.Error()) + return "", "", err + } + + scheme := "http" + if useHTTPSForBlobBasedDisk { + scheme = "https" + } + + host := fmt.Sprintf("%s://%s.%s.%s", scheme, accountName, blobServiceName, c.common.storageEndpointSuffix) + uri := fmt.Sprintf("%s/%s/%s", host, containerName, vhdName) + return vhdName, uri, nil +} + +// delete a vhd blob +func (c *BlobDiskController) deleteVhdBlob(accountName, accountKey, blobName string) error { + client, err := azstorage.NewBasicClient(accountName, accountKey) + if err != nil { + return err + } + blobSvc := client.GetBlobService() + + container := blobSvc.GetContainerReference(vhdContainerName) + blob := container.GetBlobReference(blobName) + return blob.Delete(nil) +} + +//CreateBlobDisk : create a blob disk in a node +func (c *BlobDiskController) CreateBlobDisk(dataDiskName string, storageAccountType storage.SkuName, sizeGB int, forceStandAlone bool) (string, error) { + glog.V(4).Infof("azureDisk - creating blob data disk named:%s on StorageAccountType:%s StandAlone:%v", dataDiskName, storageAccountType, forceStandAlone) + + var storageAccountName = "" + var err error + + if forceStandAlone { + // we have to wait until the storage account is is created + storageAccountName = "p" + MakeCRC32(c.common.subscriptionID+c.common.resourceGroup+dataDiskName) + err = c.createStorageAccount(storageAccountName, storageAccountType, c.common.location, false) + if err != nil { + return "", err + } + } else { + storageAccountName, err = c.findSANameForDisk(storageAccountType) + if err != nil { + return "", err + } + } + + blobClient, err := c.getBlobSvcClient(storageAccountName) + if err != nil { + return "", err + } + + _, diskURI, err := c.createVHDBlobDisk(blobClient, storageAccountName, dataDiskName, defaultContainerName, int64(sizeGB)) + if err != nil { + return "", err + } + + if !forceStandAlone { + atomic.AddInt32(&c.accounts[storageAccountName].diskCount, 1) + } + + return diskURI, nil +} + +//DeleteBlobDisk : delete a blob disk from a node +func (c *BlobDiskController) DeleteBlobDisk(diskURI string, wasForced bool) error { + storageAccountName, vhdName, err := diskNameandSANameFromURI(diskURI) + if err != nil { + return err + } + + _, ok := c.accounts[storageAccountName] + if !ok { + // the storage account is specified by user + glog.V(4).Infof("azureDisk - deleting volume %s", diskURI) + return c.DeleteVolume(diskURI) + } + // if forced (as in one disk = one storage account) + // delete the account completely + if wasForced { + return c.deleteStorageAccount(storageAccountName) + } + + blobSvc, err := c.getBlobSvcClient(storageAccountName) + if err != nil { + return err + } + + glog.V(4).Infof("azureDisk - About to delete vhd file %s on storage account %s container %s", vhdName, storageAccountName, defaultContainerName) + + container := blobSvc.GetContainerReference(defaultContainerName) + blob := container.GetBlobReference(vhdName) + _, err = blob.DeleteIfExists(nil) + + if c.accounts[storageAccountName].diskCount == -1 { + if diskCount, err := c.getDiskCount(storageAccountName); err != nil { + c.accounts[storageAccountName].diskCount = int32(diskCount) + } else { + glog.Warningf("azureDisk - failed to get disk count for %s however the delete disk operation was ok", storageAccountName) + return nil // we have failed to aquire a new count. not an error condition + } + } + atomic.AddInt32(&c.accounts[storageAccountName].diskCount, -1) + return err +} + +// Init tries best effort to ensure that 2 accounts standard/premium were created +// to be used by shared blob disks. This to increase the speed pvc provisioning (in most of cases) +func (c *BlobDiskController) init() error { + if !c.shouldInit() { + return nil + } + + c.setUniqueStrings() + + // get accounts + accounts, err := c.getAllStorageAccounts() + if err != nil { + return err + } + c.accounts = accounts + + if len(c.accounts) == 0 { + counter := 1 + for counter <= storageAccountsCountInit { + + accountType := storage.PremiumLRS + if n := math.Mod(float64(counter), 2); n == 0 { + accountType = storage.StandardLRS + } + + // We don't really care if these calls failed + // at this stage, we are trying to ensure 2 accounts (Standard/Premium) + // are there ready for PVC creation + + // if we failed here, the accounts will be created in the process + // of creating PVC + + // nor do we care if they were partially created, as the entire + // account creation process is idempotent + go func(thisNext int) { + newAccountName := getAccountNameForNum(thisNext) + + glog.Infof("azureDisk - BlobDiskController init process will create new storageAccount:%s type:%s", newAccountName, accountType) + err := c.createStorageAccount(newAccountName, accountType, c.common.location, true) + // TODO return created and error from + if err != nil { + glog.Infof("azureDisk - BlobDiskController init: create account %s with error:%s", newAccountName, err.Error()) + + } else { + glog.Infof("azureDisk - BlobDiskController init: created account %s", newAccountName) + } + }(counter) + counter = counter + 1 + } + } + + return nil +} + +//Sets unique strings to be used as accountnames && || blob containers names +func (c *BlobDiskController) setUniqueStrings() { + uniqueString := c.common.resourceGroup + c.common.location + c.common.subscriptionID + hash := MakeCRC32(uniqueString) + //used to generate a unqie container name used by this cluster PVC + defaultContainerName = hash + + storageAccountNamePrefix = fmt.Sprintf(storageAccountNameTemplate, hash) + // Used to filter relevant accounts (accounts used by shared PVC) + storageAccountNameMatch = storageAccountNamePrefix + // Used as a template to create new names for relevant accounts + storageAccountNamePrefix = storageAccountNamePrefix + "%s" +} +func (c *BlobDiskController) getStorageAccountKey(SAName string) (string, error) { + if account, exists := c.accounts[SAName]; exists && account.key != "" { + return c.accounts[SAName].key, nil + } + listKeysResult, err := c.common.cloud.StorageAccountClient.ListKeys(c.common.resourceGroup, SAName) + if err != nil { + return "", err + } + if listKeysResult.Keys == nil { + return "", fmt.Errorf("azureDisk - empty listKeysResult in storage account:%s keys", SAName) + } + for _, v := range *listKeysResult.Keys { + if v.Value != nil && *v.Value == "key1" { + if _, ok := c.accounts[SAName]; !ok { + glog.Warningf("azureDisk - account %s was not cached while getting keys", SAName) + return *v.Value, nil + } + } + + c.accounts[SAName].key = *v.Value + return c.accounts[SAName].key, nil + } + + return "", fmt.Errorf("couldn't find key named key1 in storage account:%s keys", SAName) +} + +func (c *BlobDiskController) getBlobSvcClient(SAName string) (azstorage.BlobStorageClient, error) { + key := "" + var client azstorage.Client + var blobSvc azstorage.BlobStorageClient + var err error + if key, err = c.getStorageAccountKey(SAName); err != nil { + return blobSvc, err + } + + if client, err = azstorage.NewBasicClient(SAName, key); err != nil { + return blobSvc, err + } + + blobSvc = client.GetBlobService() + return blobSvc, nil +} + +func (c *BlobDiskController) ensureDefaultContainer(storageAccountName string) error { + var err error + var blobSvc azstorage.BlobStorageClient + + // short circut the check via local cache + // we are forgiving the fact that account may not be in cache yet + if v, ok := c.accounts[storageAccountName]; ok && v.defaultContainerCreated { + return nil + } + + // not cached, check existance and readiness + bExist, provisionState, _ := c.getStorageAccountState(storageAccountName) + + // account does not exist + if !bExist { + return fmt.Errorf("azureDisk - account %s does not exist while trying to create/ensure default container", storageAccountName) + } + + // account exists but not ready yet + if provisionState != storage.Succeeded { + // we don't want many attempts to validate the account readiness + // here hence we are locking + counter := 1 + for swapped := atomic.CompareAndSwapInt32(&c.accounts[storageAccountName].isValidating, 0, 1); swapped != true; { + time.Sleep(3 * time.Second) + counter = counter + 1 + // check if we passed the max sleep + if counter >= 20 { + return fmt.Errorf("azureDisk - timeout waiting to aquire lock to validate account:%s readiness", storageAccountName) + } + } + + // swapped + defer func() { + c.accounts[storageAccountName].isValidating = 0 + }() + + // short circut the check again. + if v, ok := c.accounts[storageAccountName]; ok && v.defaultContainerCreated { + return nil + } + + err = kwait.ExponentialBackoff(defaultBackOff, func() (bool, error) { + _, provisionState, err := c.getStorageAccountState(storageAccountName) + + if err != nil { + glog.V(4).Infof("azureDisk - GetStorageAccount:%s err %s", storageAccountName, err.Error()) + return false, err + } + + if provisionState == storage.Succeeded { + return true, nil + } + + glog.V(4).Infof("azureDisk - GetStorageAccount:%s not ready yet", storageAccountName) + // leave it for next loop/sync loop + return false, fmt.Errorf("azureDisk - Account %s has not been flagged Succeeded by ARM", storageAccountName) + }) + // we have failed to ensure that account is ready for us to create + // the default vhd container + if err != nil { + return err + } + } + + if blobSvc, err = c.getBlobSvcClient(storageAccountName); err != nil { + return err + } + + container := blobSvc.GetContainerReference(defaultContainerName) + bCreated, err := container.CreateIfNotExists(&azstorage.CreateContainerOptions{Access: azstorage.ContainerAccessTypePrivate}) + if err != nil { + return err + } + if bCreated { + glog.V(2).Infof("azureDisk - storage account:%s had no default container(%s) and it was created \n", storageAccountName, defaultContainerName) + } + + // flag so we no longer have to check on ARM + c.accounts[storageAccountName].defaultContainerCreated = true + return nil +} + +// Gets Disk counts per storage account +func (c *BlobDiskController) getDiskCount(SAName string) (int, error) { + // if we have it in cache + if c.accounts[SAName].diskCount != -1 { + return int(c.accounts[SAName].diskCount), nil + } + + var err error + var blobSvc azstorage.BlobStorageClient + + if err = c.ensureDefaultContainer(SAName); err != nil { + return 0, err + } + + if blobSvc, err = c.getBlobSvcClient(SAName); err != nil { + return 0, err + } + params := azstorage.ListBlobsParameters{} + + container := blobSvc.GetContainerReference(defaultContainerName) + response, err := container.ListBlobs(params) + if err != nil { + return 0, err + } + glog.V(4).Infof("azure-Disk - refreshed data count for account %s and found %v", SAName, len(response.Blobs)) + c.accounts[SAName].diskCount = int32(len(response.Blobs)) + + return int(c.accounts[SAName].diskCount), nil +} + +// shouldInit ensures that we only init the plugin once +// and we only do that in the controller + +func (c *BlobDiskController) shouldInit() bool { + if os.Args[0] == "kube-controller-manager" || (os.Args[0] == "/hyperkube" && os.Args[1] == "controller-manager") { + swapped := atomic.CompareAndSwapInt64(&initFlag, 0, 1) + if swapped { + return true + } + } + return false +} + +func (c *BlobDiskController) getAllStorageAccounts() (map[string]*storageAccountState, error) { + accountListResult, err := c.common.cloud.StorageAccountClient.List() + if err != nil { + return nil, err + } + if accountListResult.Value == nil { + return nil, fmt.Errorf("azureDisk - empty accountListResult") + } + + accounts := make(map[string]*storageAccountState) + for _, v := range *accountListResult.Value { + if strings.Index(*v.Name, storageAccountNameMatch) != 0 { + continue + } + if v.Name == nil || v.Sku == nil { + glog.Infof("azureDisk - accountListResult Name or Sku is nil") + continue + } + glog.Infof("azureDisk - identified account %s as part of shared PVC accounts", *v.Name) + + sastate := &storageAccountState{ + name: *v.Name, + saType: (*v.Sku).Name, + diskCount: -1, + } + + accounts[*v.Name] = sastate + } + + return accounts, nil +} + +func (c *BlobDiskController) createStorageAccount(storageAccountName string, storageAccountType storage.SkuName, location string, checkMaxAccounts bool) error { + bExist, _, _ := c.getStorageAccountState(storageAccountName) + if bExist { + newAccountState := &storageAccountState{ + diskCount: -1, + saType: storageAccountType, + name: storageAccountName, + } + + c.addAccountState(storageAccountName, newAccountState) + } + // Account Does not exist + if !bExist { + if len(c.accounts) == maxStorageAccounts && checkMaxAccounts { + return fmt.Errorf("azureDisk - can not create new storage account, current storage accounts count:%v Max is:%v", len(c.accounts), maxStorageAccounts) + } + + glog.V(2).Infof("azureDisk - Creating storage account %s type %s \n", storageAccountName, string(storageAccountType)) + + cp := storage.AccountCreateParameters{ + Sku: &storage.Sku{Name: storageAccountType}, + Tags: &map[string]*string{"created-by": to.StringPtr("azure-dd")}, + Location: &location} + cancel := make(chan struct{}) + + _, errChan := c.common.cloud.StorageAccountClient.Create(c.common.resourceGroup, storageAccountName, cp, cancel) + err := <-errChan + if err != nil { + return fmt.Errorf(fmt.Sprintf("Create Storage Account: %s, error: %s", storageAccountName, err)) + } + + newAccountState := &storageAccountState{ + diskCount: -1, + saType: storageAccountType, + name: storageAccountName, + } + + c.addAccountState(storageAccountName, newAccountState) + } + + if !bExist { + // SA Accounts takes time to be provisioned + // so if this account was just created allow it sometime + // before polling + glog.V(2).Infof("azureDisk - storage account %s was just created, allowing time before polling status") + time.Sleep(25 * time.Second) // as observed 25 is the average time for SA to be provisioned + } + + // finally, make sure that we default container is created + // before handing it back over + return c.ensureDefaultContainer(storageAccountName) +} + +// finds a new suitable storageAccount for this disk +func (c *BlobDiskController) findSANameForDisk(storageAccountType storage.SkuName) (string, error) { + maxDiskCount := maxDisksPerStorageAccounts + SAName := "" + totalDiskCounts := 0 + countAccounts := 0 // account of this type. + for _, v := range c.accounts { + // filter out any stand-alone disks/accounts + if strings.Index(v.name, storageAccountNameMatch) != 0 { + continue + } + + // note: we compute avge stratified by type. + // this to enable user to grow per SA type to avoid low + //avg utilization on one account type skewing all data. + + if v.saType == storageAccountType { + // compute average + dCount, err := c.getDiskCount(v.name) + if err != nil { + return "", err + } + totalDiskCounts = totalDiskCounts + dCount + countAccounts = countAccounts + 1 + // empty account + if dCount == 0 { + glog.V(2).Infof("azureDisk - account %s identified for a new disk is because it has 0 allocated disks", v.name) + return v.name, nil // shortcircut, avg is good and no need to adjust + } + // if this account is less allocated + if dCount < maxDiskCount { + maxDiskCount = dCount + SAName = v.name + } + } + } + + // if we failed to find storageaccount + if SAName == "" { + glog.V(2).Infof("azureDisk - failed to identify a suitable account for new disk and will attempt to create new account") + SAName = getAccountNameForNum(c.getNextAccountNum()) + err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true) + if err != nil { + return "", err + } + return SAName, nil + } + + disksAfter := totalDiskCounts + 1 // with the new one! + + avgUtilization := float64(disksAfter) / float64(countAccounts*maxDisksPerStorageAccounts) + aboveAvg := (avgUtilization > storageAccountUtilizationBeforeGrowing) + + // avg are not create and we should craete more accounts if we can + if aboveAvg && countAccounts < maxStorageAccounts { + glog.V(2).Infof("azureDisk - shared storageAccounts utilzation(%v) > grow-at-avg-utilization (%v). New storage account will be created", avgUtilization, storageAccountUtilizationBeforeGrowing) + SAName = getAccountNameForNum(c.getNextAccountNum()) + err := c.createStorageAccount(SAName, storageAccountType, c.common.location, true) + if err != nil { + return "", err + } + return SAName, nil + } + + // avergates are not ok and we are at capacity(max storage accounts allowed) + if aboveAvg && countAccounts == maxStorageAccounts { + glog.Infof("azureDisk - shared storageAccounts utilzation(%v) > grow-at-avg-utilization (%v). But k8s maxed on SAs for PVC(%v). k8s will now exceed grow-at-avg-utilization without adding accounts", + avgUtilization, storageAccountUtilizationBeforeGrowing, maxStorageAccounts) + } + + // we found a storage accounts && [ avg are ok || we reached max sa count ] + return SAName, nil +} +func (c *BlobDiskController) getNextAccountNum() int { + max := 0 + + for k := range c.accounts { + // filter out accounts that are for standalone + if strings.Index(k, storageAccountNameMatch) != 0 { + continue + } + num := getAccountNumFromName(k) + if num > max { + max = num + } + } + + return max + 1 +} + +func (c *BlobDiskController) deleteStorageAccount(storageAccountName string) error { + resp, err := c.common.cloud.StorageAccountClient.Delete(c.common.resourceGroup, storageAccountName) + if err != nil { + return fmt.Errorf("azureDisk - Delete of storage account '%s' failed with status %s...%v", storageAccountName, resp.Status, err) + } + + c.removeAccountState(storageAccountName) + + glog.Infof("azureDisk - Storage Account %s was deleted", storageAccountName) + return nil +} + +//Gets storage account exist, provisionStatus, Error if any +func (c *BlobDiskController) getStorageAccountState(storageAccountName string) (bool, storage.ProvisioningState, error) { + account, err := c.common.cloud.StorageAccountClient.GetProperties(c.common.resourceGroup, storageAccountName) + if err != nil { + return false, "", err + } + return true, account.AccountProperties.ProvisioningState, nil +} + +func (c *BlobDiskController) addAccountState(key string, state *storageAccountState) { + accountsLock.Lock() + defer accountsLock.Unlock() + + if _, ok := c.accounts[key]; !ok { + c.accounts[key] = state + } +} + +func (c *BlobDiskController) removeAccountState(key string) { + accountsLock.Lock() + defer accountsLock.Unlock() + delete(c.accounts, key) +} + +// pads account num with zeros as needed +func getAccountNameForNum(num int) string { + sNum := strconv.Itoa(num) + missingZeros := 3 - len(sNum) + strZero := "" + for missingZeros > 0 { + strZero = strZero + "0" + missingZeros = missingZeros - 1 + } + + sNum = strZero + sNum + return fmt.Sprintf(storageAccountNamePrefix, sNum) +} + +func getAccountNumFromName(accountName string) int { + nameLen := len(accountName) + num, _ := strconv.Atoi(accountName[nameLen-3:]) + + return num +} + +func createVHDHeader(size uint64) ([]byte, error) { + h := vhd.CreateFixedHeader(size, &vhd.VHDOptions{}) + b := new(bytes.Buffer) + err := binary.Write(b, binary.BigEndian, h) + if err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func diskNameandSANameFromURI(diskURI string) (string, string, error) { + uri, err := url.Parse(diskURI) + if err != nil { + return "", "", err + } + + hostName := uri.Host + storageAccountName := strings.Split(hostName, ".")[0] + + segments := strings.Split(uri.Path, "/") + diskNameVhd := segments[len(segments)-1] + + return storageAccountName, diskNameVhd, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_controllerCommon.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_controllerCommon.go new file mode 100644 index 0000000000..881a7dbb2c --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_controllerCommon.go @@ -0,0 +1,270 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure + +import ( + "fmt" + "strings" + "time" + + "k8s.io/apimachinery/pkg/types" + kwait "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/cloudprovider" + + "github.com/Azure/azure-sdk-for-go/arm/compute" + "github.com/golang/glog" +) + +const ( + defaultDataDiskCount int = 16 // which will allow you to work with most medium size VMs (if not found in map) + storageAccountNameTemplate = "pvc%s" + + // for limits check https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits#storage-limits + maxStorageAccounts = 100 // max # is 200 (250 with special request). this allows 100 for everything else including stand alone disks + maxDisksPerStorageAccounts = 60 + storageAccountUtilizationBeforeGrowing = 0.5 + storageAccountsCountInit = 2 // When the plug-in is init-ed, 2 storage accounts will be created to allow fast pvc create/attach/mount + + maxLUN = 64 // max number of LUNs per VM + errLeaseFailed = "AcquireDiskLeaseFailed" + errLeaseIDMissing = "LeaseIdMissing" + errContainerNotFound = "ContainerNotFound" +) + +var defaultBackOff = kwait.Backoff{ + Steps: 20, + Duration: 2 * time.Second, + Factor: 1.5, + Jitter: 0.0, +} + +type controllerCommon struct { + tenantID string + subscriptionID string + location string + storageEndpointSuffix string + resourceGroup string + clientID string + clientSecret string + managementEndpoint string + tokenEndPoint string + aadResourceEndPoint string + aadToken string + expiresOn time.Time + cloud *Cloud +} + +// AttachDisk attaches a vhd to vm +// the vhd must exist, can be identified by diskName, diskURI, and lun. +func (c *controllerCommon) AttachDisk(isManagedDisk bool, diskName, diskURI string, nodeName types.NodeName, lun int32, cachingMode compute.CachingTypes) error { + vm, exists, err := c.cloud.getVirtualMachine(nodeName) + if err != nil { + return err + } else if !exists { + return cloudprovider.InstanceNotFound + } + disks := *vm.StorageProfile.DataDisks + if isManagedDisk { + disks = append(disks, + compute.DataDisk{ + Name: &diskName, + Lun: &lun, + Caching: cachingMode, + CreateOption: "attach", + ManagedDisk: &compute.ManagedDiskParameters{ + ID: &diskURI, + }, + }) + } else { + disks = append(disks, + compute.DataDisk{ + Name: &diskName, + Vhd: &compute.VirtualHardDisk{ + URI: &diskURI, + }, + Lun: &lun, + Caching: cachingMode, + CreateOption: "attach", + }) + } + + newVM := compute.VirtualMachine{ + Location: vm.Location, + VirtualMachineProperties: &compute.VirtualMachineProperties{ + StorageProfile: &compute.StorageProfile{ + DataDisks: &disks, + }, + }, + } + vmName := mapNodeNameToVMName(nodeName) + glog.V(2).Infof("azureDisk - update(%s): vm(%s) - attach disk", c.resourceGroup, vmName) + c.cloud.operationPollRateLimiter.Accept() + respChan, errChan := c.cloud.VirtualMachinesClient.CreateOrUpdate(c.resourceGroup, vmName, newVM, nil) + resp := <-respChan + err = <-errChan + if c.cloud.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { + glog.V(2).Infof("azureDisk - update(%s) backing off: vm(%s)", c.resourceGroup, vmName) + retryErr := c.cloud.CreateOrUpdateVMWithRetry(vmName, newVM) + if retryErr != nil { + err = retryErr + glog.V(2).Infof("azureDisk - update(%s) abort backoff: vm(%s)", c.resourceGroup, vmName) + } + } + if err != nil { + glog.Errorf("azureDisk - azure attach failed, err: %v", err) + detail := err.Error() + if strings.Contains(detail, errLeaseFailed) { + // if lease cannot be acquired, immediately detach the disk and return the original error + glog.Infof("azureDisk - failed to acquire disk lease, try detach") + c.cloud.DetachDiskByName(diskName, diskURI, nodeName) + } + } else { + glog.V(4).Infof("azureDisk - azure attach succeeded") + } + return err +} + +// DetachDiskByName detaches a vhd from host +// the vhd can be identified by diskName or diskURI +func (c *controllerCommon) DetachDiskByName(diskName, diskURI string, nodeName types.NodeName) error { + vm, exists, err := c.cloud.getVirtualMachine(nodeName) + if err != nil || !exists { + // if host doesn't exist, no need to detach + glog.Warningf("azureDisk - cannot find node %s, skip detaching disk %s", nodeName, diskName) + return nil + } + + disks := *vm.StorageProfile.DataDisks + bFoundDisk := false + for i, disk := range disks { + if disk.Lun != nil && (disk.Name != nil && diskName != "" && *disk.Name == diskName) || + (disk.Vhd != nil && disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) || + (disk.ManagedDisk != nil && diskURI != "" && *disk.ManagedDisk.ID == diskURI) { + // found the disk + glog.V(4).Infof("azureDisk - detach disk: name %q uri %q", diskName, diskURI) + disks = append(disks[:i], disks[i+1:]...) + bFoundDisk = true + break + } + } + + if !bFoundDisk { + return fmt.Errorf("detach azure disk failure, disk %s not found, diskURI: %s", diskName, diskURI) + } + + newVM := compute.VirtualMachine{ + Location: vm.Location, + VirtualMachineProperties: &compute.VirtualMachineProperties{ + StorageProfile: &compute.StorageProfile{ + DataDisks: &disks, + }, + }, + } + vmName := mapNodeNameToVMName(nodeName) + glog.V(2).Infof("azureDisk - update(%s): vm(%s) - detach disk", c.resourceGroup, vmName) + c.cloud.operationPollRateLimiter.Accept() + respChan, errChan := c.cloud.VirtualMachinesClient.CreateOrUpdate(c.resourceGroup, vmName, newVM, nil) + resp := <-respChan + err = <-errChan + if c.cloud.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { + glog.V(2).Infof("azureDisk - update(%s) backing off: vm(%s)", c.resourceGroup, vmName) + retryErr := c.cloud.CreateOrUpdateVMWithRetry(vmName, newVM) + if retryErr != nil { + err = retryErr + glog.V(2).Infof("azureDisk - update(%s) abort backoff: vm(%s)", c.cloud.ResourceGroup, vmName) + } + } + if err != nil { + glog.Errorf("azureDisk - azure disk detach failed, err: %v", err) + } else { + glog.V(4).Infof("azureDisk - azure disk detach succeeded") + } + return err +} + +// GetDiskLun finds the lun on the host that the vhd is attached to, given a vhd's diskName and diskURI +func (c *controllerCommon) GetDiskLun(diskName, diskURI string, nodeName types.NodeName) (int32, error) { + vm, exists, err := c.cloud.getVirtualMachine(nodeName) + if err != nil { + return -1, err + } else if !exists { + return -1, cloudprovider.InstanceNotFound + } + disks := *vm.StorageProfile.DataDisks + for _, disk := range disks { + if disk.Lun != nil && (disk.Name != nil && diskName != "" && *disk.Name == diskName) || + (disk.Vhd != nil && disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) || + (disk.ManagedDisk != nil && *disk.ManagedDisk.ID == diskURI) { + // found the disk + glog.V(4).Infof("azureDisk - find disk: lun %d name %q uri %q", *disk.Lun, diskName, diskURI) + return *disk.Lun, nil + } + } + return -1, fmt.Errorf("Cannot find Lun for disk %s", diskName) +} + +// GetNextDiskLun searches all vhd attachment on the host and find unused lun +// return -1 if all luns are used +func (c *controllerCommon) GetNextDiskLun(nodeName types.NodeName) (int32, error) { + vm, exists, err := c.cloud.getVirtualMachine(nodeName) + if err != nil { + return -1, err + } else if !exists { + return -1, cloudprovider.InstanceNotFound + } + used := make([]bool, maxLUN) + disks := *vm.StorageProfile.DataDisks + for _, disk := range disks { + if disk.Lun != nil { + used[*disk.Lun] = true + } + } + for k, v := range used { + if !v { + return int32(k), nil + } + } + return -1, fmt.Errorf("All Luns are used") +} + +// DisksAreAttached checks if a list of volumes are attached to the node with the specified NodeName +func (c *controllerCommon) DisksAreAttached(diskNames []string, nodeName types.NodeName) (map[string]bool, error) { + attached := make(map[string]bool) + for _, diskName := range diskNames { + attached[diskName] = false + } + vm, exists, err := c.cloud.getVirtualMachine(nodeName) + if !exists { + // if host doesn't exist, no need to detach + glog.Warningf("azureDisk - Cannot find node %q, DisksAreAttached will assume disks %v are not attached to it.", + nodeName, diskNames) + return attached, nil + } else if err != nil { + return attached, err + } + + disks := *vm.StorageProfile.DataDisks + for _, disk := range disks { + for _, diskName := range diskNames { + if disk.Name != nil && diskName != "" && *disk.Name == diskName { + attached[diskName] = true + } + } + } + + return attached, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_file.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_file.go index ccdca622a4..4829112832 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_file.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_file.go @@ -18,9 +18,13 @@ package azure import ( "fmt" - "strconv" azs "github.com/Azure/azure-sdk-for-go/storage" + "github.com/golang/glog" +) + +const ( + useHTTPS = true ) // create file share @@ -34,11 +38,15 @@ func (az *Cloud) createFileShare(accountName, accountKey, name string, sizeGB in // setting x-ms-share-quota can set quota on the new share, but in reality, setting quota in CreateShare // receives error "The metadata specified is invalid. It has characters that are not permitted." // As a result,breaking into two API calls: create share and set quota - if err = fileClient.CreateShare(name, nil); err != nil { + share := fileClient.GetShareReference(name) + if err = share.Create(nil); err != nil { return fmt.Errorf("failed to create file share, err: %v", err) } - if err = fileClient.SetShareProperties(name, azs.ShareHeaders{Quota: strconv.Itoa(sizeGB)}); err != nil { - az.deleteFileShare(accountName, accountKey, name) + share.Properties.Quota = sizeGB + if err = share.SetProperties(nil); err != nil { + if err := share.Delete(nil); err != nil { + glog.Errorf("Error deleting share: %v", err) + } return fmt.Errorf("failed to set quota on file share %s, err: %v", name, err) } return nil @@ -48,9 +56,10 @@ func (az *Cloud) createFileShare(accountName, accountKey, name string, sizeGB in func (az *Cloud) deleteFileShare(accountName, accountKey, name string) error { fileClient, err := az.getFileSvcClient(accountName, accountKey) if err == nil { - return fileClient.DeleteShare(name) + share := fileClient.GetShareReference(name) + return share.Delete(nil) } - return err + return nil } func (az *Cloud) getFileSvcClient(accountName, accountKey string) (*azs.FileServiceClient, error) { diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_loadbalancer.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_loadbalancer.go index 741280f582..d334735cb7 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_loadbalancer.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_loadbalancer.go @@ -143,8 +143,10 @@ func (az *Cloud) EnsureLoadBalancer(clusterName string, service *v1.Service, nod sg.SecurityGroupPropertiesFormat.NetworkInterfaces = nil sg.SecurityGroupPropertiesFormat.Subnets = nil az.operationPollRateLimiter.Accept() - resp, err := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *sg.Name, sg, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *sg.Name, sg, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("ensure(%s) backing off: sg(%s) - updating", serviceName, *sg.Name) retryErr := az.CreateOrUpdateSGWithRetry(sg) if retryErr != nil { @@ -222,8 +224,10 @@ func (az *Cloud) EnsureLoadBalancer(clusterName string, service *v1.Service, nod if !existsLb || lbNeedsUpdate { glog.V(3).Infof("ensure(%s): lb(%s) - updating", serviceName, lbName) az.operationPollRateLimiter.Accept() - resp, err := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("ensure(%s) backing off: lb(%s) - updating", serviceName, lbName) retryErr := az.CreateOrUpdateLBWithRetry(lb) if retryErr != nil { @@ -315,8 +319,10 @@ func (az *Cloud) EnsureLoadBalancerDeleted(clusterName string, service *v1.Servi sg.SecurityGroupPropertiesFormat.NetworkInterfaces = nil sg.SecurityGroupPropertiesFormat.Subnets = nil az.operationPollRateLimiter.Accept() - resp, err := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *reconciledSg.Name, reconciledSg, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.SecurityGroupsClient.CreateOrUpdate(az.ResourceGroup, *reconciledSg.Name, reconciledSg, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("delete(%s) backing off: sg(%s) - updating", serviceName, az.SecurityGroupName) retryErr := az.CreateOrUpdateSGWithRetry(reconciledSg) if retryErr != nil { @@ -369,8 +375,10 @@ func (az *Cloud) cleanupLoadBalancer(clusterName string, service *v1.Service, is if len(*lb.FrontendIPConfigurations) > 0 { glog.V(3).Infof("delete(%s): lb(%s) - updating", serviceName, lbName) az.operationPollRateLimiter.Accept() - resp, err := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.LoadBalancerClient.CreateOrUpdate(az.ResourceGroup, *lb.Name, lb, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("delete(%s) backing off: sg(%s) - updating", serviceName, az.SecurityGroupName) retryErr := az.CreateOrUpdateLBWithRetry(lb) if retryErr != nil { @@ -385,7 +393,9 @@ func (az *Cloud) cleanupLoadBalancer(clusterName string, service *v1.Service, is glog.V(3).Infof("delete(%s): lb(%s) - deleting; no remaining frontendipconfigs", serviceName, lbName) az.operationPollRateLimiter.Accept() - resp, err := az.LoadBalancerClient.Delete(az.ResourceGroup, lbName, nil) + respChan, errChan := az.LoadBalancerClient.Delete(az.ResourceGroup, lbName, nil) + resp := <-respChan + err := <-errChan if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { glog.V(2).Infof("delete(%s) backing off: lb(%s) - deleting; no remaining frontendipconfigs", serviceName, lbName) retryErr := az.DeleteLBWithRetry(lbName) @@ -440,8 +450,10 @@ func (az *Cloud) ensurePublicIPExists(serviceName, pipName string) (*network.Pub glog.V(3).Infof("ensure(%s): pip(%s) - creating", serviceName, *pip.Name) az.operationPollRateLimiter.Accept() - resp, err := az.PublicIPAddressesClient.CreateOrUpdate(az.ResourceGroup, *pip.Name, pip, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.PublicIPAddressesClient.CreateOrUpdate(az.ResourceGroup, *pip.Name, pip, nil) + resp := <-respChan + err = <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("ensure(%s) backing off: pip(%s) - creating", serviceName, *pip.Name) retryErr := az.CreateOrUpdatePIPWithRetry(pip) if retryErr != nil { @@ -466,8 +478,9 @@ func (az *Cloud) ensurePublicIPExists(serviceName, pipName string) (*network.Pub func (az *Cloud) ensurePublicIPDeleted(serviceName, pipName string) error { glog.V(2).Infof("ensure(%s): pip(%s) - deleting", serviceName, pipName) az.operationPollRateLimiter.Accept() - resp, deleteErr := az.PublicIPAddressesClient.Delete(az.ResourceGroup, pipName, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, deleteErr) { + resp, deleteErrChan := az.PublicIPAddressesClient.Delete(az.ResourceGroup, pipName, nil) + deleteErr := <-deleteErrChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(<-resp, deleteErr) { glog.V(2).Infof("ensure(%s) backing off: pip(%s) - deleting", serviceName, pipName) retryErr := az.DeletePublicIPWithRetry(pipName) if retryErr != nil { @@ -772,8 +785,8 @@ func (az *Cloud) reconcileSecurityGroup(sg network.SecurityGroup, clusterName st DestinationPortRange: to.StringPtr(strconv.Itoa(int(port.Port))), SourceAddressPrefix: to.StringPtr(sourceAddressPrefixes[j]), DestinationAddressPrefix: to.StringPtr("*"), - Access: network.Allow, - Direction: network.Inbound, + Access: network.SecurityRuleAccessAllow, + Direction: network.SecurityRuleDirectionInbound, }, } } @@ -918,8 +931,10 @@ func (az *Cloud) ensureHostInPool(serviceName string, nodeName types.NodeName, b glog.V(3).Infof("nicupdate(%s): nic(%s) - updating", serviceName, nicName) az.operationPollRateLimiter.Accept() - resp, err := az.InterfacesClient.CreateOrUpdate(az.ResourceGroup, *nic.Name, nic, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.InterfacesClient.CreateOrUpdate(az.ResourceGroup, *nic.Name, nic, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("nicupdate(%s) backing off: nic(%s) - updating, err=%v", serviceName, nicName, err) retryErr := az.CreateOrUpdateInterfaceWithRetry(nic) if retryErr != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_managedDiskController.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_managedDiskController.go new file mode 100644 index 0000000000..5acdf58358 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_managedDiskController.go @@ -0,0 +1,129 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure + +import ( + "path" + "strings" + + "github.com/Azure/azure-sdk-for-go/arm/disk" + storage "github.com/Azure/azure-sdk-for-go/arm/storage" + "github.com/golang/glog" + kwait "k8s.io/apimachinery/pkg/util/wait" +) + +//ManagedDiskController : managed disk controller struct +type ManagedDiskController struct { + common *controllerCommon +} + +func newManagedDiskController(common *controllerCommon) (*ManagedDiskController, error) { + return &ManagedDiskController{common: common}, nil +} + +//CreateManagedDisk : create managed disk +func (c *ManagedDiskController) CreateManagedDisk(diskName string, storageAccountType storage.SkuName, sizeGB int, tags map[string]string) (string, error) { + glog.V(4).Infof("azureDisk - creating new managed Name:%s StorageAccountType:%s Size:%v", diskName, storageAccountType, sizeGB) + + newTags := make(map[string]*string) + azureDDTag := "kubernetes-azure-dd" + newTags["created-by"] = &azureDDTag + + // insert original tags to newTags + if tags != nil { + for k, v := range tags { + // Azure won't allow / (forward slash) in tags + newKey := strings.Replace(k, "/", "-", -1) + newValue := strings.Replace(v, "/", "-", -1) + newTags[newKey] = &newValue + } + } + + diskSizeGB := int32(sizeGB) + model := disk.Model{ + Location: &c.common.location, + Tags: &newTags, + Properties: &disk.Properties{ + AccountType: disk.StorageAccountTypes(storageAccountType), + DiskSizeGB: &diskSizeGB, + CreationData: &disk.CreationData{CreateOption: disk.Empty}, + }} + cancel := make(chan struct{}) + respChan, errChan := c.common.cloud.DisksClient.CreateOrUpdate(c.common.resourceGroup, diskName, model, cancel) + <-respChan + err := <-errChan + if err != nil { + return "", err + } + + diskID := "" + + err = kwait.ExponentialBackoff(defaultBackOff, func() (bool, error) { + provisonState, id, err := c.getDisk(diskName) + diskID = id + // We are waiting for provisioningState==Succeeded + // We don't want to hand-off managed disks to k8s while they are + //still being provisioned, this is to avoid some race conditions + if err != nil { + return false, err + } + if strings.ToLower(provisonState) == "succeeded" { + return true, nil + } + return false, nil + }) + + if err != nil { + glog.V(2).Infof("azureDisk - created new MD Name:%s StorageAccountType:%s Size:%v but was unable to confirm provisioningState in poll process", diskName, storageAccountType, sizeGB) + } else { + glog.V(2).Infof("azureDisk - created new MD Name:%s StorageAccountType:%s Size:%v", diskName, storageAccountType, sizeGB) + } + + return diskID, nil +} + +//DeleteManagedDisk : delete managed disk +func (c *ManagedDiskController) DeleteManagedDisk(diskURI string) error { + diskName := path.Base(diskURI) + cancel := make(chan struct{}) + respChan, errChan := c.common.cloud.DisksClient.Delete(c.common.resourceGroup, diskName, cancel) + <-respChan + err := <-errChan + if err != nil { + return err + } + // We don't need poll here, k8s will immediatly stop referencing the disk + // the disk will be evantually deleted - cleanly - by ARM + + glog.V(2).Infof("azureDisk - deleted a managed disk: %s", diskURI) + + return nil +} + +// return: disk provisionState, diskID, error +func (c *ManagedDiskController) getDisk(diskName string) (string, string, error) { + result, err := c.common.cloud.DisksClient.Get(c.common.resourceGroup, diskName) + if err != nil { + return "", "", err + } + + if result.Properties != nil && (*result.Properties).ProvisioningState != nil { + return *(*result.Properties).ProvisioningState, *result.ID, nil + } + + return "", "", err +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_routes.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_routes.go index 0d7a23ebfd..b7cb4ae810 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_routes.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_routes.go @@ -78,8 +78,10 @@ func (az *Cloud) CreateRoute(clusterName string, nameHint string, kubeRoute *clo glog.V(3).Infof("create: creating routetable. routeTableName=%q", az.RouteTableName) az.operationPollRateLimiter.Accept() - resp, err := az.RouteTablesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, routeTable, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.RouteTablesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, routeTable, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("create backing off: creating routetable. routeTableName=%q", az.RouteTableName) retryErr := az.CreateOrUpdateRouteTableWithRetry(routeTable) if retryErr != nil { @@ -114,8 +116,10 @@ func (az *Cloud) CreateRoute(clusterName string, nameHint string, kubeRoute *clo glog.V(3).Infof("create: creating route: instance=%q cidr=%q", kubeRoute.TargetNode, kubeRoute.DestinationCIDR) az.operationPollRateLimiter.Accept() - resp, err := az.RoutesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, *route.Name, route, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { + respChan, errChan := az.RoutesClient.CreateOrUpdate(az.ResourceGroup, az.RouteTableName, *route.Name, route, nil) + resp := <-respChan + err = <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp.Response, err) { glog.V(2).Infof("create backing off: creating route: instance=%q cidr=%q", kubeRoute.TargetNode, kubeRoute.DestinationCIDR) retryErr := az.CreateOrUpdateRouteWithRetry(route) if retryErr != nil { @@ -138,7 +142,10 @@ func (az *Cloud) DeleteRoute(clusterName string, kubeRoute *cloudprovider.Route) routeName := mapNodeNameToRouteName(kubeRoute.TargetNode) az.operationPollRateLimiter.Accept() - resp, err := az.RoutesClient.Delete(az.ResourceGroup, az.RouteTableName, routeName, nil) + respChan, errChan := az.RoutesClient.Delete(az.ResourceGroup, az.RouteTableName, routeName, nil) + resp := <-respChan + err := <-errChan + if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { glog.V(2).Infof("delete backing off: deleting route. clusterName=%q instance=%q cidr=%q", clusterName, kubeRoute.TargetNode, kubeRoute.DestinationCIDR) retryErr := az.DeleteRouteWithRetry(routeName) diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_storage.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_storage.go index b810480ab4..8572b9c779 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_storage.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_storage.go @@ -18,260 +18,10 @@ package azure import ( "fmt" - "strings" - "github.com/Azure/azure-sdk-for-go/arm/compute" "github.com/golang/glog" - "k8s.io/apimachinery/pkg/types" - "k8s.io/kubernetes/pkg/cloudprovider" - "k8s.io/kubernetes/pkg/volume" ) -const ( - maxLUN = 64 // max number of LUNs per VM - errLeaseFailed = "AcquireDiskLeaseFailed" - errLeaseIDMissing = "LeaseIdMissing" - errContainerNotFound = "ContainerNotFound" -) - -// AttachDisk attaches a vhd to vm -// the vhd must exist, can be identified by diskName, diskURI, and lun. -func (az *Cloud) AttachDisk(diskName, diskURI string, nodeName types.NodeName, lun int32, cachingMode compute.CachingTypes) error { - vm, exists, err := az.getVirtualMachine(nodeName) - if err != nil { - return err - } else if !exists { - return cloudprovider.InstanceNotFound - } - disks := *vm.StorageProfile.DataDisks - disks = append(disks, - compute.DataDisk{ - Name: &diskName, - Vhd: &compute.VirtualHardDisk{ - URI: &diskURI, - }, - Lun: &lun, - Caching: cachingMode, - CreateOption: "attach", - }) - - newVM := compute.VirtualMachine{ - Location: vm.Location, - VirtualMachineProperties: &compute.VirtualMachineProperties{ - StorageProfile: &compute.StorageProfile{ - DataDisks: &disks, - }, - }, - } - vmName := mapNodeNameToVMName(nodeName) - glog.V(2).Infof("create(%s): vm(%s)", az.ResourceGroup, vmName) - az.operationPollRateLimiter.Accept() - resp, err := az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { - glog.V(2).Infof("create(%s) backing off: vm(%s)", az.ResourceGroup, vmName) - retryErr := az.CreateOrUpdateVMWithRetry(vmName, newVM) - if retryErr != nil { - err = retryErr - glog.V(2).Infof("create(%s) abort backoff: vm(%s)", az.ResourceGroup, vmName) - } - } - if err != nil { - glog.Errorf("azure attach failed, err: %v", err) - detail := err.Error() - if strings.Contains(detail, errLeaseFailed) { - // if lease cannot be acquired, immediately detach the disk and return the original error - glog.Infof("failed to acquire disk lease, try detach") - az.DetachDiskByName(diskName, diskURI, nodeName) - } - } else { - glog.V(4).Infof("azure attach succeeded") - } - return err -} - -// DisksAreAttached checks if a list of volumes are attached to the node with the specified NodeName -func (az *Cloud) DisksAreAttached(diskNames []string, nodeName types.NodeName) (map[string]bool, error) { - attached := make(map[string]bool) - for _, diskName := range diskNames { - attached[diskName] = false - } - vm, exists, err := az.getVirtualMachine(nodeName) - if !exists { - // if host doesn't exist, no need to detach - glog.Warningf("Cannot find node %q, DisksAreAttached will assume disks %v are not attached to it.", - nodeName, diskNames) - return attached, nil - } else if err != nil { - return attached, err - } - - disks := *vm.StorageProfile.DataDisks - for _, disk := range disks { - for _, diskName := range diskNames { - if disk.Name != nil && diskName != "" && *disk.Name == diskName { - attached[diskName] = true - } - } - } - - return attached, nil -} - -// DetachDiskByName detaches a vhd from host -// the vhd can be identified by diskName or diskURI -func (az *Cloud) DetachDiskByName(diskName, diskURI string, nodeName types.NodeName) error { - vm, exists, err := az.getVirtualMachine(nodeName) - if err != nil || !exists { - // if host doesn't exist, no need to detach - glog.Warningf("cannot find node %s, skip detaching disk %s", nodeName, diskName) - return nil - } - - disks := *vm.StorageProfile.DataDisks - for i, disk := range disks { - if (disk.Name != nil && diskName != "" && *disk.Name == diskName) || (disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) { - // found the disk - glog.V(4).Infof("detach disk: name %q uri %q", diskName, diskURI) - disks = append(disks[:i], disks[i+1:]...) - break - } - } - newVM := compute.VirtualMachine{ - Location: vm.Location, - VirtualMachineProperties: &compute.VirtualMachineProperties{ - StorageProfile: &compute.StorageProfile{ - DataDisks: &disks, - }, - }, - } - vmName := mapNodeNameToVMName(nodeName) - glog.V(2).Infof("create(%s): vm(%s)", az.ResourceGroup, vmName) - az.operationPollRateLimiter.Accept() - resp, err := az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil) - if az.CloudProviderBackoff && shouldRetryAPIRequest(resp, err) { - glog.V(2).Infof("create(%s) backing off: vm(%s)", az.ResourceGroup, vmName) - retryErr := az.CreateOrUpdateVMWithRetry(vmName, newVM) - if retryErr != nil { - err = retryErr - glog.V(2).Infof("create(%s) abort backoff: vm(%s)", az.ResourceGroup, vmName) - } - } - if err != nil { - glog.Errorf("azure disk detach failed, err: %v", err) - } else { - glog.V(4).Infof("azure disk detach succeeded") - } - return err -} - -// GetDiskLun finds the lun on the host that the vhd is attached to, given a vhd's diskName and diskURI -func (az *Cloud) GetDiskLun(diskName, diskURI string, nodeName types.NodeName) (int32, error) { - vm, exists, err := az.getVirtualMachine(nodeName) - if err != nil { - return -1, err - } else if !exists { - return -1, cloudprovider.InstanceNotFound - } - disks := *vm.StorageProfile.DataDisks - for _, disk := range disks { - if disk.Lun != nil && (disk.Name != nil && diskName != "" && *disk.Name == diskName) || (disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) { - // found the disk - glog.V(4).Infof("find disk: lun %d name %q uri %q", *disk.Lun, diskName, diskURI) - return *disk.Lun, nil - } - } - return -1, fmt.Errorf("Cannot find Lun for disk %s", diskName) -} - -// GetNextDiskLun searches all vhd attachment on the host and find unused lun -// return -1 if all luns are used -func (az *Cloud) GetNextDiskLun(nodeName types.NodeName) (int32, error) { - vm, exists, err := az.getVirtualMachine(nodeName) - if err != nil { - return -1, err - } else if !exists { - return -1, cloudprovider.InstanceNotFound - } - used := make([]bool, maxLUN) - disks := *vm.StorageProfile.DataDisks - for _, disk := range disks { - if disk.Lun != nil { - used[*disk.Lun] = true - } - } - for k, v := range used { - if !v { - return int32(k), nil - } - } - return -1, fmt.Errorf("All Luns are used") -} - -// CreateVolume creates a VHD blob in a storage account that has storageType and location using the given storage account. -// If no storage account is given, search all the storage accounts associated with the resource group and pick one that -// fits storage type and location. -func (az *Cloud) CreateVolume(name, storageAccount, storageType, location string, requestGB int) (string, string, int, error) { - var err error - accounts := []accountWithLocation{} - if len(storageAccount) > 0 { - accounts = append(accounts, accountWithLocation{Name: storageAccount}) - } else { - // find a storage account - accounts, err = az.getStorageAccounts() - if err != nil { - // TODO: create a storage account and container - return "", "", 0, err - } - } - for _, account := range accounts { - glog.V(4).Infof("account %s type %s location %s", account.Name, account.StorageType, account.Location) - if ((storageType == "" || account.StorageType == storageType) && (location == "" || account.Location == location)) || len(storageAccount) > 0 { - // find the access key with this account - key, err := az.getStorageAccesskey(account.Name) - if err != nil { - glog.V(2).Infof("no key found for storage account %s", account.Name) - continue - } - - // create a page blob in this account's vhd container - name, uri, err := az.createVhdBlob(account.Name, key, name, int64(requestGB), nil) - if err != nil { - glog.V(2).Infof("failed to create vhd in account %s: %v", account.Name, err) - continue - } - glog.V(4).Infof("created vhd blob uri: %s", uri) - return name, uri, requestGB, err - } - } - return "", "", 0, fmt.Errorf("failed to find a matching storage account") -} - -// DeleteVolume deletes a VHD blob -func (az *Cloud) DeleteVolume(name, uri string) error { - accountName, blob, err := az.getBlobNameAndAccountFromURI(uri) - if err != nil { - return fmt.Errorf("failed to parse vhd URI %v", err) - } - key, err := az.getStorageAccesskey(accountName) - if err != nil { - return fmt.Errorf("no key for storage account %s, err %v", accountName, err) - } - err = az.deleteVhdBlob(accountName, key, blob) - if err != nil { - glog.Warningf("failed to delete blob %s err: %v", uri, err) - detail := err.Error() - if strings.Contains(detail, errLeaseIDMissing) { - // disk is still being used - // see https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.blob.protocol.bloberrorcodestrings.leaseidmissing.aspx - return volume.NewDeletedVolumeInUseError(fmt.Sprintf("disk %q is still in use while being deleted", name)) - } - return fmt.Errorf("failed to delete vhd %v, account %s, blob %s, err: %v", uri, accountName, blob, err) - } - glog.V(4).Infof("blob %s deleted", uri) - return nil - -} - // CreateFileShare creates a file share, using a matching storage account func (az *Cloud) CreateFileShare(name, storageAccount, storageType, location string, requestGB int) (string, string, error) { var err error diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_test.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_test.go index 6bc61bf786..a7211e9175 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_test.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_test.go @@ -556,7 +556,7 @@ func TestProtocolTranslationTCP(t *testing.T) { if *transportProto != network.TransportProtocolTCP { t.Errorf("Expected TCP LoadBalancer Rule Protocol. Got %v", transportProto) } - if *securityGroupProto != network.TCP { + if *securityGroupProto != network.SecurityRuleProtocolTCP { t.Errorf("Expected TCP SecurityGroup Protocol. Got %v", transportProto) } if *probeProto != network.ProbeProtocolTCP { @@ -570,7 +570,7 @@ func TestProtocolTranslationUDP(t *testing.T) { if *transportProto != network.TransportProtocolUDP { t.Errorf("Expected UDP LoadBalancer Rule Protocol. Got %v", transportProto) } - if *securityGroupProto != network.UDP { + if *securityGroupProto != network.SecurityRuleProtocolUDP { t.Errorf("Expected UDP SecurityGroup Protocol. Got %v", transportProto) } if probeProto != nil { @@ -585,6 +585,8 @@ func TestNewCloudFromJSON(t *testing.T) { "subscriptionId": "--subscription-id--", "aadClientId": "--aad-client-id--", "aadClientSecret": "--aad-client-secret--", + "aadClientCertPath": "--aad-client-cert-path--", + "aadClientCertPassword": "--aad-client-cert-password--", "resourceGroup": "--resource-group--", "location": "--location--", "subnetName": "--subnet-name--", @@ -606,15 +608,20 @@ func TestNewCloudFromJSON(t *testing.T) { // Test Backoff and Rate Limit defaults (json) func TestCloudDefaultConfigFromJSON(t *testing.T) { - config := `{}` + config := `{ + "aadClientId": "--aad-client-id--", + "aadClientSecret": "--aad-client-secret--" + }` validateEmptyConfig(t, config) } // Test Backoff and Rate Limit defaults (yaml) func TestCloudDefaultConfigFromYAML(t *testing.T) { - config := `` - + config := ` +aadClientId: --aad-client-id-- +aadClientSecret: --aad-client-secret-- +` validateEmptyConfig(t, config) } @@ -625,6 +632,8 @@ tenantId: --tenant-id-- subscriptionId: --subscription-id-- aadClientId: --aad-client-id-- aadClientSecret: --aad-client-secret-- +aadClientCertPath: --aad-client-cert-path-- +aadClientCertPassword: --aad-client-cert-password-- resourceGroup: --resource-group-- location: --location-- subnetName: --subnet-name-- @@ -659,6 +668,12 @@ func validateConfig(t *testing.T, config string) { if azureCloud.AADClientSecret != "--aad-client-secret--" { t.Errorf("got incorrect value for AADClientSecret") } + if azureCloud.AADClientCertPath != "--aad-client-cert-path--" { + t.Errorf("got incorrect value for AADClientCertPath") + } + if azureCloud.AADClientCertPassword != "--aad-client-cert-password--" { + t.Errorf("got incorrect value for AADClientCertPassword") + } if azureCloud.ResourceGroup != "--resource-group--" { t.Errorf("got incorrect value for ResourceGroup") } diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_util.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_util.go index 9f092dcc56..bbea8ed2ba 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_util.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_util.go @@ -19,7 +19,9 @@ package azure import ( "errors" "fmt" + "hash/crc32" "regexp" + "strconv" "strings" "k8s.io/kubernetes/pkg/api/v1" @@ -135,12 +137,12 @@ func getProtocolsFromKubernetesProtocol(protocol v1.Protocol) (*network.Transpor switch protocol { case v1.ProtocolTCP: transportProto = network.TransportProtocolTCP - securityProto = network.TCP + securityProto = network.SecurityRuleProtocolTCP probeProto = network.ProbeProtocolTCP return &transportProto, &securityProto, &probeProto, nil case v1.ProtocolUDP: transportProto = network.TransportProtocolUDP - securityProto = network.UDP + securityProto = network.SecurityRuleProtocolUDP return &transportProto, &securityProto, nil, nil default: return &transportProto, &securityProto, &probeProto, fmt.Errorf("Only TCP and UDP are supported for Azure LoadBalancers") @@ -293,3 +295,58 @@ func splitProviderID(providerID string) (types.NodeName, error) { } return types.NodeName(matches[1]), nil } + +var polyTable = crc32.MakeTable(crc32.Koopman) + +//MakeCRC32 : convert string to CRC32 format +func MakeCRC32(str string) string { + crc := crc32.New(polyTable) + crc.Write([]byte(str)) + hash := crc.Sum32() + return strconv.FormatUint(uint64(hash), 10) +} + +//ExtractVMData : extract dataDisks, storageProfile from a map struct +func ExtractVMData(vmData map[string]interface{}) (dataDisks []interface{}, + storageProfile map[string]interface{}, + hardwareProfile map[string]interface{}, err error) { + props, ok := vmData["properties"].(map[string]interface{}) + if !ok { + return nil, nil, nil, fmt.Errorf("convert vmData(properties) to map error") + } + + storageProfile, ok = props["storageProfile"].(map[string]interface{}) + if !ok { + return nil, nil, nil, fmt.Errorf("convert vmData(storageProfile) to map error") + } + + hardwareProfile, ok = props["hardwareProfile"].(map[string]interface{}) + if !ok { + return nil, nil, nil, fmt.Errorf("convert vmData(hardwareProfile) to map error") + } + + dataDisks, ok = storageProfile["dataDisks"].([]interface{}) + if !ok { + return nil, nil, nil, fmt.Errorf("convert vmData(dataDisks) to map error") + } + return dataDisks, storageProfile, hardwareProfile, nil +} + +//ExtractDiskData : extract provisioningState, diskState from a map struct +func ExtractDiskData(diskData interface{}) (provisioningState string, diskState string, err error) { + fragment, ok := diskData.(map[string]interface{}) + if !ok { + return "", "", fmt.Errorf("convert diskData to map error") + } + + properties, ok := fragment["properties"].(map[string]interface{}) + if !ok { + return "", "", fmt.Errorf("convert diskData(properties) to map error") + } + + provisioningState, ok = properties["provisioningState"].(string) // if there is a disk, provisioningState property will be there + if ref, ok := properties["diskState"]; ok { + diskState = ref.(string) + } + return provisioningState, diskState, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_wrap.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_wrap.go index 613e59a439..9879655945 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_wrap.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/azure_wrap.go @@ -132,9 +132,16 @@ func (az *Cloud) getPublicIPAddress(name string) (pip network.PublicIPAddress, e func (az *Cloud) getSubnet(virtualNetworkName string, subnetName string) (subnet network.Subnet, exists bool, err error) { var realErr error + var rg string + + if len(az.VnetResourceGroup) > 0 { + rg = az.VnetResourceGroup + } else { + rg = az.ResourceGroup + } az.operationPollRateLimiter.Accept() - subnet, err = az.SubnetsClient.Get(az.ResourceGroup, virtualNetworkName, subnetName, "") + subnet, err = az.SubnetsClient.Get(rg, virtualNetworkName, subnetName, "") exists, realErr = checkResourceExistsFromError(err) if realErr != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/vhd.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/vhd.go deleted file mode 100644 index 93c857743b..0000000000 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/azure/vhd.go +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package azure - -import ( - "bytes" - "encoding/binary" - - "github.com/rubiojr/go-vhd/vhd" -) - -const ( - vhdHeaderSize = vhd.VHD_HEADER_SIZE -) - -func createVHDHeader(size uint64) ([]byte, error) { - h := vhd.CreateFixedHeader(size, &vhd.VHDOptions{}) - b := new(bytes.Buffer) - err := binary.Write(b, binary.BigEndian, h) - if err != nil { - return nil, err - } - return b.Bytes(), nil -} diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce.go index 90e2570a42..d498bbe37f 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce.go @@ -179,11 +179,11 @@ func newGCECloud(config io.Reader) (*GCECloud, error) { var nodeTags []string var nodeInstancePrefix string if config != nil { - var cfg Config - if err := gcfg.ReadInto(&cfg, config); err != nil { - glog.Errorf("Couldn't read config: %v", err) + cfg, err := readConfig(config) + if err != nil { return nil, err } + glog.Infof("Using GCE provider config %+v", cfg) if cfg.Global.ProjectID != "" { projectID = cfg.Global.ProjectID @@ -216,6 +216,15 @@ func newGCECloud(config io.Reader) (*GCECloud, error) { nodeTags, nodeInstancePrefix, tokenSource, true /* useMetadataServer */) } +func readConfig(reader io.Reader) (*Config, error) { + cfg := &Config{} + if err := gcfg.FatalOnly(gcfg.ReadInto(cfg, reader)); err != nil { + glog.Errorf("Couldn't read config: %v", err) + return nil, err + } + return cfg, nil +} + // Creates a GCECloud object using the specified parameters. // If no networkUrl is specified, loads networkName via rest call. // If no tokenSource is specified, uses oauth2.DefaultTokenSource. diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_addresses.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_addresses.go index 877d744ddf..3592fcf3b6 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_addresses.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_addresses.go @@ -33,18 +33,13 @@ func newAddressMetricContext(request, region string) *metricContext { // Caller is allocated a random IP if they do not specify an ipAddress. If an // ipAddress is specified, it must belong to the current project, eg: an // ephemeral IP associated with a global forwarding rule. -func (gce *GCECloud) ReserveGlobalAddress(addr *compute.Address) (*compute.Address, error) { +func (gce *GCECloud) ReserveGlobalAddress(addr *compute.Address) error { mc := newAddressMetricContext("reserve", "") op, err := gce.service.GlobalAddresses.Insert(gce.projectID, addr).Do() if err != nil { - return nil, mc.Observe(err) - } - - if err := gce.waitForGlobalOp(op, mc); err != nil { - return nil, err + return mc.Observe(err) } - - return gce.GetGlobalAddress(addr.Name) + return gce.waitForGlobalOp(op, mc) } // DeleteGlobalAddress deletes a global address by name. @@ -65,17 +60,13 @@ func (gce *GCECloud) GetGlobalAddress(name string) (*compute.Address, error) { } // ReserveRegionAddress creates a region address -func (gce *GCECloud) ReserveRegionAddress(addr *compute.Address, region string) (*compute.Address, error) { +func (gce *GCECloud) ReserveRegionAddress(addr *compute.Address, region string) error { mc := newAddressMetricContext("reserve", region) op, err := gce.service.Addresses.Insert(gce.projectID, region, addr).Do() if err != nil { - return nil, mc.Observe(err) - } - if err := gce.waitForRegionOp(op, region, mc); err != nil { - return nil, err + return mc.Observe(err) } - - return gce.GetRegionAddress(addr.Name, region) + return gce.waitForRegionOp(op, region, mc) } // DeleteRegionAddress deletes a region address by name. diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_annotations.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_annotations.go index a7f6683fb6..d27f230917 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_annotations.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_annotations.go @@ -16,7 +16,11 @@ limitations under the License. package gce -import "k8s.io/kubernetes/pkg/api/v1" +import ( + "k8s.io/kubernetes/pkg/api/v1" + + "github.com/golang/glog" +) type LoadBalancerType string @@ -26,12 +30,16 @@ const ( // Currently, only "internal" is supported. ServiceAnnotationLoadBalancerType = "cloud.google.com/load-balancer-type" - LBTypeInternal LoadBalancerType = "internal" + LBTypeInternal LoadBalancerType = "Internal" + // Deprecating the lowercase spelling of Internal. + deprecatedTypeInternalLowerCase LoadBalancerType = "internal" // ServiceAnnotationInternalBackendShare is annotated on a service with "true" when users // want to share GCP Backend Services for a set of internal load balancers. // ALPHA feature - this may be removed in a future release. - ServiceAnnotationILBBackendShare = "cloud.google.com/load-balancer-backend-share" + ServiceAnnotationILBBackendShare = "alpha.cloud.google.com/load-balancer-backend-share" + // This annotation did not correctly specify "alpha", so both annotations will be checked. + deprecatedServiceAnnotationILBBackendShare = "cloud.google.com/load-balancer-backend-share" ) // GetLoadBalancerAnnotationType returns the type of GCP load balancer which should be assembled. @@ -48,8 +56,8 @@ func GetLoadBalancerAnnotationType(service *v1.Service) (LoadBalancerType, bool) } switch v { - case LBTypeInternal: - return v, true + case LBTypeInternal, deprecatedTypeInternalLowerCase: + return LBTypeInternal, true default: return v, false } @@ -58,8 +66,13 @@ func GetLoadBalancerAnnotationType(service *v1.Service) (LoadBalancerType, bool) // GetLoadBalancerAnnotationBackendShare returns whether this service's backend service should be // shared with other load balancers. Health checks and the healthcheck firewall will be shared regardless. func GetLoadBalancerAnnotationBackendShare(service *v1.Service) bool { - l, exists := service.Annotations[ServiceAnnotationILBBackendShare] - if exists && l == "true" { + if l, exists := service.Annotations[ServiceAnnotationILBBackendShare]; exists && l == "true" { + return true + } + + // Check for deprecated annotation key + if l, exists := service.Annotations[deprecatedServiceAnnotationILBBackendShare]; exists && l == "true" { + glog.Warningf("Annotation %q is deprecated and replaced with an alpha-specific key: %q", deprecatedServiceAnnotationILBBackendShare, ServiceAnnotationILBBackendShare) return true } diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks.go index 4f5f90c6a1..bc5ca0b88f 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks.go @@ -37,8 +37,8 @@ var ( ) func init() { - if v, err := utilversion.ParseGeneric("1.7.0"); err != nil { - panic(err) + if v, err := utilversion.ParseGeneric("1.7.2"); err != nil { + glog.Fatalf("Failed to parse version for minNodesHealthCheckVersion: %v", err) } else { minNodesHealthCheckVersion = v } diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks_test.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks_test.go index 11be679543..d421ba5c63 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks_test.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_healthchecks_test.go @@ -27,8 +27,9 @@ func TestIsAtLeastMinNodesHealthCheckVersion(t *testing.T) { version string expect bool }{ - {"v1.7.1", true}, - {"v1.7.0-alpha.2.597+276d289b90d322", true}, + {"v1.7.3", true}, + {"v1.7.2", true}, + {"v1.7.2-alpha.2.597+276d289b90d322", true}, {"v1.6.0-beta.3.472+831q821c907t31a", false}, {"v1.5.2", false}, } @@ -52,14 +53,14 @@ func TestSupportsNodesHealthCheck(t *testing.T) { { Status: v1.NodeStatus{ NodeInfo: v1.NodeSystemInfo{ - KubeProxyVersion: "v1.7.1", + KubeProxyVersion: "v1.7.2", }, }, }, { Status: v1.NodeStatus{ NodeInfo: v1.NodeSystemInfo{ - KubeProxyVersion: "v1.7.0-alpha.2.597+276d289b90d322", + KubeProxyVersion: "v1.7.2-alpha.2.597+276d289b90d322", }, }, }, @@ -92,14 +93,14 @@ func TestSupportsNodesHealthCheck(t *testing.T) { { Status: v1.NodeStatus{ NodeInfo: v1.NodeSystemInfo{ - KubeProxyVersion: "v1.7.1", + KubeProxyVersion: "v1.7.3", }, }, }, { Status: v1.NodeStatus{ NodeInfo: v1.NodeSystemInfo{ - KubeProxyVersion: "v1.7.0-alpha.2.597+276d289b90d322", + KubeProxyVersion: "v1.7.2-alpha.2.597+276d289b90d322", }, }, }, diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_loadbalancer_external.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_loadbalancer_external.go index 74aefee65a..5a6ddd5615 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_loadbalancer_external.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_loadbalancer_external.go @@ -807,7 +807,7 @@ func (gce *GCECloud) ensureHttpHealthCheckFirewall(serviceName, ipAddress, regio if fw.Description != desc || len(fw.Allowed) != 1 || fw.Allowed[0].IPProtocol != string(ports[0].Protocol) || - !equalStringSets(fw.Allowed[0].Ports, []string{string(ports[0].Port)}) || + !equalStringSets(fw.Allowed[0].Ports, []string{strconv.Itoa(int(ports[0].Port))}) || !equalStringSets(fw.SourceRanges, sourceRanges.StringSlice()) { glog.Warningf("Firewall %v exists but parameters have drifted - updating...", fwName) if err := gce.updateFirewall(fwName, region, desc, sourceRanges, ports, hosts); err != nil { @@ -939,8 +939,7 @@ func (gce *GCECloud) ensureStaticIP(name, serviceName, region, existingIP string addressObj.Address = existingIP } - address, err := gce.ReserveRegionAddress(addressObj, region) - if err != nil { + if err = gce.ReserveRegionAddress(addressObj, region); err != nil { if !isHTTPErrorCode(err, http.StatusConflict) { return "", false, fmt.Errorf("error creating gce static IP address: %v", err) } @@ -948,5 +947,10 @@ func (gce *GCECloud) ensureStaticIP(name, serviceName, region, existingIP string existed = true } - return address.Address, existed, nil + addr, err := gce.GetRegionAddress(name, region) + if err != nil { + return "", false, fmt.Errorf("error getting static IP address: %v", err) + } + + return addr.Address, existed, nil } diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_test.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_test.go index c04473f938..0eff53dbdf 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_test.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/gce/gce_test.go @@ -18,9 +18,26 @@ package gce import ( "reflect" + "strings" "testing" ) +func TestExtraKeyInConfig(t *testing.T) { + const s = `[Global] +project-id = my-project +unknown-key = abc +network-name = my-network + ` + reader := strings.NewReader(s) + config, err := readConfig(reader) + if err != nil { + t.Fatalf("Unexpected config parsing error %v", err) + } + if config.Global.ProjectID != "my-project" || config.Global.NetworkName != "my-network" { + t.Fatalf("Expected config values to continue to be read despite extra key-value pair.") + } +} + func TestGetRegion(t *testing.T) { zoneName := "us-central1-b" regionName, err := GetGCERegion(zoneName) diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/openstack/openstack_volumes.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/openstack/openstack_volumes.go index 7f7b499bb7..f9a46140c8 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/openstack/openstack_volumes.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/openstack/openstack_volumes.go @@ -230,11 +230,9 @@ func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) { glog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID) return volume.ID, nil } - glog.V(2).Infof("Disk %s is attached to a different instance (%s), detaching", volumeID, volume.AttachedServerId) - err = os.DetachDisk(volume.AttachedServerId, volumeID) - if err != nil { - return "", err - } + errmsg := fmt.Sprintf("Disk %s is attached to a different instance (%s)", volumeID, volume.AttachedServerId) + glog.V(2).Infof(errmsg) + return "", errors.New(errmsg) } startTime := time.Now() diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere.go index 63383a0657..457872b6a6 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -19,6 +19,7 @@ package vsphere import ( "errors" "fmt" + "hash/fnv" "io" "io/ioutil" "net" @@ -332,8 +333,8 @@ func newVSphere(cfg VSphereConfig) (*VSphere, error) { if cfg.Global.RoundTripperCount == 0 { cfg.Global.RoundTripperCount = RoundTripperDefaultCount } - if cfg.Global.VCenterPort != "" { - glog.Warningf("port is a deprecated field in vsphere.conf and will be removed in future release.") + if cfg.Global.VCenterPort == "" { + cfg.Global.VCenterPort = "443" } var c *govmomi.Client @@ -382,7 +383,7 @@ func logout(vs *VSphere) { func newClient(ctx context.Context, cfg *VSphereConfig) (*govmomi.Client, error) { // Parse URL from string - u, err := url.Parse(fmt.Sprintf("https://%s/sdk", cfg.Global.VCenterIP)) + u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIP, cfg.Global.VCenterPort)) if err != nil { return nil, err } @@ -806,7 +807,7 @@ func (vs *VSphere) AttachDisk(vmDiskPath string, storagePolicyID string, nodeNam } scsiControllersOfRequiredType := getSCSIControllersOfType(vmDevices, diskControllerType) - scsiController := getAvailableSCSIController(scsiControllersOfRequiredType) + scsiController = getAvailableSCSIController(scsiControllersOfRequiredType) if scsiController == nil { glog.Errorf("cannot find SCSI controller in VM") // attempt clean up of scsi controller @@ -1401,7 +1402,9 @@ func (vs *VSphere) CreateVolume(volumeOptions *VolumeOptions) (volumePath string // Check if the VM exists in kubernetes cluster folder. // The kubernetes cluster folder - vs.cfg.Global.WorkingDir is where all the nodes in the kubernetes cluster are created. - dummyVMFullName := DummyVMPrefixName + "-" + volumeOptions.Name + fnvHash := fnv.New32a() + fnvHash.Write([]byte(volumeOptions.Name)) + dummyVMFullName := DummyVMPrefixName + "-" + fmt.Sprint(fnvHash.Sum32()) vmRegex := vs.cfg.Global.WorkingDir + dummyVMFullName dummyVM, err := f.VirtualMachine(ctx, vmRegex) if err != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_test.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_test.go index 7ab128ecc9..4dd44a6e7b 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_test.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_test.go @@ -33,6 +33,7 @@ func configFromEnv() (cfg VSphereConfig, ok bool) { var InsecureFlag bool var err error cfg.Global.VCenterIP = os.Getenv("VSPHERE_VCENTER") + cfg.Global.VCenterPort = os.Getenv("VSPHERE_VCENTER_PORT") cfg.Global.User = os.Getenv("VSPHERE_USER") cfg.Global.Password = os.Getenv("VSPHERE_PASSWORD") cfg.Global.Datacenter = os.Getenv("VSPHERE_DATACENTER") diff --git a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_util.go b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_util.go index 75ed698809..a5bd63b15c 100644 --- a/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_util.go +++ b/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere_util.go @@ -61,6 +61,7 @@ func GetVSphere() (*VSphere, error) { func getVSphereConfig() *VSphereConfig { var cfg VSphereConfig cfg.Global.VCenterIP = os.Getenv("VSPHERE_VCENTER") + cfg.Global.VCenterPort = os.Getenv("VSPHERE_VCENTER_PORT") cfg.Global.User = os.Getenv("VSPHERE_USER") cfg.Global.Password = os.Getenv("VSPHERE_PASSWORD") cfg.Global.Datacenter = os.Getenv("VSPHERE_DATACENTER") diff --git a/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove.go b/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove.go index 26832c3d36..c844ae9bbb 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove.go @@ -90,10 +90,15 @@ func (a *sarApprover) handle(csr *capi.CertificateSigningRequest) error { return fmt.Errorf("unable to parse csr %q: %v", csr.Name, err) } + tried := []string{} + for _, r := range a.recognizers { if !r.recognize(csr, x509cr) { continue } + + tried = append(tried, r.permission.Subresource) + approved, err := a.authorize(csr, r.permission) if err != nil { return err @@ -107,6 +112,11 @@ func (a *sarApprover) handle(csr *capi.CertificateSigningRequest) error { return nil } } + + if len(tried) != 0 { + return fmt.Errorf("recognized csr %q as %v but subject access review was not approved", csr.Name, tried) + } + return nil } diff --git a/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove_test.go b/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove_test.go index b5842d8dc6..0088a423c8 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/certificates/approver/sarapprove_test.go @@ -88,6 +88,7 @@ func TestHandle(t *testing.T) { message string allowed bool recognized bool + err bool verify func(*testing.T, []testclient.Action) }{ { @@ -118,6 +119,7 @@ func TestHandle(t *testing.T) { } _ = as[0].(testclient.CreateActionImpl) }, + err: true, }, { recognized: true, @@ -154,7 +156,7 @@ func TestHandle(t *testing.T) { } for _, c := range cases { - t.Run(fmt.Sprintf("recognized:%v,allowed: %v", c.recognized, c.allowed), func(t *testing.T) { + t.Run(fmt.Sprintf("recognized:%v,allowed: %v,err: %v", c.recognized, c.allowed, c.err), func(t *testing.T) { client := &fake.Clientset{} client.AddReactor("create", "subjectaccessreviews", func(action testclient.Action) (handled bool, ret runtime.Object, err error) { return true, &authorization.SubjectAccessReview{ @@ -176,7 +178,7 @@ func TestHandle(t *testing.T) { }, } csr := makeTestCsr() - if err := approver.handle(csr); err != nil { + if err := approver.handle(csr); err != nil && !c.err { t.Errorf("unexpected err: %v", err) } c.verify(t, client.Actions()) diff --git a/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller.go b/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller.go index 5f0e9e601d..312a80b371 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller.go @@ -1022,30 +1022,6 @@ func (dsc *DaemonSetsController) syncDaemonSet(key string) error { return dsc.updateDaemonSetStatus(ds, hash) } -// hasIntentionalPredicatesReasons checks if any of the given predicate failure reasons -// is intentional. -func hasIntentionalPredicatesReasons(reasons []algorithm.PredicateFailureReason) bool { - for _, r := range reasons { - switch reason := r.(type) { - case *predicates.PredicateFailureError: - switch reason { - // intentional - case - predicates.ErrNodeSelectorNotMatch, - predicates.ErrPodNotMatchHostName, - predicates.ErrNodeLabelPresenceViolated, - // this one is probably intentional since it's a workaround for not having - // pod hard anti affinity. - predicates.ErrPodNotFitsHostPorts, - // DaemonSet is expected to respect taints and tolerations - predicates.ErrTaintsTolerationsNotMatch: - return true - } - } - } - return false -} - // nodeShouldRunDaemonPod checks a set of preconditions against a (node,daemonset) and returns a // summary. Returned booleans are: // * wantToRun: @@ -1064,7 +1040,14 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *exten // Because these bools require an && of all their required conditions, we start // with all bools set to true and set a bool to false if a condition is not met. - // A bool should probably not be set to true after this line. + // A bool should probably not be set to true after this line. We can + // return early if we are: + // + // 1. return false, false, false, err + // 2. return false, false, false, nil + // + // Otherwise if a condition is not met, we should set one of these + // bools to false. wantToRun, shouldSchedule, shouldContinueRunning = true, true, true // If the daemon set specifies a node name, check that it matches with node.Name. if !(ds.Spec.Template.Spec.NodeName == "" || ds.Spec.Template.Spec.NodeName == node.Name) { @@ -1135,22 +1118,37 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *exten return false, false, false, err } - // Return directly if there is any intentional predicate failure reason, so that daemonset controller skips - // checking other predicate failures, such as InsufficientResourceError and unintentional errors. - if hasIntentionalPredicatesReasons(reasons) { - return false, false, false, nil - } + var insufficientResourceErr error for _, r := range reasons { glog.V(4).Infof("DaemonSet Predicates failed on node %s for ds '%s/%s' for reason: %v", node.Name, ds.ObjectMeta.Namespace, ds.ObjectMeta.Name, r.GetReason()) switch reason := r.(type) { case *predicates.InsufficientResourceError: - dsc.eventRecorder.Eventf(ds, v1.EventTypeWarning, FailedPlacementReason, "failed to place pod on %q: %s", node.ObjectMeta.Name, reason.Error()) - shouldSchedule = false + insufficientResourceErr = reason case *predicates.PredicateFailureError: var emitEvent bool + // we try to partition predicates into two partitions here: intentional on the part of the operator and not. switch reason { - // unintentional predicates reasons need to be fired out to event. + // intentional + case + predicates.ErrNodeSelectorNotMatch, + predicates.ErrPodNotMatchHostName, + predicates.ErrNodeLabelPresenceViolated, + // this one is probably intentional since it's a workaround for not having + // pod hard anti affinity. + predicates.ErrPodNotFitsHostPorts: + return false, false, false, nil + case predicates.ErrTaintsTolerationsNotMatch: + // DaemonSet is expected to respect taints and tolerations + fitsNoExecute, _, err := predicates.PodToleratesNodeNoExecuteTaints(newPod, nil, nodeInfo) + if err != nil { + return false, false, false, err + } + if !fitsNoExecute { + return false, false, false, nil + } + wantToRun, shouldSchedule = false, false + // unintentional case predicates.ErrDiskConflict, predicates.ErrVolumeZoneConflict, @@ -1178,6 +1176,12 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *exten } } } + // only emit this event if insufficient resource is the only thing + // preventing the daemon pod from scheduling + if shouldSchedule && insufficientResourceErr != nil { + dsc.eventRecorder.Eventf(ds, v1.EventTypeWarning, FailedPlacementReason, "failed to place pod on %q: %s", node.ObjectMeta.Name, insufficientResourceErr.Error()) + shouldSchedule = false + } return } diff --git a/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller_test.go b/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller_test.go index 486b2ebbe1..1326881e23 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/daemon/daemoncontroller_test.go @@ -60,6 +60,7 @@ var ( var ( noScheduleTolerations = []v1.Toleration{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}} noScheduleTaints = []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoSchedule"}} + noExecuteTaints = []v1.Taint{{Key: "dedicated", Value: "user1", Effect: "NoExecute"}} ) var ( @@ -1079,10 +1080,46 @@ func TestDaemonKillFailedPods(t *testing.T) { } } +// Daemonset should not remove a running pod from a node if the pod doesn't +// tolerate the nodes NoSchedule taint +func TestNoScheduleTaintedDoesntEvicitRunningIntolerantPod(t *testing.T) { + for _, strategy := range updateStrategies() { + ds := newDaemonSet("intolerant") + ds.Spec.UpdateStrategy = *strategy + manager, podControl, _ := newTestController(ds) + + node := newNode("tainted", nil) + manager.nodeStore.Add(node) + setNodeTaint(node, noScheduleTaints) + manager.podStore.Add(newPod("keep-running-me", "tainted", simpleDaemonSetLabel, ds)) + manager.dsStore.Add(ds) + + syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 0) + } +} + +// Daemonset should remove a running pod from a node if the pod doesn't +// tolerate the nodes NoExecute taint +func TestNoExecuteTaintedDoesEvicitRunningIntolerantPod(t *testing.T) { + for _, strategy := range updateStrategies() { + ds := newDaemonSet("intolerant") + ds.Spec.UpdateStrategy = *strategy + manager, podControl, _ := newTestController(ds) + + node := newNode("tainted", nil) + manager.nodeStore.Add(node) + setNodeTaint(node, noExecuteTaints) + manager.podStore.Add(newPod("stop-running-me", "tainted", simpleDaemonSetLabel, ds)) + manager.dsStore.Add(ds) + + syncAndValidateDaemonSets(t, manager, ds, podControl, 0, 1) + } +} + // DaemonSet should not launch a pod on a tainted node when the pod doesn't tolerate that taint. -func TestTaintedNodeDaemonDoesNotLaunchUntoleratePod(t *testing.T) { +func TestTaintedNodeDaemonDoesNotLaunchIntolerantPod(t *testing.T) { for _, strategy := range updateStrategies() { - ds := newDaemonSet("untolerate") + ds := newDaemonSet("intolerant") ds.Spec.UpdateStrategy = *strategy manager, podControl, _ := newTestController(ds) diff --git a/vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/operations.go b/vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/operations.go index b488fb8d1a..fcfdcd1cee 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/operations.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/garbagecollector/operations.go @@ -115,7 +115,7 @@ func (gc *GarbageCollector) removeFinalizer(owner *node, targetFinalizer string) for _, f := range finalizers { if f == targetFinalizer { found = true - break + continue } newFinalizers = append(newFinalizers, f) } diff --git a/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/BUILD b/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/BUILD index af0663379f..c9dbe75caf 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/BUILD @@ -21,6 +21,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/dynamic:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/namespaced_resources_deleter.go b/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/namespaced_resources_deleter.go index 2593428bb4..fcdc69ff44 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/namespaced_resources_deleter.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/namespace/deletion/namespaced_resources_deleter.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" @@ -165,7 +166,10 @@ func (d *namespacedResourcesDeleter) initOpCache() { // TODO(sttts): get rid of opCache and http 405 logic around it and trust discovery info resources, err := d.discoverResourcesFn() if err != nil { - glog.Fatalf("Failed to get supported resources: %v", err) + utilruntime.HandleError(fmt.Errorf("unable to get all supported resources from server: %v", err)) + } + if len(resources) == 0 { + glog.Fatalf("Unable to get any supported resources from server: %v", err) } deletableGroupVersionResources := []schema.GroupVersionResource{} for _, rl := range resources { diff --git a/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal.go b/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal.go index 6182d175c2..9651d75ec2 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal.go @@ -450,14 +450,14 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho case desiredReplicas > scaleUpLimit: setCondition(hpa, autoscalingv2.ScalingLimited, v1.ConditionTrue, "ScaleUpLimit", "the desired replica count is increasing faster than the maximum scale rate") desiredReplicas = scaleUpLimit - case desiredReplicas == 0: - // never scale down to 0, reserved for disabling autoscaling - setCondition(hpa, autoscalingv2.ScalingLimited, v1.ConditionTrue, "TooFewReplicas", "the desired replica count was zero") - desiredReplicas = 1 case hpa.Spec.MinReplicas != nil && desiredReplicas < *hpa.Spec.MinReplicas: // make sure we aren't below our minimum setCondition(hpa, autoscalingv2.ScalingLimited, v1.ConditionTrue, "TooFewReplicas", "the desired replica count was less than the minimum replica count") desiredReplicas = *hpa.Spec.MinReplicas + case desiredReplicas == 0: + // never scale down to 0, reserved for disabling autoscaling + setCondition(hpa, autoscalingv2.ScalingLimited, v1.ConditionTrue, "TooFewReplicas", "the desired replica count was zero") + desiredReplicas = 1 case desiredReplicas > hpa.Spec.MaxReplicas: // make sure we aren't above our maximum setCondition(hpa, autoscalingv2.ScalingLimited, v1.ConditionTrue, "TooManyReplicas", "the desired replica count was more than the maximum replica count") diff --git a/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal_test.go b/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal_test.go index dfe9d756b7..11bf6ad566 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/podautoscaler/horizontal_test.go @@ -994,6 +994,25 @@ func TestMinReplicas(t *testing.T) { tc.runTest(t) } +func TestMinReplicasDesiredZero(t *testing.T) { + tc := testCase{ + minReplicas: 2, + maxReplicas: 5, + initialReplicas: 3, + desiredReplicas: 2, + CPUTarget: 90, + reportedLevels: []uint64{0, 0, 0}, + reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, + useMetricsApi: true, + expectedConditions: statusOkWithOverrides(autoscalingv2.HorizontalPodAutoscalerCondition{ + Type: autoscalingv2.ScalingLimited, + Status: v1.ConditionTrue, + Reason: "TooFewReplicas", + }), + } + tc.runTest(t) +} + func TestZeroReplicas(t *testing.T) { tc := testCase{ minReplicas: 3, diff --git a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_pod_control_test.go b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_pod_control_test.go index 0e376785b4..01c1cc3d32 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_pod_control_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_pod_control_test.go @@ -391,34 +391,6 @@ func TestStatefulPodControlUpdatePodConflictSuccess(t *testing.T) { } } -func TestStatefulPodControlUpdatePodConflictFailure(t *testing.T) { - recorder := record.NewFakeRecorder(10) - set := newStatefulSet(3) - pod := newStatefulSetPod(set, 0) - fakeClient := &fake.Clientset{} - indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - updatedPod := newStatefulSetPod(set, 0) - updatedPod.Spec.Hostname = "wrong" - indexer.Add(updatedPod) - podLister := corelisters.NewPodLister(indexer) - control := NewRealStatefulPodControl(fakeClient, nil, podLister, nil, recorder) - fakeClient.AddReactor("update", "pods", func(action core.Action) (bool, runtime.Object, error) { - update := action.(core.UpdateAction) - return true, update.GetObject(), apierrors.NewConflict(action.GetResource().GroupResource(), pod.Name, errors.New("conflict")) - - }) - pod.Name = "goo-0" - if err := control.UpdateStatefulPod(set, pod); err == nil { - t.Error("Failed update did not return an error") - } - events := collectEvents(recorder.Events) - if eventCount := len(events); eventCount != 1 { - t.Errorf("Expected 1 event for failed Pod update found %d", eventCount) - } else if !strings.Contains(events[0], v1.EventTypeWarning) { - t.Errorf("Expected normal event found %s", events[0]) - } -} - func TestStatefulPodControlDeletesStatefulPod(t *testing.T) { recorder := record.NewFakeRecorder(10) set := newStatefulSet(3) diff --git a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils.go b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils.go index c55a1e0455..7d240c6cd3 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils.go @@ -116,9 +116,7 @@ func identityMatches(set *apps.StatefulSet, pod *v1.Pod) bool { return ordinal >= 0 && set.Name == parent && pod.Name == getPodName(set, ordinal) && - pod.Namespace == set.Namespace && - pod.Spec.Hostname == pod.Name && - pod.Spec.Subdomain == set.Spec.ServiceName + pod.Namespace == set.Namespace } // storageMatches returns true if pod's Volumes cover the set of PersistentVolumeClaims @@ -186,12 +184,18 @@ func updateStorage(set *apps.StatefulSet, pod *v1.Pod) { pod.Spec.Volumes = newVolumes } +func initIdentity(set *apps.StatefulSet, pod *v1.Pod) { + updateIdentity(set, pod) + // Set these immutable fields only on initial Pod creation, not updates. + pod.Spec.Hostname = pod.Name + pod.Spec.Subdomain = set.Spec.ServiceName +} + // updateIdentity updates pod's name, hostname, and subdomain to conform to set's name and headless service. func updateIdentity(set *apps.StatefulSet, pod *v1.Pod) { pod.Name = getPodName(set, getOrdinal(pod)) pod.Namespace = set.Namespace - pod.Spec.Hostname = pod.Name - pod.Spec.Subdomain = set.Spec.ServiceName + } // isRunningAndReady returns true if pod is in the PodRunning Phase, if it has a condition of PodReady, and if the init @@ -276,7 +280,7 @@ func getPodRevision(pod *v1.Pod) string { func newStatefulSetPod(set *apps.StatefulSet, ordinal int) *v1.Pod { pod, _ := controller.GetPodFromTemplate(&set.Spec.Template, set, newControllerRef(set)) pod.Name = getPodName(set, ordinal) - updateIdentity(set, pod) + initIdentity(set, pod) updateStorage(set, pod) return pod } diff --git a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils_test.go b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils_test.go index b27145e5ad..817078caf7 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/statefulset/stateful_set_utils_test.go @@ -79,16 +79,6 @@ func TestIdentityMatches(t *testing.T) { if identityMatches(set, pod) { t.Error("identity matches for a Pod with the wrong namespace") } - pod = newStatefulSetPod(set, 1) - pod.Spec.Hostname = "" - if identityMatches(set, pod) { - t.Error("identity matches for a Pod with no hostname") - } - pod = newStatefulSetPod(set, 1) - pod.Spec.Subdomain = "" - if identityMatches(set, pod) { - t.Error("identity matches for a Pod with no subdomain") - } } func TestStorageMatches(t *testing.T) { @@ -138,24 +128,6 @@ func TestUpdateIdentity(t *testing.T) { if !identityMatches(set, pod) { t.Error("updateIdentity failed to update the Pods namespace") } - pod = newStatefulSetPod(set, 1) - pod.Spec.Hostname = "" - if identityMatches(set, pod) { - t.Error("identity matches for a Pod with no hostname") - } - updateIdentity(set, pod) - if !identityMatches(set, pod) { - t.Error("updateIdentity failed to update the Pod's hostname") - } - pod = newStatefulSetPod(set, 1) - pod.Spec.Subdomain = "" - if identityMatches(set, pod) { - t.Error("identity matches for a Pod with no subdomain") - } - updateIdentity(set, pod) - if !identityMatches(set, pod) { - t.Error("updateIdentity failed to update the Pod's subdomain") - } } func TestUpdateStorage(t *testing.T) { diff --git a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world.go b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world.go index 552530170f..3bffc60a60 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world.go @@ -125,10 +125,6 @@ type ActualStateOfWorld interface { // GetNodesToUpdateStatusFor returns the map of nodeNames to nodeToUpdateStatusFor GetNodesToUpdateStatusFor() map[types.NodeName]nodeToUpdateStatusFor - - // Removes the given node from the record of attach updates. The node's entire - // volumesToReportAsAttached list is removed. - RemoveNodeFromAttachUpdates(nodeName types.NodeName) error } // AttachedVolume represents a volume that is attached to a node. @@ -264,19 +260,6 @@ func (asw *actualStateOfWorld) AddVolumeToReportAsAttached( asw.addVolumeToReportAsAttached(volumeName, nodeName) } -func (asw *actualStateOfWorld) RemoveNodeFromAttachUpdates(nodeName types.NodeName) error { - asw.Lock() - defer asw.Unlock() - - _, nodeToUpdateExists := asw.nodesToUpdateStatusFor[nodeName] - if nodeToUpdateExists { - delete(asw.nodesToUpdateStatusFor, nodeName) - return nil - } - return fmt.Errorf("node %q does not exist in volumesToReportAsAttached list", - nodeName) -} - func (asw *actualStateOfWorld) AddVolumeNode( uniqueName v1.UniqueVolumeName, volumeSpec *volume.Spec, nodeName types.NodeName, devicePath string) (v1.UniqueVolumeName, error) { asw.Lock() diff --git a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world_test.go b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world_test.go index 88ae500d82..fa19728b33 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world_test.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache/actual_state_of_world_test.go @@ -1165,89 +1165,6 @@ func Test_updateNodeStatusUpdateNeededError(t *testing.T) { } } -// Test_RemoveNodeFromAttachUpdates_Positive expects an entire node entry to be removed -// from nodesToUpdateStatusFor -func Test_RemoveNodeFromAttachUpdates_Positive(t *testing.T) { - // Arrange - volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) - asw := &actualStateOfWorld{ - attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), - nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor), - volumePluginMgr: volumePluginMgr, - } - nodeName := types.NodeName("node-1") - nodeToUpdate := nodeToUpdateStatusFor{ - nodeName: nodeName, - statusUpdateNeeded: true, - volumesToReportAsAttached: make(map[v1.UniqueVolumeName]v1.UniqueVolumeName), - } - asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate - - // Act - err := asw.RemoveNodeFromAttachUpdates(nodeName) - - // Assert - if err != nil { - t.Fatalf("RemoveNodeFromAttachUpdates should not return error, but got: %v", err) - } - if len(asw.nodesToUpdateStatusFor) > 0 { - t.Fatal("nodesToUpdateStatusFor should be empty as its only entry has been deleted.") - } -} - -// Test_RemoveNodeFromAttachUpdates_Negative_NodeDoesNotExist expects an error to be thrown -// when nodeName is not in nodesToUpdateStatusFor. -func Test_RemoveNodeFromAttachUpdates_Negative_NodeDoesNotExist(t *testing.T) { - // Arrange - volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) - asw := &actualStateOfWorld{ - attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), - nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor), - volumePluginMgr: volumePluginMgr, - } - nodeName := types.NodeName("node-1") - nodeToUpdate := nodeToUpdateStatusFor{ - nodeName: nodeName, - statusUpdateNeeded: true, - volumesToReportAsAttached: make(map[v1.UniqueVolumeName]v1.UniqueVolumeName), - } - asw.nodesToUpdateStatusFor[nodeName] = nodeToUpdate - - // Act - err := asw.RemoveNodeFromAttachUpdates("node-2") - - // Assert - if err == nil { - t.Fatal("RemoveNodeFromAttachUpdates should return an error as the nodeName doesn't exist.") - } - if len(asw.nodesToUpdateStatusFor) != 1 { - t.Fatal("The length of nodesToUpdateStatusFor should not change because no operation was performed.") - } -} - -// Test_RemoveNodeFromAttachUpdates_Negative_Empty expects an error to be thrown -// when a nodesToUpdateStatusFor is empty. -func Test_RemoveNodeFromAttachUpdates_Negative_Empty(t *testing.T) { - // Arrange - volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) - asw := &actualStateOfWorld{ - attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), - nodesToUpdateStatusFor: make(map[types.NodeName]nodeToUpdateStatusFor), - volumePluginMgr: volumePluginMgr, - } - - // Act - err := asw.RemoveNodeFromAttachUpdates("node-1") - - // Assert - if err == nil { - t.Fatal("RemoveNodeFromAttachUpdates should return an error as nodeToUpdateStatusFor is empty.") - } - if len(asw.nodesToUpdateStatusFor) != 0 { - t.Fatal("The length of nodesToUpdateStatusFor should be 0.") - } -} - func verifyAttachedVolume( t *testing.T, attachedVolumes []AttachedVolume, diff --git a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/reconciler/reconciler.go b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/reconciler/reconciler.go index e66253cfd0..66169be4f9 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/reconciler/reconciler.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/reconciler/reconciler.go @@ -148,6 +148,11 @@ func (rc *reconciler) isMultiAttachForbidden(volumeSpec *volume.Spec) bool { // Only if this volume is a persistent volume, we have reliable information on wether it's allowed or not to // multi-attach. We trust in the individual volume implementations to not allow unsupported access modes if volumeSpec.PersistentVolume != nil { + // Check for persistent volume types which do not fail when trying to multi-attach + if volumeSpec.PersistentVolume.Spec.VsphereVolume != nil { + return false + } + if len(volumeSpec.PersistentVolume.Spec.AccessModes) == 0 { // No access mode specified so we don't know for sure. Let the attacher fail if needed return false diff --git a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go index 94db1f2b6b..818f3c6d9c 100644 --- a/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go +++ b/vendor/k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater/node_status_updater.go @@ -68,13 +68,11 @@ func (nsu *nodeStatusUpdater) UpdateNodeStatuses() error { nodeObj, err := nsu.nodeLister.Get(string(nodeName)) if errors.IsNotFound(err) { // If node does not exist, its status cannot be updated. - // Remove the node entry from the collection of attach updates, preventing the - // status updater from unnecessarily updating the node. + // Do nothing so that there is no retry until node is created. glog.V(2).Infof( "Could not update node status. Failed to find node %q in NodeInformer cache. Error: '%v'", nodeName, err) - nsu.actualStateOfWorld.RemoveNodeFromAttachUpdates(nodeName) continue } else if err != nil { // For all other errors, log error and reset flag statusUpdateNeeded diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/BUILD b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/BUILD index 41b2154ad5..aacd43a55a 100644 --- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/BUILD @@ -16,10 +16,10 @@ go_library( "//pkg/cloudprovider/providers/azure:go_default_library", "//pkg/credentialprovider:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/arm/containerregistry:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library", - "//vendor/gopkg.in/yaml.v2:go_default_library", ], ) diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go index 771c41780b..257cbee5b8 100644 --- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go +++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials.go @@ -17,12 +17,12 @@ limitations under the License. package azure import ( - "io/ioutil" + "io" + "os" "time" - yaml "gopkg.in/yaml.v2" - "github.com/Azure/azure-sdk-for-go/arm/containerregistry" + "github.com/Azure/go-autorest/autorest" azureapi "github.com/Azure/go-autorest/autorest/azure" "github.com/golang/glog" "github.com/spf13/pflag" @@ -45,10 +45,12 @@ func init() { }) } +// RegistriesClient is a testable interface for the ACR client List operation. type RegistriesClient interface { List() (containerregistry.RegistryListResult, error) } +// NewACRProvider parses the specified configFile and returns a DockerConfigProvider func NewACRProvider(configFile *string) credentialprovider.DockerConfigProvider { return &acrProvider{ file: configFile, @@ -57,24 +59,16 @@ func NewACRProvider(configFile *string) credentialprovider.DockerConfigProvider type acrProvider struct { file *string - config azure.Config - environment azureapi.Environment + config *azure.Config + environment *azureapi.Environment registryClient RegistriesClient } -func (a *acrProvider) loadConfig(contents []byte) error { - err := yaml.Unmarshal(contents, &a.config) +func (a *acrProvider) loadConfig(rdr io.Reader) error { + var err error + a.config, a.environment, err = azure.ParseConfig(rdr) if err != nil { - return err - } - - if a.config.Cloud == "" { - a.environment = azureapi.PublicCloud - } else { - a.environment, err = azureapi.EnvironmentFromName(a.config.Cloud) - if err != nil { - return err - } + glog.Errorf("Failed to load azure credential file: %v", err) } return nil } @@ -84,27 +78,21 @@ func (a *acrProvider) Enabled() bool { glog.V(5).Infof("Azure config unspecified, disabling") return false } - contents, err := ioutil.ReadFile(*a.file) + + f, err := os.Open(*a.file) if err != nil { - glog.Errorf("Failed to load azure credential file: %v", err) - return false - } - if err := a.loadConfig(contents); err != nil { - glog.Errorf("Failed to parse azure credential file: %v", err) + glog.Errorf("Failed to load config from file: %s", *a.file) return false } + defer f.Close() - oauthConfig, err := a.environment.OAuthConfigForTenant(a.config.TenantID) + err = a.loadConfig(f) if err != nil { - glog.Errorf("Failed to get oauth config: %v", err) + glog.Errorf("Failed to load config from file: %s", *a.file) return false } - servicePrincipalToken, err := azureapi.NewServicePrincipalToken( - *oauthConfig, - a.config.AADClientID, - a.config.AADClientSecret, - a.environment.ServiceManagementEndpoint) + servicePrincipalToken, err := azure.GetServicePrincipalToken(a.config, a.environment) if err != nil { glog.Errorf("Failed to create service principal token: %v", err) return false @@ -112,7 +100,7 @@ func (a *acrProvider) Enabled() bool { registryClient := containerregistry.NewRegistriesClient(a.config.SubscriptionID) registryClient.BaseURI = a.environment.ResourceManagerEndpoint - registryClient.Authorizer = servicePrincipalToken + registryClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) a.registryClient = registryClient return true diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials_test.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials_test.go index 8f69738776..9d966fe6be 100644 --- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials_test.go +++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/azure/azure_credentials_test.go @@ -17,6 +17,7 @@ limitations under the License. package azure import ( + "bytes" "testing" "github.com/Azure/azure-sdk-for-go/arm/containerregistry" @@ -66,7 +67,7 @@ func Test(t *testing.T) { provider := &acrProvider{ registryClient: fakeClient, } - provider.loadConfig([]byte(configStr)) + provider.loadConfig(bytes.NewBufferString(configStr)) creds := provider.Provide() diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/BUILD b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/BUILD index 218ed11ea5..4cf9f02270 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/BUILD @@ -12,14 +12,17 @@ go_test( name = "go_default_test", srcs = [ "configuration_manager_test.go", + "external_admission_hook_manager_test.go", "initializer_manager_test.go", ], library = ":go_default_library", tags = ["automanaged"], deps = [ "//pkg/apis/admissionregistration/v1alpha1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", ], ) diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager.go index 64d4bd3758..5ca2d62061 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager.go @@ -20,6 +20,9 @@ import ( "fmt" "reflect" + "github.com/golang/glog" + + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" @@ -37,6 +40,10 @@ func NewExternalAdmissionHookConfigurationManager(c ExternalAdmissionHookConfigu getFn := func() (runtime.Object, error) { list, err := c.List(metav1.ListOptions{}) if err != nil { + if errors.IsNotFound(err) || errors.IsForbidden(err) { + glog.V(5).Infof("ExternalAdmissionHookConfiguration are disabled due to an error: %v", err) + return nil, ErrDisabled + } return nil, err } return mergeExternalAdmissionHookConfigurations(list), nil diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager_test.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager_test.go new file mode 100644 index 0000000000..14a3debfb4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/external_admission_hook_manager_test.go @@ -0,0 +1,40 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package configuration + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" +) + +type disabledWebhookConfigLister struct{} + +func (l *disabledWebhookConfigLister) List(options metav1.ListOptions) (*v1alpha1.ExternalAdmissionHookConfigurationList, error) { + return nil, errors.NewNotFound(schema.GroupResource{Group: "admissionregistration", Resource: "externalAdmissionHookConfigurations"}, "") +} +func TestWebhookConfigDisabled(t *testing.T) { + manager := NewExternalAdmissionHookConfigurationManager(&disabledWebhookConfigLister{}) + manager.sync() + _, err := manager.ExternalAdmissionHooks() + if err.Error() != ErrDisabled.Error() { + t.Errorf("expected %v, got %v", ErrDisabled, err) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/initializer_manager_test.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/initializer_manager_test.go index b9d1e79913..63d4337034 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/initializer_manager_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/admission/configuration/initializer_manager_test.go @@ -22,7 +22,9 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1" ) @@ -164,3 +166,17 @@ func TestMergeInitializerConfigurations(t *testing.T) { t.Errorf("expected: %#v, got: %#v", expected, got) } } + +type disabledInitializerConfigLister struct{} + +func (l *disabledInitializerConfigLister) List(options metav1.ListOptions) (*v1alpha1.InitializerConfigurationList, error) { + return nil, errors.NewNotFound(schema.GroupResource{Group: "admissionregistration", Resource: "initializerConfigurations"}, "") +} +func TestInitializerConfigDisabled(t *testing.T) { + manager := NewInitializerConfigurationManager(&disabledInitializerConfigLister{}) + manager.sync() + _, err := manager.Initializers() + if err.Error() != ErrDisabled.Error() { + t.Errorf("expected %v, got %v", ErrDisabled, err) + } +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go index 24127f546a..8186a0ac7a 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go @@ -46,7 +46,7 @@ func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.H handler = genericapifilters.WithAuthentication(handler, c.RequestContextMapper, insecureSuperuser{}, nil) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithPanicRecovery(handler) - handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc) + handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.RequestContextMapper, c.LongRunningFunc) handler = genericapifilters.WithRequestInfo(handler, server.NewRequestInfoResolver(c), c.RequestContextMapper) handler = apirequest.WithRequestContext(handler, c.RequestContextMapper) diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go index 97360fc29f..4383019322 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go @@ -494,9 +494,12 @@ func (o *DrainOptions) evictPods(pods []api.Pod, policyGroupVersion string, getP err = o.evictPod(pod, policyGroupVersion) if err == nil { break + } else if apierrors.IsNotFound(err) { + doneCh <- true + return } else if apierrors.IsTooManyRequests(err) { time.Sleep(5 * time.Second) - } else if !apierrors.IsNotFound(err) { + } else { errCh <- fmt.Errorf("error when evicting pod %q: %v", pod.Name, err) return } diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/set/set_selector.go b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/set/set_selector.go index 3cbb859707..a7f3a60e05 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/set/set_selector.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/set/set_selector.go @@ -116,6 +116,10 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ mapper, _ := f.Object() o.mapper = mapper o.encoder = f.JSONEncoder() + o.resources, o.selector, err = getResourcesAndSelector(args) + if err != nil { + return err + } o.builder = f.NewBuilder(!o.local). ContinueOnError(). @@ -135,8 +139,6 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ o.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { return f.ClientForMapping(mapping) } - - o.resources, o.selector, err = getResourcesAndSelector(args) return err } diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/resource_filter.go b/vendor/k8s.io/kubernetes/pkg/kubectl/resource_filter.go index 34b5dba915..a783a8155d 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/resource_filter.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/resource_filter.go @@ -38,21 +38,18 @@ func NewResourceFilter() Filters { } // filterPods returns true if a pod should be skipped. -// defaults to true for terminated pods +// If show-all is true, the pod will be never be skipped (return false); +// otherwise, skip terminated pod. func filterPods(obj runtime.Object, options printers.PrintOptions) bool { + if options.ShowAll { + return false + } + switch p := obj.(type) { case *v1.Pod: - reason := string(p.Status.Phase) - if p.Status.Reason != "" { - reason = p.Status.Reason - } - return !options.ShowAll && (reason == string(v1.PodSucceeded) || reason == string(v1.PodFailed)) + return p.Status.Phase == v1.PodSucceeded || p.Status.Phase == v1.PodFailed case *api.Pod: - reason := string(p.Status.Phase) - if p.Status.Reason != "" { - reason = p.Status.Reason - } - return !options.ShowAll && (reason == string(api.PodSucceeded) || reason == string(api.PodFailed)) + return p.Status.Phase == api.PodSucceeded || p.Status.Phase == api.PodFailed } return false } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD index ce6fdc59d8..3fa667a977 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/BUILD @@ -41,6 +41,7 @@ go_library( "//pkg/util/sysctl:go_default_library", "//pkg/util/version:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/google/cadvisor/info/v2:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go index 7ab9b59d9c..175f7c02c0 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux.go @@ -30,6 +30,7 @@ import ( "time" "github.com/golang/glog" + cadvisorapiv2 "github.com/google/cadvisor/info/v2" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/configs" @@ -219,30 +220,12 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I var capacity = v1.ResourceList{} // It is safe to invoke `MachineInfo` on cAdvisor before logically initializing cAdvisor here because // machine info is computed and cached once as part of cAdvisor object creation. + // But `RootFsInfo` and `ImagesFsInfo` are not available at this moment so they will be called later during manager starts if info, err := cadvisorInterface.MachineInfo(); err == nil { capacity = cadvisor.CapacityFromMachineInfo(info) } else { return nil, err } - rootfs, err := cadvisorInterface.RootFsInfo() - if err != nil { - capacity[v1.ResourceStorageScratch] = resource.MustParse("0Gi") - } else { - for rName, rCap := range cadvisor.StorageScratchCapacityFromFsInfo(rootfs) { - capacity[rName] = rCap - } - } - - if hasDedicatedImageFs, _ := cadvisorInterface.HasDedicatedImageFs(); hasDedicatedImageFs { - imagesfs, err := cadvisorInterface.ImagesFsInfo() - if err != nil { - glog.Errorf("Failed to get Image filesystem information: %v", err) - } else { - for rName, rCap := range cadvisor.StorageOverlayCapacityFromFsInfo(imagesfs) { - capacity[rName] = rCap - } - } - } cgroupRoot := nodeConfig.CgroupRoot cgroupManager := NewCgroupManager(subsystems, nodeConfig.CgroupDriver) @@ -551,6 +534,44 @@ func (cm *containerManagerImpl) Start(node *v1.Node, activePods ActivePodsFunc) }, 5*time.Minute, wait.NeverStop) } + // Local storage filesystem information from `RootFsInfo` and `ImagesFsInfo` is available at a later time + // depending on the time when cadvisor manager updates container stats. Therefore use a go routine to keep + // retrieving the information until it is available. + stopChan := make(chan struct{}) + go wait.Until(func() { + if err := cm.setFsCapacity(); err != nil { + glog.Errorf("[ContainerManager]: %v", err) + return + } + close(stopChan) + }, time.Second, stopChan) + return nil +} + +func (cm *containerManagerImpl) setFsCapacity() error { + rootfs, err := cm.cadvisorInterface.RootFsInfo() + if err != nil { + return fmt.Errorf("Fail to get rootfs information %v", err) + } + hasDedicatedImageFs, _ := cm.cadvisorInterface.HasDedicatedImageFs() + var imagesfs cadvisorapiv2.FsInfo + if hasDedicatedImageFs { + imagesfs, err = cm.cadvisorInterface.ImagesFsInfo() + if err != nil { + return fmt.Errorf("Fail to get imagefs information %v", err) + } + } + + cm.Lock() + for rName, rCap := range cadvisor.StorageScratchCapacityFromFsInfo(rootfs) { + cm.capacity[rName] = rCap + } + if hasDedicatedImageFs { + for rName, rCap := range cadvisor.StorageOverlayCapacityFromFsInfo(imagesfs) { + cm.capacity[rName] = rCap + } + } + cm.Unlock() return nil } @@ -809,6 +830,8 @@ func getDockerAPIVersion(cadvisor cadvisor.Interface) *utilversion.Version { return dockerAPIVersion } -func (m *containerManagerImpl) GetCapacity() v1.ResourceList { - return m.capacity +func (cm *containerManagerImpl) GetCapacity() v1.ResourceList { + cm.RLock() + defer cm.RUnlock() + return cm.capacity } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go index 12219d0b9b..d1cba37ae4 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_linux_test.go @@ -47,6 +47,14 @@ func (mi *fakeMountInterface) List() ([]mount.MountPoint, error) { return mi.mountPoints, nil } +func (mi *fakeMountInterface) IsMountPointMatch(mp mount.MountPoint, dir string) bool { + return (mp.Path == dir) +} + +func (mi *fakeMountInterface) IsNotMountPoint(dir string) (bool, error) { + return false, fmt.Errorf("unsupported") +} + func (mi *fakeMountInterface) IsLikelyNotMountPoint(file string) (bool, error) { return false, fmt.Errorf("unsupported") } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go index 11d70260e9..d1451946fc 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/container_manager_unsupported_test.go @@ -40,6 +40,14 @@ func (mi *fakeMountInterface) List() ([]mount.MountPoint, error) { return mi.mountPoints, nil } +func (f *fakeMountInterface) IsMountPointMatch(mp mount.MountPoint, dir string) bool { + return (mp.Path == dir) +} + +func (f *fakeMountInterface) IsNotMountPoint(dir string) (bool, error) { + return false, fmt.Errorf("unsupported") +} + func (mi *fakeMountInterface) IsLikelyNotMountPoint(file string) (bool, error) { return false, fmt.Errorf("unsupported") } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/node_container_manager.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/node_container_manager.go index 7fd127b2a4..58097429e0 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/node_container_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/node_container_manager.go @@ -217,6 +217,10 @@ func hardEvictionReservation(thresholds []evictionapi.Threshold, capacity v1.Res memoryCapacity := capacity[v1.ResourceMemory] value := evictionapi.GetThresholdQuantity(threshold.Value, &memoryCapacity) ret[v1.ResourceMemory] = *value + case evictionapi.SignalNodeFsAvailable: + storageCapacity := capacity[v1.ResourceStorageScratch] + value := evictionapi.GetThresholdQuantity(threshold.Value, &storageCapacity) + ret[v1.ResourceStorageScratch] = *value } } return ret diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/BUILD b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/BUILD index 864dfcac8f..8f646da597 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/BUILD @@ -54,6 +54,7 @@ go_library( "//pkg/security/apparmor:go_default_library", "//pkg/util/exec:go_default_library", "//pkg/util/hash:go_default_library", + "//pkg/util/parsers:go_default_library", "//pkg/util/term:go_default_library", "//vendor/github.com/blang/semver:go_default_library", "//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/exec.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/exec.go index 1d73a8a8d5..f7344eb727 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/exec.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/exec.go @@ -135,6 +135,9 @@ func (*NsenterExecHandler) ExecInContainer(client libdocker.Interface, container type NativeExecHandler struct{} func (*NativeExecHandler) ExecInContainer(client libdocker.Interface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error { + done := make(chan struct{}) + defer close(done) + createOpts := dockertypes.ExecConfig{ Cmd: cmd, AttachStdin: stdin != nil, @@ -149,9 +152,23 @@ func (*NativeExecHandler) ExecInContainer(client libdocker.Interface, container // Have to start this before the call to client.StartExec because client.StartExec is a blocking // call :-( Otherwise, resize events don't get processed and the terminal never resizes. - kubecontainer.HandleResizing(resize, func(size remotecommand.TerminalSize) { - client.ResizeExecTTY(execObj.ID, int(size.Height), int(size.Width)) - }) + // + // We also have to delay attempting to send a terminal resize request to docker until after the + // exec has started; otherwise, the initial resize request will fail. + execStarted := make(chan struct{}) + go func() { + select { + case <-execStarted: + // client.StartExec has started the exec, so we can start resizing + case <-done: + // ExecInContainer has returned, so short-circuit + return + } + + kubecontainer.HandleResizing(resize, func(size remotecommand.TerminalSize) { + client.ResizeExecTTY(execObj.ID, int(size.Height), int(size.Width)) + }) + }() startOpts := dockertypes.ExecStartCheck{Detach: false, Tty: tty} streamOpts := libdocker.StreamOptions{ @@ -159,6 +176,7 @@ func (*NativeExecHandler) ExecInContainer(client libdocker.Interface, container OutputStream: stdout, ErrorStream: stderr, RawTerminal: tty, + ExecStarted: execStarted, } err = client.StartExec(execObj.ID, startOpts, streamOpts) if err != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers.go index c5b99a32d5..20b538a72c 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers.go @@ -22,7 +22,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "os" "path/filepath" "regexp" "strconv" @@ -34,13 +33,14 @@ import ( dockernat "github.com/docker/go-connections/nat" "github.com/golang/glog" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/credentialprovider" runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" + "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker" "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/security/apparmor" - - "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker" + "k8s.io/kubernetes/pkg/util/parsers" ) const ( @@ -393,11 +393,6 @@ func getSecurityOptSeparator(v *semver.Version) rune { // ensureSandboxImageExists pulls the sandbox image when it's not present. func ensureSandboxImageExists(client libdocker.Interface, image string) error { - dockerCfgSearchPath := []string{"/.docker", filepath.Join(os.Getenv("HOME"), ".docker")} - return ensureSandboxImageExistsDockerCfg(client, image, dockerCfgSearchPath) -} - -func ensureSandboxImageExistsDockerCfg(client libdocker.Interface, image string, dockerCfgSearchPath []string) error { _, err := client.InspectImageByRef(image) if err == nil { return nil @@ -406,34 +401,37 @@ func ensureSandboxImageExistsDockerCfg(client libdocker.Interface, image string, return fmt.Errorf("failed to inspect sandbox image %q: %v", image, err) } - // To support images in private registries, try to read docker config - authConfig := dockertypes.AuthConfig{} - keyring := &credentialprovider.BasicDockerKeyring{} - var cfgLoadErr error - if cfg, err := credentialprovider.ReadDockerConfigJSONFile(dockerCfgSearchPath); err == nil { - keyring.Add(cfg) - } else if cfg, err := credentialprovider.ReadDockercfgFile(dockerCfgSearchPath); err == nil { - keyring.Add(cfg) - } else { - cfgLoadErr = err - } - if creds, withCredentials := keyring.Lookup(image); withCredentials { - // Use the first one that matched our image - for _, cred := range creds { - authConfig.Username = cred.Username - authConfig.Password = cred.Password - break + repoToPull, _, _, err := parsers.ParseImageName(image) + if err != nil { + return err + } + + keyring := credentialprovider.NewDockerKeyring() + creds, withCredentials := keyring.Lookup(repoToPull) + if !withCredentials { + glog.V(3).Infof("Pulling image %q without credentials", image) + + err := client.PullImage(image, dockertypes.AuthConfig{}, dockertypes.ImagePullOptions{}) + if err != nil { + return fmt.Errorf("failed pulling image %q: %v", image, err) } + + return nil } - err = client.PullImage(image, authConfig, dockertypes.ImagePullOptions{}) - if err != nil { - if cfgLoadErr != nil { - glog.Warningf("Couldn't load Docker cofig. If sandbox image %q is in a private registry, this will cause further errors. Error: %v", image, cfgLoadErr) + var pullErrs []error + for _, currentCreds := range creds { + authConfig := credentialprovider.LazyProvide(currentCreds) + err := client.PullImage(image, authConfig, dockertypes.ImagePullOptions{}) + // If there was no error, return success + if err == nil { + return nil } - return fmt.Errorf("unable to pull sandbox image %q: %v", image, err) + + pullErrs = append(pullErrs, err) } - return nil + + return utilerrors.NewAggregate(pullErrs) } func getAppArmorOpts(profile string) ([]dockerOpt, error) { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers_test.go index 7304abfd96..109726cb34 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/helpers_test.go @@ -17,7 +17,6 @@ limitations under the License. package dockershim import ( - "encoding/base64" "fmt" "io/ioutil" "os" @@ -34,9 +33,8 @@ import ( "k8s.io/kubernetes/pkg/api/v1" runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" - "k8s.io/kubernetes/pkg/security/apparmor" - "k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker" + "k8s.io/kubernetes/pkg/security/apparmor" ) func TestLabelsAndAnnotationsRoundTrip(t *testing.T) { @@ -267,10 +265,7 @@ func writeDockerConfig(cfg string) (string, error) { func TestEnsureSandboxImageExists(t *testing.T) { sandboxImage := "gcr.io/test/image" - registryHost := "https://gcr.io/" authConfig := dockertypes.AuthConfig{Username: "user", Password: "pass"} - authB64 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", authConfig.Username, authConfig.Password))) - authJSON := fmt.Sprintf("{\"auths\": {\"%s\": {\"auth\": \"%s\"} } }", registryHost, authB64) for desc, test := range map[string]struct { injectImage bool imgNeedsAuth bool @@ -302,14 +297,6 @@ func TestEnsureSandboxImageExists(t *testing.T) { calls: []string{"inspect_image", "pull"}, err: true, }, - "should pull private image using dockerauth if image doesn't exist": { - injectImage: true, - imgNeedsAuth: true, - injectErr: libdocker.ImageNotFoundError{ID: "image_id"}, - calls: []string{"inspect_image", "pull"}, - configJSON: authJSON, - err: false, - }, } { t.Logf("TestCase: %q", desc) _, fakeDocker, _ := newTestDockerService() @@ -322,15 +309,7 @@ func TestEnsureSandboxImageExists(t *testing.T) { } fakeDocker.InjectError("inspect_image", test.injectErr) - var dockerCfgSearchPath []string - if test.configJSON != "" { - tmpdir, err := writeDockerConfig(test.configJSON) - require.NoError(t, err, "could not create a temp docker config file") - dockerCfgSearchPath = append(dockerCfgSearchPath, filepath.Join(tmpdir, ".docker")) - defer os.RemoveAll(tmpdir) - } - - err := ensureSandboxImageExistsDockerCfg(fakeDocker, sandboxImage, dockerCfgSearchPath) + err := ensureSandboxImageExists(fakeDocker, sandboxImage) assert.NoError(t, fakeDocker.AssertCalls(test.calls)) assert.Equal(t, test.err, err != nil) } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker/kube_docker_client.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker/kube_docker_client.go index f3bbc3f053..7fdfb03e1c 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker/kube_docker_client.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker/kube_docker_client.go @@ -463,6 +463,15 @@ func (d *kubeDockerClient) StartExec(startExec string, opts dockertypes.ExecStar return err } defer resp.Close() + + if sopts.ExecStarted != nil { + // Send a message to the channel indicating that the exec has started. This is needed so + // interactive execs can handle resizing correctly - the request to resize the TTY has to happen + // after the call to d.client.ContainerExecAttach, and because d.holdHijackedConnection below + // blocks, we use sopts.ExecStarted to signal the caller that it's ok to resize. + sopts.ExecStarted <- struct{}{} + } + return d.holdHijackedConnection(sopts.RawTerminal || opts.Tty, sopts.InputStream, sopts.OutputStream, sopts.ErrorStream, resp) } @@ -593,6 +602,7 @@ type StreamOptions struct { InputStream io.Reader OutputStream io.Writer ErrorStream io.Writer + ExecStarted chan struct{} } // operationTimeout is the error returned when the docker operations are timeout. diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager.go b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager.go index 458cb6e7b1..bc7776328a 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager.go @@ -148,11 +148,11 @@ func (m *managerImpl) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAd } // Start starts the control loop to observe and response to low compute resources. -func (m *managerImpl) Start(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, podCleanedUpFunc PodCleanedUpFunc, nodeProvider NodeProvider, monitoringInterval time.Duration) { +func (m *managerImpl) Start(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, podCleanedUpFunc PodCleanedUpFunc, capacityProvider CapacityProvider, monitoringInterval time.Duration) { // start the eviction manager monitoring go func() { for { - if evictedPods := m.synchronize(diskInfoProvider, podFunc, nodeProvider); evictedPods != nil { + if evictedPods := m.synchronize(diskInfoProvider, podFunc, capacityProvider); evictedPods != nil { glog.Infof("eviction manager: pods %s evicted, waiting for pod to be cleaned up", format.Pods(evictedPods)) m.waitForPodsCleanup(podCleanedUpFunc, evictedPods) } else { @@ -211,7 +211,7 @@ func startMemoryThresholdNotifier(thresholds []evictionapi.Threshold, observatio // synchronize is the main control loop that enforces eviction thresholds. // Returns the pod that was killed, or nil if no pod was killed. -func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, nodeProvider NodeProvider) []*v1.Pod { +func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, capacityProvider CapacityProvider) []*v1.Pod { // if we have nothing to do, just return thresholds := m.config.Thresholds if len(thresholds) == 0 { @@ -233,7 +233,7 @@ func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc Act activePods := podFunc() // make observations and get a function to derive pod usage stats relative to those observations. - observations, statsFunc, err := makeSignalObservations(m.summaryProvider, nodeProvider, activePods, *m.dedicatedImageFs) + observations, statsFunc, err := makeSignalObservations(m.summaryProvider, capacityProvider, activePods, *m.dedicatedImageFs) if err != nil { glog.Errorf("eviction manager: unexpected err: %v", err) return nil @@ -248,7 +248,7 @@ func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc Act err = startMemoryThresholdNotifier(m.config.Thresholds, observations, false, func(desc string) { glog.Infof("soft memory eviction threshold crossed at %s", desc) // TODO wait grace period for soft memory limit - m.synchronize(diskInfoProvider, podFunc, nodeProvider) + m.synchronize(diskInfoProvider, podFunc, capacityProvider) }) if err != nil { glog.Warningf("eviction manager: failed to create hard memory threshold notifier: %v", err) @@ -256,7 +256,7 @@ func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc Act // start hard memory notification err = startMemoryThresholdNotifier(m.config.Thresholds, observations, true, func(desc string) { glog.Infof("hard memory eviction threshold crossed at %s", desc) - m.synchronize(diskInfoProvider, podFunc, nodeProvider) + m.synchronize(diskInfoProvider, podFunc, capacityProvider) }) if err != nil { glog.Warningf("eviction manager: failed to create soft memory threshold notifier: %v", err) @@ -491,7 +491,7 @@ func (m *managerImpl) emptyDirLimitEviction(podStats statsapi.PodStats, pod *v1. if source.EmptyDir != nil { size := source.EmptyDir.SizeLimit used := podVolumeUsed[pod.Spec.Volumes[i].Name] - if used != nil && size.Sign() == 1 && used.Cmp(size) > 0 { + if used != nil && size != nil && size.Sign() == 1 && used.Cmp(*size) > 0 { // the emptyDir usage exceeds the size limit, evict the pod return m.evictPod(pod, v1.ResourceName("EmptyDir"), fmt.Sprintf("emptyDir usage exceeds the limit %q", size.String())) } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager_test.go index 2177be4b35..644444309a 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/eviction_manager_test.go @@ -59,22 +59,25 @@ func (m *mockDiskInfoProvider) HasDedicatedImageFs() (bool, error) { return m.dedicatedImageFs, nil } -func newMockNodeProvider(allocatableCapacity v1.ResourceList) *mockNodeProvider { - return &mockNodeProvider{ - node: v1.Node{ - Status: v1.NodeStatus{ - Allocatable: allocatableCapacity, - }, - }, +func newMockCapacityProvider(capacity, reservation v1.ResourceList) *mockCapacityProvider { + return &mockCapacityProvider{ + capacity: capacity, + reservation: reservation, } } -type mockNodeProvider struct { - node v1.Node +type mockCapacityProvider struct { + capacity v1.ResourceList + reservation v1.ResourceList +} + +func (m *mockCapacityProvider) GetCapacity() v1.ResourceList { + return m.capacity + } -func (m *mockNodeProvider) GetNode() (*v1.Node, error) { - return &m.node, nil +func (m *mockCapacityProvider) GetNodeAllocatableReservation() v1.ResourceList { + return m.reservation } // mockDiskGC is used to simulate invoking image and container garbage collection. @@ -200,7 +203,7 @@ func TestMemoryPressure(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) imageGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -243,7 +246,7 @@ func TestMemoryPressure(t *testing.T) { burstablePodToAdmit, _ := podMaker("burst-admit", newResourceList("100m", "100Mi"), newResourceList("200m", "200Mi"), "0Gi") // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure if manager.IsUnderMemoryPressure() { @@ -261,7 +264,7 @@ func TestMemoryPressure(t *testing.T) { // induce soft threshold fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("1500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -276,7 +279,7 @@ func TestMemoryPressure(t *testing.T) { // step forward in time pass the grace period fakeClock.Step(3 * time.Minute) summaryProvider.result = summaryStatsMaker("1500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -301,7 +304,7 @@ func TestMemoryPressure(t *testing.T) { // remove memory pressure fakeClock.Step(20 * time.Minute) summaryProvider.result = summaryStatsMaker("3Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure if manager.IsUnderMemoryPressure() { @@ -311,7 +314,7 @@ func TestMemoryPressure(t *testing.T) { // induce memory pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -339,7 +342,7 @@ func TestMemoryPressure(t *testing.T) { fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("2Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure (because transition period not yet met) if !manager.IsUnderMemoryPressure() { @@ -363,7 +366,7 @@ func TestMemoryPressure(t *testing.T) { fakeClock.Step(5 * time.Minute) summaryProvider.result = summaryStatsMaker("2Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure (because transition period met) if manager.IsUnderMemoryPressure() { @@ -418,7 +421,7 @@ func TestDiskPressureNodeFs(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) diskGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -461,7 +464,7 @@ func TestDiskPressureNodeFs(t *testing.T) { podToAdmit, _ := podMaker("pod-to-admit", newResourceList("", ""), newResourceList("", ""), "0Gi", "0Gi", "0Gi") // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -476,7 +479,7 @@ func TestDiskPressureNodeFs(t *testing.T) { // induce soft threshold fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("1.5Gi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -491,7 +494,7 @@ func TestDiskPressureNodeFs(t *testing.T) { // step forward in time pass the grace period fakeClock.Step(3 * time.Minute) summaryProvider.result = summaryStatsMaker("1.5Gi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -516,7 +519,7 @@ func TestDiskPressureNodeFs(t *testing.T) { // remove disk pressure fakeClock.Step(20 * time.Minute) summaryProvider.result = summaryStatsMaker("16Gi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -526,7 +529,7 @@ func TestDiskPressureNodeFs(t *testing.T) { // induce disk pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("500Mi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -551,7 +554,7 @@ func TestDiskPressureNodeFs(t *testing.T) { fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("16Gi", "200Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure (because transition period not yet met) if !manager.IsUnderDiskPressure() { @@ -572,7 +575,7 @@ func TestDiskPressureNodeFs(t *testing.T) { fakeClock.Step(5 * time.Minute) summaryProvider.result = summaryStatsMaker("16Gi", "200Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure (because transition period met) if manager.IsUnderDiskPressure() { @@ -617,7 +620,7 @@ func TestMinReclaim(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) diskGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -652,7 +655,7 @@ func TestMinReclaim(t *testing.T) { } // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure if manager.IsUnderMemoryPressure() { @@ -662,7 +665,7 @@ func TestMinReclaim(t *testing.T) { // induce memory pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -682,7 +685,7 @@ func TestMinReclaim(t *testing.T) { fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("1.2Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure (because transition period not yet met) if !manager.IsUnderMemoryPressure() { @@ -702,7 +705,7 @@ func TestMinReclaim(t *testing.T) { fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("2Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure (because transition period not yet met) if !manager.IsUnderMemoryPressure() { @@ -718,7 +721,7 @@ func TestMinReclaim(t *testing.T) { fakeClock.Step(5 * time.Minute) summaryProvider.result = summaryStatsMaker("2Gi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure (because transition period met) if manager.IsUnderMemoryPressure() { @@ -757,7 +760,7 @@ func TestNodeReclaimFuncs(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) imageGcFree := resource.MustParse("700Mi") diskGC := &mockDiskGC{imageBytesFreed: imageGcFree.Value(), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -793,7 +796,7 @@ func TestNodeReclaimFuncs(t *testing.T) { } // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -803,7 +806,7 @@ func TestNodeReclaimFuncs(t *testing.T) { // induce hard threshold fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker(".9Gi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -827,7 +830,7 @@ func TestNodeReclaimFuncs(t *testing.T) { // remove disk pressure fakeClock.Step(20 * time.Minute) summaryProvider.result = summaryStatsMaker("16Gi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -837,7 +840,7 @@ func TestNodeReclaimFuncs(t *testing.T) { // induce disk pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("400Mi", "200Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -864,7 +867,7 @@ func TestNodeReclaimFuncs(t *testing.T) { diskGC.imageGCInvoked = false // reset state diskGC.containerGCInvoked = false // reset state podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure (because transition period not yet met) if !manager.IsUnderDiskPressure() { @@ -887,7 +890,7 @@ func TestNodeReclaimFuncs(t *testing.T) { diskGC.imageGCInvoked = false // reset state diskGC.containerGCInvoked = false // reset state podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure (because transition period met) if manager.IsUnderDiskPressure() { @@ -955,7 +958,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) diskGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -998,7 +1001,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { podToAdmit, _ := podMaker("pod-to-admit", newResourceList("", ""), newResourceList("", ""), "0", "0", "0") // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -1013,7 +1016,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { // induce soft threshold fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("1.5Mi", "4Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -1028,7 +1031,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { // step forward in time pass the grace period fakeClock.Step(3 * time.Minute) summaryProvider.result = summaryStatsMaker("1.5Mi", "4Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -1053,7 +1056,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { // remove inode pressure fakeClock.Step(20 * time.Minute) summaryProvider.result = summaryStatsMaker("3Mi", "4Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure if manager.IsUnderDiskPressure() { @@ -1063,7 +1066,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { // induce inode pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("0.5Mi", "4Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure if !manager.IsUnderDiskPressure() { @@ -1088,7 +1091,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("3Mi", "4Mi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have disk pressure (because transition period not yet met) if !manager.IsUnderDiskPressure() { @@ -1109,7 +1112,7 @@ func TestInodePressureNodeFsInodes(t *testing.T) { fakeClock.Step(5 * time.Minute) summaryProvider.result = summaryStatsMaker("3Mi", "4Mi", podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have disk pressure (because transition period met) if manager.IsUnderDiskPressure() { @@ -1157,7 +1160,7 @@ func TestCriticalPodsAreNotEvicted(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) diskGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{ Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: "", @@ -1203,7 +1206,7 @@ func TestCriticalPodsAreNotEvicted(t *testing.T) { // induce soft threshold fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("1500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -1218,7 +1221,7 @@ func TestCriticalPodsAreNotEvicted(t *testing.T) { // step forward in time pass the grace period fakeClock.Step(3 * time.Minute) summaryProvider.result = summaryStatsMaker("1500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -1236,7 +1239,7 @@ func TestCriticalPodsAreNotEvicted(t *testing.T) { // remove memory pressure fakeClock.Step(20 * time.Minute) summaryProvider.result = summaryStatsMaker("3Gi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure if manager.IsUnderMemoryPressure() { @@ -1249,7 +1252,7 @@ func TestCriticalPodsAreNotEvicted(t *testing.T) { // induce memory pressure! fakeClock.Step(1 * time.Minute) summaryProvider.result = summaryStatsMaker("500Mi", podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -1290,7 +1293,7 @@ func TestAllocatableMemoryPressure(t *testing.T) { fakeClock := clock.NewFakeClock(time.Now()) podKiller := &mockPodKiller{} diskInfoProvider := &mockDiskInfoProvider{dedicatedImageFs: false} - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("2Gi")}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("3Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("1Gi")}) diskGC := &mockDiskGC{imageBytesFreed: int64(0), err: nil} nodeRef := &clientv1.ObjectReference{Kind: "Node", Name: "test", UID: types.UID("test"), Namespace: ""} @@ -1326,7 +1329,7 @@ func TestAllocatableMemoryPressure(t *testing.T) { burstablePodToAdmit, _ := podMaker("burst-admit", newResourceList("100m", "100Mi"), newResourceList("200m", "200Mi"), "0Gi") // synchronize - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure if manager.IsUnderMemoryPressure() { @@ -1346,7 +1349,7 @@ func TestAllocatableMemoryPressure(t *testing.T) { pod, podStat := podMaker("guaranteed-high-2", newResourceList("100m", "1Gi"), newResourceList("100m", "1Gi"), "1Gi") podStats[pod] = podStat summaryProvider.result = summaryStatsMaker(constantCapacity, podStats) - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure if !manager.IsUnderMemoryPressure() { @@ -1382,7 +1385,7 @@ func TestAllocatableMemoryPressure(t *testing.T) { } summaryProvider.result = summaryStatsMaker(constantCapacity, podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should have memory pressure (because transition period not yet met) if !manager.IsUnderMemoryPressure() { @@ -1406,7 +1409,7 @@ func TestAllocatableMemoryPressure(t *testing.T) { fakeClock.Step(5 * time.Minute) summaryProvider.result = summaryStatsMaker(constantCapacity, podStats) podKiller.pod = nil // reset state - manager.synchronize(diskInfoProvider, activePodsFunc, nodeProvider) + manager.synchronize(diskInfoProvider, activePodsFunc, capacityProvider) // we should not have memory pressure (because transition period met) if manager.IsUnderMemoryPressure() { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers.go b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers.go index 4c9532c614..835054ed3e 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers.go @@ -658,16 +658,11 @@ func (a byEvictionPriority) Less(i, j int) bool { } // makeSignalObservations derives observations using the specified summary provider. -func makeSignalObservations(summaryProvider stats.SummaryProvider, nodeProvider NodeProvider, pods []*v1.Pod, withImageFs bool) (signalObservations, statsFunc, error) { +func makeSignalObservations(summaryProvider stats.SummaryProvider, capacityProvider CapacityProvider, pods []*v1.Pod, withImageFs bool) (signalObservations, statsFunc, error) { summary, err := summaryProvider.Get() if err != nil { return nil, nil, err } - node, err := nodeProvider.GetNode() - if err != nil { - return nil, nil, err - } - // build the function to work against for pod stats statsFunc := cachedStatsFunc(summary.Pods) // build an evaluation context for current eviction signals @@ -714,8 +709,12 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, nodeProvider } } } - if memoryAllocatableCapacity, ok := node.Status.Allocatable[v1.ResourceMemory]; ok { - memoryAllocatableAvailable := memoryAllocatableCapacity.Copy() + + nodeCapacity := capacityProvider.GetCapacity() + allocatableReservation := capacityProvider.GetNodeAllocatableReservation() + + memoryAllocatableCapacity, memoryAllocatableAvailable, exist := getResourceAllocatable(nodeCapacity, allocatableReservation, v1.ResourceMemory) + if exist { for _, pod := range summary.Pods { mu, err := podMemoryUsage(pod) if err == nil { @@ -724,12 +723,12 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, nodeProvider } result[evictionapi.SignalAllocatableMemoryAvailable] = signalObservation{ available: memoryAllocatableAvailable, - capacity: memoryAllocatableCapacity.Copy(), + capacity: memoryAllocatableCapacity, } } - if storageScratchAllocatableCapacity, ok := node.Status.Allocatable[v1.ResourceStorage]; ok { - storageScratchAllocatable := storageScratchAllocatableCapacity.Copy() + storageScratchCapacity, storageScratchAllocatable, exist := getResourceAllocatable(nodeCapacity, allocatableReservation, v1.ResourceStorageScratch) + if exist { for _, pod := range pods { podStat, ok := statsFunc(pod) if !ok { @@ -754,13 +753,25 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider, nodeProvider } result[evictionapi.SignalAllocatableNodeFsAvailable] = signalObservation{ available: storageScratchAllocatable, - capacity: storageScratchAllocatableCapacity.Copy(), + capacity: storageScratchCapacity, } } return result, statsFunc, nil } +func getResourceAllocatable(capacity v1.ResourceList, reservation v1.ResourceList, resourceName v1.ResourceName) (*resource.Quantity, *resource.Quantity, bool) { + if capacity, ok := capacity[resourceName]; ok { + allocate := capacity.Copy() + if reserved, exists := reservation[resourceName]; exists { + allocate.Sub(reserved) + } + return capacity.Copy(), allocate, true + } + glog.Errorf("Could not find capacity information for resource %v", resourceName) + return nil, nil, false +} + // thresholdsMet returns the set of thresholds that were met independent of grace period func thresholdsMet(thresholds []evictionapi.Threshold, observations signalObservations, enforceMinReclaim bool) []evictionapi.Threshold { results := []evictionapi.Threshold{} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers_test.go index fda1d010e1..a2dc238f4d 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/helpers_test.go @@ -782,12 +782,12 @@ func TestMakeSignalObservations(t *testing.T) { fakeStats.Pods = append(fakeStats.Pods, newPodStats(pod, containerWorkingSetBytes)) } res := quantityMustParse("5Gi") - nodeProvider := newMockNodeProvider(v1.ResourceList{v1.ResourceMemory: *res}) + capacityProvider := newMockCapacityProvider(v1.ResourceList{v1.ResourceMemory: *quantityMustParse("5Gi")}, v1.ResourceList{v1.ResourceMemory: *quantityMustParse("0Gi")}) // Allocatable thresholds are always 100%. Verify that Threshold == Capacity. if res.CmpInt64(int64(allocatableMemoryCapacity)) != 0 { t.Errorf("Expected Threshold %v to be equal to value %v", res.Value(), allocatableMemoryCapacity) } - actualObservations, statsFunc, err := makeSignalObservations(provider, nodeProvider, pods, false) + actualObservations, statsFunc, err := makeSignalObservations(provider, capacityProvider, pods, false) if err != nil { t.Errorf("Unexpected err: %v", err) } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/types.go b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/types.go index 8f986eb0d1..00d798c22c 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/types.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/eviction/types.go @@ -53,7 +53,7 @@ type Config struct { // Manager evaluates when an eviction threshold for node stability has been met on the node. type Manager interface { // Start starts the control loop to monitor eviction thresholds at specified interval. - Start(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, podCleanedUpFunc PodCleanedUpFunc, nodeProvider NodeProvider, monitoringInterval time.Duration) + Start(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, podCleanedUpFunc PodCleanedUpFunc, capacityProvider CapacityProvider, monitoringInterval time.Duration) // IsUnderMemoryPressure returns true if the node is under memory pressure. IsUnderMemoryPressure() bool @@ -68,10 +68,12 @@ type DiskInfoProvider interface { HasDedicatedImageFs() (bool, error) } -// NodeProvider is responsible for providing the node api object describing this node -type NodeProvider interface { - // GetNode returns the node info for this node - GetNode() (*v1.Node, error) +// CapacityProvider is responsible for providing the resource capacity and reservation information +type CapacityProvider interface { + // GetCapacity returns the amount of compute resources tracked by container manager available on the node. + GetCapacity() v1.ResourceList + // GetNodeAllocatable returns the amount of compute resources that have to be reserved from scheduling. + GetNodeAllocatableReservation() v1.ResourceList } // ImageGC is responsible for performing garbage collection of unused images. diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go index e3aaadc54b..cecca876a5 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go @@ -1301,7 +1301,7 @@ func (kl *Kubelet) initializeRuntimeDependentModules() { glog.Fatalf("Failed to start cAdvisor %v", err) } // eviction manager must start after cadvisor because it needs to know if the container runtime has a dedicated imagefs - kl.evictionManager.Start(kl.cadvisor, kl.GetActivePods, kl.podResourcesAreReclaimed, kl, evictionMonitoringPeriod) + kl.evictionManager.Start(kl.cadvisor, kl.GetActivePods, kl.podResourcesAreReclaimed, kl.containerManager, evictionMonitoringPeriod) } // Run starts the kubelet reacting to config updates diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_cadvisor.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_cadvisor.go index 779095f567..f87330cd0c 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_cadvisor.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_cadvisor.go @@ -76,6 +76,11 @@ func (kl *Kubelet) GetRawContainerInfo(containerName string, req *cadvisorapi.Co } } +// GetVersionInfo returns information about the version of cAdvisor in use. +func (kl *Kubelet) GetVersionInfo() (*cadvisorapi.VersionInfo, error) { + return kl.cadvisor.VersionInfo() +} + // GetCachedMachineInfo assumes that the machine info can't change without a reboot func (kl *Kubelet) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) { if kl.machineInfo == nil { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go index b1d286fde5..e0589f5212 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go @@ -156,7 +156,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h hostPath = filepath.Join(hostPath, mount.SubPath) - if subPathExists, err := util.FileExists(hostPath); err != nil { + if subPathExists, err := util.FileOrSymlinkExists(hostPath); err != nil { glog.Errorf("Could not determine if subPath %s exists; will not attempt to change its permissions", hostPath) } else if !subPathExists { // Create the sub path now because if it's auto-created later when referenced, it may have an diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_logs.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_logs.go index 7a4526c0b1..4f9513d4b5 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_logs.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_logs.go @@ -280,16 +280,14 @@ func parseCRILog(log []byte, msg *logMessage) error { return nil } -// dockerJSONLog is the JSON log buffer used in parseDockerJSONLog. -var dockerJSONLog = &jsonlog.JSONLog{} - // parseDockerJSONLog parses logs in Docker JSON log format. Docker JSON log format // example: // {"log":"content 1","stream":"stdout","time":"2016-10-20T18:39:20.57606443Z"} // {"log":"content 2","stream":"stderr","time":"2016-10-20T18:39:20.57606444Z"} func parseDockerJSONLog(log []byte, msg *logMessage) error { - dockerJSONLog.Reset() - l := dockerJSONLog + var l = &jsonlog.JSONLog{} + l.Reset() + // TODO: JSON decoding is fairly expensive, we should evaluate this. if err := json.Unmarshal(log, l); err != nil { return fmt.Errorf("failed with %v to unmarshal log %q", err, l) diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/BUILD b/vendor/k8s.io/kubernetes/pkg/kubelet/server/BUILD index c823ac4f80..8a44d81797 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/server/BUILD @@ -26,6 +26,7 @@ go_library( "//pkg/kubelet/server/remotecommand:go_default_library", "//pkg/kubelet/server/stats:go_default_library", "//pkg/kubelet/server/streaming:go_default_library", + "//pkg/kubelet/types:go_default_library", "//pkg/util/configz:go_default_library", "//pkg/util/limitwriter:go_default_library", "//pkg/volume:go_default_library", @@ -33,7 +34,9 @@ go_library( "//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/google/cadvisor/info/v1:go_default_library", "//vendor/github.com/google/cadvisor/info/v2:go_default_library", + "//vendor/github.com/google/cadvisor/metrics:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/server.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/server.go index a633d3fefd..0977b3e847 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/server.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/server/server.go @@ -34,7 +34,9 @@ import ( "github.com/golang/glog" cadvisorapi "github.com/google/cadvisor/info/v1" cadvisorapiv2 "github.com/google/cadvisor/info/v2" + "github.com/google/cadvisor/metrics" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -58,16 +60,18 @@ import ( remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand" "k8s.io/kubernetes/pkg/kubelet/server/stats" "k8s.io/kubernetes/pkg/kubelet/server/streaming" + kubelettypes "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/util/configz" "k8s.io/kubernetes/pkg/util/limitwriter" "k8s.io/kubernetes/pkg/volume" ) const ( - metricsPath = "/metrics" - specPath = "/spec/" - statsPath = "/stats/" - logsPath = "/logs/" + metricsPath = "/metrics" + cadvisorMetricsPath = "/metrics/cadvisor" + specPath = "/spec/" + statsPath = "/stats/" + logsPath = "/logs/" ) // Server is a http.Handler which exposes kubelet functionality over HTTP. @@ -169,6 +173,7 @@ type HostInterface interface { GetContainerInfo(podFullName string, uid types.UID, containerName string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) GetContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) GetRawContainerInfo(containerName string, req *cadvisorapi.ContainerInfoRequest, subcontainers bool) (map[string]*cadvisorapi.ContainerInfo, error) + GetVersionInfo() (*cadvisorapi.VersionInfo, error) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) GetPods() []*v1.Pod GetRunningPods() ([]*v1.Pod, error) @@ -280,6 +285,13 @@ func (s *Server) InstallDefaultHandlers() { s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer)) s.restfulCont.Handle(metricsPath, prometheus.Handler()) + // cAdvisor metrics are exposed under the secured handler as well + r := prometheus.NewRegistry() + r.MustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabels)) + s.restfulCont.Handle(cadvisorMetricsPath, + promhttp.HandlerFor(r, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}), + ) + ws = new(restful.WebService) ws. Path(specPath). @@ -780,3 +792,45 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { ).Log() s.restfulCont.ServeHTTP(w, req) } + +// prometheusHostAdapter adapts the HostInterface to the interface expected by the +// cAdvisor prometheus collector. +type prometheusHostAdapter struct { + host HostInterface +} + +func (a prometheusHostAdapter) SubcontainersInfo(containerName string, query *cadvisorapi.ContainerInfoRequest) ([]*cadvisorapi.ContainerInfo, error) { + all, err := a.host.GetRawContainerInfo(containerName, query, true) + items := make([]*cadvisorapi.ContainerInfo, 0, len(all)) + for _, v := range all { + items = append(items, v) + } + return items, err +} +func (a prometheusHostAdapter) GetVersionInfo() (*cadvisorapi.VersionInfo, error) { + return a.host.GetVersionInfo() +} +func (a prometheusHostAdapter) GetMachineInfo() (*cadvisorapi.MachineInfo, error) { + return a.host.GetCachedMachineInfo() +} + +// containerPrometheusLabels maps cAdvisor labels to prometheus labels. +func containerPrometheusLabels(c *cadvisorapi.ContainerInfo) map[string]string { + set := map[string]string{metrics.LabelID: c.Name} + if len(c.Aliases) > 0 { + set[metrics.LabelName] = c.Aliases[0] + } + if image := c.Spec.Image; len(image) > 0 { + set[metrics.LabelImage] = image + } + if v, ok := c.Spec.Labels[kubelettypes.KubernetesPodNameLabel]; ok { + set["pod_name"] = v + } + if v, ok := c.Spec.Labels[kubelettypes.KubernetesPodNamespaceLabel]; ok { + set["namespace"] = v + } + if v, ok := c.Spec.Labels[kubelettypes.KubernetesContainerNameLabel]; ok { + set["container_name"] = v + } + return set +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/server/server_test.go b/vendor/k8s.io/kubernetes/pkg/kubelet/server/server_test.go index c1a28ec503..14c4deadc2 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/server/server_test.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/server/server_test.go @@ -108,6 +108,10 @@ func (fk *fakeKubelet) GetCachedMachineInfo() (*cadvisorapi.MachineInfo, error) return fk.machineInfoFunc() } +func (_ *fakeKubelet) GetVersionInfo() (*cadvisorapi.VersionInfo, error) { + return &cadvisorapi.VersionInfo{}, nil +} + func (fk *fakeKubelet) GetPods() []*v1.Pod { return fk.podsFunc() } @@ -605,7 +609,7 @@ func TestAuthFilters(t *testing.T) { // This is a sanity check that the Handle->HandleWithFilter() delegation is working // Ideally, these would move to registered web services and this list would get shorter - expectedPaths := []string{"/healthz", "/metrics"} + expectedPaths := []string{"/healthz", "/metrics", "/metrics/cadvisor"} paths := sets.NewString(fw.serverUnderTest.restfulCont.RegisteredHandlePaths()...) for _, expectedPath := range expectedPaths { if !paths.Has(expectedPath) { diff --git a/vendor/k8s.io/kubernetes/pkg/master/thirdparty/tprregistration_controller.go b/vendor/k8s.io/kubernetes/pkg/master/thirdparty/tprregistration_controller.go index 6e0bcc3fac..432c985edc 100644 --- a/vendor/k8s.io/kubernetes/pkg/master/thirdparty/tprregistration_controller.go +++ b/vendor/k8s.io/kubernetes/pkg/master/thirdparty/tprregistration_controller.go @@ -59,6 +59,8 @@ type tprRegistrationController struct { syncHandler func(groupVersion schema.GroupVersion) error + syncedInitialSet chan struct{} + // queue is where incoming work is placed to de-dup and to allow "easy" rate limited requeues on errors // this is actually keyed by a groupVersion queue workqueue.RateLimitingInterface @@ -75,7 +77,8 @@ func NewAutoRegistrationController(tprInformer informers.ThirdPartyResourceInfor crdLister: crdinformer.Lister(), crdSynced: crdinformer.Informer().HasSynced, apiServiceRegistration: apiServiceRegistration, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "tpr-autoregister"), + syncedInitialSet: make(chan struct{}), + queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "tpr-autoregister"), } c.syncHandler = c.handleVersionUpdate @@ -145,10 +148,39 @@ func (c *tprRegistrationController) Run(threadiness int, stopCh <-chan struct{}) defer glog.Infof("Shutting down tpr-autoregister controller") // wait for your secondary caches to fill before starting your work - if !controller.WaitForCacheSync("tpr-autoregister", stopCh, c.tprSynced) { + if !controller.WaitForCacheSync("tpr-autoregister", stopCh, c.tprSynced, c.crdSynced) { return } + // process each tpr in the list once + if tprs, err := c.tprLister.List(labels.Everything()); err != nil { + utilruntime.HandleError(err) + } else { + for _, tpr := range tprs { + _, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind(tpr) + if err != nil { + utilruntime.HandleError(err) + continue + } + for _, version := range tpr.Versions { + if err := c.syncHandler(schema.GroupVersion{Group: group, Version: version.Name}); err != nil { + utilruntime.HandleError(err) + } + } + } + } + // process each item in the list once + if crds, err := c.crdLister.List(labels.Everything()); err != nil { + utilruntime.HandleError(err) + } else { + for _, crd := range crds { + if err := c.syncHandler(schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Version}); err != nil { + utilruntime.HandleError(err) + } + } + } + close(c.syncedInitialSet) + // start up your worker threads based on threadiness. Some controllers have multiple kinds of workers for i := 0; i < threadiness; i++ { // runWorker will loop until "something bad" happens. The .Until will then rekick the worker @@ -160,6 +192,11 @@ func (c *tprRegistrationController) Run(threadiness int, stopCh <-chan struct{}) <-stopCh } +// WaitForInitialSync blocks until the initial set of CRD resources has been processed +func (c *tprRegistrationController) WaitForInitialSync() { + <-c.syncedInitialSet +} + func (c *tprRegistrationController) runWorker() { // hot loop until we're told to stop. processNextWorkItem will automatically wait until there's work // available, so we don't worry about secondary waits diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go index 9eb1bf38db..9d29d7b426 100644 --- a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go +++ b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go @@ -250,6 +250,17 @@ type serviceChangeMap struct { items map[types.NamespacedName]*serviceChange } +type updateEndpointMapResult struct { + hcEndpoints map[types.NamespacedName]int + staleEndpoints map[endpointServicePair]bool + staleServiceNames map[proxy.ServicePortName]bool +} + +type updateServiceMapResult struct { + hcServices map[types.NamespacedName]uint16 + staleServices sets.String +} + type proxyServiceMap map[proxy.ServicePortName]*serviceInfo type proxyEndpointsMap map[proxy.ServicePortName][]*endpointsInfo @@ -694,29 +705,29 @@ func shouldSkipService(svcName types.NamespacedName, service *api.Service) bool // map is cleared after applying them. func updateServiceMap( serviceMap proxyServiceMap, - changes *serviceChangeMap) (hcServices map[types.NamespacedName]uint16, staleServices sets.String) { - staleServices = sets.NewString() + changes *serviceChangeMap) (result updateServiceMapResult) { + result.staleServices = sets.NewString() func() { changes.lock.Lock() defer changes.lock.Unlock() for _, change := range changes.items { existingPorts := serviceMap.merge(change.current) - serviceMap.unmerge(change.previous, existingPorts, staleServices) + serviceMap.unmerge(change.previous, existingPorts, result.staleServices) } changes.items = make(map[types.NamespacedName]*serviceChange) }() // TODO: If this will appear to be computationally expensive, consider // computing this incrementally similarly to serviceMap. - hcServices = make(map[types.NamespacedName]uint16) + result.hcServices = make(map[types.NamespacedName]uint16) for svcPortName, info := range serviceMap { if info.healthCheckNodePort != 0 { - hcServices[svcPortName.NamespacedName] = uint16(info.healthCheckNodePort) + result.hcServices[svcPortName.NamespacedName] = uint16(info.healthCheckNodePort) } } - return hcServices, staleServices + return result } func (proxier *Proxier) OnEndpointsAdd(endpoints *api.Endpoints) { @@ -755,8 +766,9 @@ func (proxier *Proxier) OnEndpointsSynced() { func updateEndpointsMap( endpointsMap proxyEndpointsMap, changes *endpointsChangeMap, - hostname string) (hcEndpoints map[types.NamespacedName]int, staleSet map[endpointServicePair]bool) { - staleSet = make(map[endpointServicePair]bool) + hostname string) (result updateEndpointMapResult) { + result.staleEndpoints = make(map[endpointServicePair]bool) + result.staleServiceNames = make(map[proxy.ServicePortName]bool) func() { changes.lock.Lock() @@ -764,7 +776,7 @@ func updateEndpointsMap( for _, change := range changes.items { endpointsMap.unmerge(change.previous) endpointsMap.merge(change.current) - detectStaleConnections(change.previous, change.current, staleSet) + detectStaleConnections(change.previous, change.current, result.staleEndpoints, result.staleServiceNames) } changes.items = make(map[types.NamespacedName]*endpointsChange) }() @@ -775,18 +787,17 @@ func updateEndpointsMap( // TODO: If this will appear to be computationally expensive, consider // computing this incrementally similarly to endpointsMap. - hcEndpoints = make(map[types.NamespacedName]int) + result.hcEndpoints = make(map[types.NamespacedName]int) localIPs := getLocalIPs(endpointsMap) for nsn, ips := range localIPs { - hcEndpoints[nsn] = len(ips) + result.hcEndpoints[nsn] = len(ips) } - return hcEndpoints, staleSet + return result } -// are modified by this function with detected stale -// connections. -func detectStaleConnections(oldEndpointsMap, newEndpointsMap proxyEndpointsMap, staleEndpoints map[endpointServicePair]bool) { +// and are modified by this function with detected stale connections. +func detectStaleConnections(oldEndpointsMap, newEndpointsMap proxyEndpointsMap, staleEndpoints map[endpointServicePair]bool, staleServiceNames map[proxy.ServicePortName]bool) { for svcPortName, epList := range oldEndpointsMap { for _, ep := range epList { stale := true @@ -802,6 +813,13 @@ func detectStaleConnections(oldEndpointsMap, newEndpointsMap proxyEndpointsMap, } } } + + for svcPortName, epList := range newEndpointsMap { + // For udp service, if its backend changes from 0 to non-0. There may exist a conntrack entry that could blackhole traffic to the service. + if len(epList) > 0 && len(oldEndpointsMap[svcPortName]) == 0 { + staleServiceNames[svcPortName] = true + } + } } func getLocalIPs(endpointsMap proxyEndpointsMap) map[types.NamespacedName]sets.String { @@ -983,11 +1001,20 @@ func (proxier *Proxier) syncProxyRules() { // We assume that if this was called, we really want to sync them, // even if nothing changed in the meantime. In other words, callers are // responsible for detecting no-op changes and not calling this function. - hcServices, staleServices := updateServiceMap( + serviceUpdateResult := updateServiceMap( proxier.serviceMap, &proxier.serviceChanges) - hcEndpoints, staleEndpoints := updateEndpointsMap( + endpointUpdateResult := updateEndpointsMap( proxier.endpointsMap, &proxier.endpointsChanges, proxier.hostname) + staleServices := serviceUpdateResult.staleServices + // merge stale services gathered from updateEndpointsMap + for svcPortName := range endpointUpdateResult.staleServiceNames { + if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.protocol == api.ProtocolUDP { + glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.clusterIP.String()) + staleServices.Insert(svcInfo.clusterIP.String()) + } + } + glog.V(3).Infof("Syncing iptables rules") // Create and link the kube services chain. @@ -1594,17 +1621,17 @@ func (proxier *Proxier) syncProxyRules() { // Update healthchecks. The endpoints list might include services that are // not "OnlyLocal", but the services list will not, and the healthChecker // will just drop those endpoints. - if err := proxier.healthChecker.SyncServices(hcServices); err != nil { + if err := proxier.healthChecker.SyncServices(serviceUpdateResult.hcServices); err != nil { glog.Errorf("Error syncing healtcheck services: %v", err) } - if err := proxier.healthChecker.SyncEndpoints(hcEndpoints); err != nil { + if err := proxier.healthChecker.SyncEndpoints(endpointUpdateResult.hcEndpoints); err != nil { glog.Errorf("Error syncing healthcheck endoints: %v", err) } // Finish housekeeping. // TODO: these and clearUDPConntrackForPort() could be made more consistent. utilproxy.DeleteServiceConnections(proxier.exec, staleServices.List()) - proxier.deleteEndpointConnections(staleEndpoints) + proxier.deleteEndpointConnections(endpointUpdateResult.staleEndpoints) } // Clear UDP conntrack for port or all conntrack entries when port equal zero. diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go index 989c244776..619b543cbb 100644 --- a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go +++ b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier_test.go @@ -1088,24 +1088,24 @@ func TestBuildServiceMapAddRemove(t *testing.T) { for i := range services { fp.OnServiceAdd(services[i]) } - hcPorts, staleUDPServices := updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result := updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 8 { t.Errorf("expected service map length 8, got %v", fp.serviceMap) } // The only-local-loadbalancer ones get added - if len(hcPorts) != 1 { - t.Errorf("expected 1 healthcheck port, got %v", hcPorts) + if len(result.hcServices) != 1 { + t.Errorf("expected 1 healthcheck port, got %v", result.hcServices) } else { nsn := makeNSN("somewhere", "only-local-load-balancer") - if port, found := hcPorts[nsn]; !found || port != 345 { - t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, hcPorts) + if port, found := result.hcServices[nsn]; !found || port != 345 { + t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, result.hcServices) } } - if len(staleUDPServices) != 0 { + if len(result.staleServices) != 0 { // Services only added, so nothing stale yet - t.Errorf("expected stale UDP services length 0, got %d", len(staleUDPServices)) + t.Errorf("expected stale UDP services length 0, got %d", len(result.staleServices)) } // Remove some stuff @@ -1121,24 +1121,24 @@ func TestBuildServiceMapAddRemove(t *testing.T) { fp.OnServiceDelete(services[2]) fp.OnServiceDelete(services[3]) - hcPorts, staleUDPServices = updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result = updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 1 { t.Errorf("expected service map length 1, got %v", fp.serviceMap) } - if len(hcPorts) != 0 { - t.Errorf("expected 0 healthcheck ports, got %v", hcPorts) + if len(result.hcServices) != 0 { + t.Errorf("expected 0 healthcheck ports, got %v", result.hcServices) } // All services but one were deleted. While you'd expect only the ClusterIPs // from the three deleted services here, we still have the ClusterIP for // the not-deleted service, because one of it's ServicePorts was deleted. expectedStaleUDPServices := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"} - if len(staleUDPServices) != len(expectedStaleUDPServices) { - t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), staleUDPServices.List()) + if len(result.staleServices) != len(expectedStaleUDPServices) { + t.Errorf("expected stale UDP services length %d, got %v", len(expectedStaleUDPServices), result.staleServices.List()) } for _, ip := range expectedStaleUDPServices { - if !staleUDPServices.Has(ip) { + if !result.staleServices.Has(ip) { t.Errorf("expected stale UDP service service %s", ip) } } @@ -1157,18 +1157,18 @@ func TestBuildServiceMapServiceHeadless(t *testing.T) { ) // Headless service should be ignored - hcPorts, staleUDPServices := updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result := updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 0 { t.Errorf("expected service map length 0, got %d", len(fp.serviceMap)) } // No proxied services, so no healthchecks - if len(hcPorts) != 0 { - t.Errorf("expected healthcheck ports length 0, got %d", len(hcPorts)) + if len(result.hcServices) != 0 { + t.Errorf("expected healthcheck ports length 0, got %d", len(result.hcServices)) } - if len(staleUDPServices) != 0 { - t.Errorf("expected stale UDP services length 0, got %d", len(staleUDPServices)) + if len(result.staleServices) != 0 { + t.Errorf("expected stale UDP services length 0, got %d", len(result.staleServices)) } } @@ -1185,16 +1185,16 @@ func TestBuildServiceMapServiceTypeExternalName(t *testing.T) { }), ) - hcPorts, staleUDPServices := updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result := updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 0 { t.Errorf("expected service map length 0, got %v", fp.serviceMap) } // No proxied services, so no healthchecks - if len(hcPorts) != 0 { - t.Errorf("expected healthcheck ports length 0, got %v", hcPorts) + if len(result.hcServices) != 0 { + t.Errorf("expected healthcheck ports length 0, got %v", result.hcServices) } - if len(staleUDPServices) != 0 { - t.Errorf("expected stale UDP services length 0, got %v", staleUDPServices) + if len(result.staleServices) != 0 { + t.Errorf("expected stale UDP services length 0, got %v", result.staleServices) } } @@ -1227,57 +1227,57 @@ func TestBuildServiceMapServiceUpdate(t *testing.T) { fp.OnServiceAdd(servicev1) - hcPorts, staleUDPServices := updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result := updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 2 { t.Errorf("expected service map length 2, got %v", fp.serviceMap) } - if len(hcPorts) != 0 { - t.Errorf("expected healthcheck ports length 0, got %v", hcPorts) + if len(result.hcServices) != 0 { + t.Errorf("expected healthcheck ports length 0, got %v", result.hcServices) } - if len(staleUDPServices) != 0 { + if len(result.staleServices) != 0 { // Services only added, so nothing stale yet - t.Errorf("expected stale UDP services length 0, got %d", len(staleUDPServices)) + t.Errorf("expected stale UDP services length 0, got %d", len(result.staleServices)) } // Change service to load-balancer fp.OnServiceUpdate(servicev1, servicev2) - hcPorts, staleUDPServices = updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result = updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 2 { t.Errorf("expected service map length 2, got %v", fp.serviceMap) } - if len(hcPorts) != 1 { - t.Errorf("expected healthcheck ports length 1, got %v", hcPorts) + if len(result.hcServices) != 1 { + t.Errorf("expected healthcheck ports length 1, got %v", result.hcServices) } - if len(staleUDPServices) != 0 { - t.Errorf("expected stale UDP services length 0, got %v", staleUDPServices.List()) + if len(result.staleServices) != 0 { + t.Errorf("expected stale UDP services length 0, got %v", result.staleServices.List()) } // No change; make sure the service map stays the same and there are // no health-check changes fp.OnServiceUpdate(servicev2, servicev2) - hcPorts, staleUDPServices = updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result = updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 2 { t.Errorf("expected service map length 2, got %v", fp.serviceMap) } - if len(hcPorts) != 1 { - t.Errorf("expected healthcheck ports length 1, got %v", hcPorts) + if len(result.hcServices) != 1 { + t.Errorf("expected healthcheck ports length 1, got %v", result.hcServices) } - if len(staleUDPServices) != 0 { - t.Errorf("expected stale UDP services length 0, got %v", staleUDPServices.List()) + if len(result.staleServices) != 0 { + t.Errorf("expected stale UDP services length 0, got %v", result.staleServices.List()) } // And back to ClusterIP fp.OnServiceUpdate(servicev2, servicev1) - hcPorts, staleUDPServices = updateServiceMap(fp.serviceMap, &fp.serviceChanges) + result = updateServiceMap(fp.serviceMap, &fp.serviceChanges) if len(fp.serviceMap) != 2 { t.Errorf("expected service map length 2, got %v", fp.serviceMap) } - if len(hcPorts) != 0 { - t.Errorf("expected healthcheck ports length 0, got %v", hcPorts) + if len(result.hcServices) != 0 { + t.Errorf("expected healthcheck ports length 0, got %v", result.hcServices) } - if len(staleUDPServices) != 0 { + if len(result.staleServices) != 0 { // Services only added, so nothing stale yet - t.Errorf("expected stale UDP services length 0, got %d", len(staleUDPServices)) + t.Errorf("expected stale UDP services length 0, got %d", len(result.staleServices)) } } @@ -1606,6 +1606,9 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap, expected map[proxy.Serv func Test_updateEndpointsMap(t *testing.T) { var nodeName = testHostname + emptyEndpoint := func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{} + } unnamedPort := func(ept *api.Endpoints) { ept.Subsets = []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{ @@ -1910,18 +1913,20 @@ func Test_updateEndpointsMap(t *testing.T) { // previousEndpoints and currentEndpoints are used to call appropriate // handlers OnEndpoints* (based on whether corresponding values are nil // or non-nil) and must be of equal length. - previousEndpoints []*api.Endpoints - currentEndpoints []*api.Endpoints - oldEndpoints map[proxy.ServicePortName][]*endpointsInfo - expectedResult map[proxy.ServicePortName][]*endpointsInfo - expectedStale []endpointServicePair - expectedHealthchecks map[types.NamespacedName]int + previousEndpoints []*api.Endpoints + currentEndpoints []*api.Endpoints + oldEndpoints map[proxy.ServicePortName][]*endpointsInfo + expectedResult map[proxy.ServicePortName][]*endpointsInfo + expectedStaleEndpoints []endpointServicePair + expectedStaleServiceNames map[proxy.ServicePortName]bool + expectedHealthchecks map[types.NamespacedName]int }{{ // Case[0]: nothing - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedStale: []endpointServicePair{}, - expectedHealthchecks: map[types.NamespacedName]int{}, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[1]: no change, unnamed port previousEndpoints: []*api.Endpoints{ @@ -1940,8 +1945,9 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: false}, }, }, - expectedStale: []endpointServicePair{}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[2]: no change, named port, local previousEndpoints: []*api.Endpoints{ @@ -1960,7 +1966,8 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: true}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 1, }, @@ -1988,8 +1995,9 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.2:12", isLocal: false}, }, }, - expectedStale: []endpointServicePair{}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[4]: no change, multiple subsets, multiple ports, local previousEndpoints: []*api.Endpoints{ @@ -2020,7 +2028,8 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.3:13", isLocal: false}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 1, }, @@ -2086,7 +2095,8 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "2.2.2.2:22", isLocal: true}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 2, makeNSN("ns2", "ep2"): 1, @@ -2105,7 +2115,10 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: true}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", ""): true, + }, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 1, }, @@ -2123,11 +2136,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "1.1.1.1:11", servicePortName: makeServicePortName("ns1", "ep1", ""), }}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[8]: add an IP and port previousEndpoints: []*api.Endpoints{ @@ -2151,7 +2165,10 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.2:12", isLocal: true}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", "p12"): true, + }, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 1, }, @@ -2178,7 +2195,7 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: false}, }, }, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "1.1.1.2:11", servicePortName: makeServicePortName("ns1", "ep1", "p11"), }, { @@ -2188,7 +2205,8 @@ func Test_updateEndpointsMap(t *testing.T) { endpoint: "1.1.1.2:12", servicePortName: makeServicePortName("ns1", "ep1", "p12"), }}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[10]: add a subset previousEndpoints: []*api.Endpoints{ @@ -2210,7 +2228,10 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.2:12", isLocal: true}, }, }, - expectedStale: []endpointServicePair{}, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", "p12"): true, + }, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns1", "ep1"): 1, }, @@ -2235,11 +2256,12 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: false}, }, }, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "1.1.1.2:12", servicePortName: makeServicePortName("ns1", "ep1", "p12"), }}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[12]: rename a port previousEndpoints: []*api.Endpoints{ @@ -2258,10 +2280,13 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:11", isLocal: false}, }, }, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "1.1.1.1:11", servicePortName: makeServicePortName("ns1", "ep1", "p11"), }}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", "p11-2"): true, + }, expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[13]: renumber a port @@ -2281,11 +2306,12 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "1.1.1.1:22", isLocal: false}, }, }, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "1.1.1.1:11", servicePortName: makeServicePortName("ns1", "ep1", "p11"), }}, - expectedHealthchecks: map[types.NamespacedName]int{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, + expectedHealthchecks: map[types.NamespacedName]int{}, }, { // Case[14]: complex add and remove previousEndpoints: []*api.Endpoints{ @@ -2337,7 +2363,7 @@ func Test_updateEndpointsMap(t *testing.T) { {endpoint: "4.4.4.4:44", isLocal: true}, }, }, - expectedStale: []endpointServicePair{{ + expectedStaleEndpoints: []endpointServicePair{{ endpoint: "2.2.2.2:22", servicePortName: makeServicePortName("ns2", "ep2", "p22"), }, { @@ -2353,10 +2379,35 @@ func Test_updateEndpointsMap(t *testing.T) { endpoint: "4.4.4.6:45", servicePortName: makeServicePortName("ns4", "ep4", "p45"), }}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", "p12"): true, + makeServicePortName("ns1", "ep1", "p122"): true, + makeServicePortName("ns3", "ep3", "p33"): true, + }, expectedHealthchecks: map[types.NamespacedName]int{ makeNSN("ns4", "ep4"): 1, }, - }} + }, { + // Case[15]: change from 0 endpoint address to 1 unnamed port + previousEndpoints: []*api.Endpoints{ + makeTestEndpoints("ns1", "ep1", emptyEndpoint), + }, + currentEndpoints: []*api.Endpoints{ + makeTestEndpoints("ns1", "ep1", unnamedPort), + }, + oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + makeServicePortName("ns1", "ep1", ""): { + {endpoint: "1.1.1.1:11", isLocal: false}, + }, + }, + expectedStaleEndpoints: []endpointServicePair{}, + expectedStaleServiceNames: map[proxy.ServicePortName]bool{ + makeServicePortName("ns1", "ep1", ""): true, + }, + expectedHealthchecks: map[types.NamespacedName]int{}, + }, + } for tci, tc := range testCases { ipt := iptablestest.NewFake() @@ -2390,19 +2441,27 @@ func Test_updateEndpointsMap(t *testing.T) { fp.OnEndpointsUpdate(prev, curr) } } - hcEndpoints, stale := updateEndpointsMap(fp.endpointsMap, &fp.endpointsChanges, fp.hostname) + result := updateEndpointsMap(fp.endpointsMap, &fp.endpointsChanges, fp.hostname) newMap := fp.endpointsMap compareEndpointsMaps(t, tci, newMap, tc.expectedResult) - if len(stale) != len(tc.expectedStale) { - t.Errorf("[%d] expected %d stale, got %d: %v", tci, len(tc.expectedStale), len(stale), stale) + if len(result.staleEndpoints) != len(tc.expectedStaleEndpoints) { + t.Errorf("[%d] expected %d staleEndpoints, got %d: %v", tci, len(tc.expectedStaleEndpoints), len(result.staleEndpoints), result.staleEndpoints) + } + for _, x := range tc.expectedStaleEndpoints { + if result.staleEndpoints[x] != true { + t.Errorf("[%d] expected staleEndpoints[%v], but didn't find it: %v", tci, x, result.staleEndpoints) + } + } + if len(result.staleServiceNames) != len(tc.expectedStaleServiceNames) { + t.Errorf("[%d] expected %d staleServiceNames, got %d: %v", tci, len(tc.expectedStaleServiceNames), len(result.staleServiceNames), result.staleServiceNames) } - for _, x := range tc.expectedStale { - if stale[x] != true { - t.Errorf("[%d] expected stale[%v], but didn't find it: %v", tci, x, stale) + for svcName := range tc.expectedStaleServiceNames { + if result.staleServiceNames[svcName] != true { + t.Errorf("[%d] expected staleServiceNames[%v], but didn't find it: %v", tci, svcName, result.staleServiceNames) } } - if !reflect.DeepEqual(hcEndpoints, tc.expectedHealthchecks) { - t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedHealthchecks, hcEndpoints) + if !reflect.DeepEqual(result.hcEndpoints, tc.expectedHealthchecks) { + t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedHealthchecks, result.hcEndpoints) } } } diff --git a/vendor/k8s.io/kubernetes/pkg/quota/evaluator/core/pods.go b/vendor/k8s.io/kubernetes/pkg/quota/evaluator/core/pods.go index 85ca0279be..c9ea8aff2e 100644 --- a/vendor/k8s.io/kubernetes/pkg/quota/evaluator/core/pods.go +++ b/vendor/k8s.io/kubernetes/pkg/quota/evaluator/core/pods.go @@ -194,18 +194,22 @@ func podUsageHelper(requests api.ResourceList, limits api.ResourceList) api.Reso } func toInternalPodOrError(obj runtime.Object) (*api.Pod, error) { - pod := &api.Pod{} switch t := obj.(type) { case *v1.Pod: - if err := v1.Convert_v1_Pod_To_api_Pod(t, pod, nil); err != nil { + converted, err := api.Scheme.ConvertToVersion(obj, api.SchemeGroupVersion) + if err != nil { return nil, err } + if pod, ok := converted.(*api.Pod); ok { + return pod, nil + } else { + return nil, fmt.Errorf("expect *api.Pod, got %v", converted) + } case *api.Pod: - pod = t + return t, nil default: return nil, fmt.Errorf("expect *api.Pod or *v1.Pod, got %v", t) } - return pod, nil } // podMatchesScopeFunc is a function that knows how to evaluate if a pod matches a scope diff --git a/vendor/k8s.io/kubernetes/pkg/registry/core/node/rest/proxy.go b/vendor/k8s.io/kubernetes/pkg/registry/core/node/rest/proxy.go index adea1b4b1b..627ec716cc 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/core/node/rest/proxy.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/core/node/rest/proxy.go @@ -70,7 +70,7 @@ func (r *ProxyREST) Connect(ctx genericapirequest.Context, id string, opts runti if err != nil { return nil, err } - location.Path = path.Join(location.Path, proxyOpts.Path) + location.Path = path.Join("/", location.Path, proxyOpts.Path) // Return a proxy handler that uses the desired transport, wrapped with additional proxy handling (to get URL rewriting, X-Forwarded-* headers, etc) return newThrottledUpgradeAwareProxyHandler(location, transport, true, false, responder), nil } diff --git a/vendor/k8s.io/kubernetes/pkg/registry/core/pod/rest/subresources.go b/vendor/k8s.io/kubernetes/pkg/registry/core/pod/rest/subresources.go index e7fae10cd7..3b54089a46 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/core/pod/rest/subresources.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/core/pod/rest/subresources.go @@ -69,7 +69,7 @@ func (r *ProxyREST) Connect(ctx genericapirequest.Context, id string, opts runti if err != nil { return nil, err } - location.Path = path.Join(location.Path, proxyOpts.Path) + location.Path = path.Join("/", location.Path, proxyOpts.Path) // Return a proxy handler that uses the desired transport, wrapped with additional proxy handling (to get URL rewriting, X-Forwarded-* headers, etc) return newThrottledUpgradeAwareProxyHandler(location, transport, true, false, false, responder), nil } diff --git a/vendor/k8s.io/kubernetes/pkg/registry/core/service/proxy.go b/vendor/k8s.io/kubernetes/pkg/registry/core/service/proxy.go index 7f5f503a39..e4fc0d4e4d 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/core/service/proxy.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/core/service/proxy.go @@ -66,7 +66,7 @@ func (r *ProxyREST) Connect(ctx genericapirequest.Context, id string, opts runti if err != nil { return nil, err } - location.Path = path.Join(location.Path, proxyOpts.Path) + location.Path = path.Join("/", location.Path, proxyOpts.Path) // Return a proxy handler that uses the desired transport, wrapped with additional proxy handling (to get URL rewriting, X-Forwarded-* headers, etc) return newThrottledUpgradeAwareProxyHandler(location, transport, true, false, responder), nil } diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/BUILD b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/BUILD index 36a5cc05d9..7ffc2828e0 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/BUILD @@ -37,6 +37,7 @@ go_library( deps = [ "//pkg/api:go_default_library", "//pkg/apis/rbac:go_default_library", + "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library", "//pkg/registry/rbac/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/role_interfaces.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/role_interfaces.go index b3bc3c882b..9cabec6231 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/role_interfaces.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/role_interfaces.go @@ -17,8 +17,11 @@ limitations under the License. package reconciliation import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/rbac" + core "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" ) @@ -59,7 +62,8 @@ func (o RoleRuleOwner) SetRules(in []rbac.PolicyRule) { } type RoleModifier struct { - Client internalversion.RolesGetter + Client internalversion.RolesGetter + NamespaceClient core.NamespaceInterface } func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) { @@ -71,6 +75,11 @@ func (c RoleModifier) Get(namespace, name string) (RuleOwner, error) { } func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) { + ns := &api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}} + if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) { + return nil, err + } + ret, err := c.Client.Roles(in.GetNamespace()).Create(in.(RoleRuleOwner).Role) if err != nil { return nil, err diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go index 6ec14ab2db..fde4b1e67b 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/reconciliation/rolebinding_interfaces.go @@ -17,9 +17,12 @@ limitations under the License. package reconciliation import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/rbac" + core "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" ) @@ -68,7 +71,8 @@ func (o RoleBindingAdapter) SetSubjects(in []rbac.Subject) { } type RoleBindingClientAdapter struct { - Client internalversion.RoleBindingsGetter + Client internalversion.RoleBindingsGetter + NamespaceClient core.NamespaceInterface } func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) { @@ -80,6 +84,11 @@ func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, erro } func (c RoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) { + ns := &api.Namespace{ObjectMeta: metav1.ObjectMeta{Name: in.GetNamespace()}} + if _, err := c.NamespaceClient.Create(ns); err != nil && !apierrors.IsAlreadyExists(err) { + return nil, err + } + ret, err := c.Client.RoleBindings(in.GetNamespace()).Create(in.(RoleBindingAdapter).RoleBinding) if err != nil { return nil, err diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/BUILD b/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/BUILD index 226bb9c27f..109d016052 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/BUILD @@ -16,6 +16,7 @@ go_library( "//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library", "//pkg/apis/rbac/v1beta1:go_default_library", + "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library", "//pkg/client/retry:go_default_library", "//pkg/registry/rbac/clusterrole:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/storage_rbac.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/storage_rbac.go index 34df168d87..199c1b2f50 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/storage_rbac.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/rest/storage_rbac.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/apis/rbac" rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" rbacapiv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" + coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" "k8s.io/kubernetes/pkg/client/retry" "k8s.io/kubernetes/pkg/registry/rbac/clusterrole" @@ -134,6 +135,13 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { // intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server // starts, the roles don't initialize, and nothing works. err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { + + coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig) + if err != nil { + utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) + return false, nil + } + clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig) if err != nil { utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) @@ -212,7 +220,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { for _, role := range roles { opts := reconciliation.ReconcileRoleOptions{ Role: reconciliation.RoleRuleOwner{Role: &role}, - Client: reconciliation.RoleModifier{Client: clientset}, + Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, Confirm: true, } err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { @@ -242,7 +250,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { for _, roleBinding := range roleBindings { opts := reconciliation.ReconcileRoleBindingOptions{ RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding}, - Client: reconciliation.RoleBindingClientAdapter{Client: clientset}, + Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, Confirm: true, } err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/fake.go b/vendor/k8s.io/kubernetes/pkg/util/mount/fake.go index 972bff26a1..2b71fa0a72 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/fake.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/fake.go @@ -124,6 +124,14 @@ func (f *FakeMounter) List() ([]MountPoint, error) { return f.MountPoints, nil } +func (f *FakeMounter) IsMountPointMatch(mp MountPoint, dir string) bool { + return (mp.Path == dir) +} + +func (f *FakeMounter) IsNotMountPoint(dir string) (bool, error) { + return IsNotMountPoint(f, dir) +} + func (f *FakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { f.mutex.Lock() defer f.mutex.Unlock() diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/mount.go b/vendor/k8s.io/kubernetes/pkg/util/mount/mount.go index 44058042d5..0c458d64b4 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/mount.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/mount.go @@ -44,8 +44,21 @@ type Interface interface { // it could change between chunked reads). This is guaranteed to be // consistent. List() ([]MountPoint, error) - // IsLikelyNotMountPoint determines if a directory is a mountpoint. + // IsMountPointMatch determines if the mountpoint matches the dir + IsMountPointMatch(mp MountPoint, dir string) bool + // IsNotMountPoint determines if a directory is a mountpoint. // It should return ErrNotExist when the directory does not exist. + // IsNotMountPoint is more expensive than IsLikelyNotMountPoint. + // IsNotMountPoint detects bind mounts in linux. + // IsNotMountPoint enumerates all the mountpoints using List() and + // the list of mountpoints may be large, then it uses + // IsMountPointMatch to evaluate whether the directory is a mountpoint + IsNotMountPoint(file string) (bool, error) + // IsLikelyNotMountPoint uses heuristics to determine if a directory + // is a mountpoint. + // It should return ErrNotExist when the directory does not exist. + // IsLikelyNotMountPoint does NOT properly detect all mountpoint types + // most notably linux bind mounts. IsLikelyNotMountPoint(file string) (bool, error) // DeviceOpened determines if the device is in use elsewhere // on the system, i.e. still mounted. @@ -199,3 +212,34 @@ func getDeviceNameFromMount(mounter Interface, mountPath, pluginDir string) (str return path.Base(mountPath), nil } + +// IsNotMountPoint determines if a directory is a mountpoint. +// It should return ErrNotExist when the directory does not exist. +// This method uses the List() of all mountpoints +// It is more extensive than IsLikelyNotMountPoint +// and it detects bind mounts in linux +func IsNotMountPoint(mounter Interface, file string) (bool, error) { + // IsLikelyNotMountPoint provides a quick check + // to determine whether file IS A mountpoint + notMnt, notMntErr := mounter.IsLikelyNotMountPoint(file) + if notMntErr != nil { + return notMnt, notMntErr + } + // identified as mountpoint, so return this fact + if notMnt == false { + return notMnt, nil + } + // check all mountpoints since IsLikelyNotMountPoint + // is not reliable for some mountpoint types + mountPoints, mountPointsErr := mounter.List() + if mountPointsErr != nil { + return notMnt, mountPointsErr + } + for _, mp := range mountPoints { + if mounter.IsMountPointMatch(mp, file) { + notMnt = false + break + } + } + return notMnt, nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go b/vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go index 1685ecb48f..4c141ad5b0 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/mount_linux.go @@ -161,6 +161,15 @@ func (*Mounter) List() ([]MountPoint, error) { return listProcMounts(procMountsPath) } +func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { + deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) + return ((mp.Path == dir) || (mp.Path == deletedDir)) +} + +func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { + return IsNotMountPoint(mounter, dir) +} + // IsLikelyNotMountPoint determines if a directory is not a mountpoint. // It is fast but not necessarily ALWAYS correct. If the path is in fact // a bind mount from one part of a mount to another it will not be detected. @@ -168,10 +177,6 @@ func (*Mounter) List() ([]MountPoint, error) { // will return true. When in fact /tmp/b is a mount point. If this situation // if of interest to you, don't use this function... func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { - return IsNotMountPoint(file) -} - -func IsNotMountPoint(file string) (bool, error) { stat, err := os.Stat(file) if err != nil { return true, err diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go b/vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go index f9abab813d..632ad0606e 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/mount_unsupported.go @@ -34,6 +34,14 @@ func (mounter *Mounter) List() ([]MountPoint, error) { return []MountPoint{}, nil } +func (mounter *Mounter) IsMountPointMatch(mp MountPoint, dir string) bool { + return (mp.Path == dir) +} + +func (mounter *Mounter) IsNotMountPoint(dir string) (bool, error) { + return IsNotMountPoint(mounter, dir) +} + func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { return true, nil } @@ -57,7 +65,3 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) { return true, nil } - -func IsNotMountPoint(file string) (bool, error) { - return true, nil -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go b/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go index f3a4afc1b0..4af8ef0d82 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount.go @@ -19,6 +19,7 @@ limitations under the License. package mount import ( + "fmt" "os" "path/filepath" "strings" @@ -162,6 +163,15 @@ func (*NsenterMounter) List() ([]MountPoint, error) { return listProcMounts(hostProcMountsPath) } +func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) { + return IsNotMountPoint(m, dir) +} + +func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool { + deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) + return ((mp.Path == dir) || (mp.Path == deletedDir)) +} + // IsLikelyNotMountPoint determines whether a path is a mountpoint by calling findmnt // in the host's root mount namespace. func (n *NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) { diff --git a/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go b/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go index dcf19edefd..e955e1b781 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go +++ b/vendor/k8s.io/kubernetes/pkg/util/mount/nsenter_mount_unsupported.go @@ -38,6 +38,14 @@ func (*NsenterMounter) List() ([]MountPoint, error) { return []MountPoint{}, nil } +func (m *NsenterMounter) IsNotMountPoint(dir string) (bool, error) { + return IsNotMountPoint(m, dir) +} + +func (*NsenterMounter) IsMountPointMatch(mp MountPoint, dir string) bool { + return (mp.Path == dir) +} + func (*NsenterMounter) IsLikelyNotMountPoint(file string) (bool, error) { return true, nil } diff --git a/vendor/k8s.io/kubernetes/pkg/util/removeall/removeall_test.go b/vendor/k8s.io/kubernetes/pkg/util/removeall/removeall_test.go index 938ef08e35..a5b19fe41a 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/removeall/removeall_test.go +++ b/vendor/k8s.io/kubernetes/pkg/util/removeall/removeall_test.go @@ -49,6 +49,12 @@ func (mounter *fakeMounter) PathIsDevice(pathname string) (bool, error) { func (mounter *fakeMounter) GetDeviceNameFromMount(mountPath, pluginDir string) (string, error) { return "", errors.New("not implemented") } +func (mounter *fakeMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool { + return (mp.Path == dir) +} +func (mounter *fakeMounter) IsNotMountPoint(dir string) (bool, error) { + return mount.IsNotMountPoint(mounter, dir) +} func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { name := path.Base(file) if strings.HasPrefix(name, "mount") { diff --git a/vendor/k8s.io/kubernetes/pkg/util/util.go b/vendor/k8s.io/kubernetes/pkg/util/util.go index 356b295a3e..389e145e84 100644 --- a/vendor/k8s.io/kubernetes/pkg/util/util.go +++ b/vendor/k8s.io/kubernetes/pkg/util/util.go @@ -84,6 +84,15 @@ func FileExists(filename string) (bool, error) { return true, nil } +func FileOrSymlinkExists(filename string) (bool, error) { + if _, err := os.Lstat(filename); os.IsNotExist(err) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + // ReadDirNoStat returns a string of files/directories contained // in dirname without calling lstat on them. func ReadDirNoStat(dirname string) ([]string, error) { diff --git a/vendor/k8s.io/kubernetes/pkg/version/base.go b/vendor/k8s.io/kubernetes/pkg/version/base.go index 0762697303..311b63d01c 100644 --- a/vendor/k8s.io/kubernetes/pkg/version/base.go +++ b/vendor/k8s.io/kubernetes/pkg/version/base.go @@ -39,8 +39,8 @@ var ( // them irrelevant. (Next we'll take it out, which may muck with // scripts consuming the kubectl version output - but most of // these should be looking at gitVersion already anyways.) - gitMajor string = "1" // major version, always numeric - gitMinor string = "7+" // minor version, numeric possibly followed by "+" + gitMajor string = "1" // major version, always numeric + gitMinor string = "7" // minor version, numeric possibly followed by "+" // semantic version, derived by build scripts (see // https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md @@ -51,7 +51,7 @@ var ( // semantic version is a git hash, but the version itself is no // longer the direct output of "git describe", but a slight // translation to be semver compliant. - gitVersion string = "v1.7.1-beta.0+$Format:%h$" + gitVersion string = "v1.7.6+$Format:%h$" gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD) gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty" diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/BUILD b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/BUILD index acc86be976..6f95f7748b 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/BUILD @@ -12,12 +12,14 @@ go_library( name = "go_default_library", srcs = [ "attacher.go", + "azure_common.go", "azure_dd.go", + "azure_mounter.go", "azure_provision.go", - "vhd_util.go", ], tags = ["automanaged"], deps = [ + "//pkg/api:go_default_library", "//pkg/api/v1:go_default_library", "//pkg/cloudprovider:go_default_library", "//pkg/cloudprovider/providers/azure:go_default_library", @@ -27,45 +29,43 @@ go_library( "//pkg/util/strings:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/volumehelper:go_default_library", "//vendor/github.com/Azure/azure-sdk-for-go/arm/compute:go_default_library", + "//vendor/github.com/Azure/azure-sdk-for-go/arm/storage:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", ], ) +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) + go_test( name = "go_default_test", srcs = [ + "azure_common_test.go", "azure_dd_test.go", - "vhd_util_test.go", ], library = ":go_default_library", tags = ["automanaged"], deps = [ "//pkg/api/v1:go_default_library", "//pkg/util/exec:go_default_library", - "//pkg/util/mount:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", - "//vendor/github.com/Azure/azure-sdk-for-go/arm/compute:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/client-go/util/testing:go_default_library", ], ) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go index 92cb203c46..89eb195b4a 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go @@ -28,52 +28,41 @@ import ( "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/cloudprovider" + "k8s.io/kubernetes/pkg/cloudprovider/providers/azure" "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/keymutex" "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" - "k8s.io/kubernetes/pkg/volume/util" + volumeutil "k8s.io/kubernetes/pkg/volume/util" ) +type azureDiskDetacher struct { + plugin *azureDataDiskPlugin + cloud *azure.Cloud +} + type azureDiskAttacher struct { - host volume.VolumeHost - azureProvider azureCloudProvider + plugin *azureDataDiskPlugin + cloud *azure.Cloud } var _ volume.Attacher = &azureDiskAttacher{} - -var _ volume.AttachableVolumePlugin = &azureDataDiskPlugin{} - -const ( - checkSleepDuration = time.Second -) +var _ volume.Detacher = &azureDiskDetacher{} // acquire lock to get an lun number var getLunMutex = keymutex.NewKeyMutex() -// NewAttacher initializes an Attacher -func (plugin *azureDataDiskPlugin) NewAttacher() (volume.Attacher, error) { - azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) - if err != nil { - glog.V(4).Infof("failed to get azure provider") - return nil, err - } - - return &azureDiskAttacher{ - host: plugin.host, - azureProvider: azure, - }, nil -} - // Attach attaches a volume.Spec to an Azure VM referenced by NodeName, returning the disk's LUN -func (attacher *azureDiskAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { +func (a *azureDiskAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string, error) { volumeSource, err := getVolumeSource(spec) if err != nil { glog.Warningf("failed to get azure disk spec") return "", err } - instanceid, err := attacher.azureProvider.InstanceID(nodeName) + + instanceid, err := a.cloud.InstanceID(nodeName) if err != nil { glog.Warningf("failed to get azure instance id") return "", fmt.Errorf("failed to get azure instance id for node %q", nodeName) @@ -82,7 +71,12 @@ func (attacher *azureDiskAttacher) Attach(spec *volume.Spec, nodeName types.Node instanceid = instanceid[(ind + 1):] } - lun, err := attacher.azureProvider.GetDiskLun(volumeSource.DiskName, volumeSource.DataDiskURI, nodeName) + diskController, err := getDiskController(a.plugin.host) + if err != nil { + return "", err + } + + lun, err := diskController.GetDiskLun(volumeSource.DiskName, volumeSource.DataDiskURI, nodeName) if err == cloudprovider.InstanceNotFound { // Log error and continue with attach glog.Warningf( @@ -98,13 +92,14 @@ func (attacher *azureDiskAttacher) Attach(spec *volume.Spec, nodeName types.Node getLunMutex.LockKey(instanceid) defer getLunMutex.UnlockKey(instanceid) - lun, err = attacher.azureProvider.GetNextDiskLun(nodeName) + lun, err = diskController.GetNextDiskLun(nodeName) if err != nil { glog.Warningf("no LUN available for instance %q", nodeName) return "", fmt.Errorf("all LUNs are used, cannot attach volume %q to instance %q", volumeSource.DiskName, instanceid) } glog.V(4).Infof("Trying to attach volume %q lun %d to node %q.", volumeSource.DataDiskURI, lun, nodeName) - err = attacher.azureProvider.AttachDisk(volumeSource.DiskName, volumeSource.DataDiskURI, nodeName, lun, compute.CachingTypes(*volumeSource.CachingMode)) + isManagedDisk := (*volumeSource.Kind == v1.AzureManagedDisk) + err = diskController.AttachDisk(isManagedDisk, volumeSource.DiskName, volumeSource.DataDiskURI, nodeName, lun, compute.CachingTypes(*volumeSource.CachingMode)) if err == nil { glog.V(4).Infof("Attach operation successful: volume %q attached to node %q.", volumeSource.DataDiskURI, nodeName) } else { @@ -116,14 +111,14 @@ func (attacher *azureDiskAttacher) Attach(spec *volume.Spec, nodeName types.Node return strconv.Itoa(int(lun)), err } -func (attacher *azureDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { +func (a *azureDiskAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { volumesAttachedCheck := make(map[*volume.Spec]bool) volumeSpecMap := make(map[string]*volume.Spec) volumeIDList := []string{} for _, spec := range specs { volumeSource, err := getVolumeSource(spec) if err != nil { - glog.Errorf("Error getting volume (%q) source : %v", spec.Name(), err) + glog.Errorf("azureDisk - Error getting volume (%q) source : %v", spec.Name(), err) continue } @@ -131,11 +126,16 @@ func (attacher *azureDiskAttacher) VolumesAreAttached(specs []*volume.Spec, node volumesAttachedCheck[spec] = true volumeSpecMap[volumeSource.DiskName] = spec } - attachedResult, err := attacher.azureProvider.DisksAreAttached(volumeIDList, nodeName) + + diskController, err := getDiskController(a.plugin.host) + if err != nil { + return nil, err + } + attachedResult, err := diskController.DisksAreAttached(volumeIDList, nodeName) if err != nil { // Log error and continue with attach glog.Errorf( - "Error checking if volumes (%v) are attached to current node (%q). err=%v", + "azureDisk - Error checking if volumes (%v) are attached to current node (%q). err=%v", volumeIDList, nodeName, err) return volumesAttachedCheck, err } @@ -144,71 +144,84 @@ func (attacher *azureDiskAttacher) VolumesAreAttached(specs []*volume.Spec, node if !attached { spec := volumeSpecMap[volumeID] volumesAttachedCheck[spec] = false - glog.V(2).Infof("VolumesAreAttached: check volume %q (specName: %q) is no longer attached", volumeID, spec.Name()) + glog.V(2).Infof("azureDisk - VolumesAreAttached: check volume %q (specName: %q) is no longer attached", volumeID, spec.Name()) } } return volumesAttachedCheck, nil } -// WaitForAttach runs on the node to detect if the volume (referenced by LUN) is attached. If attached, the device path is returned -func (attacher *azureDiskAttacher) WaitForAttach(spec *volume.Spec, lunStr string, timeout time.Duration) (string, error) { +func (a *azureDiskAttacher) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) { + var err error + lun, err := strconv.Atoi(devicePath) + if err != nil { + return "", fmt.Errorf("azureDisk - Wait for attach expect device path as a lun number, instead got: %s", devicePath) + } + volumeSource, err := getVolumeSource(spec) if err != nil { return "", err } - if len(lunStr) == 0 { - return "", fmt.Errorf("WaitForAttach failed for Azure disk %q: lun is empty.", volumeSource.DiskName) - } + io := &osIOHandler{} + scsiHostRescan(io) - lun, err := strconv.Atoi(lunStr) - if err != nil { - return "", fmt.Errorf("WaitForAttach: wrong lun %q, err: %v", lunStr, err) - } - scsiHostRescan(&osIOHandler{}) - exe := exec.New() - devicePath := "" - - err = wait.Poll(checkSleepDuration, timeout, func() (bool, error) { - glog.V(4).Infof("Checking Azure disk %q(lun %s) is attached.", volumeSource.DiskName, lunStr) - if devicePath, err = findDiskByLun(lun, &osIOHandler{}, exe); err == nil { - if len(devicePath) == 0 { - glog.Warningf("cannot find attached Azure disk %q(lun %s) locally.", volumeSource.DiskName, lunStr) - return false, fmt.Errorf("cannot find attached Azure disk %q(lun %s) locally.", volumeSource.DiskName, lunStr) - } - glog.V(4).Infof("Successfully found attached Azure disk %q(lun %s, device path %s).", volumeSource.DiskName, lunStr, devicePath) + diskName := volumeSource.DiskName + nodeName := a.plugin.host.GetHostName() + newDevicePath := "" + + err = wait.Poll(1*time.Second, timeout, func() (bool, error) { + exe := exec.New() + + if newDevicePath, err = findDiskByLun(lun, io, exe); err != nil { + return false, fmt.Errorf("azureDisk - WaitForAttach ticker failed node (%s) disk (%s) lun(%v) err(%s)", nodeName, diskName, lun, err) + } + + // did we find it? + if newDevicePath != "" { + // the curent sequence k8s uses for unformated disk (check-disk, mount, fail, mkfs.extX) hangs on + // Azure Managed disk scsi interface. this is a hack and will be replaced once we identify and solve + // the root case on Azure. + formatIfNotFormatted(newDevicePath, *volumeSource.FSType) return true, nil - } else { - //Log error, if any, and continue checking periodically - glog.V(4).Infof("Error Stat Azure disk (%q) is attached: %v", volumeSource.DiskName, err) - return false, nil } + + return false, fmt.Errorf("azureDisk - WaitForAttach failed within timeout node (%s) diskId:(%s) lun:(%v)", nodeName, diskName, lun) }) - return devicePath, err + + return newDevicePath, err } -// GetDeviceMountPath finds the volume's mount path on the node -func (attacher *azureDiskAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) { +// to avoid name conflicts (similar *.vhd name) +// we use hash diskUri and we use it as device mount target. +// this is generalized for both managed and blob disks +// we also prefix the hash with m/b based on disk kind +func (a *azureDiskAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) { volumeSource, err := getVolumeSource(spec) if err != nil { return "", err } - return makeGlobalPDPath(attacher.host, volumeSource.DiskName), nil + if volumeSource.Kind == nil { // this spec was constructed from info on the node + pdPath := path.Join(a.plugin.host.GetPluginDir(azureDataDiskPluginName), mount.MountsInGlobalPDPath, volumeSource.DataDiskURI) + return pdPath, nil + } + + isManagedDisk := (*volumeSource.Kind == v1.AzureManagedDisk) + return makeGlobalPDPath(a.plugin.host, volumeSource.DataDiskURI, isManagedDisk) } -// MountDevice runs mount command on the node to mount the volume func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { - mounter := attacher.host.GetMounter() + mounter := attacher.plugin.host.GetMounter() notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) + if err != nil { if os.IsNotExist(err) { if err := os.MkdirAll(deviceMountPath, 0750); err != nil { - return err + return fmt.Errorf("azureDisk - mountDevice:CreateDirectory failed with %s", err) } notMnt = true } else { - return err + return fmt.Errorf("azureDisk - mountDevice:IsLikelyNotMountPoint failed with %s", err) } } @@ -218,47 +231,27 @@ func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath str } options := []string{} - if spec.ReadOnly { - options = append(options, "ro") - } if notMnt { diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Runner: exec.New()} mountOptions := volume.MountOptionFromSpec(spec, options...) err = diskMounter.FormatAndMount(devicePath, deviceMountPath, *volumeSource.FSType, mountOptions) if err != nil { - os.Remove(deviceMountPath) - return err + if cleanErr := os.Remove(deviceMountPath); cleanErr != nil { + return fmt.Errorf("azureDisk - mountDevice:FormatAndMount failed with %s and clean up failed with :%v", err, cleanErr) + } + return fmt.Errorf("azureDisk - mountDevice:FormatAndMount failed with %s", err) } } return nil } -type azureDiskDetacher struct { - mounter mount.Interface - azureProvider azureCloudProvider -} - -var _ volume.Detacher = &azureDiskDetacher{} - -// NewDetacher initializes a volume Detacher -func (plugin *azureDataDiskPlugin) NewDetacher() (volume.Detacher, error) { - azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) - if err != nil { - return nil, err - } - - return &azureDiskDetacher{ - mounter: plugin.host.GetMounter(), - azureProvider: azure, - }, nil -} - // Detach detaches disk from Azure VM. -func (detacher *azureDiskDetacher) Detach(diskName string, nodeName types.NodeName) error { - if diskName == "" { - return fmt.Errorf("invalid disk to detach: %q", diskName) +func (d *azureDiskDetacher) Detach(diskURI string, nodeName types.NodeName) error { + if diskURI == "" { + return fmt.Errorf("invalid disk to detach: %q", diskURI) } - instanceid, err := detacher.azureProvider.InstanceID(nodeName) + + instanceid, err := d.cloud.InstanceID(nodeName) if err != nil { glog.Warningf("no instance id for node %q, skip detaching", nodeName) return nil @@ -267,22 +260,28 @@ func (detacher *azureDiskDetacher) Detach(diskName string, nodeName types.NodeNa instanceid = instanceid[(ind + 1):] } - glog.V(4).Infof("detach %v from node %q", diskName, nodeName) - err = detacher.azureProvider.DetachDiskByName(diskName, "" /* diskURI */, nodeName) + glog.V(4).Infof("detach %v from node %q", diskURI, nodeName) + + diskController, err := getDiskController(d.plugin.host) if err != nil { - glog.Errorf("failed to detach azure disk %q, err %v", diskName, err) + return err + } + err = diskController.DetachDiskByName("", diskURI, nodeName) + if err != nil { + glog.Errorf("failed to detach azure disk %q, err %v", diskURI, err) } + glog.V(2).Infof("azureDisk - disk:%s was detached from node:%v", diskURI, nodeName) return err } // UnmountDevice unmounts the volume on the node func (detacher *azureDiskDetacher) UnmountDevice(deviceMountPath string) error { - volume := path.Base(deviceMountPath) - if err := util.UnmountPath(deviceMountPath, detacher.mounter); err != nil { - glog.Errorf("Error unmounting %q: %v", volume, err) - return err + err := volumeutil.UnmountPath(deviceMountPath, detacher.plugin.host.GetMounter()) + if err == nil { + glog.V(4).Infof("azureDisk - Device %s was unmounted", deviceMountPath) } else { - return nil + glog.Infof("azureDisk - Device %s failed to unmount with error: %s", deviceMountPath, err.Error()) } + return err } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common.go new file mode 100644 index 0000000000..485284d704 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common.go @@ -0,0 +1,342 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure_dd + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "regexp" + "strconv" + libstrings "strings" + + storage "github.com/Azure/azure-sdk-for-go/arm/storage" + "github.com/golang/glog" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/cloudprovider/providers/azure" + "k8s.io/kubernetes/pkg/util/exec" + "k8s.io/kubernetes/pkg/util/mount" + "k8s.io/kubernetes/pkg/util/strings" + "k8s.io/kubernetes/pkg/volume" +) + +const ( + defaultFSType = "ext4" + defaultStorageAccountType = storage.StandardLRS +) + +type dataDisk struct { + volume.MetricsProvider + volumeName string + diskName string + podUID types.UID +} + +var ( + supportedCachingModes = sets.NewString( + string(api.AzureDataDiskCachingNone), + string(api.AzureDataDiskCachingReadOnly), + string(api.AzureDataDiskCachingReadWrite)) + + supportedDiskKinds = sets.NewString( + string(api.AzureSharedBlobDisk), + string(api.AzureDedicatedBlobDisk), + string(api.AzureManagedDisk)) + + supportedStorageAccountTypes = sets.NewString("Premium_LRS", "Standard_LRS") +) + +func getPath(uid types.UID, volName string, host volume.VolumeHost) string { + return host.GetPodVolumeDir(uid, strings.EscapeQualifiedNameForDisk(azureDataDiskPluginName), volName) +} + +// creates a unique path for disks (even if they share the same *.vhd name) +func makeGlobalPDPath(host volume.VolumeHost, diskUri string, isManaged bool) (string, error) { + diskUri = libstrings.ToLower(diskUri) // always lower uri because users may enter it in caps. + uniqueDiskNameTemplate := "%s%s" + hashedDiskUri := azure.MakeCRC32(diskUri) + prefix := "b" + if isManaged { + prefix = "m" + } + // "{m for managed b for blob}{hashed diskUri or DiskId depending on disk kind }" + diskName := fmt.Sprintf(uniqueDiskNameTemplate, prefix, hashedDiskUri) + pdPath := path.Join(host.GetPluginDir(azureDataDiskPluginName), mount.MountsInGlobalPDPath, diskName) + + return pdPath, nil +} + +func makeDataDisk(volumeName string, podUID types.UID, diskName string, host volume.VolumeHost) *dataDisk { + var metricProvider volume.MetricsProvider + if podUID != "" { + metricProvider = volume.NewMetricsStatFS(getPath(podUID, volumeName, host)) + } + + return &dataDisk{ + MetricsProvider: metricProvider, + volumeName: volumeName, + diskName: diskName, + podUID: podUID, + } +} + +func getVolumeSource(spec *volume.Spec) (*v1.AzureDiskVolumeSource, error) { + if spec.Volume != nil && spec.Volume.AzureDisk != nil { + return spec.Volume.AzureDisk, nil + } + + if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureDisk != nil { + return spec.PersistentVolume.Spec.AzureDisk, nil + } + + return nil, fmt.Errorf("azureDisk - Spec does not reference an Azure disk volume type") +} + +func normalizeFsType(fsType string) string { + if fsType == "" { + return defaultFSType + } + + return fsType +} + +func normalizeKind(kind string) (v1.AzureDataDiskKind, error) { + if kind == "" { + return v1.AzureDedicatedBlobDisk, nil + } + + if !supportedDiskKinds.Has(kind) { + return "", fmt.Errorf("azureDisk - %s is not supported disk kind. Supported values are %s", kind, supportedDiskKinds.List()) + } + + return v1.AzureDataDiskKind(kind), nil +} + +func normalizeStorageAccountType(storageAccountType string) (storage.SkuName, error) { + if storageAccountType == "" { + return defaultStorageAccountType, nil + } + + if !supportedStorageAccountTypes.Has(storageAccountType) { + return "", fmt.Errorf("azureDisk - %s is not supported sku/storageaccounttype. Supported values are %s", storageAccountType, supportedStorageAccountTypes.List()) + } + + return storage.SkuName(storageAccountType), nil +} + +func normalizeCachingMode(cachingMode v1.AzureDataDiskCachingMode) (v1.AzureDataDiskCachingMode, error) { + if cachingMode == "" { + return v1.AzureDataDiskCachingReadWrite, nil + } + + if !supportedCachingModes.Has(string(cachingMode)) { + return "", fmt.Errorf("azureDisk - %s is not supported cachingmode. Supported values are %s", cachingMode, supportedCachingModes.List()) + } + + return cachingMode, nil +} + +type ioHandler interface { + ReadDir(dirname string) ([]os.FileInfo, error) + WriteFile(filename string, data []byte, perm os.FileMode) error + Readlink(name string) (string, error) +} + +//TODO: check if priming the iscsi interface is actually needed + +type osIOHandler struct{} + +func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) { + return ioutil.ReadDir(dirname) +} + +func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error { + return ioutil.WriteFile(filename, data, perm) +} + +func (handler *osIOHandler) Readlink(name string) (string, error) { + return os.Readlink(name) +} + +// exclude those used by azure as resource and OS root in /dev/disk/azure +func listAzureDiskPath(io ioHandler) []string { + azureDiskPath := "/dev/disk/azure/" + var azureDiskList []string + if dirs, err := io.ReadDir(azureDiskPath); err == nil { + for _, f := range dirs { + name := f.Name() + diskPath := azureDiskPath + name + if link, linkErr := io.Readlink(diskPath); linkErr == nil { + sd := link[(libstrings.LastIndex(link, "/") + 1):] + azureDiskList = append(azureDiskList, sd) + } + } + } + glog.V(12).Infof("Azure sys disks paths: %v", azureDiskList) + return azureDiskList +} + +func scsiHostRescan(io ioHandler) { + scsi_path := "/sys/class/scsi_host/" + if dirs, err := io.ReadDir(scsi_path); err == nil { + for _, f := range dirs { + name := scsi_path + f.Name() + "/scan" + data := []byte("- - -") + if err = io.WriteFile(name, data, 0666); err != nil { + glog.Warningf("failed to rescan scsi host %s", name) + } + } + } else { + glog.Warningf("failed to read %s, err %v", scsi_path, err) + } +} + +func findDiskByLun(lun int, io ioHandler, exe exec.Interface) (string, error) { + azureDisks := listAzureDiskPath(io) + return findDiskByLunWithConstraint(lun, io, exe, azureDisks) +} + +// finds a device mounted to "current" node +func findDiskByLunWithConstraint(lun int, io ioHandler, exe exec.Interface, azureDisks []string) (string, error) { + var err error + sys_path := "/sys/bus/scsi/devices" + if dirs, err := io.ReadDir(sys_path); err == nil { + for _, f := range dirs { + name := f.Name() + // look for path like /sys/bus/scsi/devices/3:0:0:1 + arr := libstrings.Split(name, ":") + if len(arr) < 4 { + continue + } + // extract LUN from the path. + // LUN is the last index of the array, i.e. 1 in /sys/bus/scsi/devices/3:0:0:1 + l, err := strconv.Atoi(arr[3]) + if err != nil { + // unknown path format, continue to read the next one + glog.V(4).Infof("azure disk - failed to parse lun from %v (%v), err %v", arr[3], name, err) + continue + } + if lun == l { + // find the matching LUN + // read vendor and model to ensure it is a VHD disk + vendor := path.Join(sys_path, name, "vendor") + model := path.Join(sys_path, name, "model") + out, err := exe.Command("cat", vendor, model).CombinedOutput() + if err != nil { + glog.V(4).Infof("azure disk - failed to cat device vendor and model, err: %v", err) + continue + } + matched, err := regexp.MatchString("^MSFT[ ]{0,}\nVIRTUAL DISK[ ]{0,}\n$", libstrings.ToUpper(string(out))) + if err != nil || !matched { + glog.V(4).Infof("azure disk - doesn't match VHD, output %v, error %v", string(out), err) + continue + } + // find a disk, validate name + dir := path.Join(sys_path, name, "block") + if dev, err := io.ReadDir(dir); err == nil { + found := false + for _, diskName := range azureDisks { + glog.V(12).Infof("azure disk - validating disk %q with sys disk %q", dev[0].Name(), diskName) + if string(dev[0].Name()) == diskName { + found = true + break + } + } + if !found { + return "/dev/" + dev[0].Name(), nil + } + } + } + } + } + return "", err +} + +func formatIfNotFormatted(disk string, fstype string) { + notFormatted, err := diskLooksUnformatted(disk) + if err == nil && notFormatted { + args := []string{disk} + // Disk is unformatted so format it. + // Use 'ext4' as the default + if len(fstype) == 0 { + fstype = "ext4" + } + if fstype == "ext4" || fstype == "ext3" { + args = []string{"-E", "lazy_itable_init=0,lazy_journal_init=0", "-F", disk} + } + glog.Infof("azureDisk - Disk %q appears to be unformatted, attempting to format as type: %q with options: %v", disk, fstype, args) + runner := exec.New() + cmd := runner.Command("mkfs."+fstype, args...) + _, err := cmd.CombinedOutput() + if err == nil { + // the disk has been formatted successfully try to mount it again. + glog.Infof("azureDisk - Disk successfully formatted (mkfs): %s - %s %s", fstype, disk, "tt") + } + glog.Warningf("azureDisk - format of disk %q failed: type:(%q) target:(%q) options:(%q)error:(%v)", disk, fstype, "tt", "o", err) + } else { + if err != nil { + glog.Warningf("azureDisk - Failed to check if the disk %s formatted with error %s, will attach anyway", disk, err) + } else { + glog.Infof("azureDisk - Disk %s already formatted, will not format", disk) + } + } +} + +func diskLooksUnformatted(disk string) (bool, error) { + args := []string{"-nd", "-o", "FSTYPE", disk} + runner := exec.New() + cmd := runner.Command("lsblk", args...) + glog.V(4).Infof("Attempting to determine if disk %q is formatted using lsblk with args: (%v)", disk, args) + dataOut, err := cmd.CombinedOutput() + if err != nil { + glog.Errorf("Could not determine if disk %q is formatted (%v)", disk, err) + return false, err + } + output := libstrings.TrimSpace(string(dataOut)) + return output == "", nil +} + +func getDiskController(host volume.VolumeHost) (DiskController, error) { + cloudProvider := host.GetCloudProvider() + az, ok := cloudProvider.(*azure.Cloud) + + if !ok || az == nil { + return nil, fmt.Errorf("AzureDisk - failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider) + } + return az, nil +} + +func getCloud(host volume.VolumeHost) (*azure.Cloud, error) { + cloudProvider := host.GetCloudProvider() + az, ok := cloudProvider.(*azure.Cloud) + + if !ok || az == nil { + return nil, fmt.Errorf("AzureDisk - failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider) + } + return az, nil +} + +func strFirstLetterToUpper(str string) string { + if len(str) < 2 { + return str + } + return libstrings.ToUpper(string(str[0])) + str[1:] +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util_test.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common_test.go similarity index 98% rename from vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util_test.go rename to vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common_test.go index 93c7672177..b0f4988a9e 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_common_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +Copyright 2017 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd.go index edffe4fd75..343439f19d 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd.go @@ -17,67 +17,63 @@ limitations under the License. package azure_dd import ( - "fmt" - "os" - "path" - "github.com/Azure/azure-sdk-for-go/arm/compute" - + storage "github.com/Azure/azure-sdk-for-go/arm/storage" "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/api/v1" - "k8s.io/kubernetes/pkg/cloudprovider" - "k8s.io/kubernetes/pkg/cloudprovider/providers/azure" - "k8s.io/kubernetes/pkg/util/exec" - "k8s.io/kubernetes/pkg/util/keymutex" "k8s.io/kubernetes/pkg/util/mount" - utilstrings "k8s.io/kubernetes/pkg/util/strings" "k8s.io/kubernetes/pkg/volume" - "k8s.io/kubernetes/pkg/volume/util" ) -// This is the primary entrypoint for volume plugins. -func ProbeVolumePlugins() []volume.VolumePlugin { - return []volume.VolumePlugin{&azureDataDiskPlugin{}} -} +// interface exposed by the cloud provider implementing Disk functionlity +type DiskController interface { + CreateBlobDisk(dataDiskName string, storageAccountType storage.SkuName, sizeGB int, forceStandAlone bool) (string, error) + DeleteBlobDisk(diskUri string, wasForced bool) error -type azureDataDiskPlugin struct { - host volume.VolumeHost - volumeLocks keymutex.KeyMutex -} + CreateManagedDisk(diskName string, storageAccountType storage.SkuName, sizeGB int, tags map[string]string) (string, error) + DeleteManagedDisk(diskURI string) error -// Abstract interface to disk operations. -// azure cloud provider should implement it -type azureCloudProvider interface { // Attaches the disk to the host machine. - AttachDisk(diskName, diskUri string, nodeName types.NodeName, lun int32, cachingMode compute.CachingTypes) error + AttachDisk(isManagedDisk bool, diskName, diskUri string, nodeName types.NodeName, lun int32, cachingMode compute.CachingTypes) error // Detaches the disk, identified by disk name or uri, from the host machine. DetachDiskByName(diskName, diskUri string, nodeName types.NodeName) error + // Check if a list of volumes are attached to the node with the specified NodeName DisksAreAttached(diskNames []string, nodeName types.NodeName) (map[string]bool, error) + // Get the LUN number of the disk that is attached to the host GetDiskLun(diskName, diskUri string, nodeName types.NodeName) (int32, error) // Get the next available LUN number to attach a new VHD GetNextDiskLun(nodeName types.NodeName) (int32, error) - // InstanceID returns the cloud provider ID of the specified instance. - InstanceID(nodeName types.NodeName) (string, error) + // Create a VHD blob - CreateVolume(name, storageAccount, storageType, location string, requestGB int) (string, string, int, error) + CreateVolume(name, storageAccount string, storageAccountType storage.SkuName, location string, requestGB int) (string, string, int, error) // Delete a VHD blob - DeleteVolume(name, uri string) error + DeleteVolume(diskURI string) error +} + +type azureDataDiskPlugin struct { + host volume.VolumeHost } var _ volume.VolumePlugin = &azureDataDiskPlugin{} var _ volume.PersistentVolumePlugin = &azureDataDiskPlugin{} +var _ volume.DeletableVolumePlugin = &azureDataDiskPlugin{} +var _ volume.ProvisionableVolumePlugin = &azureDataDiskPlugin{} +var _ volume.AttachableVolumePlugin = &azureDataDiskPlugin{} const ( azureDataDiskPluginName = "kubernetes.io/azure-disk" ) +func ProbeVolumePlugins() []volume.VolumePlugin { + return []volume.VolumePlugin{&azureDataDiskPlugin{}} +} + func (plugin *azureDataDiskPlugin) Init(host volume.VolumeHost) error { plugin.host = host - plugin.volumeLocks = keymutex.NewKeyMutex() return nil } @@ -91,7 +87,7 @@ func (plugin *azureDataDiskPlugin) GetVolumeName(spec *volume.Spec) (string, err return "", err } - return volumeSource.DiskName, nil + return volumeSource.DataDiskURI, nil } func (plugin *azureDataDiskPlugin) CanSupport(spec *volume.Spec) bool { @@ -117,281 +113,104 @@ func (plugin *azureDataDiskPlugin) GetAccessModes() []v1.PersistentVolumeAccessM } } -func (plugin *azureDataDiskPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) { - return plugin.newMounterInternal(spec, pod.UID, plugin.host.GetMounter()) -} - -func (plugin *azureDataDiskPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, mounter mount.Interface) (volume.Mounter, error) { - // azures used directly in a pod have a ReadOnly flag set by the pod author. - // azures used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV - azure, err := getVolumeSource(spec) +// NewAttacher initializes an Attacher +func (plugin *azureDataDiskPlugin) NewAttacher() (volume.Attacher, error) { + azure, err := getCloud(plugin.host) if err != nil { + glog.V(4).Infof("failed to get azure cloud in NewAttacher, plugin.host : %s", plugin.host.GetHostName()) return nil, err } - fsType := "ext4" - if azure.FSType != nil { - fsType = *azure.FSType - } - cachingMode := v1.AzureDataDiskCachingNone - if azure.CachingMode != nil { - cachingMode = *azure.CachingMode - } - readOnly := false - if azure.ReadOnly != nil { - readOnly = *azure.ReadOnly - } - diskName := azure.DiskName - diskUri := azure.DataDiskURI - return &azureDiskMounter{ - azureDisk: &azureDisk{ - podUID: podUID, - volName: spec.Name(), - diskName: diskName, - diskUri: diskUri, - cachingMode: cachingMode, - mounter: mounter, - plugin: plugin, - }, - fsType: fsType, - readOnly: readOnly, - diskMounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(), Runner: exec.New()}}, nil -} -func (plugin *azureDataDiskPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { - return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter()) -} - -func (plugin *azureDataDiskPlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) { - return &azureDiskUnmounter{ - &azureDisk{ - podUID: podUID, - volName: volName, - mounter: mounter, - plugin: plugin, - }, + return &azureDiskAttacher{ + plugin: plugin, + cloud: azure, }, nil } -func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) { - mounter := plugin.host.GetMounter() - pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName()) - sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginDir) +func (plugin *azureDataDiskPlugin) NewDetacher() (volume.Detacher, error) { + azure, err := getCloud(plugin.host) if err != nil { + glog.V(4).Infof("failed to get azure cloud in NewDetacher, plugin.host : %s", plugin.host.GetHostName()) return nil, err } - azVolume := &v1.Volume{ - Name: volName, - VolumeSource: v1.VolumeSource{ - AzureDisk: &v1.AzureDiskVolumeSource{ - DiskName: sourceName, - }, - }, - } - return volume.NewSpecFromVolume(azVolume), nil -} - -func (plugin *azureDataDiskPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { - mounter := plugin.host.GetMounter() - return mount.GetMountRefs(mounter, deviceMountPath) -} - -type azureDisk struct { - volName string - podUID types.UID - diskName string - diskUri string - cachingMode v1.AzureDataDiskCachingMode - mounter mount.Interface - plugin *azureDataDiskPlugin - volume.MetricsNil -} -type azureDiskMounter struct { - *azureDisk - // Filesystem type, optional. - fsType string - // Specifies whether the disk will be attached as read-only. - readOnly bool - // diskMounter provides the interface that is used to mount the actual block device. - diskMounter *mount.SafeFormatAndMount + return &azureDiskDetacher{ + plugin: plugin, + cloud: azure, + }, nil } -var _ volume.Mounter = &azureDiskMounter{} - -func (b *azureDiskMounter) GetAttributes() volume.Attributes { - return volume.Attributes{ - ReadOnly: b.readOnly, - Managed: !b.readOnly, - SupportsSELinux: true, +func (plugin *azureDataDiskPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) { + volumeSource, err := getVolumeSource(spec) + if err != nil { + return nil, err } -} -// Checks prior to mount operations to verify that the required components (binaries, etc.) -// to mount the volume are available on the underlying node. -// If not, it returns an error -func (b *azureDiskMounter) CanMount() error { - return nil -} + disk := makeDataDisk(spec.Name(), "", volumeSource.DiskName, plugin.host) -// SetUp attaches the disk and bind mounts to the volume path. -func (b *azureDiskMounter) SetUp(fsGroup *int64) error { - return b.SetUpAt(b.GetPath(), fsGroup) + return &azureDiskDeleter{ + spec: spec, + plugin: plugin, + dataDisk: disk, + }, nil } -// SetUpAt attaches the disk and bind mounts to the volume path. -func (b *azureDiskMounter) SetUpAt(dir string, fsGroup *int64) error { - b.plugin.volumeLocks.LockKey(b.diskName) - defer b.plugin.volumeLocks.UnlockKey(b.diskName) - - // TODO: handle failed mounts here. - notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) - glog.V(4).Infof("DataDisk set up: %s %v %v", dir, !notMnt, err) - if err != nil && !os.IsNotExist(err) { - glog.Errorf("IsLikelyNotMountPoint failed: %v", err) - return err +func (plugin *azureDataDiskPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { + if len(options.PVC.Spec.AccessModes) == 0 { + options.PVC.Spec.AccessModes = plugin.GetAccessModes() } - if !notMnt { - glog.V(4).Infof("%s is a mount point", dir) - return nil - } - - globalPDPath := makeGlobalPDPath(b.plugin.host, b.diskName) - if err := os.MkdirAll(dir, 0750); err != nil { - glog.V(4).Infof("Could not create directory %s: %v", dir, err) - return err - } + return &azureDiskProvisioner{ + plugin: plugin, + options: options, + }, nil +} - // Perform a bind mount to the full path to allow duplicate mounts of the same PD. - options := []string{"bind"} - if b.readOnly { - options = append(options, "ro") - } - err = b.mounter.Mount(globalPDPath, dir, "", options) +func (plugin *azureDataDiskPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, options volume.VolumeOptions) (volume.Mounter, error) { + volumeSource, err := getVolumeSource(spec) if err != nil { - notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if !notMnt { - if mntErr = b.mounter.Unmount(dir); mntErr != nil { - glog.Errorf("Failed to unmount: %v", mntErr) - return err - } - notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if !notMnt { - // This is very odd, we don't expect it. We'll try again next sync loop. - glog.Errorf("%s is still mounted, despite call to unmount(). Will try again next sync loop.", dir) - return err - } - } - os.Remove(dir) - return err - } - - if !b.readOnly { - volume.SetVolumeOwnership(b, fsGroup) + return nil, err } - glog.V(3).Infof("Azure disk volume %s mounted to %s", b.diskName, dir) - return nil -} - -func makeGlobalPDPath(host volume.VolumeHost, volume string) string { - return path.Join(host.GetPluginDir(azureDataDiskPluginName), mount.MountsInGlobalPDPath, volume) -} - -func (azure *azureDisk) GetPath() string { - name := azureDataDiskPluginName - return azure.plugin.host.GetPodVolumeDir(azure.podUID, utilstrings.EscapeQualifiedNameForDisk(name), azure.volName) -} + disk := makeDataDisk(spec.Name(), pod.UID, volumeSource.DiskName, plugin.host) -type azureDiskUnmounter struct { - *azureDisk + return &azureDiskMounter{ + plugin: plugin, + spec: spec, + options: options, + dataDisk: disk, + }, nil } -var _ volume.Unmounter = &azureDiskUnmounter{} +func (plugin *azureDataDiskPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) { + disk := makeDataDisk(volName, podUID, "", plugin.host) -// Unmounts the bind mount, and detaches the disk only if the PD -// resource was the last reference to that disk on the kubelet. -func (c *azureDiskUnmounter) TearDown() error { - return c.TearDownAt(c.GetPath()) + return &azureDiskUnmounter{ + plugin: plugin, + dataDisk: disk, + }, nil } -// Unmounts the bind mount, and detaches the disk only if the PD -// resource was the last reference to that disk on the kubelet. -func (c *azureDiskUnmounter) TearDownAt(dir string) error { - if pathExists, pathErr := util.PathExists(dir); pathErr != nil { - return fmt.Errorf("Error checking if path exists: %v", pathErr) - } else if !pathExists { - glog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir) - return nil - } +func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { + mounter := plugin.host.GetMounter() + pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName()) + sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginDir) - notMnt, err := c.mounter.IsLikelyNotMountPoint(dir) - if err != nil { - glog.Errorf("Error checking if mountpoint %s: %v", dir, err) - return err - } - if notMnt { - glog.V(2).Info("Not mountpoint, deleting") - return os.Remove(dir) - } - // lock the volume (and thus wait for any concurrrent SetUpAt to finish) - c.plugin.volumeLocks.LockKey(c.diskName) - defer c.plugin.volumeLocks.UnlockKey(c.diskName) - refs, err := mount.GetMountRefs(c.mounter, dir) if err != nil { - glog.Errorf("Error getting mountrefs for %s: %v", dir, err) - return err - } - if len(refs) == 0 { - glog.Errorf("Did not find pod-mount for %s during tear down", dir) - return fmt.Errorf("%s is not mounted", dir) - } - c.diskName = path.Base(refs[0]) - glog.V(4).Infof("Found volume %s mounted to %s", c.diskName, dir) - - // Unmount the bind-mount inside this pod - if err := c.mounter.Unmount(dir); err != nil { - glog.Errorf("Error unmounting dir %s %v", dir, err) - return err - } - notMnt, mntErr := c.mounter.IsLikelyNotMountPoint(dir) - if mntErr != nil { - glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) - return err - } - if notMnt { - if err := os.Remove(dir); err != nil { - glog.Errorf("Error removing mountpoint %s %v", dir, err) - return err - } + return nil, err } - return nil -} -func getVolumeSource(spec *volume.Spec) (*v1.AzureDiskVolumeSource, error) { - if spec.Volume != nil && spec.Volume.AzureDisk != nil { - return spec.Volume.AzureDisk, nil - } - if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureDisk != nil { - return spec.PersistentVolume.Spec.AzureDisk, nil + azureVolume := &v1.Volume{ + Name: volumeName, + VolumeSource: v1.VolumeSource{ + AzureDisk: &v1.AzureDiskVolumeSource{ + DataDiskURI: sourceName, + }, + }, } - - return nil, fmt.Errorf("Spec does not reference an Azure disk volume type") + return volume.NewSpecFromVolume(azureVolume), nil } -// Return cloud provider -func getAzureCloudProvider(cloudProvider cloudprovider.Interface) (azureCloudProvider, error) { - azureCloudProvider, ok := cloudProvider.(*azure.Cloud) - if !ok || azureCloudProvider == nil { - return nil, fmt.Errorf("Failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider) - } - - return azureCloudProvider, nil +func (plugin *azureDataDiskPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { + m := plugin.host.GetMounter() + return mount.GetMountRefs(m, deviceMountPath) } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd_test.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd_test.go index db885c40f3..e3454d524f 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_dd_test.go @@ -17,17 +17,11 @@ limitations under the License. package azure_dd import ( - "fmt" "os" - "path" "testing" - "github.com/Azure/azure-sdk-for-go/arm/compute" - - "k8s.io/apimachinery/pkg/types" utiltesting "k8s.io/client-go/util/testing" "k8s.io/kubernetes/pkg/api/v1" - "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) @@ -57,121 +51,5 @@ func TestCanSupport(t *testing.T) { } } -const ( - fakeDiskName = "foo" - fakeDiskUri = "https://azure/vhds/bar.vhd" - fakeLun = 2 -) - -type fakeAzureProvider struct { -} - -func (fake *fakeAzureProvider) AttachDisk(diskName, diskUri, vmName string, lun int32, cachingMode compute.CachingTypes) error { - if diskName != fakeDiskName || diskUri != fakeDiskUri || lun != fakeLun { - return fmt.Errorf("wrong disk") - } - return nil - -} - -func (fake *fakeAzureProvider) DetachDiskByName(diskName, diskUri, vmName string) error { - if diskName != fakeDiskName || diskUri != fakeDiskUri { - return fmt.Errorf("wrong disk") - } - return nil -} -func (fake *fakeAzureProvider) GetDiskLun(diskName, diskUri, vmName string) (int32, error) { - return int32(fakeLun), nil -} - -func (fake *fakeAzureProvider) GetNextDiskLun(vmName string) (int32, error) { - return fakeLun, nil -} -func (fake *fakeAzureProvider) InstanceID(name string) (string, error) { - return "localhost", nil -} - -func (fake *fakeAzureProvider) CreateVolume(name, storageAccount, storageType, location string, requestGB int) (string, string, int, error) { - return "", "", 0, fmt.Errorf("not implemented") -} - -func (fake *fakeAzureProvider) DeleteVolume(name, uri string) error { - return fmt.Errorf("not implemented") -} - -func TestPlugin(t *testing.T) { - tmpDir, err := utiltesting.MkTmpdir("azure_ddTest") - if err != nil { - t.Fatalf("can't make a temp dir: %v", err) - } - defer os.RemoveAll(tmpDir) - plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil)) - - plug, err := plugMgr.FindPluginByName(azureDataDiskPluginName) - if err != nil { - t.Errorf("Can't find the plugin by name") - } - fs := "ext4" - ro := false - caching := v1.AzureDataDiskCachingNone - spec := &v1.Volume{ - Name: "vol1", - VolumeSource: v1.VolumeSource{ - AzureDisk: &v1.AzureDiskVolumeSource{ - DiskName: fakeDiskName, - DataDiskURI: fakeDiskUri, - FSType: &fs, - CachingMode: &caching, - ReadOnly: &ro, - }, - }, - } - mounter, err := plug.(*azureDataDiskPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &mount.FakeMounter{}) - if err != nil { - t.Errorf("Failed to make a new Mounter: %v", err) - } - if mounter == nil { - t.Errorf("Got a nil Mounter") - } - volPath := path.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~azure-disk/vol1") - path := mounter.GetPath() - if path != volPath { - t.Errorf("Got unexpected path: %s, should be %s", path, volPath) - } - - if err := mounter.SetUp(nil); err != nil { - t.Errorf("Expected success, got: %v", err) - } - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - t.Errorf("SetUp() failed, volume path not created: %s", path) - } else { - t.Errorf("SetUp() failed: %v", err) - } - } - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - t.Errorf("SetUp() failed, volume path not created: %s", path) - } else { - t.Errorf("SetUp() failed: %v", err) - } - } - - unmounter, err := plug.(*azureDataDiskPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &mount.FakeMounter{}) - if err != nil { - t.Errorf("Failed to make a new Unmounter: %v", err) - } - if unmounter == nil { - t.Errorf("Got a nil Unmounter") - } - - if err := unmounter.TearDown(); err != nil { - t.Errorf("Expected success, got: %v", err) - } - if _, err := os.Stat(path); err == nil { - t.Errorf("TearDown() failed, volume path still exists: %s", path) - } else if !os.IsNotExist(err) { - t.Errorf("SetUp() failed: %v", err) - } -} +// fakeAzureProvider type was removed because all functions were not used +// Testing mounting will require path calculation which depends on the cloud provider, which is faked in the above test. diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_mounter.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_mounter.go new file mode 100644 index 0000000000..21b98becb7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_mounter.go @@ -0,0 +1,184 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure_dd + +import ( + "fmt" + "os" + + "github.com/golang/glog" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/volume" + "k8s.io/kubernetes/pkg/volume/util" +) + +type azureDiskMounter struct { + *dataDisk + spec *volume.Spec + plugin *azureDataDiskPlugin + options volume.VolumeOptions +} + +type azureDiskUnmounter struct { + *dataDisk + plugin *azureDataDiskPlugin +} + +var _ volume.Unmounter = &azureDiskUnmounter{} +var _ volume.Mounter = &azureDiskMounter{} + +func (m *azureDiskMounter) GetAttributes() volume.Attributes { + volumeSource, _ := getVolumeSource(m.spec) + return volume.Attributes{ + ReadOnly: *volumeSource.ReadOnly, + Managed: !*volumeSource.ReadOnly, + SupportsSELinux: true, + } +} + +func (m *azureDiskMounter) CanMount() error { + return nil +} + +func (m *azureDiskMounter) SetUp(fsGroup *int64) error { + return m.SetUpAt(m.GetPath(), fsGroup) +} + +func (m *azureDiskMounter) GetPath() string { + return getPath(m.dataDisk.podUID, m.dataDisk.volumeName, m.plugin.host) +} + +func (m *azureDiskMounter) SetUpAt(dir string, fsGroup *int64) error { + mounter := m.plugin.host.GetMounter() + volumeSource, err := getVolumeSource(m.spec) + + if err != nil { + glog.Infof("azureDisk - mounter failed to get volume source for spec %s", m.spec.Name()) + return err + } + + diskName := volumeSource.DiskName + mountPoint, err := mounter.IsLikelyNotMountPoint(dir) + + if err != nil && !os.IsNotExist(err) { + glog.Infof("azureDisk - cannot validate mount point for disk %s on %s %v", diskName, dir, err) + return err + } + if !mountPoint { + return fmt.Errorf("azureDisk - Not a mounting point for disk %s on %s", diskName, dir) + } + + if err := os.MkdirAll(dir, 0750); err != nil { + glog.Infof("azureDisk - mkdir failed on disk %s on dir: %s (%v)", diskName, dir, err) + return err + } + + options := []string{"bind"} + + if *volumeSource.ReadOnly { + options = append(options, "ro") + } + + glog.V(4).Infof("azureDisk - Attempting to mount %s on %s", diskName, dir) + isManagedDisk := (*volumeSource.Kind == v1.AzureManagedDisk) + globalPDPath, err := makeGlobalPDPath(m.plugin.host, volumeSource.DataDiskURI, isManagedDisk) + + if err != nil { + return err + } + + mountErr := mounter.Mount(globalPDPath, dir, *volumeSource.FSType, options) + // Everything in the following control flow is meant as an + // attempt cleanup a failed setupAt (bind mount) + if mountErr != nil { + glog.Infof("azureDisk - SetupAt:Mount disk:%s at dir:%s failed during mounting with error:%v, will attempt to clean up", diskName, dir, mountErr) + mountPoint, err := mounter.IsLikelyNotMountPoint(dir) + if err != nil { + return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup IsLikelyNotMountPoint check failed for disk:%s on dir:%s with error %v original-mountErr:%v", diskName, dir, err, mountErr) + } + + if !mountPoint { + if err = mounter.Unmount(dir); err != nil { + return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup failed to unmount disk:%s on dir:%s with error:%v original-mountErr:%v", diskName, dir, err, mountErr) + } + mountPoint, err := mounter.IsLikelyNotMountPoint(dir) + if err != nil { + return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup IsLikelyNotMountPoint for disk:%s on dir:%s check failed with error:%v original-mountErr:%v", diskName, dir, err, mountErr) + } + if !mountPoint { + // not cool. leave for next sync loop. + return fmt.Errorf("azureDisk - SetupAt:Mount:Failure:cleanup disk %s is still mounted on %s during cleanup original-mountErr:%v, despite call to unmount(). Will try again next sync loop.", diskName, dir, mountErr) + } + } + + if err = os.Remove(dir); err != nil { + return fmt.Errorf("azureDisk - SetupAt:Mount:Failure error cleaning up (removing dir:%s) with error:%v original-mountErr:%v", dir, err, mountErr) + } + + glog.V(2).Infof("azureDisk - Mount of disk:%s on dir:%s failed with mount error:%v post failure clean up was completed", diskName, dir, err, mountErr) + return mountErr + } + + if !*volumeSource.ReadOnly { + volume.SetVolumeOwnership(m, fsGroup) + } + + glog.V(2).Infof("azureDisk - successfully mounted disk %s on %s", diskName, dir) + return nil +} + +func (u *azureDiskUnmounter) TearDown() error { + return u.TearDownAt(u.GetPath()) +} + +func (u *azureDiskUnmounter) TearDownAt(dir string) error { + if pathExists, pathErr := util.PathExists(dir); pathErr != nil { + return fmt.Errorf("Error checking if path exists: %v", pathErr) + } else if !pathExists { + glog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir) + return nil + } + + glog.V(4).Infof("azureDisk - TearDownAt: %s", dir) + mounter := u.plugin.host.GetMounter() + mountPoint, err := mounter.IsLikelyNotMountPoint(dir) + if err != nil { + return fmt.Errorf("azureDisk - TearDownAt: %s failed to do IsLikelyNotMountPoint %s", dir, err) + } + if mountPoint { + if err := os.Remove(dir); err != nil { + return fmt.Errorf("azureDisk - TearDownAt: %s failed to do os.Remove %s", dir, err) + } + } + if err := mounter.Unmount(dir); err != nil { + return fmt.Errorf("azureDisk - TearDownAt: %s failed to do mounter.Unmount %s", dir, err) + } + mountPoint, err = mounter.IsLikelyNotMountPoint(dir) + if err != nil { + return fmt.Errorf("azureDisk - TearTownAt:IsLikelyNotMountPoint check failed: %v", err) + } + + if mountPoint { + return os.Remove(dir) + } + + return fmt.Errorf("azureDisk - failed to un-bind-mount volume dir") +} + +func (u *azureDiskUnmounter) GetPath() string { + return getPath(u.dataDisk.podUID, u.dataDisk.volumeName, u.plugin.host) +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_provision.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_provision.go index 0b63b5b73d..6770102b9b 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_provision.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/azure_provision.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +Copyright 2017 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,147 +20,182 @@ import ( "fmt" "strings" - "github.com/golang/glog" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api/v1" - utilstrings "k8s.io/kubernetes/pkg/util/strings" "k8s.io/kubernetes/pkg/volume" - "k8s.io/kubernetes/pkg/volume/util/volumehelper" ) -var _ volume.DeletableVolumePlugin = &azureDataDiskPlugin{} -var _ volume.ProvisionableVolumePlugin = &azureDataDiskPlugin{} +type azureDiskProvisioner struct { + plugin *azureDataDiskPlugin + options volume.VolumeOptions +} type azureDiskDeleter struct { - *azureDisk - azureProvider azureCloudProvider + *dataDisk + spec *volume.Spec + plugin *azureDataDiskPlugin } -func (plugin *azureDataDiskPlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) { - azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) - if err != nil { - glog.V(4).Infof("failed to get azure provider") - return nil, err - } +var _ volume.Provisioner = &azureDiskProvisioner{} +var _ volume.Deleter = &azureDiskDeleter{} - return plugin.newDeleterInternal(spec, azure) +func (d *azureDiskDeleter) GetPath() string { + return getPath(d.podUID, d.dataDisk.diskName, d.plugin.host) } -func (plugin *azureDataDiskPlugin) newDeleterInternal(spec *volume.Spec, azure azureCloudProvider) (volume.Deleter, error) { - if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureDisk == nil { - return nil, fmt.Errorf("invalid PV spec") +func (d *azureDiskDeleter) Delete() error { + volumeSource, err := getVolumeSource(d.spec) + if err != nil { + return err } - diskName := spec.PersistentVolume.Spec.AzureDisk.DiskName - diskUri := spec.PersistentVolume.Spec.AzureDisk.DataDiskURI - return &azureDiskDeleter{ - azureDisk: &azureDisk{ - volName: spec.Name(), - diskName: diskName, - diskUri: diskUri, - plugin: plugin, - }, - azureProvider: azure, - }, nil -} -func (plugin *azureDataDiskPlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) { - azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider()) + diskController, err := getDiskController(d.plugin.host) if err != nil { - glog.V(4).Infof("failed to get azure provider") - return nil, err - } - if len(options.PVC.Spec.AccessModes) == 0 { - options.PVC.Spec.AccessModes = plugin.GetAccessModes() + return err } - return plugin.newProvisionerInternal(options, azure) -} -func (plugin *azureDataDiskPlugin) newProvisionerInternal(options volume.VolumeOptions, azure azureCloudProvider) (volume.Provisioner, error) { - return &azureDiskProvisioner{ - azureDisk: &azureDisk{ - plugin: plugin, - }, - azureProvider: azure, - options: options, - }, nil -} + wasStandAlone := (*volumeSource.Kind != v1.AzureSharedBlobDisk) + managed := (*volumeSource.Kind == v1.AzureManagedDisk) -var _ volume.Deleter = &azureDiskDeleter{} - -func (d *azureDiskDeleter) GetPath() string { - name := azureDataDiskPluginName - return d.plugin.host.GetPodVolumeDir(d.podUID, utilstrings.EscapeQualifiedNameForDisk(name), d.volName) -} + if managed { + return diskController.DeleteManagedDisk(volumeSource.DataDiskURI) + } -func (d *azureDiskDeleter) Delete() error { - glog.V(4).Infof("deleting volume %s", d.diskUri) - return d.azureProvider.DeleteVolume(d.diskName, d.diskUri) + return diskController.DeleteBlobDisk(volumeSource.DataDiskURI, wasStandAlone) } -type azureDiskProvisioner struct { - *azureDisk - azureProvider azureCloudProvider - options volume.VolumeOptions -} +func (p *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) { + if !volume.AccessModesContainedInAll(p.plugin.GetAccessModes(), p.options.PVC.Spec.AccessModes) { + return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", p.options.PVC.Spec.AccessModes, p.plugin.GetAccessModes()) + } + supportedModes := p.plugin.GetAccessModes() -var _ volume.Provisioner = &azureDiskProvisioner{} + // perform static validation first + if p.options.PVC.Spec.Selector != nil { + return nil, fmt.Errorf("azureDisk - claim.Spec.Selector is not supported for dynamic provisioning on Azure disk") + } -func (a *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) { - if !volume.AccessModesContainedInAll(a.plugin.GetAccessModes(), a.options.PVC.Spec.AccessModes) { - return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", a.options.PVC.Spec.AccessModes, a.plugin.GetAccessModes()) + if len(p.options.PVC.Spec.AccessModes) > 1 { + return nil, fmt.Errorf("AzureDisk - multiple access modes are not supported on AzureDisk plugin") } - var sku, location, account string + if len(p.options.PVC.Spec.AccessModes) == 1 { + if p.options.PVC.Spec.AccessModes[0] != supportedModes[0] { + return nil, fmt.Errorf("AzureDisk - mode %s is not supporetd by AzureDisk plugin supported mode is %s", p.options.PVC.Spec.AccessModes[0], supportedModes) + } + } + var ( + location, account string + storageAccountType, fsType string + cachingMode v1.AzureDataDiskCachingMode + strKind string + err error + ) // maxLength = 79 - (4 for ".vhd") = 75 - name := volume.GenerateVolumeName(a.options.ClusterName, a.options.PVName, 75) - capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] + name := volume.GenerateVolumeName(p.options.ClusterName, p.options.PVName, 75) + capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] requestBytes := capacity.Value() requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) - // Apply ProvisionerParameters (case-insensitive). We leave validation of - // the values to the cloud provider. - for k, v := range a.options.Parameters { + for k, v := range p.options.Parameters { switch strings.ToLower(k) { case "skuname": - sku = v + storageAccountType = v case "location": location = v case "storageaccount": account = v + case "storageaccounttype": + storageAccountType = v + case "kind": + strKind = v + case "cachingmode": + cachingMode = v1.AzureDataDiskCachingMode(v) + case "fstype": + fsType = strings.ToLower(v) default: - return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, a.plugin.GetPluginName()) + return nil, fmt.Errorf("AzureDisk - invalid option %s in storage class", k) } } - // TODO: implement c.options.ProvisionerSelector parsing - if a.options.PVC.Spec.Selector != nil { - return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure disk") + + // normalize values + fsType = normalizeFsType(fsType) + skuName, err := normalizeStorageAccountType(storageAccountType) + if err != nil { + return nil, err + } + + kind, err := normalizeKind(strFirstLetterToUpper(strKind)) + if err != nil { + return nil, err } - diskName, diskUri, sizeGB, err := a.azureProvider.CreateVolume(name, account, sku, location, requestGB) + if cachingMode, err = normalizeCachingMode(cachingMode); err != nil { + return nil, err + } + + diskController, err := getDiskController(p.plugin.host) if err != nil { return nil, err } + // create disk + diskURI := "" + if kind == v1.AzureManagedDisk { + diskURI, err = diskController.CreateManagedDisk(name, skuName, requestGB, *(p.options.CloudTags)) + if err != nil { + return nil, err + } + } else { + forceStandAlone := (kind == v1.AzureDedicatedBlobDisk) + if kind == v1.AzureDedicatedBlobDisk { + if location != "" && account != "" { + // use dedicated kind (by default) for compatibility + _, diskURI, _, err = diskController.CreateVolume(name, account, skuName, location, requestGB) + if err != nil { + return nil, err + } + } else { + if location != "" || account != "" { + return nil, fmt.Errorf("AzureDisk - location(%s) and account(%s) must be both empty or specified for dedicated kind, only one value specified is not allowed", + location, account) + } + diskURI, err = diskController.CreateBlobDisk(name, skuName, requestGB, forceStandAlone) + if err != nil { + return nil, err + } + } + } else { + diskURI, err = diskController.CreateBlobDisk(name, skuName, requestGB, forceStandAlone) + if err != nil { + return nil, err + } + } + } + pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ - Name: a.options.PVName, + Name: p.options.PVName, Labels: map[string]string{}, Annotations: map[string]string{ - volumehelper.VolumeDynamicallyCreatedByKey: "azure-disk-dynamic-provisioner", + "volumehelper.VolumeDynamicallyCreatedByKey": "azure-disk-dynamic-provisioner", }, }, Spec: v1.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: a.options.PersistentVolumeReclaimPolicy, - AccessModes: a.options.PVC.Spec.AccessModes, + PersistentVolumeReclaimPolicy: p.options.PersistentVolumeReclaimPolicy, + AccessModes: supportedModes, Capacity: v1.ResourceList{ - v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), + v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", requestGB)), }, PersistentVolumeSource: v1.PersistentVolumeSource{ AzureDisk: &v1.AzureDiskVolumeSource{ - DiskName: diskName, - DataDiskURI: diskUri, + CachingMode: &cachingMode, + DiskName: name, + DataDiskURI: diskURI, + Kind: &kind, + FSType: &fsType, }, }, }, diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util.go deleted file mode 100644 index 8db5093b76..0000000000 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/vhd_util.go +++ /dev/null @@ -1,145 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package azure_dd - -import ( - "io/ioutil" - "os" - "path" - "regexp" - "strconv" - "strings" - - "github.com/golang/glog" - "k8s.io/kubernetes/pkg/util/exec" -) - -type ioHandler interface { - ReadDir(dirname string) ([]os.FileInfo, error) - WriteFile(filename string, data []byte, perm os.FileMode) error - Readlink(name string) (string, error) -} - -type osIOHandler struct{} - -func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) { - return ioutil.ReadDir(dirname) -} -func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error { - return ioutil.WriteFile(filename, data, perm) -} -func (handler *osIOHandler) Readlink(name string) (string, error) { - return os.Readlink(name) -} - -// exclude those used by azure as resource and OS root in /dev/disk/azure -func listAzureDiskPath(io ioHandler) []string { - azureDiskPath := "/dev/disk/azure/" - var azureDiskList []string - if dirs, err := io.ReadDir(azureDiskPath); err == nil { - for _, f := range dirs { - name := f.Name() - diskPath := azureDiskPath + name - if link, linkErr := io.Readlink(diskPath); linkErr == nil { - sd := link[(strings.LastIndex(link, "/") + 1):] - azureDiskList = append(azureDiskList, sd) - } - } - } - glog.V(12).Infof("Azure sys disks paths: %v", azureDiskList) - return azureDiskList -} - -// given a LUN find the VHD device path like /dev/sdd -// exclude those disks used by Azure resources and OS root -func findDiskByLun(lun int, io ioHandler, exe exec.Interface) (string, error) { - azureDisks := listAzureDiskPath(io) - return findDiskByLunWithConstraint(lun, io, exe, azureDisks) -} - -// look for device /dev/sdX and validate it is a VHD -// return empty string if no disk is found -func findDiskByLunWithConstraint(lun int, io ioHandler, exe exec.Interface, azureDisks []string) (string, error) { - var err error - sys_path := "/sys/bus/scsi/devices" - if dirs, err := io.ReadDir(sys_path); err == nil { - for _, f := range dirs { - name := f.Name() - // look for path like /sys/bus/scsi/devices/3:0:0:1 - arr := strings.Split(name, ":") - if len(arr) < 4 { - continue - } - // extract LUN from the path. - // LUN is the last index of the array, i.e. 1 in /sys/bus/scsi/devices/3:0:0:1 - l, err := strconv.Atoi(arr[3]) - if err != nil { - // unknown path format, continue to read the next one - glog.Errorf("failed to parse lun from %v (%v), err %v", arr[3], name, err) - continue - } - if lun == l { - // find the matching LUN - // read vendor and model to ensure it is a VHD disk - vendor := path.Join(sys_path, name, "vendor") - model := path.Join(sys_path, name, "model") - out, err := exe.Command("cat", vendor, model).CombinedOutput() - if err != nil { - glog.Errorf("failed to cat device vendor and model, err: %v", err) - continue - } - matched, err := regexp.MatchString("^MSFT[ ]{0,}\nVIRTUAL DISK[ ]{0,}\n$", strings.ToUpper(string(out))) - if err != nil || !matched { - glog.V(4).Infof("doesn't match VHD, output %v, error %v", string(out), err) - continue - } - // find a disk, validate name - dir := path.Join(sys_path, name, "block") - if dev, err := io.ReadDir(dir); err == nil { - found := false - for _, diskName := range azureDisks { - glog.V(12).Infof("validating disk %q with sys disk %q", dev[0].Name(), diskName) - if string(dev[0].Name()) == diskName { - found = true - break - } - } - if !found { - return "/dev/" + dev[0].Name(), nil - } - } - } - } - } - return "", err -} - -// rescan scsi bus -func scsiHostRescan(io ioHandler) { - scsi_path := "/sys/class/scsi_host/" - if dirs, err := io.ReadDir(scsi_path); err == nil { - for _, f := range dirs { - name := scsi_path + f.Name() + "/scan" - data := []byte("- - -") - if err = io.WriteFile(name, data, 0666); err != nil { - glog.Errorf("failed to rescan scsi host %s", name) - } - } - } else { - glog.Errorf("failed to read %s, err %v", scsi_path, err) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/unmounter.go b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/unmounter.go index 2959b53f94..2f1e189b1c 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/unmounter.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/flexvolume/unmounter.go @@ -51,23 +51,15 @@ func (f *flexVolumeUnmounter) TearDownAt(dir string) error { return nil } - notmnt, err := isNotMounted(f.mounter, dir) + call := f.plugin.NewDriverCall(unmountCmd) + call.Append(dir) + _, err := call.Run() + if isCmdNotSupportedErr(err) { + err = (*unmounterDefaults)(f).TearDownAt(dir) + } if err != nil { return err } - if notmnt { - glog.Warningf("Warning: Path: %v already unmounted", dir) - } else { - call := f.plugin.NewDriverCall(unmountCmd) - call.Append(dir) - _, err := call.Run() - if isCmdNotSupportedErr(err) { - err = (*unmounterDefaults)(f).TearDownAt(dir) - } - if err != nil { - return err - } - } // Flexvolume driver may remove the directory. Ignore if it does. if pathExists, pathErr := util.PathExists(dir); pathErr != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/glusterfs/glusterfs.go b/vendor/k8s.io/kubernetes/pkg/volume/glusterfs/glusterfs.go index 6c16d524c1..a771611f91 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/glusterfs/glusterfs.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/glusterfs/glusterfs.go @@ -342,24 +342,23 @@ func (b *glusterfsMounter) setUpAtInternal(dir string) error { return nil } - // Give a try without `auto_unmount mount option, because - // it could be that gluster fuse client is older version and - // mount.glusterfs is unaware of `auto_unmount`. - // Use a mount string without `auto_unmount`` - - autoMountOptions := make([]string, len(mountOptions)) - for _, opt := range mountOptions { - if opt != "auto_unmount" { - autoMountOptions = append(autoMountOptions, opt) + const invalidOption = "Invalid option auto_unmount" + if dstrings.Contains(errs.Error(), invalidOption) { + // Give a try without `auto_unmount` mount option, because + // it could be that gluster fuse client is older version and + // mount.glusterfs is unaware of `auto_unmount`. + noAutoMountOptions := make([]string, len(mountOptions)) + for _, opt := range mountOptions { + if opt != "auto_unmount" { + noAutoMountOptions = append(noAutoMountOptions, opt) + } + } + errs = b.mounter.Mount(ip+":"+b.path, dir, "glusterfs", noAutoMountOptions) + if errs == nil { + glog.Infof("glusterfs: successfully mounted %s", dir) + return nil } } - - autoerrs := b.mounter.Mount(ip+":"+b.path, dir, "glusterfs", autoMountOptions) - if autoerrs == nil { - glog.Infof("glusterfs: successfully mounted %s", dir) - return nil - } - } // Failed mount scenario. diff --git a/vendor/k8s.io/kubernetes/pkg/volume/local/local.go b/vendor/k8s.io/kubernetes/pkg/volume/local/local.go index bf23136227..9e4f91fd75 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/local/local.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/local/local.go @@ -198,7 +198,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { return fmt.Errorf("invalid path: %s %v", m.globalPath, err) } - notMnt, err := m.mounter.IsLikelyNotMountPoint(dir) + notMnt, err := m.mounter.IsNotMountPoint(dir) glog.V(4).Infof("LocalVolume mount setup: PodDir(%s) VolDir(%s) Mounted(%t) Error(%v), ReadOnly(%t)", dir, m.globalPath, !notMnt, err, m.readOnly) if err != nil && !os.IsNotExist(err) { glog.Errorf("cannot validate mount point: %s %v", dir, err) @@ -223,9 +223,9 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { err = m.mounter.Mount(m.globalPath, dir, "", options) if err != nil { glog.Errorf("Mount of volume %s failed: %v", dir, err) - notMnt, mntErr := m.mounter.IsLikelyNotMountPoint(dir) + notMnt, mntErr := m.mounter.IsNotMountPoint(dir) if mntErr != nil { - glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) + glog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err } if !notMnt { @@ -233,9 +233,9 @@ func (m *localVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { glog.Errorf("Failed to unmount: %v", mntErr) return err } - notMnt, mntErr = m.mounter.IsLikelyNotMountPoint(dir) + notMnt, mntErr = m.mounter.IsNotMountPoint(dir) if mntErr != nil { - glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr) + glog.Errorf("IsNotMountPoint check failed: %v", mntErr) return err } if !notMnt { @@ -269,5 +269,5 @@ func (u *localVolumeUnmounter) TearDown() error { // TearDownAt unmounts the bind mount func (u *localVolumeUnmounter) TearDownAt(dir string) error { glog.V(4).Infof("Unmounting volume %q at path %q\n", u.volName, dir) - return util.UnmountPath(dir, u.mounter) + return util.UnmountMountPoint(dir, u.mounter, true) /* extensiveMountPointCheck = true */ } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx.go b/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx.go index 291baa06e0..82f31d3af5 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx.go @@ -266,7 +266,7 @@ func (b *portworxVolumeMounter) SetUp(fsGroup *int64) error { // SetUpAt attaches the disk and bind mounts to the volume path. func (b *portworxVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) - glog.V(4).Infof("Portworx Volume set up: %s %v %v", dir, !notMnt, err) + glog.Infof("Portworx Volume set up. Dir: %s %v %v", dir, !notMnt, err) if err != nil && !os.IsNotExist(err) { glog.Errorf("Cannot validate mountpoint: %s", dir) return err @@ -291,7 +291,7 @@ func (b *portworxVolumeMounter) SetUpAt(dir string, fsGroup *int64) error { if !b.readOnly { volume.SetVolumeOwnership(b, fsGroup) } - glog.V(4).Infof("Portworx Volume %s mounted to %s", b.volumeID, dir) + glog.Infof("Portworx Volume %s setup at %s", b.volumeID, dir) return nil } @@ -314,8 +314,8 @@ func (c *portworxVolumeUnmounter) TearDown() error { // Unmounts the bind mount, and detaches the disk only if the PD // resource was the last reference to that disk on the kubelet. func (c *portworxVolumeUnmounter) TearDownAt(dir string) error { - glog.V(4).Infof("Portworx Volume TearDown of %s", dir) - // Call Portworx Unmount for Portworx's book-keeping. + glog.Infof("Portworx Volume TearDown of %s", dir) + if err := c.manager.UnmountVolume(c, dir); err != nil { return err } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx_util.go b/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx_util.go index 54f9c61376..0a727df981 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx_util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/portworx/portworx_util.go @@ -43,12 +43,14 @@ type PortworxVolumeUtil struct { // CreateVolume creates a Portworx volume. func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (string, int, map[string]string, error) { - driver, err := util.getPortworxDriver(p.plugin.host) + driver, err := util.getPortworxDriver(p.plugin.host, false /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return "", 0, nil, err } + glog.Infof("Creating Portworx volume for PVC: %v", p.options.PVC.Name) + capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] // Portworx Volumes are specified in GB requestGB := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024)) @@ -56,6 +58,7 @@ func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (stri specHandler := osdspec.NewSpecHandler() spec, err := specHandler.SpecFromOpts(p.options.Parameters) if err != nil { + glog.Errorf("Error parsing parameters for PVC: %v. Err: %v", p.options.PVC.Name, err) return "", 0, nil, err } spec.Size = uint64(requestGB * 1024 * 1024 * 1024) @@ -68,14 +71,16 @@ func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (stri locator.VolumeLabels[pvcClaimLabel] = p.options.PVC.Name volumeID, err := driver.Create(&locator, &source, spec) if err != nil { - glog.V(2).Infof("Error creating Portworx Volume : %v", err) + glog.Errorf("Error creating Portworx Volume : %v", err) } + + glog.Infof("Successfully created Portworx volume for PVC: %v", p.options.PVC.Name) return volumeID, requestGB, nil, err } // DeleteVolume deletes a Portworx volume func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error { - driver, err := util.getPortworxDriver(d.plugin.host) + driver, err := util.getPortworxDriver(d.plugin.host, false /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return err @@ -83,7 +88,7 @@ func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error { err = driver.Delete(d.volumeID) if err != nil { - glog.V(2).Infof("Error deleting Portworx Volume (%v): %v", d.volName, err) + glog.Errorf("Error deleting Portworx Volume (%v): %v", d.volName, err) return err } return nil @@ -91,7 +96,7 @@ func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error { // AttachVolume attaches a Portworx Volume func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, error) { - driver, err := util.getPortworxDriver(m.plugin.host) + driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return "", err @@ -99,7 +104,7 @@ func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, devicePath, err := driver.Attach(m.volName) if err != nil { - glog.V(2).Infof("Error attaching Portworx Volume (%v): %v", m.volName, err) + glog.Errorf("Error attaching Portworx Volume (%v): %v", m.volName, err) return "", err } return devicePath, nil @@ -107,7 +112,7 @@ func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, // DetachVolume detaches a Portworx Volume func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error { - driver, err := util.getPortworxDriver(u.plugin.host) + driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return err @@ -115,7 +120,7 @@ func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error { err = driver.Detach(u.volName) if err != nil { - glog.V(2).Infof("Error detaching Portworx Volume (%v): %v", u.volName, err) + glog.Errorf("Error detaching Portworx Volume (%v): %v", u.volName, err) return err } return nil @@ -123,7 +128,7 @@ func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error { // MountVolume mounts a Portworx Volume on the specified mountPath func (util *PortworxVolumeUtil) MountVolume(m *portworxVolumeMounter, mountPath string) error { - driver, err := util.getPortworxDriver(m.plugin.host) + driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return err @@ -131,7 +136,7 @@ func (util *PortworxVolumeUtil) MountVolume(m *portworxVolumeMounter, mountPath err = driver.Mount(m.volName, mountPath) if err != nil { - glog.V(2).Infof("Error mounting Portworx Volume (%v) on Path (%v): %v", m.volName, mountPath, err) + glog.Errorf("Error mounting Portworx Volume (%v) on Path (%v): %v", m.volName, mountPath, err) return err } return nil @@ -139,7 +144,7 @@ func (util *PortworxVolumeUtil) MountVolume(m *portworxVolumeMounter, mountPath // UnmountVolume unmounts a Portworx Volume func (util *PortworxVolumeUtil) UnmountVolume(u *portworxVolumeUnmounter, mountPath string) error { - driver, err := util.getPortworxDriver(u.plugin.host) + driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/) if err != nil || driver == nil { glog.Errorf("Failed to get portworx driver. Err: %v", err) return err @@ -147,7 +152,7 @@ func (util *PortworxVolumeUtil) UnmountVolume(u *portworxVolumeUnmounter, mountP err = driver.Unmount(u.volName, mountPath) if err != nil { - glog.V(2).Infof("Error unmounting Portworx Volume (%v) on Path (%v): %v", u.volName, mountPath, err) + glog.Errorf("Error unmounting Portworx Volume (%v) on Path (%v): %v", u.volName, mountPath, err) return err } return nil @@ -181,13 +186,34 @@ func createDriverClient(hostname string) (*osdclient.Client, error) { } } -func (util *PortworxVolumeUtil) getPortworxDriver(volumeHost volume.VolumeHost) (volumeapi.VolumeDriver, error) { +// getPortworxDriver() returns a Portworx volume driver which can be used for volume operations +// localOnly: If true, the returned driver will be connected to Portworx API server on volume host. +// If false, driver will be connected to API server on volume host or Portworx k8s service cluster IP +// This flag is required to explicitly force certain operations (mount, unmount, detach, attach) to +// go to the volume host instead of the k8s service which might route it to any host. This pertains to how +// Portworx mounts and attaches a volume to the running container. The node getting these requests needs to +// see the pod container mounts (specifically /var/lib/kubelet/pods/) +// Operations like create and delete volume don't need to be restricted to local volume host since +// any node in the Portworx cluster can co-ordinate the create/delete request and forward the operations to +// the Portworx node that will own/owns the data. +func (util *PortworxVolumeUtil) getPortworxDriver(volumeHost volume.VolumeHost, localOnly bool) (volumeapi.VolumeDriver, error) { + var err error + if localOnly { + util.portworxClient, err = createDriverClient(volumeHost.GetHostName()) + if err != nil { + return nil, err + } else { + glog.V(4).Infof("Using portworx local service at: %v as api endpoint", volumeHost.GetHostName()) + return volumeclient.VolumeDriver(util.portworxClient), nil + } + } + + // check if existing saved client is valid if isValid, _ := isClientValid(util.portworxClient); isValid { return volumeclient.VolumeDriver(util.portworxClient), nil } // create new client - var err error util.portworxClient, err = createDriverClient(volumeHost.GetHostName()) // for backward compatibility if err != nil || util.portworxClient == nil { // Create client from portworx service @@ -215,7 +241,7 @@ func (util *PortworxVolumeUtil) getPortworxDriver(volumeHost volume.VolumeHost) return nil, err } - glog.Infof("Using portworx service at: %v as api endpoint", svc.Spec.ClusterIP) + glog.Infof("Using portworx cluster service at: %v as api endpoint", svc.Spec.ClusterIP) } else { glog.Infof("Using portworx service at: %v as api endpoint", volumeHost.GetHostName()) } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/BUILD b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/BUILD index 99d375f8de..58825b4076 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/BUILD @@ -24,6 +24,7 @@ go_test( "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//vendor/github.com/codedellemc/goscaleio/types/v1:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/client-go/util/testing:go_default_library", diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_client.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_client.go index bfcb6f0d06..8742905ed0 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_client.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_client.go @@ -45,7 +45,7 @@ type sioInterface interface { FindVolume(name string) (*siotypes.Volume, error) Volume(sioVolumeID) (*siotypes.Volume, error) CreateVolume(name string, sizeGB int64) (*siotypes.Volume, error) - AttachVolume(sioVolumeID) error + AttachVolume(sioVolumeID, bool) error DetachVolume(sioVolumeID) error DeleteVolume(sioVolumeID) error IID() (string, error) @@ -217,8 +217,9 @@ func (c *sioClient) CreateVolume(name string, sizeGB int64) (*siotypes.Volume, e return c.Volume(sioVolumeID(createResponse.ID)) } -// AttachVolume maps the scaleio volume to an sdc node. -func (c *sioClient) AttachVolume(id sioVolumeID) error { +// AttachVolume maps the scaleio volume to an sdc node. If the multipleMappings flag +// is true, ScaleIO will allow other SDC to map to that volume. +func (c *sioClient) AttachVolume(id sioVolumeID, multipleMappings bool) error { if err := c.init(); err != nil { glog.Error(log("failed to init'd client in attach volume: %v", err)) return err @@ -232,7 +233,7 @@ func (c *sioClient) AttachVolume(id sioVolumeID) error { params := &siotypes.MapVolumeSdcParam{ SdcID: iid, - AllowMultipleMappings: "false", + AllowMultipleMappings: strconv.FormatBool(multipleMappings), AllSdcs: "", } volClient := sio.NewVolume(c.client) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr.go index ca10677dd7..83d5e498dc 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr.go @@ -27,7 +27,7 @@ import ( type storageInterface interface { CreateVolume(string, int64) (*siotypes.Volume, error) - AttachVolume(string) (string, error) + AttachVolume(string, bool) (string, error) IsAttached(string) (bool, error) DetachVolume(string) error DeleteVolume(string) error @@ -103,8 +103,9 @@ func (m *sioMgr) CreateVolume(volName string, sizeGB int64) (*siotypes.Volume, e return vol, nil } -// AttachVolume maps a ScaleIO volume to the running node -func (m *sioMgr) AttachVolume(volName string) (string, error) { +// AttachVolume maps a ScaleIO volume to the running node. If flag multiMaps, +// ScaleIO will allow other SDC to map to volume. +func (m *sioMgr) AttachVolume(volName string, multipleMappings bool) (string, error) { client, err := m.getClient() if err != nil { glog.Error(log("attach volume failed: %v", err)) @@ -139,7 +140,7 @@ func (m *sioMgr) AttachVolume(volName string) (string, error) { } // attach volume, get deviceName - if err := client.AttachVolume(sioVolumeID(vol.ID)); err != nil { + if err := client.AttachVolume(sioVolumeID(vol.ID), multipleMappings); err != nil { glog.Error(log("attachment for volume %s failed :%v", volName, err)) return "", err } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr_test.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr_test.go index c8f4b44927..3d580b6b99 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_mgr_test.go @@ -99,7 +99,7 @@ func TestMgrCreateVolume(t *testing.T) { func TestMgrAttachVolume(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - device, err := mgr.AttachVolume("test-vol-0001") + device, err := mgr.AttachVolume("test-vol-0001", false) if err != nil { t.Fatal(err) } @@ -111,8 +111,8 @@ func TestMgrAttachVolume(t *testing.T) { func TestMgrAttachVolume_AlreadyAttached(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - mgr.AttachVolume("test-vol-0001") - dev, err := mgr.AttachVolume("test-vol-0001") + mgr.AttachVolume("test-vol-0001", false) + dev, err := mgr.AttachVolume("test-vol-0001", false) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -124,7 +124,8 @@ func TestMgrAttachVolume_AlreadyAttached(t *testing.T) { func TestMgrAttachVolume_VolumeNotFoundError(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - _, err := mgr.AttachVolume("test-vol-0002") + _, err := mgr.AttachVolume("test-vol-0002", false) + if err == nil { t.Error("attachVolume should fail with volume not found error") } @@ -137,7 +138,7 @@ func TestMgrAttachVolume_WaitForAttachError(t *testing.T) { c := mgr.client.(*fakeSio) close(c.waitAttachCtrl) }() - _, err := mgr.AttachVolume("test-vol-0001") + _, err := mgr.AttachVolume("test-vol-0001", false) if err == nil { t.Error("attachVolume should fail with attach timeout error") } @@ -146,7 +147,7 @@ func TestMgrAttachVolume_WaitForAttachError(t *testing.T) { func TestMgrDetachVolume(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - mgr.AttachVolume("test-vol-0001") + mgr.AttachVolume("test-vol-0001", false) if err := mgr.DetachVolume("test-vol-0001"); err != nil { t.Fatal(err) } @@ -162,7 +163,7 @@ func TestMgrDetachVolume(t *testing.T) { func TestMgrDetachVolume_VolumeNotFound(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - mgr.AttachVolume("test-vol-0001") + mgr.AttachVolume("test-vol-0001", false) err := mgr.DetachVolume("test-vol-0002") if err == nil { t.Fatal("expected a volume not found failure") @@ -181,7 +182,7 @@ func TestMgrDetachVolume_VolumeNotAttached(t *testing.T) { func TestMgrDetachVolume_VolumeAlreadyDetached(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - mgr.AttachVolume("test-vol-0001") + mgr.AttachVolume("test-vol-0001", false) mgr.DetachVolume("test-vol-0001") err := mgr.DetachVolume("test-vol-0001") if err != nil { @@ -192,7 +193,7 @@ func TestMgrDetachVolume_VolumeAlreadyDetached(t *testing.T) { func TestMgrDetachVolume_WaitForDetachError(t *testing.T) { mgr := newTestMgr(t) mgr.CreateVolume("test-vol-0001", 8*1024*1024) - mgr.AttachVolume("test-vol-0001") + mgr.AttachVolume("test-vol-0001", false) err := mgr.DetachVolume("test-vol-0001") if err != nil { t.Error("detachVolume failed") @@ -227,6 +228,7 @@ type fakeSio struct { waitAttachCtrl chan struct{} waitDetachCtrl chan struct{} devs map[string]string + isMultiMap bool } func newFakeSio() *fakeSio { @@ -261,7 +263,8 @@ func (f *fakeSio) CreateVolume(volName string, sizeGB int64) (*siotypes.Volume, return f.volume, nil } -func (f *fakeSio) AttachVolume(id sioVolumeID) error { +func (f *fakeSio) AttachVolume(id sioVolumeID, multiMaps bool) error { + f.isMultiMap = multiMaps _, err := f.Volume(id) if err != nil { return err diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_plugin.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_plugin.go index ff45c41b02..04bf707932 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_plugin.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_plugin.go @@ -149,6 +149,7 @@ var _ volume.PersistentVolumePlugin = &sioPlugin{} func (p *sioPlugin) GetAccessModes() []api.PersistentVolumeAccessMode { return []api.PersistentVolumeAccessMode{ api.ReadWriteOnce, + api.ReadOnlyMany, } } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util.go index 42cc31c9f4..2ee7d918dc 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util.go @@ -68,11 +68,13 @@ var ( nsSep = "%" sdcRootPath = "/opt/emc/scaleio/sdc/bin" - secretNotFoundErr = errors.New("secret not found") - configMapNotFoundErr = errors.New("configMap not found") - gatewayNotProvidedErr = errors.New("gateway not provided") - secretRefNotProvidedErr = errors.New("secret ref not provided") - systemNotProvidedErr = errors.New("secret not provided") + secretNotFoundErr = errors.New("secret not found") + configMapNotFoundErr = errors.New("configMap not found") + gatewayNotProvidedErr = errors.New("ScaleIO gateway not provided") + secretRefNotProvidedErr = errors.New("secret ref not provided") + systemNotProvidedErr = errors.New("ScaleIO system not provided") + storagePoolNotProvidedErr = errors.New("ScaleIO storage pool not provided") + protectionDomainNotProvidedErr = errors.New("ScaleIO protection domain not provided") ) // mapScaleIOVolumeSource maps attributes from a ScaleIOVolumeSource to config @@ -107,6 +109,12 @@ func validateConfigs(config map[string]string) error { if config[confKey.system] == "" { return systemNotProvidedErr } + if config[confKey.storagePool] == "" { + return storagePoolNotProvidedErr + } + if config[confKey.protectionDomain] == "" { + return protectionDomainNotProvidedErr + } return nil } @@ -119,8 +127,6 @@ func applyConfigDefaults(config map[string]string) { b = false } config[confKey.sslEnabled] = strconv.FormatBool(b) - config[confKey.protectionDomain] = defaultString(config[confKey.protectionDomain], "default") - config[confKey.storagePool] = defaultString(config[confKey.storagePool], "default") config[confKey.storageMode] = defaultString(config[confKey.storageMode], "ThinProvisioned") config[confKey.fsType] = defaultString(config[confKey.fsType], "xfs") b, err = strconv.ParseBool(config[confKey.readOnly]) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util_test.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util_test.go index 2de09752f1..97e5512f8b 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_util_test.go @@ -115,10 +115,10 @@ func TestUtilApplyConfigDefaults(t *testing.T) { if data[confKey.system] != "sio" { t.Error("Unexpected system value") } - if data[confKey.protectionDomain] != "default" { + if data[confKey.protectionDomain] != "" { t.Error("Unexpected protection domain value") } - if data[confKey.storagePool] != "default" { + if data[confKey.storagePool] != "" { t.Error("Unexpected storage pool value") } if data[confKey.volumeName] != "sio-vol" { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume.go index 3abebd6a38..b3c2177b8d 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume.go @@ -88,7 +88,7 @@ func (v *sioVolume) SetUpAt(dir string, fsGroup *int64) error { v.plugin.volumeMtx.LockKey(v.volSpecName) defer v.plugin.volumeMtx.UnlockKey(v.volSpecName) - glog.V(4).Info(log("setting up volume %s", v.volSpecName)) + glog.V(4).Info(log("setting up volume for PV.spec %s", v.volSpecName)) if err := v.setSioMgr(); err != nil { glog.Error(log("setup failed to create scalio manager: %v", err)) return err @@ -104,18 +104,36 @@ func (v *sioVolume) SetUpAt(dir string, fsGroup *int64) error { return nil } - // attach the volume and mount + // should multiple-mapping be enabled + enableMultiMaps := false + isROM := false + if v.spec.PersistentVolume != nil { + ams := v.spec.PersistentVolume.Spec.AccessModes + for _, am := range ams { + if am == api.ReadOnlyMany { + enableMultiMaps = true + isROM = true + } + } + } + glog.V(4).Info(log("multiple mapping enabled = %v", enableMultiMaps)) + volName := v.volName - devicePath, err := v.sioMgr.AttachVolume(volName) + devicePath, err := v.sioMgr.AttachVolume(volName, enableMultiMaps) if err != nil { glog.Error(log("setup of volume %v: %v", v.volSpecName, err)) return err } options := []string{} - if v.source.ReadOnly { - options = append(options, "ro") - } else { + switch { + default: + options = append(options, "rw") + case isROM && !v.source.ReadOnly: options = append(options, "rw") + case isROM: + options = append(options, "ro") + case v.source.ReadOnly: + options = append(options, "ro") } glog.V(4).Info(log("mounting device %s -> %s", devicePath, dir)) @@ -140,7 +158,12 @@ func (v *sioVolume) SetUpAt(dir string, fsGroup *int64) error { return err } - glog.V(4).Info(log("successfully setup volume %s attached %s:%s as %s", v.volSpecName, v.volName, devicePath, dir)) + if !v.readOnly && fsGroup != nil { + glog.V(4).Info(log("applying value FSGroup ownership")) + volume.SetVolumeOwnership(v, fsGroup) + } + + glog.V(4).Info(log("successfully setup PV %s: volume %s mapped as %s mounted at %s", v.volSpecName, v.volName, devicePath, dir)) return nil } @@ -191,7 +214,7 @@ func (v *sioVolume) TearDownAt(dir string) error { // use "last attempt wins" strategy to detach volume from node // only allow volume to detach when it is not busy (not being used by other pods) if !deviceBusy { - glog.V(4).Info(log("teardown is attempting to detach/unmap volume for %s", v.volSpecName)) + glog.V(4).Info(log("teardown is attempting to detach/unmap volume for PV %s", v.volSpecName)) if err := v.resetSioMgr(); err != nil { glog.Error(log("teardown failed, unable to reset scalio mgr: %v", err)) } @@ -224,7 +247,7 @@ func (v *sioVolume) Delete() error { return err } - glog.V(4).Info(log("successfully deleted pvc %s", v.volSpecName)) + glog.V(4).Info(log("successfully deleted PV %s with volume %s", v.volSpecName, v.volName)) return nil } @@ -234,17 +257,30 @@ func (v *sioVolume) Delete() error { var _ volume.Provisioner = &sioVolume{} func (v *sioVolume) Provision() (*api.PersistentVolume, error) { - glog.V(4).Info(log("attempting to dynamically provision pvc %v", v.options.PVName)) + glog.V(4).Info(log("attempting to dynamically provision pvc %v", v.options.PVC.Name)) if !volume.AccessModesContainedInAll(v.plugin.GetAccessModes(), v.options.PVC.Spec.AccessModes) { return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", v.options.PVC.Spec.AccessModes, v.plugin.GetAccessModes()) } // setup volume attrributes - name := v.generateVolName() + genName := v.generateName("k8svol", 11) + var oneGig int64 = 1024 * 1024 * 1024 + var eightGig int64 = 8 * oneGig + capacity := v.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] volSizeBytes := capacity.Value() - volSizeGB := int64(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) + volSizeGB := int64(volume.RoundUpSize(volSizeBytes, oneGig)) + + if volSizeBytes == 0 { + return nil, fmt.Errorf("invalid volume size of 0 specified") + } + + if volSizeBytes < eightGig { + volSizeGB = int64(volume.RoundUpSize(eightGig, oneGig)) + glog.V(4).Info(log("capacity less than 8Gi found, adjusted to %dGi", volSizeGB)) + + } // create sio manager if err := v.setSioMgrFromConfig(); err != nil { @@ -253,14 +289,15 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) { } // create volume - vol, err := v.sioMgr.CreateVolume(name, volSizeGB) + volName := genName + vol, err := v.sioMgr.CreateVolume(volName, volSizeGB) if err != nil { glog.Error(log("provision failed while creating volume: %v", err)) return nil, err } // prepare data for pv - v.configData[confKey.volumeName] = name + v.configData[confKey.volumeName] = volName sslEnabled, err := strconv.ParseBool(v.configData[confKey.sslEnabled]) if err != nil { glog.Warning(log("failed to parse parameter sslEnabled, setting to false")) @@ -273,9 +310,10 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) { } // describe created pv + pvName := genName pv := &api.PersistentVolume{ ObjectMeta: meta.ObjectMeta{ - Name: v.options.PVName, + Name: pvName, Namespace: v.options.PVC.Namespace, Labels: map[string]string{}, Annotations: map[string]string{ @@ -299,7 +337,7 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) { ProtectionDomain: v.configData[confKey.protectionDomain], StoragePool: v.configData[confKey.storagePool], StorageMode: v.configData[confKey.storageMode], - VolumeName: name, + VolumeName: volName, FSType: v.configData[confKey.fsType], ReadOnly: readOnly, }, @@ -310,14 +348,14 @@ func (v *sioVolume) Provision() (*api.PersistentVolume, error) { pv.Spec.AccessModes = v.plugin.GetAccessModes() } - glog.V(4).Info(log("provisioner dynamically created pvc %v with volume %s successfully", pv.Name, vol.Name)) + glog.V(4).Info(log("provisioner created pv %v and volume %s successfully", pvName, vol.Name)) return pv, nil } // setSioMgr creates scaleio mgr from cached config data if found // otherwise, setups new config data and create mgr func (v *sioVolume) setSioMgr() error { - glog.V(4).Info(log("setting up sio mgr for vol %s", v.volSpecName)) + glog.V(4).Info(log("setting up sio mgr for spec %s", v.volSpecName)) podDir := v.plugin.host.GetPodPluginDir(v.podUID, sioPluginName) configName := path.Join(podDir, sioConfigFileName) if v.sioMgr == nil { @@ -455,6 +493,6 @@ func (v *sioVolume) setSioMgrFromSpec() error { return nil } -func (v *sioVolume) generateVolName() string { - return "sio-" + strings.Replace(string(uuid.NewUUID()), "-", "", -1)[0:25] +func (v *sioVolume) generateName(prefix string, size int) string { + return fmt.Sprintf("%s-%s", prefix, strings.Replace(string(uuid.NewUUID()), "-", "", -1)[0:size]) } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume_test.go b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume_test.go index 536a833304..6609922287 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume_test.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/scaleio/sio_volume_test.go @@ -23,6 +23,7 @@ import ( "strings" "testing" + "github.com/golang/glog" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" utiltesting "k8s.io/client-go/util/testing" @@ -149,6 +150,7 @@ func TestVolumeMounterUnmounter(t *testing.T) { VolumeName: testSioVol, FSType: "ext4", SecretRef: &api.LocalObjectReference{Name: "sio-secret"}, + ReadOnly: false, }, }, } @@ -191,6 +193,10 @@ func TestVolumeMounterUnmounter(t *testing.T) { } } + if sio.isMultiMap { + t.Errorf("SetUp() - expecting multiple volume disabled by default") + } + // rebuild spec builtSpec, err := sioPlug.ConstructVolumeSpec(volume.NewSpecFromVolume(vol).Name(), path) if err != nil { @@ -235,25 +241,23 @@ func TestVolumeProvisioner(t *testing.T) { plug, err := plugMgr.FindPluginByName(sioPluginName) if err != nil { - t.Errorf("Can't find the plugin %v", sioPluginName) + t.Fatalf("Can't find the plugin %v", sioPluginName) } sioPlug, ok := plug.(*sioPlugin) if !ok { - t.Errorf("Cannot assert plugin to be type sioPlugin") + t.Fatal("Cannot assert plugin to be type sioPlugin") } options := volume.VolumeOptions{ ClusterName: "testcluster", - PVName: "pvc-sio-dynamic-vol", PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}), PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, } + options.PVC.Name = "testpvc" options.PVC.Namespace = testns - // incomplete options, test should fail - _, err = sioPlug.NewProvisioner(options) - if err == nil { - t.Fatal("expected failure due to incomplete options") + options.PVC.Spec.AccessModes = []api.PersistentVolumeAccessMode{ + api.ReadOnlyMany, } options.Parameters = map[string]string{ @@ -288,10 +292,9 @@ func TestVolumeProvisioner(t *testing.T) { // validate provision actualSpecName := spec.Name actualVolName := spec.Spec.PersistentVolumeSource.ScaleIO.VolumeName - if !strings.HasPrefix(actualSpecName, "pvc-") { - t.Errorf("expecting volume name to start with pov-, got %s", actualSpecName) + if !strings.HasPrefix(actualSpecName, "k8svol-") { + t.Errorf("expecting volume name to start with k8svol-, got %s", actualSpecName) } - vol, err := sio.FindVolume(actualVolName) if err != nil { t.Fatalf("failed getting volume %v: %v", actualVolName, err) @@ -299,6 +302,9 @@ func TestVolumeProvisioner(t *testing.T) { if vol.Name != actualVolName { t.Errorf("expected volume name to be %s, got %s", actualVolName, vol.Name) } + if vol.SizeInKb != 8*1024*1024 { + glog.V(4).Info(log("unexpected volume size")) + } // mount dynamic vol sioMounter, err := sioPlug.NewMounter( @@ -315,8 +321,14 @@ func TestVolumeProvisioner(t *testing.T) { } sioVol.sioMgr.client = sio if err := sioMounter.SetUp(nil); err != nil { - t.Errorf("Expected success, got: %v", err) + t.Fatalf("Expected success, got: %v", err) + } + + // isMultiMap applied + if !sio.isMultiMap { + t.Errorf("SetUp() expecting attached volume with multi-mapping") } + // teardown dynamic vol sioUnmounter, err := sioPlug.NewUnmounter(spec.Name, podUID) if err != nil { @@ -351,3 +363,83 @@ func TestVolumeProvisioner(t *testing.T) { t.Errorf("Deleter did not delete path %v: %v", path, err) } } + +func TestVolumeProvisionerWithIncompleteConfig(t *testing.T) { + plugMgr, tmpDir := newPluginMgr(t) + defer os.RemoveAll(tmpDir) + + plug, err := plugMgr.FindPluginByName(sioPluginName) + if err != nil { + t.Fatalf("Can't find the plugin %v", sioPluginName) + } + sioPlug, ok := plug.(*sioPlugin) + if !ok { + t.Fatal("Cannot assert plugin to be type sioPlugin") + } + + options := volume.VolumeOptions{ + ClusterName: "testcluster", + PVName: "pvc-sio-dynamic-vol", + PVC: volumetest.CreateTestPVC("100Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}), + PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, + } + options.PVC.Namespace = testns + + options.PVC.Spec.AccessModes = []api.PersistentVolumeAccessMode{ + api.ReadWriteOnce, + } + + // incomplete options, test should fail + _, err = sioPlug.NewProvisioner(options) + if err == nil { + t.Fatal("expected failure due to incomplete options") + } +} + +func TestVolumeProvisionerWithZeroCapacity(t *testing.T) { + plugMgr, tmpDir := newPluginMgr(t) + defer os.RemoveAll(tmpDir) + + plug, err := plugMgr.FindPluginByName(sioPluginName) + if err != nil { + t.Fatalf("Can't find the plugin %v", sioPluginName) + } + sioPlug, ok := plug.(*sioPlugin) + if !ok { + t.Fatal("Cannot assert plugin to be type sioPlugin") + } + + options := volume.VolumeOptions{ + ClusterName: "testcluster", + PVName: "pvc-sio-dynamic-vol", + PVC: volumetest.CreateTestPVC("0Mi", []api.PersistentVolumeAccessMode{api.ReadWriteOnce}), + PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete, + } + options.PVC.Namespace = testns + + options.PVC.Spec.AccessModes = []api.PersistentVolumeAccessMode{ + api.ReadWriteOnce, + } + + options.Parameters = map[string]string{ + confKey.gateway: "http://test.scaleio:11111", + confKey.system: "sio", + confKey.protectionDomain: testSioPD, + confKey.storagePool: "default", + confKey.secretRef: "sio-secret", + } + + provisioner, _ := sioPlug.NewProvisioner(options) + sio := newFakeSio() + sioVol := provisioner.(*sioVolume) + if err := sioVol.setSioMgrFromConfig(); err != nil { + t.Fatalf("failed to create scaleio mgr from config: %v", err) + } + sioVol.sioMgr.client = sio + + _, err = provisioner.Provision() + if err == nil { + t.Fatalf("call to Provision() should fail with invalid capacity") + } + +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go b/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go index 4c189d96dd..2633649278 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go @@ -115,6 +115,10 @@ func (og *operationGenerator) GenerateVolumesAreAttachedFunc( volumeSpecMap := make(map[*volume.Spec]v1.UniqueVolumeName) // Iterate each volume spec and put them into a map index by the pluginName for _, volumeAttached := range attachedVolumes { + if volumeAttached.VolumeSpec == nil { + glog.Errorf("VerifyVolumesAreAttached.GenerateVolumesAreAttachedFunc: nil spec for volume %s", volumeAttached.VolumeName) + continue + } volumePlugin, err := og.volumePluginMgr.FindPluginBySpec(volumeAttached.VolumeSpec) if err != nil || volumePlugin == nil { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/util/util.go b/vendor/k8s.io/kubernetes/pkg/volume/util/util.go index a9ab2845a7..660c3c9db8 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/util/util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/util/util.go @@ -72,6 +72,15 @@ func SetReady(dir string) { // UnmountPath is a common unmount routine that unmounts the given path and // deletes the remaining directory if successful. func UnmountPath(mountPath string, mounter mount.Interface) error { + return UnmountMountPoint(mountPath, mounter, false /* extensiveMountPointCheck */) +} + +// UnmountMountPoint is a common unmount routine that unmounts the given path and +// deletes the remaining directory if successful. +// if extensiveMountPointCheck is true +// IsNotMountPoint will be called instead of IsLikelyNotMountPoint. +// IsNotMountPoint is more expensive but properly handles bind mounts. +func UnmountMountPoint(mountPath string, mounter mount.Interface, extensiveMountPointCheck bool) error { if pathExists, pathErr := PathExists(mountPath); pathErr != nil { return fmt.Errorf("Error checking if path exists: %v", pathErr) } else if !pathExists { @@ -79,16 +88,26 @@ func UnmountPath(mountPath string, mounter mount.Interface) error { return nil } - notMnt, err := mounter.IsLikelyNotMountPoint(mountPath) + var notMnt bool + var err error + + if extensiveMountPointCheck { + notMnt, err = mount.IsNotMountPoint(mounter, mountPath) + } else { + notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) + } + if err != nil { return err } + if notMnt { glog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath) return os.Remove(mountPath) } // Unmount the mount path + glog.V(4).Infof("%q is a mountpoint, unmounting", mountPath) if err := mounter.Unmount(mountPath); err != nil { return err } diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/BUILD b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/BUILD index f8b14ee149..4bf848152f 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/BUILD +++ b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/BUILD @@ -15,6 +15,7 @@ go_library( deps = [ "//pkg/api:go_default_library", "//pkg/api/pod:go_default_library", + "//pkg/apis/policy:go_default_library", "//pkg/auth/nodeidentifier:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", @@ -32,6 +33,7 @@ go_test( tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", + "//pkg/apis/policy:go_default_library", "//pkg/auth/nodeidentifier:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission.go b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission.go index 1779cf57a3..e02d1a8617 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission.go @@ -25,6 +25,7 @@ import ( "k8s.io/apiserver/pkg/admission" "k8s.io/kubernetes/pkg/api" podutil "k8s.io/kubernetes/pkg/api/pod" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/auth/nodeidentifier" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" coreinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" @@ -102,6 +103,8 @@ func (c *nodePlugin) Admit(a admission.Attributes) error { return c.admitPod(nodeName, a) case "status": return c.admitPodStatus(nodeName, a) + case "eviction": + return c.admitPodEviction(nodeName, a) default: return admission.NewForbidden(a, fmt.Errorf("unexpected pod subresource %s", a.GetSubresource())) } @@ -161,6 +164,9 @@ func (c *nodePlugin) admitPod(nodeName string, a admission.Attributes) error { if errors.IsNotFound(err) { // wasn't found in the server cache, do a live lookup before forbidding existingPod, err = c.podsGetter.Pods(a.GetNamespace()).Get(a.GetName(), v1.GetOptions{}) + if errors.IsNotFound(err) { + return err + } } if err != nil { return admission.NewForbidden(a, err) @@ -195,6 +201,45 @@ func (c *nodePlugin) admitPodStatus(nodeName string, a admission.Attributes) err } } +func (c *nodePlugin) admitPodEviction(nodeName string, a admission.Attributes) error { + switch a.GetOperation() { + case admission.Create: + // require eviction to an existing pod object + eviction, ok := a.GetObject().(*policy.Eviction) + if !ok { + return admission.NewForbidden(a, fmt.Errorf("unexpected type %T", a.GetObject())) + } + // use pod name from the admission attributes, if set, rather than from the submitted Eviction object + podName := a.GetName() + if len(podName) == 0 { + if len(eviction.Name) == 0 { + return admission.NewForbidden(a, fmt.Errorf("could not determine pod from request data")) + } + podName = eviction.Name + } + // get the existing pod from the server cache + existingPod, err := c.podsGetter.Pods(a.GetNamespace()).Get(podName, v1.GetOptions{ResourceVersion: "0"}) + if errors.IsNotFound(err) { + // wasn't found in the server cache, do a live lookup before forbidding + existingPod, err = c.podsGetter.Pods(a.GetNamespace()).Get(podName, v1.GetOptions{}) + if errors.IsNotFound(err) { + return err + } + } + if err != nil { + return admission.NewForbidden(a, err) + } + // only allow a node to evict a pod bound to itself + if existingPod.Spec.NodeName != nodeName { + return admission.NewForbidden(a, fmt.Errorf("node %s can only evict pods with spec.nodeName set to itself", nodeName)) + } + return nil + + default: + return admission.NewForbidden(a, fmt.Errorf("unexpected operation %s", a.GetOperation())) + } +} + func (c *nodePlugin) admitNode(nodeName string, a admission.Attributes) error { requestedName := a.GetName() diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission_test.go b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission_test.go index 9dbc838870..25f263cf97 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission_test.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/admission/noderestriction/admission_test.go @@ -24,6 +24,8 @@ import ( "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authentication/user" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/policy" + policyapi "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/auth/nodeidentifier" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" coreinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" @@ -40,6 +42,12 @@ func makeTestPod(namespace, name, node string, mirror bool) *api.Pod { return pod } +func makeTestPodEviction(name string) *policy.Eviction { + eviction := &policy.Eviction{} + eviction.Name = name + return eviction +} + func Test_nodePlugin_Admit(t *testing.T) { var ( mynode = &user.DefaultInfo{Name: "system:node:mynode", Groups: []string{"system:nodes"}} @@ -54,12 +62,22 @@ func Test_nodePlugin_Admit(t *testing.T) { mypod = makeTestPod("ns", "mypod", "mynode", false) otherpod = makeTestPod("ns", "otherpod", "othernode", false) unboundpod = makeTestPod("ns", "unboundpod", "", false) + unnamedpod = makeTestPod("ns", "", "mynode", false) + + mymirrorpodEviction = makeTestPodEviction("mymirrorpod") + othermirrorpodEviction = makeTestPodEviction("othermirrorpod") + unboundmirrorpodEviction = makeTestPodEviction("unboundmirrorpod") + mypodEviction = makeTestPodEviction("mypod") + otherpodEviction = makeTestPodEviction("otherpod") + unboundpodEviction = makeTestPodEviction("unboundpod") + unnamedEviction = makeTestPodEviction("") configmapResource = api.Resource("configmap").WithVersion("v1") configmapKind = api.Kind("ConfigMap").WithVersion("v1") - podResource = api.Resource("pods").WithVersion("v1") - podKind = api.Kind("Pod").WithVersion("v1") + podResource = api.Resource("pods").WithVersion("v1") + podKind = api.Kind("Pod").WithVersion("v1") + evictionKind = policyapi.Kind("Eviction").WithVersion("v1beta1") nodeResource = api.Resource("nodes").WithVersion("v1") nodeKind = api.Kind("Node").WithVersion("v1") @@ -123,6 +141,30 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "allow create of eviction for mirror pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "", + }, + { + name: "forbid update of eviction for mirror pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for mirror pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mymirrorpodEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "allow create of unnamed eviction for mirror pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mymirrorpod.Namespace, mymirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "", + }, // Mirror pods bound to another node { @@ -161,6 +203,30 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "forbid create of eviction for mirror pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, + { + name: "forbid update of eviction for mirror pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for mirror pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(othermirrorpodEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of unnamed eviction for mirror pod to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, othermirrorpod.Namespace, othermirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, // Mirror pods not bound to any node { @@ -199,6 +265,30 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "forbid create of eviction for mirror pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, + { + name: "forbid update of eviction for mirror pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for mirror pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundmirrorpodEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of unnamed eviction for mirror pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundmirrorpod.Namespace, unboundmirrorpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, // Normal pods bound to us { @@ -237,6 +327,24 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, mypod.Namespace, mypod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "forbid update of eviction for normal pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for normal pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "allow create of unnamed eviction for normal pod bound to self", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + err: "", + }, // Normal pods bound to another { @@ -275,6 +383,30 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, otherpod.Namespace, otherpod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "forbid create of eviction for normal pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, + { + name: "forbid update of eviction for normal pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for normal pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(otherpodEviction, nil, evictionKind, otherpodEviction.Namespace, otherpodEviction.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of eviction for normal pod bound to another", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, otherpod.Namespace, otherpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, // Normal pods not bound to any node { @@ -313,6 +445,30 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "status", admission.Delete, mynode), err: "forbidden: unexpected operation", }, + { + name: "forbid create of eviction for normal pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, + { + name: "forbid update of eviction for normal pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for normal pod unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unboundpodEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of unnamed eviction for normal unbound", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unboundpod.Namespace, unboundpod.Name, podResource, "eviction", admission.Create, mynode), + err: "spec.nodeName set to itself", + }, // Missing pod { @@ -321,6 +477,57 @@ func Test_nodePlugin_Admit(t *testing.T) { attributes: admission.NewAttributesRecord(nil, nil, podKind, unboundpod.Namespace, unboundpod.Name, podResource, "", admission.Delete, mynode), err: "not found", }, + { + name: "forbid create of eviction for unknown pod", + podsGetter: noExistingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + err: "not found", + }, + { + name: "forbid update of eviction for unknown pod", + podsGetter: noExistingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for unknown pod", + podsGetter: noExistingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of unnamed eviction for unknown pod", + podsGetter: noExistingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, mypod.Namespace, mypod.Name, podResource, "eviction", admission.Create, mynode), + err: "not found", + }, + + // Eviction for unnamed pod + { + name: "allow create of eviction for unnamed pod", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, mynode), + // use the submitted eviction resource name as the pod name + err: "", + }, + { + name: "forbid update of eviction for unnamed pod", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Update, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid delete of eviction for unnamed pod", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(mypodEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Delete, mynode), + err: "forbidden: unexpected operation", + }, + { + name: "forbid create of unnamed eviction for unnamed pod", + podsGetter: existingPods, + attributes: admission.NewAttributesRecord(unnamedEviction, nil, evictionKind, unnamedpod.Namespace, unnamedpod.Name, podResource, "eviction", admission.Create, mynode), + err: "could not determine pod from request data", + }, // Resource pods { diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index 1697ad680d..876f52f469 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -113,6 +113,9 @@ func NodeRules() []rbac.PolicyRule { // Needed for the node to report status of pods it is running. // Use the NodeRestriction admission plugin to limit a node to updating status of pods bound to itself. rbac.NewRule("update").Groups(legacyGroup).Resources("pods/status").RuleOrDie(), + // Needed for the node to create pod evictions. + // Use the NodeRestriction admission plugin to limit a node to creating evictions for pods bound to itself. + rbac.NewRule("create").Groups(legacyGroup).Resources("pods/eviction").RuleOrDie(), // Needed for imagepullsecrets, rbd/ceph and secret volumes, and secrets in envs // Needed for configmap volume and envs diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml index d5c47f0fa6..bb1205bb9d 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml +++ b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml @@ -678,6 +678,12 @@ items: - pods/status verbs: - update + - apiGroups: + - "" + resources: + - pods/eviction + verbs: + - create - apiGroups: - "" resources: diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates.go index 95939bf504..e2f8cd690d 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates.go @@ -522,8 +522,7 @@ func GetResourceRequest(pod *v1.Pod) *schedulercache.Resource { // Account for storage requested by emptydir volumes // If the storage medium is memory, should exclude the size for _, vol := range pod.Spec.Volumes { - if vol.EmptyDir != nil && vol.EmptyDir.Medium != v1.StorageMediumMemory { - + if vol.EmptyDir != nil && vol.EmptyDir.SizeLimit != nil && vol.EmptyDir.Medium != v1.StorageMediumMemory { result.StorageScratch += vol.EmptyDir.SizeLimit.Value() } } @@ -1234,15 +1233,26 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node } func PodToleratesNodeTaints(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) { + return podToleratesNodeTaints(pod, nodeInfo, func(t *v1.Taint) bool { + // PodToleratesNodeTaints is only interested in NoSchedule and NoExecute taints. + return t.Effect == v1.TaintEffectNoSchedule || t.Effect == v1.TaintEffectNoExecute + }) +} + +// PodToleratesNodeNoExecuteTaints checks if a pod tolertaions can tolerate the node's NoExecute taints +func PodToleratesNodeNoExecuteTaints(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) { + return podToleratesNodeTaints(pod, nodeInfo, func(t *v1.Taint) bool { + return t.Effect == v1.TaintEffectNoExecute + }) +} + +func podToleratesNodeTaints(pod *v1.Pod, nodeInfo *schedulercache.NodeInfo, filter func(t *v1.Taint) bool) (bool, []algorithm.PredicateFailureReason, error) { taints, err := nodeInfo.Taints() if err != nil { return false, nil, err } - if v1helper.TolerationsTolerateTaintsWithFilter(pod.Spec.Tolerations, taints, func(t *v1.Taint) bool { - // PodToleratesNodeTaints is only interested in NoSchedule and NoExecute taints. - return t.Effect == v1.TaintEffectNoSchedule || t.Effect == v1.TaintEffectNoExecute - }) { + if v1helper.TolerationsTolerateTaintsWithFilter(pod.Spec.Tolerations, taints, filter) { return true, nil, nil } return false, []algorithm.PredicateFailureReason{ErrTaintsTolerationsNotMatch}, nil diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go index a410641e19..ab26a8062f 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go @@ -81,24 +81,24 @@ var ( func makeResources(milliCPU, memory, nvidiaGPUs, pods, opaqueA, storage int64) v1.NodeResources { return v1.NodeResources{ Capacity: v1.ResourceList{ - v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), - v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), - v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI), - v1.ResourceNvidiaGPU: *resource.NewQuantity(nvidiaGPUs, resource.DecimalSI), - opaqueResourceA: *resource.NewQuantity(opaqueA, resource.DecimalSI), - v1.ResourceStorage: *resource.NewQuantity(storage, resource.BinarySI), + v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), + v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI), + v1.ResourceNvidiaGPU: *resource.NewQuantity(nvidiaGPUs, resource.DecimalSI), + opaqueResourceA: *resource.NewQuantity(opaqueA, resource.DecimalSI), + v1.ResourceStorageScratch: *resource.NewQuantity(storage, resource.BinarySI), }, } } func makeAllocatableResources(milliCPU, memory, nvidiaGPUs, pods, opaqueA, storage int64) v1.ResourceList { return v1.ResourceList{ - v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), - v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), - v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI), - v1.ResourceNvidiaGPU: *resource.NewQuantity(nvidiaGPUs, resource.DecimalSI), - opaqueResourceA: *resource.NewQuantity(opaqueA, resource.DecimalSI), - v1.ResourceStorage: *resource.NewQuantity(storage, resource.BinarySI), + v1.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI), + v1.ResourcePods: *resource.NewQuantity(pods, resource.DecimalSI), + v1.ResourceNvidiaGPU: *resource.NewQuantity(nvidiaGPUs, resource.DecimalSI), + opaqueResourceA: *resource.NewQuantity(opaqueA, resource.DecimalSI), + v1.ResourceStorageScratch: *resource.NewQuantity(storage, resource.BinarySI), } } @@ -125,7 +125,7 @@ func addStorageLimit(pod *v1.Pod, sizeLimit int64, medium v1.StorageMedium) *v1. Name: "emptyDirVolumeName", VolumeSource: v1.VolumeSource{ EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(sizeLimit, resource.BinarySI), + SizeLimit: resource.NewQuantity(sizeLimit, resource.BinarySI), Medium: medium, }, }, diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler.go index f13f2f5c9e..2c91cbb58e 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler.go @@ -36,8 +36,6 @@ import ( "k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache" "k8s.io/kubernetes/plugin/pkg/scheduler/util" - "fmt" - "github.com/golang/glog" ) @@ -186,21 +184,29 @@ func (sched *Scheduler) schedule(pod *v1.Pod) (string, error) { } // assume signals to the cache that a pod is already in the cache, so that binding can be asnychronous. -func (sched *Scheduler) assume(pod *v1.Pod, host string) error { +// assume modifies `assumed`. +func (sched *Scheduler) assume(assumed *v1.Pod, host string) error { // Optimistically assume that the binding will succeed and send it to apiserver // in the background. // If the binding fails, scheduler will release resources allocated to assumed pod // immediately. - assumed := *pod assumed.Spec.NodeName = host - if err := sched.config.SchedulerCache.AssumePod(&assumed); err != nil { + if err := sched.config.SchedulerCache.AssumePod(assumed); err != nil { glog.Errorf("scheduler cache AssumePod failed: %v", err) - // TODO: This means that a given pod is already in cache (which means it - // is either assumed or already added). This is most probably result of a - // BUG in retrying logic. As a temporary workaround (which doesn't fully - // fix the problem, but should reduce its impact), we simply return here, - // as binding doesn't make sense anyway. - // This should be fixed properly though. + + // This is most probably result of a BUG in retrying logic. + // We report an error here so that pod scheduling can be retried. + // This relies on the fact that Error will check if the pod has been bound + // to a node and if so will not add it back to the unscheduled pods queue + // (otherwise this would cause an infinite loop). + sched.config.Error(assumed, err) + sched.config.Recorder.Eventf(assumed, v1.EventTypeWarning, "FailedScheduling", "AssumePod failed: %v", err) + sched.config.PodConditionUpdater.Update(assumed, &v1.PodCondition{ + Type: v1.PodScheduled, + Status: v1.ConditionFalse, + Reason: "SchedulerError", + Message: err.Error(), + }) return err } @@ -208,7 +214,7 @@ func (sched *Scheduler) assume(pod *v1.Pod, host string) error { // predicates in equivalence cache. // If the binding fails, these invalidated item will not break anything. if sched.config.Ecache != nil { - sched.config.Ecache.InvalidateCachedPredicateItemForPodAdd(pod, host) + sched.config.Ecache.InvalidateCachedPredicateItemForPodAdd(assumed, host) } return nil } @@ -221,12 +227,12 @@ func (sched *Scheduler) bind(assumed *v1.Pod, b *v1.Binding) error { // it's atomic with setting host. err := sched.config.Binder.Bind(b) if err := sched.config.SchedulerCache.FinishBinding(assumed); err != nil { - return fmt.Errorf("scheduler cache FinishBinding failed: %v", err) + glog.Errorf("scheduler cache FinishBinding failed: %v", err) } if err != nil { glog.V(1).Infof("Failed to bind pod: %v/%v", assumed.Namespace, assumed.Name) if err := sched.config.SchedulerCache.ForgetPod(assumed); err != nil { - return fmt.Errorf("scheduler cache ForgetPod failed: %v", err) + glog.Errorf("scheduler cache ForgetPod failed: %v", err) } sched.config.Error(assumed, err) sched.config.Recorder.Eventf(assumed, v1.EventTypeWarning, "FailedScheduling", "Binding rejected: %v", err) @@ -237,6 +243,7 @@ func (sched *Scheduler) bind(assumed *v1.Pod, b *v1.Binding) error { }) return err } + metrics.BindingLatency.Observe(metrics.SinceInMicroseconds(bindingStart)) sched.config.Recorder.Eventf(assumed, v1.EventTypeNormal, "Scheduled", "Successfully assigned %v to %v", assumed.Name, b.Target.Name) return nil @@ -263,15 +270,17 @@ func (sched *Scheduler) scheduleOne() { // Tell the cache to assume that a pod now is running on a given node, even though it hasn't been bound yet. // This allows us to keep scheduling without waiting on binding to occur. - err = sched.assume(pod, suggestedHost) + assumedPod := *pod + // assume modifies `assumedPod` by setting NodeName=suggestedHost + err = sched.assume(&assumedPod, suggestedHost) if err != nil { return } // bind the pod to its host asynchronously (we can do this b/c of the assumption step above). go func() { - err := sched.bind(pod, &v1.Binding{ - ObjectMeta: metav1.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name, UID: pod.UID}, + err := sched.bind(&assumedPod, &v1.Binding{ + ObjectMeta: metav1.ObjectMeta{Namespace: assumedPod.Namespace, Name: assumedPod.Name, UID: assumedPod.UID}, Target: v1.ObjectReference{ Kind: "Node", Name: suggestedHost, diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler_test.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler_test.go index e9c4c21fd9..3245451017 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler_test.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/scheduler_test.go @@ -116,6 +116,7 @@ func TestScheduler(t *testing.T) { sendPod *v1.Pod algo algorithm.ScheduleAlgorithm expectErrorPod *v1.Pod + expectForgetPod *v1.Pod expectAssumedPod *v1.Pod expectError error expectBind *v1.Binding @@ -140,7 +141,8 @@ func TestScheduler(t *testing.T) { expectAssumedPod: podWithID("foo", testNode.Name), injectBindError: errB, expectError: errB, - expectErrorPod: podWithID("foo", ""), + expectErrorPod: podWithID("foo", testNode.Name), + expectForgetPod: podWithID("foo", testNode.Name), eventReason: "FailedScheduling", }, { sendPod: deletingPod("foo"), @@ -152,11 +154,15 @@ func TestScheduler(t *testing.T) { for i, item := range table { var gotError error var gotPod *v1.Pod + var gotForgetPod *v1.Pod var gotAssumedPod *v1.Pod var gotBinding *v1.Binding configurator := &FakeConfigurator{ Config: &Config{ SchedulerCache: &schedulertesting.FakeCache{ + ForgetFunc: func(pod *v1.Pod) { + gotForgetPod = pod + }, AssumeFunc: func(pod *v1.Pod) { gotAssumedPod = pod }, @@ -197,6 +203,9 @@ func TestScheduler(t *testing.T) { if e, a := item.expectErrorPod, gotPod; !reflect.DeepEqual(e, a) { t.Errorf("%v: error pod: wanted %v, got %v", i, e, a) } + if e, a := item.expectForgetPod, gotForgetPod; !reflect.DeepEqual(e, a) { + t.Errorf("%v: forget pod: wanted %v, got %v", i, e, a) + } if e, a := item.expectError, gotError; !reflect.DeepEqual(e, a) { t.Errorf("%v: error: wanted %v, got %v", i, e, a) } diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache/node_info.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache/node_info.go index 4717b1d8e8..5b56943e26 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache/node_info.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache/node_info.go @@ -80,6 +80,7 @@ func (r *Resource) ResourceList() v1.ResourceList { v1.ResourceMemory: *resource.NewQuantity(r.Memory, resource.BinarySI), v1.ResourceNvidiaGPU: *resource.NewQuantity(r.NvidiaGPU, resource.DecimalSI), v1.ResourceStorageOverlay: *resource.NewQuantity(r.StorageOverlay, resource.BinarySI), + v1.ResourceStorageScratch: *resource.NewQuantity(r.StorageScratch, resource.BinarySI), } for rName, rQuant := range r.OpaqueIntResources { result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI) @@ -372,7 +373,7 @@ func calculateResource(pod *v1.Pod) (res Resource, non0_cpu int64, non0_mem int6 // Account for storage requested by emptydir volumes // If the storage medium is memory, should exclude the size for _, vol := range pod.Spec.Volumes { - if vol.EmptyDir != nil && vol.EmptyDir.Medium != v1.StorageMediumMemory { + if vol.EmptyDir != nil && vol.EmptyDir.SizeLimit != nil && vol.EmptyDir.Medium != v1.StorageMediumMemory { res.StorageScratch += vol.EmptyDir.SizeLimit.Value() } } @@ -407,7 +408,7 @@ func (n *NodeInfo) SetNode(node *v1.Node) error { n.allocatableResource.NvidiaGPU = rQuant.Value() case v1.ResourcePods: n.allowedPodNumber = int(rQuant.Value()) - case v1.ResourceStorage: + case v1.ResourceStorageScratch: n.allocatableResource.StorageScratch = rQuant.Value() case v1.ResourceStorageOverlay: n.allocatableResource.StorageOverlay = rQuant.Value() diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/testing/fake_cache.go b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/testing/fake_cache.go index 1e302d3c24..068ac9ce1b 100644 --- a/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/testing/fake_cache.go +++ b/vendor/k8s.io/kubernetes/plugin/pkg/scheduler/testing/fake_cache.go @@ -25,6 +25,7 @@ import ( // FakeCache is used for testing type FakeCache struct { AssumeFunc func(*v1.Pod) + ForgetFunc func(*v1.Pod) } func (f *FakeCache) AssumePod(pod *v1.Pod) error { @@ -34,7 +35,10 @@ func (f *FakeCache) AssumePod(pod *v1.Pod) error { func (f *FakeCache) FinishBinding(pod *v1.Pod) error { return nil } -func (f *FakeCache) ForgetPod(pod *v1.Pod) error { return nil } +func (f *FakeCache) ForgetPod(pod *v1.Pod) error { + f.ForgetFunc(pod) + return nil +} func (f *FakeCache) AddPod(pod *v1.Pod) error { return nil } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go index cf60827ae7..feb97447f2 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go @@ -343,8 +343,17 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti storage: storage, requestScope: requestScope, } - storageMap[crd.UID] = ret - r.customStorage.Store(storageMap) + + storageMap2 := make(crdStorageMap, len(storageMap)) + + // Copy because we cannot write to storageMap without a race + // as it is used without locking elsewhere + for k, v := range storageMap { + storageMap2[k] = v + } + + storageMap2[crd.UID] = ret + r.customStorage.Store(storageMap2) return ret } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go index ad300e28b5..12bef075da 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/httpstream/spdy/roundtripper.go @@ -158,15 +158,16 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) { return nil, err } - if s.tlsConfig == nil { - s.tlsConfig = &tls.Config{} + tlsConfig := s.tlsConfig + switch { + case tlsConfig == nil: + tlsConfig = &tls.Config{ServerName: host} + case len(tlsConfig.ServerName) == 0: + tlsConfig = tlsConfig.Clone() + tlsConfig.ServerName = host } - if len(s.tlsConfig.ServerName) == 0 { - s.tlsConfig.ServerName = host - } - - tlsConn := tls.Client(rwc, s.tlsConfig) + tlsConn := tls.Client(rwc, tlsConfig) // need to manually call Handshake() so we can call VerifyHostname() below if err := tlsConn.Handshake(); err != nil { @@ -174,11 +175,11 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) { } // Return if we were configured to skip validation - if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify { + if tlsConfig.InsecureSkipVerify { return tlsConn, nil } - if err := tlsConn.VerifyHostname(host); err != nil { + if err := tlsConn.VerifyHostname(tlsConfig.ServerName); err != nil { return nil, err } @@ -218,6 +219,9 @@ func (s *SpdyRoundTripper) dialWithoutProxy(url *url.URL) (net.Conn, error) { if err != nil { return nil, err } + if s.tlsConfig != nil && len(s.tlsConfig.ServerName) > 0 { + host = s.tlsConfig.ServerName + } err = conn.VerifyHostname(host) if err != nil { return nil, err diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go index 828df44351..8884c738ed 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch.go @@ -1138,7 +1138,7 @@ func mergePatchIntoOriginal(original, patch map[string]interface{}, t reflect.Ty return err } case !foundOriginal && !foundPatch: - return nil + continue } // Split all items into patch items and server-only items and then enforce the order. diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go index 507c8cffa1..7f6372db6a 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go @@ -5966,6 +5966,75 @@ retainKeysMergingList: retainKeysMergingList: - name: bar - name: foo +`), + }, + }, + { + Description: "delete and reorder in one list, reorder in another", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: +- name: a + value: a +- name: b + value: b +mergeItemPtr: +- name: c + value: c +- name: d + value: d +`), + Current: []byte(` +mergingList: +- name: a + value: a +- name: b + value: b +mergeItemPtr: +- name: c + value: c +- name: d + value: d +`), + Modified: []byte(` +mergingList: +- name: b + value: b +mergeItemPtr: +- name: d + value: d +- name: c + value: c +`), + TwoWay: []byte(` +$setElementOrder/mergingList: +- name: b +$setElementOrder/mergeItemPtr: +- name: d +- name: c +mergingList: +- $patch: delete + name: a +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: +- name: b +$setElementOrder/mergeItemPtr: +- name: d +- name: c +mergingList: +- $patch: delete + name: a +`), + Result: []byte(` +mergingList: +- name: b + value: b +mergeItemPtr: +- name: d + value: d +- name: c + value: c `), }, }, @@ -5993,9 +6062,12 @@ func TestStrategicMergePatch(t *testing.T) { testThreeWayPatch(t, c) } - for _, c := range strategicMergePatchRawTestCases { - testTwoWayPatchForRawTestCase(t, c) - testThreeWayPatchForRawTestCase(t, c) + // run multiple times to exercise different map traversal orders + for i := 0; i < 10; i++ { + for _, c := range strategicMergePatchRawTestCases { + testTwoWayPatchForRawTestCase(t, c) + testThreeWayPatchForRawTestCase(t, c) + } } } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/Godeps/Godeps.json b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/Godeps/Godeps.json index 7f6082d50e..6801e750d5 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/Godeps/Godeps.json +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/Godeps/Godeps.json @@ -252,23 +252,23 @@ }, { "ImportPath": "github.com/coreos/go-oidc/http", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/jose", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/key", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oauth2", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oidc", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-semver/semver", @@ -416,31 +416,31 @@ }, { "ImportPath": "github.com/gophercloud/gophercloud", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/gophercloud/gophercloud/pagination", - "Rev": "ce1e02c3ccfdb7fab257340dc4d603ec3035fa11" + "Rev": "ed590d9afe113c6107cd60717b196155e6579e78" }, { "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go index e01445621e..2ee881a604 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission.go @@ -105,6 +105,11 @@ func (l *lifecycle) Admit(a admission.Attributes) error { return nil } + // always allow deletion of other resources + if a.GetOperation() == admission.Delete { + return nil + } + // always allow access review checks. Returning status about the namespace would be leaking information if isAccessReview(a) { return nil diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index 7b2e2b0641..0fd9d7ab56 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -135,6 +135,24 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { } t.Errorf("expected error returned from admission handler: %v", actions) } + + // verify create operations in the namespace cause an error + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, nil)) + if err == nil { + t.Errorf("Expected error rejecting creates in a namespace when it is missing") + } + + // verify update operations in the namespace cause an error + err = handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, nil)) + if err == nil { + t.Errorf("Expected error rejecting updates in a namespace when it is missing") + } + + // verify delete operations in the namespace can proceed + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, nil)) + if err != nil { + t.Errorf("Unexpected error returned from admission handler: %v", err) + } } // TestAdmissionNamespaceActive verifies a resource is admitted when the namespace is active. diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index d0ecf6c6d2..971fff58ef 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -575,6 +575,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag routes := []*restful.RouteBuilder{} + // If there is a subresource, kind should be the parent's kind. + if hasSubresource { + fqParentKind, err := a.getResourceKind(resource, a.group.Storage[resource]) + if err != nil { + return nil, err + } + kind = fqParentKind.Kind + } switch action.Verb { case "GET": // Get a resource. var handler restful.RouteFunction diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go index 271a30db3d..182c51796d 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go @@ -63,10 +63,6 @@ func GetOperationIDAndTags(r *restful.Route) (string, []string, error) { op := r.Operation path := r.Path var tags []string - // TODO: This is hacky, figure out where this name conflict is created and fix it at the root. - if strings.HasPrefix(path, "/apis/extensions/v1beta1/namespaces/{namespace}/") && strings.HasSuffix(op, "ScaleScale") { - op = op[:len(op)-10] + strings.Title(strings.Split(path[48:], "/")[0]) + "Scale" - } prefix, exists := verbs.GetPrefix(op) if !exists { return op, tags, fmt.Errorf("operation names should start with a verb. Cannot determine operation verb from %v", op) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go index 2dcea903a0..2153c16c5b 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go @@ -403,12 +403,8 @@ func (e *Store) WaitForInitialized(ctx genericapirequest.Context, obj runtime.Ob // shouldDeleteDuringUpdate checks if a Update is removing all the object's // finalizers. If so, it further checks if the object's -// DeletionGracePeriodSeconds is 0. If so, it returns true. If garbage collection -// is disabled it always returns false. +// DeletionGracePeriodSeconds is 0. If so, it returns true. func (e *Store) shouldDeleteDuringUpdate(ctx genericapirequest.Context, key string, obj, existing runtime.Object) bool { - if !e.EnableGarbageCollection { - return false - } newMeta, err := meta.Accessor(obj) if err != nil { utilruntime.HandleError(err) @@ -719,9 +715,18 @@ func shouldUpdateFinalizerDeleteDependents(e *Store, accessor metav1.Object, opt return shouldUpdate, shouldDeleteDependentInForeground } -// shouldUpdateFinalizers returns if we need to update the finalizers of the -// object, and the desired list of finalizers. -func shouldUpdateFinalizers(e *Store, accessor metav1.Object, options *metav1.DeleteOptions) (shouldUpdate bool, newFinalizers []string) { +// deletionFinalizersForGarbageCollection analyzes the object and delete options +// to determine whether the object is in need of finalization by the garbage +// collector. If so, returns the set of deletion finalizers to apply and a bool +// indicating whether the finalizer list has changed and is in need of updating. +// +// The finalizers returned are intended to be handled by the garbage collector. +// If garbage collection is disabled for the store, this function returns false +// to ensure finalizers aren't set which will never be cleared. +func deletionFinalizersForGarbageCollection(e *Store, accessor metav1.Object, options *metav1.DeleteOptions) (shouldUpdate bool, newFinalizers []string) { + if !e.EnableGarbageCollection { + return false, []string{} + } shouldUpdate1, shouldOrphan := shouldUpdateFinalizerOrphanDependents(e, accessor, options) shouldUpdate2, shouldDeleteDependentInForeground := shouldUpdateFinalizerDeleteDependents(e, accessor, options) oldFinalizers := accessor.GetFinalizers() @@ -766,72 +771,6 @@ func markAsDeleting(obj runtime.Object) (err error) { return nil } -// updateForGracefulDeletion and updateForGracefulDeletionAndFinalizers both -// implement deletion flows for graceful deletion. Graceful deletion is -// implemented as setting the deletion timestamp in an update. If the -// implementation of graceful deletion is changed, both of these methods -// should be changed together. - -// updateForGracefulDeletion updates the given object for graceful deletion by -// setting the deletion timestamp and grace period seconds and returns: -// -// 1. an error -// 2. a boolean indicating that the object was not found, but it should be -// ignored -// 3. a boolean indicating that the object's grace period is exhausted and it -// should be deleted immediately -// 4. a new output object with the state that was updated -// 5. a copy of the last existing state of the object -func (e *Store) updateForGracefulDeletion(ctx genericapirequest.Context, name, key string, options *metav1.DeleteOptions, preconditions storage.Preconditions, in runtime.Object) (err error, ignoreNotFound, deleteImmediately bool, out, lastExisting runtime.Object) { - lastGraceful := int64(0) - out = e.NewFunc() - err = e.Storage.GuaranteedUpdate( - ctx, - key, - out, - false, /* ignoreNotFound */ - &preconditions, - storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) { - graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, existing, options) - if err != nil { - return nil, err - } - if pendingGraceful { - return nil, errAlreadyDeleting - } - if !graceful { - return nil, errDeleteNow - } - lastGraceful = *options.GracePeriodSeconds - lastExisting = existing - return existing, nil - }), - ) - switch err { - case nil: - if lastGraceful > 0 { - return nil, false, false, out, lastExisting - } - // If we are here, the registry supports grace period mechanism and - // we are intentionally delete gracelessly. In this case, we may - // enter a race with other k8s components. If other component wins - // the race, the object will not be found, and we should tolerate - // the NotFound error. See - // https://github.com/kubernetes/kubernetes/issues/19403 for - // details. - return nil, true, true, out, lastExisting - case errDeleteNow: - // we've updated the object to have a zero grace period, or it's already at 0, so - // we should fall through and truly delete the object. - return nil, false, true, out, lastExisting - case errAlreadyDeleting: - out, err = e.finalizeDelete(in, true) - return err, false, false, out, lastExisting - default: - return storeerr.InterpretUpdateError(err, e.QualifiedResource, name), false, false, out, lastExisting - } -} - // updateForGracefulDeletionAndFinalizers updates the given object for // graceful deletion and finalization by setting the deletion timestamp and // grace period seconds (graceful deletion) and updating the list of @@ -871,7 +810,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx genericapirequest.Con if err != nil { return nil, err } - shouldUpdate, newFinalizers := shouldUpdateFinalizers(e, existingAccessor, options) + shouldUpdate, newFinalizers := deletionFinalizersForGarbageCollection(e, existingAccessor, options) if shouldUpdate { existingAccessor.SetFinalizers(newFinalizers) } @@ -963,18 +902,12 @@ func (e *Store) Delete(ctx genericapirequest.Context, name string, options *meta // Handle combinations of graceful deletion and finalization by issuing // the correct updates. - if e.EnableGarbageCollection { - shouldUpdateFinalizers, _ := shouldUpdateFinalizers(e, accessor, options) - // TODO: remove the check, because we support no-op updates now. - if graceful || pendingFinalizers || shouldUpdateFinalizers { - err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, obj) - } - } else { - // TODO: remove the check on graceful, because we support no-op updates now. - if graceful { - err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletion(ctx, name, key, options, preconditions, obj) - } + shouldUpdateFinalizers, _ := deletionFinalizersForGarbageCollection(e, accessor, options) + // TODO: remove the check, because we support no-op updates now. + if graceful || pendingFinalizers || shouldUpdateFinalizers { + err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, obj) } + // !deleteImmediately covers all cases where err != nil. We keep both to be future-proof. if !deleteImmediately || err != nil { return out, false, err diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go index fa61ac97b9..096517a662 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go @@ -923,56 +923,62 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) - registry.EnableGarbageCollection = true defaultDeleteStrategy := testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} defer destroyFunc() - // create pod - _, err := registry.Create(testContext, podWithFinalizer, false) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - // delete the pod with grace period=0, the pod should still exist because it has a finalizer - _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, metav1.NewDeleteOptions(0)) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if wasDeleted { - t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name) - } - _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + gcStates := []bool{true, false} + for _, gcEnabled := range gcStates { + t.Logf("garbage collection enabled: %t", gcEnabled) + registry.EnableGarbageCollection = gcEnabled - updatedPodWithFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, - Spec: example.PodSpec{NodeName: "machine"}, - } - _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme)) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + // create pod + _, err := registry.Create(testContext, podWithFinalizer, false) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } - // the object should still exist, because it still has a finalizer - _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + // delete the pod with grace period=0, the pod should still exist because it has a finalizer + _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, metav1.NewDeleteOptions(0)) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if wasDeleted { + t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name) + } + _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } - podWithNoFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, - Spec: example.PodSpec{NodeName: "anothermachine"}, - } - _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme)) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - // the pod should be removed, because its finalizer is removed - _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if !errors.IsNotFound(err) { - t.Fatalf("Unexpected error: %v", err) + updatedPodWithFinalizer := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, + Spec: example.PodSpec{NodeName: "machine"}, + } + _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme)) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // the object should still exist, because it still has a finalizer + _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + podWithNoFinalizer := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, + Spec: example.PodSpec{NodeName: "anothermachine"}, + } + _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme)) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + // the pod should be removed, because its finalizer is removed + _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if !errors.IsNotFound(err) { + t.Fatalf("Unexpected error: %v", err) + } } } @@ -1022,73 +1028,79 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) - registry.EnableGarbageCollection = true + defer destroyFunc() - // create pod - _, err := registry.Create(testContext, podWithFinalizer, false) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + gcStates := []bool{true, false} + for _, gcEnabled := range gcStates { + t.Logf("garbage collection enabled: %t", gcEnabled) + registry.EnableGarbageCollection = gcEnabled - // delete object with nil delete options doesn't delete the object - _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, nil) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if wasDeleted { - t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name) - } + // create pod + _, err := registry.Create(testContext, podWithFinalizer, false) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } - // the object should still exist - obj, err := registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - podWithFinalizer, ok := obj.(*example.Pod) - if !ok { - t.Errorf("Unexpected object: %#v", obj) - } - if podWithFinalizer.ObjectMeta.DeletionTimestamp == nil { - t.Errorf("Expect the object to have DeletionTimestamp set, but got %#v", podWithFinalizer.ObjectMeta) - } - if podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds == nil || *podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds != 0 { - t.Errorf("Expect the object to have 0 DeletionGracePeriodSecond, but got %#v", podWithFinalizer.ObjectMeta) - } - if podWithFinalizer.Generation <= initialGeneration { - t.Errorf("Deletion didn't increase Generation.") - } + // delete object with nil delete options doesn't delete the object + _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, nil) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if wasDeleted { + t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name) + } - updatedPodWithFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, - Spec: example.PodSpec{NodeName: "machine"}, - } - _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme)) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + // the object should still exist + obj, err := registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + podWithFinalizer, ok := obj.(*example.Pod) + if !ok { + t.Errorf("Unexpected object: %#v", obj) + } + if podWithFinalizer.ObjectMeta.DeletionTimestamp == nil { + t.Errorf("Expect the object to have DeletionTimestamp set, but got %#v", podWithFinalizer.ObjectMeta) + } + if podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds == nil || *podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds != 0 { + t.Errorf("Expect the object to have 0 DeletionGracePeriodSecond, but got %#v", podWithFinalizer.ObjectMeta) + } + if podWithFinalizer.Generation <= initialGeneration { + t.Errorf("Deletion didn't increase Generation.") + } - // the object should still exist, because it still has a finalizer - obj, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - podWithFinalizer, ok = obj.(*example.Pod) - if !ok { - t.Errorf("Unexpected object: %#v", obj) - } + updatedPodWithFinalizer := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, + Spec: example.PodSpec{NodeName: "machine"}, + } + _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme)) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } - podWithNoFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, - Spec: example.PodSpec{NodeName: "anothermachine"}, - } - _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme)) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - // the pod should be removed, because its finalizer is removed - _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) - if !errors.IsNotFound(err) { - t.Errorf("Unexpected error: %v", err) + // the object should still exist, because it still has a finalizer + obj, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + podWithFinalizer, ok = obj.(*example.Pod) + if !ok { + t.Errorf("Unexpected object: %#v", obj) + } + + podWithNoFinalizer := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, + Spec: example.PodSpec{NodeName: "anothermachine"}, + } + _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme)) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + // the pod should be removed, because its finalizer is removed + _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) + if !errors.IsNotFound(err) { + t.Errorf("Unexpected error: %v", err) + } } } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy.go index e6ef8cb924..6cc091b237 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy.go @@ -64,11 +64,20 @@ type ErrorResponder interface { Error(err error) } +// normalizeLocation returns the result of parsing the full URL, with scheme set to http if missing +func normalizeLocation(location *url.URL) *url.URL { + normalized, _ := url.Parse(location.String()) + if len(normalized.Scheme) == 0 { + normalized.Scheme = "http" + } + return normalized +} + // NewUpgradeAwareProxyHandler creates a new proxy handler with a default flush interval. Responder is required for returning // errors to the caller. func NewUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, wrapTransport, upgradeRequired bool, responder ErrorResponder) *UpgradeAwareProxyHandler { return &UpgradeAwareProxyHandler{ - Location: location, + Location: normalizeLocation(location), Transport: transport, WrapTransport: wrapTransport, UpgradeRequired: upgradeRequired, @@ -79,9 +88,6 @@ func NewUpgradeAwareProxyHandler(location *url.URL, transport http.RoundTripper, // ServeHTTP handles the proxy request func (h *UpgradeAwareProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if len(h.Location.Scheme) == 0 { - h.Location.Scheme = "http" - } if h.tryUpgrade(w, req) { return } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy_test.go index 96ebed4d0b..ba61d30c7f 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/registry/generic/rest/proxy_test.go @@ -248,11 +248,7 @@ func TestServeHTTP(t *testing.T) { responder := &fakeResponder{t: t} backendURL, _ := url.Parse(backendServer.URL) backendURL.Path = test.requestPath - proxyHandler := &UpgradeAwareProxyHandler{ - Location: backendURL, - Responder: responder, - UpgradeRequired: test.upgradeRequired, - } + proxyHandler := NewUpgradeAwareProxyHandler(backendURL, nil, false, test.upgradeRequired, responder) proxyServer := httptest.NewServer(proxyHandler) defer proxyServer.Close() proxyURL, _ := url.Parse(proxyServer.URL) @@ -428,12 +424,8 @@ func TestProxyUpgrade(t *testing.T) { serverURL, _ := url.Parse(backendServer.URL) serverURL.Path = backendPath - proxyHandler := &UpgradeAwareProxyHandler{ - Location: serverURL, - Transport: tc.ProxyTransport, - InterceptRedirects: redirect, - Responder: &noErrorsAllowed{t: t}, - } + proxyHandler := NewUpgradeAwareProxyHandler(serverURL, tc.ProxyTransport, false, false, &noErrorsAllowed{t: t}) + proxyHandler.InterceptRedirects = redirect proxy := httptest.NewServer(proxyHandler) defer proxy.Close() @@ -479,14 +471,15 @@ func TestProxyUpgradeErrorResponse(t *testing.T) { return &fakeConn{err: expectedErr}, nil } responder = &fakeResponder{t: t, w: w} - proxyHandler := &UpgradeAwareProxyHandler{ - Location: &url.URL{ + proxyHandler := NewUpgradeAwareProxyHandler( + &url.URL{ Host: "fake-backend", }, - UpgradeRequired: true, - Responder: responder, - Transport: transport, - } + transport, + false, + true, + responder, + ) proxyHandler.ServeHTTP(w, r) })) defer proxy.Close() @@ -545,9 +538,7 @@ func TestDefaultProxyTransport(t *testing.T) { for _, test := range tests { locURL, _ := url.Parse(test.location) URL, _ := url.Parse(test.url) - h := UpgradeAwareProxyHandler{ - Location: locURL, - } + h := NewUpgradeAwareProxyHandler(locURL, nil, false, false, nil) result := h.defaultProxyTransport(URL, nil) transport := result.(*corsRemovingTransport).RoundTripper.(*proxy.Transport) if transport.Scheme != test.expectedScheme { @@ -721,11 +712,7 @@ func TestProxyRequestContentLengthAndTransferEncoding(t *testing.T) { responder := &fakeResponder{t: t} backendURL, _ := url.Parse(downstreamServer.URL) - proxyHandler := &UpgradeAwareProxyHandler{ - Location: backendURL, - Responder: responder, - UpgradeRequired: false, - } + proxyHandler := NewUpgradeAwareProxyHandler(backendURL, nil, false, false, responder) proxyServer := httptest.NewServer(proxyHandler) defer proxyServer.Close() diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/config.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/config.go index 9708277f37..c5c26e4b8d 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -148,8 +148,11 @@ type Config struct { // RESTOptionsGetter is used to construct RESTStorage types via the generic registry. RESTOptionsGetter genericregistry.RESTOptionsGetter - // If specified, requests will be allocated a random timeout between this value, and twice this value. - // Note that it is up to the request handlers to ignore or honor this timeout. In seconds. + // If specified, all requests except those which match the LongRunningFunc predicate will timeout + // after this duration. + RequestTimeout time.Duration + // If specified, long running requests such as watch will be allocated a random timeout between this value, and + // twice this value. Note that it is up to the request handlers to ignore or honor this timeout. In seconds. MinRequestTimeout int // MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further // request has to wait. Applies only to non-mutating requests. @@ -218,6 +221,7 @@ func NewConfig(codecs serializer.CodecFactory) *Config { EnableProfiling: true, MaxRequestsInFlight: 400, MaxMutatingRequestsInFlight: 200, + RequestTimeout: time.Duration(60) * time.Second, MinRequestTimeout: 1800, // Default to treating watch as a long-running operation @@ -470,7 +474,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericapifilters.WithAuthentication(handler, c.RequestContextMapper, c.Authenticator, genericapifilters.Unauthorized(c.SupportsBasicAuth)) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithPanicRecovery(handler) - handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc) + handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.RequestContextMapper, c.LongRunningFunc) handler = genericapifilters.WithRequestInfo(handler, NewRequestInfoResolver(c), c.RequestContextMapper) handler = apirequest.WithRequestContext(handler, c.RequestContextMapper) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go index 19894b470b..69066dcc4e 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go @@ -30,12 +30,10 @@ import ( apirequest "k8s.io/apiserver/pkg/endpoints/request" ) -const globalTimeout = time.Minute - var errConnKilled = fmt.Errorf("kill connection/stream") -// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by globalTimeout. -func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, longRunning apirequest.LongRunningRequestCheck) http.Handler { +// WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by timeout. +func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMapper apirequest.RequestContextMapper, longRunning apirequest.LongRunningRequestCheck, timeout time.Duration) http.Handler { if longRunning == nil { return handler } @@ -44,19 +42,19 @@ func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMa ctx, ok := requestContextMapper.Get(req) if !ok { // if this happens, the handler chain isn't setup correctly because there is no context mapper - return time.After(globalTimeout), apierrors.NewInternalError(fmt.Errorf("no context found for request during timeout")) + return time.After(timeout), apierrors.NewInternalError(fmt.Errorf("no context found for request during timeout")) } requestInfo, ok := apirequest.RequestInfoFrom(ctx) if !ok { // if this happens, the handler chain isn't setup correctly because there is no request info - return time.After(globalTimeout), apierrors.NewInternalError(fmt.Errorf("no request info found for request during timeout")) + return time.After(timeout), apierrors.NewInternalError(fmt.Errorf("no request info found for request during timeout")) } if longRunning(req, requestInfo) { return nil, nil } - return time.After(globalTimeout), apierrors.NewServerTimeout(schema.GroupResource{Group: requestInfo.APIGroup, Resource: requestInfo.Resource}, requestInfo.Verb, 0) + return time.After(timeout), apierrors.NewServerTimeout(schema.GroupResource{Group: requestInfo.APIGroup, Resource: requestInfo.Resource}, requestInfo.Verb, 0) } return WithTimeout(handler, timeoutFunc) } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go index 0ca9d5973a..57ae12e9d1 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/server/options/server_run_options.go @@ -19,6 +19,7 @@ package options import ( "fmt" "net" + "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/serializer" @@ -39,6 +40,7 @@ type ServerRunOptions struct { ExternalHost string MaxRequestsInFlight int MaxMutatingRequestsInFlight int + RequestTimeout time.Duration MinRequestTimeout int TargetRAMMB int WatchCacheSizes []string @@ -49,6 +51,7 @@ func NewServerRunOptions() *ServerRunOptions { return &ServerRunOptions{ MaxRequestsInFlight: defaults.MaxRequestsInFlight, MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight, + RequestTimeout: defaults.RequestTimeout, MinRequestTimeout: defaults.MinRequestTimeout, } } @@ -59,6 +62,7 @@ func (s *ServerRunOptions) ApplyTo(c *server.Config) error { c.ExternalAddress = s.ExternalHost c.MaxRequestsInFlight = s.MaxRequestsInFlight c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight + c.RequestTimeout = s.RequestTimeout c.MinRequestTimeout = s.MinRequestTimeout c.PublicAddress = s.AdvertiseAddress @@ -122,6 +126,11 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) { "The maximum number of mutating requests in flight at a given time. When the server exceeds this, "+ "it rejects requests. Zero for no limit.") + fs.DurationVar(&s.RequestTimeout, "request-timeout", s.RequestTimeout, ""+ + "An optional field indicating the duration a handler must keep a request open before timing "+ + "it out. This is the default request timeout for requests but may be overridden by flags such as "+ + "--min-request-timeout for specific types of requests.") + fs.IntVar(&s.MinRequestTimeout, "min-request-timeout", s.MinRequestTimeout, ""+ "An optional field indicating the minimum number of seconds a handler must keep "+ "a request open before timing it out. Currently only honored by the watch request "+ diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/tests/cacher_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/tests/cacher_test.go index ef0c4f38de..447be77997 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/tests/cacher_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/tests/cacher_test.go @@ -537,6 +537,70 @@ func TestStartingResourceVersion(t *testing.T) { } } +func TestEmptyWatchEventCache(t *testing.T) { + server, etcdStorage := newEtcdTestStorage(t, etcdtest.PathPrefix()) + defer server.Terminate(t) + + // add a few objects + updatePod(t, etcdStorage, makeTestPod("pod1"), nil) + updatePod(t, etcdStorage, makeTestPod("pod2"), nil) + updatePod(t, etcdStorage, makeTestPod("pod3"), nil) + updatePod(t, etcdStorage, makeTestPod("pod4"), nil) + updatePod(t, etcdStorage, makeTestPod("pod5"), nil) + + fooCreated := updatePod(t, etcdStorage, makeTestPod("foo"), nil) + + // get rv of last pod created + rv, err := storage.ParseWatchResourceVersion(fooCreated.ResourceVersion) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + cacher := newTestCacher(etcdStorage, 10) + defer cacher.Stop() + + // We now have a cacher with an empty cache of watch events and a resourceVersion of rv. + // It should support establishing watches from rv and higher, but not older. + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv-1)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + expectedGoneError := errors.NewGone("").ErrStatus + verifyWatchEvent(t, watcher, watch.Error, &expectedGoneError) + } + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv+1)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + select { + case e := <-watcher.ResultChan(): + t.Errorf("unexpected event %#v", e) + case <-time.After(3 * time.Second): + // watch from rv+1 remained established successfully + } + } + + { + watcher, err := cacher.Watch(context.TODO(), "pods/ns", strconv.Itoa(int(rv)), storage.Everything) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer watcher.Stop() + select { + case e := <-watcher.ResultChan(): + t.Errorf("unexpected event %#v", e) + case <-time.After(3 * time.Second): + // watch from rv remained established successfully + } + } +} + func TestRandomWatchDeliver(t *testing.T) { server, etcdStorage := newEtcdTestStorage(t, etcdtest.PathPrefix()) defer server.Terminate(t) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/watch_cache.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/watch_cache.go index 1268b9d7a5..602312b605 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/watch_cache.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/watch_cache.go @@ -412,7 +412,9 @@ func (w *watchCache) SetOnEvent(onEvent func(*watchCacheEvent)) { func (w *watchCache) GetAllEventsSinceThreadUnsafe(resourceVersion uint64) ([]*watchCacheEvent, error) { size := w.endIndex - w.startIndex - oldest := w.resourceVersion + // if we have no watch events in our cache, the oldest one we can successfully deliver to a watcher + // is the *next* event we'll receive, which will be at least one greater than our current resourceVersion + oldest := w.resourceVersion + 1 if size > 0 { oldest = w.cache[w.startIndex%w.capacity].resourceVersion } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/util/proxy/dial.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/util/proxy/dial.go index d9fbb85b7b..e737319094 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/util/proxy/dial.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/util/proxy/dial.go @@ -94,6 +94,9 @@ func DialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) { // Verify host, _, _ := net.SplitHostPort(dialAddr) + if tlsConfig != nil && len(tlsConfig.ServerName) > 0 { + host = tlsConfig.ServerName + } if err := tlsConn.VerifyHostname(host); err != nil { tlsConn.Close() return nil, err diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/Godeps/Godeps.json b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/Godeps/Godeps.json index b854e51325..5ac98b9b66 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/Godeps/Godeps.json +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/Godeps/Godeps.json @@ -16,15 +16,19 @@ }, { "ImportPath": "github.com/Azure/go-autorest/autorest", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" + }, + { + "ImportPath": "github.com/Azure/go-autorest/autorest/adal", + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/azure", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/Azure/go-autorest/autorest/date", - "Rev": "d7c034a8af24eda120dd6460bfcd6d9ed14e43ca" + "Rev": "58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d" }, { "ImportPath": "github.com/PuerkitoBio/purell", @@ -36,23 +40,23 @@ }, { "ImportPath": "github.com/coreos/go-oidc/http", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/jose", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/key", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oauth2", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/go-oidc/oidc", - "Rev": "be73733bb8cc830d0205609b95d125215f8e9c70" + "Rev": "a4973d9a4225417aecf5d450a9522f00c1f7130f" }, { "ImportPath": "github.com/coreos/pkg/health", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/discovery_client.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/discovery_client.go index 0ee46b863b..011dd9ecf2 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/discovery_client.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/discovery_client.go @@ -183,7 +183,7 @@ func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (r } // serverResources returns the supported resources for all groups and versions. -func (d *DiscoveryClient) serverResources(failEarly bool) ([]*metav1.APIResourceList, error) { +func (d *DiscoveryClient) serverResources() ([]*metav1.APIResourceList, error) { apiGroups, err := d.ServerGroups() if err != nil { return nil, err @@ -199,9 +199,6 @@ func (d *DiscoveryClient) serverResources(failEarly bool) ([]*metav1.APIResource if err != nil { // TODO: maybe restrict this to NotFound errors failedGroups[gv] = err - if failEarly { - return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups} - } continue } @@ -245,7 +242,7 @@ func IsGroupDiscoveryFailedError(err error) bool { } // serverPreferredResources returns the supported resources with the version preferred by the server. -func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.APIResourceList, error) { +func (d *DiscoveryClient) serverPreferredResources() ([]*metav1.APIResourceList, error) { serverGroupList, err := d.ServerGroups() if err != nil { return nil, err @@ -265,9 +262,6 @@ func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.AP if err != nil { // TODO: maybe restrict this to NotFound errors failedGroups[groupVersion] = err - if failEarly { - return nil, &ErrGroupDiscoveryFailed{Groups: failedGroups} - } continue } @@ -312,9 +306,7 @@ func (d *DiscoveryClient) serverPreferredResources(failEarly bool) ([]*metav1.AP // ServerPreferredResources returns the supported resources with the version preferred by the // server. func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) { - return withRetries(defaultRetries, func(retryEarly bool) ([]*metav1.APIResourceList, error) { - return d.serverPreferredResources(retryEarly) - }) + return withRetries(defaultRetries, d.serverPreferredResources) } // ServerPreferredNamespacedResources returns the supported namespaced resources with the @@ -391,12 +383,11 @@ func (d *DiscoveryClient) OpenAPISchema() (*spec.Swagger, error) { } // withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns. -func withRetries(maxRetries int, f func(failEarly bool) ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) { +func withRetries(maxRetries int, f func() ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) { var result []*metav1.APIResourceList var err error for i := 0; i < maxRetries; i++ { - failEarly := i < maxRetries-1 - result, err = f(failEarly) + result, err = f() if err == nil { return result, nil } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper.go index 756669001f..9651716bd1 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper.go @@ -49,6 +49,7 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V for _, group := range groupResources { groupPriority = append(groupPriority, group.Group.Name) + // Make sure the preferred version comes first if len(group.Group.PreferredVersion.Version) != 0 { preferred := group.Group.PreferredVersion.Version if _, ok := group.VersionedResources[preferred]; ok { @@ -72,6 +73,21 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V continue } + // Add non-preferred versions after the preferred version, in case there are resources that only exist in those versions + if discoveryVersion.Version != group.Group.PreferredVersion.Version { + resourcePriority = append(resourcePriority, schema.GroupVersionResource{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Resource: meta.AnyResource, + }) + + kindPriority = append(kindPriority, schema.GroupVersionKind{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Kind: meta.AnyKind, + }) + } + gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version} versionMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv}, versionInterfaces) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper_test.go index 6bc16ccbf4..40f89a8c21 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/discovery/restmapper_test.go @@ -67,6 +67,32 @@ func TestRESTMapper(t *testing.T) { }, }, }, + + // This group tests finding and prioritizing resources that only exist in non-preferred versions + { + Group: metav1.APIGroup{ + Name: "unpreferred", + Versions: []metav1.GroupVersionForDiscovery{ + {Version: "v1"}, + {Version: "v2beta1"}, + {Version: "v2alpha1"}, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"}, + }, + VersionedResources: map[string][]metav1.APIResource{ + "v1": { + {Name: "broccoli", Namespaced: true, Kind: "Broccoli"}, + }, + "v2beta1": { + {Name: "broccoli", Namespaced: true, Kind: "Broccoli"}, + {Name: "peas", Namespaced: true, Kind: "Pea"}, + }, + "v2alpha1": { + {Name: "broccoli", Namespaced: true, Kind: "Broccoli"}, + {Name: "peas", Namespaced: true, Kind: "Pea"}, + }, + }, + }, } restMapper := NewRESTMapper(resources, nil) @@ -123,6 +149,16 @@ func TestRESTMapper(t *testing.T) { Kind: "Job", }, }, + { + input: schema.GroupVersionResource{ + Resource: "peas", + }, + want: schema.GroupVersionKind{ + Group: "unpreferred", + Version: "v2beta1", + Kind: "Pea", + }, + }, } for _, tc := range kindTCs { diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/types.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/types.go index b59f7202e4..454b94ef20 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/types.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/types.go @@ -615,7 +615,7 @@ type EmptyDirVolumeSource struct { // The default is nil which means that the limit is undefined. // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir // +optional - SizeLimit resource.Quantity + SizeLimit *resource.Quantity } // StorageMedium defines ways that storage can be allocated to a volume. diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/generated.pb.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/generated.pb.go index dcfc99ea0f..c5a99f6787 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/generated.pb.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/generated.pb.go @@ -2591,14 +2591,16 @@ func (m *EmptyDirVolumeSource) MarshalTo(dAtA []byte) (int, error) { i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Medium))) i += copy(dAtA[i:], m.Medium) - dAtA[i] = 0x12 - i++ - i = encodeVarintGenerated(dAtA, i, uint64(m.SizeLimit.Size())) - n31, err := m.SizeLimit.MarshalTo(dAtA[i:]) - if err != nil { - return 0, err + if m.SizeLimit != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.SizeLimit.Size())) + n31, err := m.SizeLimit.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n31 } - i += n31 return i, nil } @@ -10033,8 +10035,10 @@ func (m *EmptyDirVolumeSource) Size() (n int) { _ = l l = len(m.Medium) n += 1 + l + sovGenerated(uint64(l)) - l = m.SizeLimit.Size() - n += 1 + l + sovGenerated(uint64(l)) + if m.SizeLimit != nil { + l = m.SizeLimit.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -12949,7 +12953,7 @@ func (this *EmptyDirVolumeSource) String() string { } s := strings.Join([]string{`&EmptyDirVolumeSource{`, `Medium:` + fmt.Sprintf("%v", this.Medium) + `,`, - `SizeLimit:` + strings.Replace(strings.Replace(this.SizeLimit.String(), "Quantity", "k8s_io_apimachinery_pkg_api_resource.Quantity", 1), `&`, ``, 1) + `,`, + `SizeLimit:` + strings.Replace(fmt.Sprintf("%v", this.SizeLimit), "Quantity", "k8s_io_apimachinery_pkg_api_resource.Quantity", 1) + `,`, `}`, }, "") return s @@ -19966,6 +19970,9 @@ func (m *EmptyDirVolumeSource) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } + if m.SizeLimit == nil { + m.SizeLimit = &k8s_io_apimachinery_pkg_api_resource.Quantity{} + } if err := m.SizeLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -44391,720 +44398,720 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 11429 bytes of a gzipped FileDescriptorProto + // 11430 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x8c, 0x24, 0xc7, 0x75, 0x98, 0x7a, 0x66, 0xf6, 0x63, 0xde, 0x7e, 0xd7, 0xed, 0x1d, 0x97, 0x2b, 0xf2, 0xf6, 0xd8, 0x14, 0xe9, 0x23, 0x79, 0xdc, 0xd3, 0x1d, 0x49, 0x91, 0x12, 0x65, 0x5a, 0xbb, 0x3b, 0xbb, 0x77, 0xeb, 0xfb, 0x1a, 0xd6, 0xec, 0xdd, 0x51, 0x14, 0x43, 0xb2, 0x6f, 0xba, 0x76, 0xb7, 0x79, 0xb3, 0xdd, 0xc3, 0xee, 0x9e, 0xbd, 0x5b, 0x1a, 0x06, 0x6c, 0x45, 0xb0, 0x14, 0x40, 0x49, 0x64, 0x38, - 0x02, 0x02, 0x27, 0x80, 0x02, 0x03, 0x71, 0x94, 0x6f, 0x2b, 0x82, 0x3e, 0x0c, 0xcb, 0x09, 0xe2, - 0x48, 0x8e, 0x1c, 0x24, 0x8e, 0x00, 0x23, 0xb1, 0x02, 0xc3, 0x6b, 0x6b, 0x85, 0xf8, 0x4f, 0x80, - 0xfc, 0x48, 0xfe, 0x6d, 0x3e, 0x10, 0xd4, 0x67, 0x57, 0xf5, 0xf4, 0x6c, 0xf7, 0x2c, 0x6f, 0xd7, - 0x94, 0x90, 0x7f, 0x33, 0xf5, 0x5e, 0xbd, 0xaa, 0xae, 0x8f, 0x57, 0xef, 0xbd, 0x7a, 0xef, 0x15, - 0x9c, 0xbb, 0xfb, 0x52, 0x34, 0xef, 0x05, 0xe7, 0xef, 0x76, 0xee, 0x90, 0xd0, 0x27, 0x31, 0x89, - 0xce, 0xb7, 0xef, 0x6e, 0x9c, 0x77, 0xda, 0xde, 0xf9, 0xed, 0x0b, 0xe7, 0x37, 0x88, 0x4f, 0x42, - 0x27, 0x26, 0xee, 0x7c, 0x3b, 0x0c, 0xe2, 0x00, 0x3d, 0xc2, 0xb1, 0xe7, 0x13, 0xec, 0xf9, 0xf6, - 0xdd, 0x8d, 0x79, 0xa7, 0xed, 0xcd, 0x6f, 0x5f, 0x98, 0x7d, 0x76, 0xc3, 0x8b, 0x37, 0x3b, 0x77, - 0xe6, 0x9b, 0xc1, 0xd6, 0xf9, 0x8d, 0x60, 0x23, 0x38, 0xcf, 0x2a, 0xdd, 0xe9, 0xac, 0xb3, 0x7f, - 0xec, 0x0f, 0xfb, 0xc5, 0x89, 0xcd, 0x3e, 0x2f, 0x9a, 0x76, 0xda, 0xde, 0x96, 0xd3, 0xdc, 0xf4, - 0x7c, 0x12, 0xee, 0xa8, 0xc6, 0x43, 0x12, 0x05, 0x9d, 0xb0, 0x49, 0xd2, 0x5d, 0x38, 0xb0, 0x56, - 0x74, 0x7e, 0x8b, 0xc4, 0x4e, 0x46, 0xc7, 0x67, 0xcf, 0xf7, 0xaa, 0x15, 0x76, 0xfc, 0xd8, 0xdb, - 0xea, 0x6e, 0xe6, 0x63, 0x79, 0x15, 0xa2, 0xe6, 0x26, 0xd9, 0x72, 0xba, 0xea, 0x3d, 0xd7, 0xab, - 0x5e, 0x27, 0xf6, 0x5a, 0xe7, 0x3d, 0x3f, 0x8e, 0xe2, 0x30, 0x5d, 0xc9, 0xfe, 0x63, 0x0b, 0xce, - 0x2c, 0xdc, 0x6e, 0x2c, 0xb7, 0x9c, 0x28, 0xf6, 0x9a, 0x8b, 0xad, 0xa0, 0x79, 0xb7, 0x11, 0x07, - 0x21, 0xb9, 0x15, 0xb4, 0x3a, 0x5b, 0xa4, 0xc1, 0x06, 0x02, 0x9d, 0x83, 0xe1, 0x6d, 0xf6, 0x7f, - 0xb5, 0x36, 0x63, 0x9d, 0xb1, 0xce, 0x56, 0x17, 0x27, 0xbf, 0xbf, 0x3b, 0xf7, 0xa1, 0xbd, 0xdd, - 0xb9, 0xe1, 0x5b, 0xa2, 0x1c, 0x2b, 0x0c, 0xf4, 0x24, 0x0c, 0xae, 0x47, 0x6b, 0x3b, 0x6d, 0x32, - 0x53, 0x62, 0xb8, 0xe3, 0x02, 0x77, 0x70, 0xa5, 0x41, 0x4b, 0xb1, 0x80, 0xa2, 0xf3, 0x50, 0x6d, - 0x3b, 0x61, 0xec, 0xc5, 0x5e, 0xe0, 0xcf, 0x94, 0xcf, 0x58, 0x67, 0x07, 0x16, 0xa7, 0x04, 0x6a, - 0xb5, 0x2e, 0x01, 0x38, 0xc1, 0xa1, 0xdd, 0x08, 0x89, 0xe3, 0xde, 0xf0, 0x5b, 0x3b, 0x33, 0x95, - 0x33, 0xd6, 0xd9, 0xe1, 0xa4, 0x1b, 0x58, 0x94, 0x63, 0x85, 0x61, 0x7f, 0xbb, 0x04, 0xc3, 0x0b, - 0xeb, 0xeb, 0x9e, 0xef, 0xc5, 0x3b, 0xe8, 0x6d, 0x18, 0xf5, 0x03, 0x97, 0xc8, 0xff, 0xec, 0x2b, - 0x46, 0x2e, 0x3e, 0x3d, 0x7f, 0xd0, 0xa2, 0x9a, 0xbf, 0xae, 0xd5, 0x58, 0x9c, 0xdc, 0xdb, 0x9d, - 0x1b, 0xd5, 0x4b, 0xb0, 0x41, 0x11, 0xbd, 0x01, 0x23, 0xed, 0xc0, 0x55, 0x0d, 0x94, 0x58, 0x03, - 0x4f, 0x1d, 0xdc, 0x40, 0x3d, 0xa9, 0xb0, 0x38, 0xb1, 0xb7, 0x3b, 0x37, 0xa2, 0x15, 0x60, 0x9d, - 0x1c, 0x6a, 0xc1, 0x04, 0xfd, 0xeb, 0xc7, 0x9e, 0x6a, 0xa1, 0xcc, 0x5a, 0x78, 0x36, 0xbf, 0x05, - 0xad, 0xd2, 0xe2, 0x89, 0xbd, 0xdd, 0xb9, 0x89, 0x54, 0x21, 0x4e, 0x93, 0xb6, 0xdf, 0x83, 0xf1, - 0x85, 0x38, 0x76, 0x9a, 0x9b, 0xc4, 0xe5, 0xf3, 0x8b, 0x9e, 0x87, 0x8a, 0xef, 0x6c, 0x11, 0x31, - 0xfb, 0x67, 0xc4, 0xb0, 0x57, 0xae, 0x3b, 0x5b, 0x64, 0x7f, 0x77, 0x6e, 0xf2, 0xa6, 0xef, 0xbd, - 0xdb, 0x11, 0x6b, 0x86, 0x96, 0x61, 0x86, 0x8d, 0x2e, 0x02, 0xb8, 0x64, 0xdb, 0x6b, 0x92, 0xba, - 0x13, 0x6f, 0x8a, 0xd5, 0x80, 0x44, 0x5d, 0xa8, 0x29, 0x08, 0xd6, 0xb0, 0xec, 0xcf, 0x5a, 0x50, - 0x5d, 0xd8, 0x0e, 0x3c, 0xb7, 0x1e, 0xb8, 0x11, 0xea, 0xc0, 0x44, 0x3b, 0x24, 0xeb, 0x24, 0x54, - 0x45, 0x33, 0xd6, 0x99, 0xf2, 0xd9, 0x91, 0x8b, 0x17, 0x73, 0xbe, 0xdb, 0xac, 0xb4, 0xec, 0xc7, - 0xe1, 0xce, 0xe2, 0x43, 0xa2, 0xe9, 0x89, 0x14, 0x14, 0xa7, 0xdb, 0xb0, 0xbf, 0x5b, 0x82, 0x93, - 0x0b, 0xef, 0x75, 0x42, 0x52, 0xf3, 0xa2, 0xbb, 0xe9, 0xad, 0xe0, 0x7a, 0xd1, 0xdd, 0xeb, 0xc9, - 0x60, 0xa8, 0x35, 0x58, 0x13, 0xe5, 0x58, 0x61, 0xa0, 0x67, 0x61, 0x88, 0xfe, 0xbe, 0x89, 0x57, - 0xc5, 0xd7, 0x9f, 0x10, 0xc8, 0x23, 0x35, 0x27, 0x76, 0x6a, 0x1c, 0x84, 0x25, 0x0e, 0xba, 0x06, - 0x23, 0x4d, 0xb6, 0x73, 0x37, 0xae, 0x05, 0x2e, 0x61, 0x33, 0x5c, 0x5d, 0x7c, 0x86, 0xa2, 0x2f, - 0x25, 0xc5, 0xfb, 0xbb, 0x73, 0x33, 0xbc, 0x6f, 0x82, 0x84, 0x06, 0xc3, 0x7a, 0x7d, 0x64, 0xab, - 0x8d, 0x58, 0x61, 0x94, 0x20, 0x63, 0x13, 0x9e, 0xd5, 0xf6, 0xd4, 0x00, 0xdb, 0x53, 0xa3, 0xd9, - 0xfb, 0x09, 0x5d, 0x80, 0xca, 0x5d, 0xcf, 0x77, 0x67, 0x06, 0x19, 0xad, 0x47, 0xe9, 0xf4, 0x5f, - 0xf1, 0x7c, 0x77, 0x7f, 0x77, 0x6e, 0xca, 0xe8, 0x0e, 0x2d, 0xc4, 0x0c, 0xd5, 0xfe, 0x47, 0x96, - 0x18, 0xc6, 0x15, 0xaf, 0x65, 0x72, 0x94, 0x8b, 0x00, 0x11, 0x69, 0x86, 0x24, 0xd6, 0x06, 0x52, - 0xad, 0x8c, 0x86, 0x82, 0x60, 0x0d, 0x8b, 0xf2, 0x8b, 0x68, 0xd3, 0x09, 0xd9, 0x02, 0x13, 0xc3, - 0xa9, 0xf8, 0x45, 0x43, 0x02, 0x70, 0x82, 0x63, 0xf0, 0x8b, 0x72, 0x2e, 0xbf, 0xf8, 0x3d, 0x0b, - 0x86, 0x16, 0x3d, 0xdf, 0xf5, 0xfc, 0x0d, 0xf4, 0x36, 0x0c, 0x53, 0x76, 0xee, 0x3a, 0xb1, 0x23, - 0x58, 0xc5, 0x47, 0xe5, 0x7a, 0xd3, 0xb9, 0xab, 0x5c, 0x71, 0xd1, 0x3c, 0xc5, 0xa6, 0xeb, 0xee, - 0xc6, 0x9d, 0x77, 0x48, 0x33, 0xbe, 0x46, 0x62, 0x27, 0xf9, 0x9c, 0xa4, 0x0c, 0x2b, 0xaa, 0xe8, - 0x26, 0x0c, 0xc6, 0x4e, 0xb8, 0x41, 0x62, 0xc1, 0x29, 0x72, 0xf6, 0x31, 0xa7, 0x81, 0xe9, 0x2a, - 0x25, 0x7e, 0x93, 0x24, 0x3c, 0x75, 0x8d, 0x11, 0xc1, 0x82, 0x98, 0xdd, 0x84, 0xd1, 0x25, 0xa7, - 0xed, 0xdc, 0xf1, 0x5a, 0x5e, 0xec, 0x91, 0x08, 0xfd, 0x0c, 0x94, 0x1d, 0xd7, 0x65, 0x7b, 0xa6, - 0xba, 0x78, 0x72, 0x6f, 0x77, 0xae, 0xbc, 0xe0, 0xd2, 0x29, 0x03, 0x85, 0xb5, 0x83, 0x29, 0x06, - 0x7a, 0x1a, 0x2a, 0x6e, 0x18, 0xb4, 0x67, 0x4a, 0x0c, 0xf3, 0x14, 0x9d, 0xdd, 0x5a, 0x18, 0xb4, - 0x53, 0xa8, 0x0c, 0xc7, 0xfe, 0x5e, 0x09, 0xd0, 0x12, 0x69, 0x6f, 0xae, 0x34, 0x8c, 0x39, 0x3d, - 0x0b, 0xc3, 0x5b, 0x81, 0xef, 0xc5, 0x41, 0x18, 0x89, 0x06, 0xd9, 0x52, 0xba, 0x26, 0xca, 0xb0, - 0x82, 0xa2, 0x33, 0x50, 0x69, 0x27, 0x1c, 0x61, 0x54, 0x72, 0x13, 0xc6, 0x0b, 0x18, 0x84, 0x62, - 0x74, 0x22, 0x12, 0x8a, 0x2d, 0xa0, 0x30, 0x6e, 0x46, 0x24, 0xc4, 0x0c, 0x92, 0xac, 0x20, 0xba, - 0xb6, 0xc4, 0x02, 0x4f, 0xad, 0x20, 0x0a, 0xc1, 0x1a, 0x16, 0x7a, 0x0b, 0xaa, 0xfc, 0x1f, 0x26, - 0xeb, 0x6c, 0xb5, 0xe7, 0xf2, 0x91, 0xab, 0x41, 0xd3, 0x69, 0xa5, 0x07, 0x7f, 0x8c, 0xad, 0x38, - 0x49, 0x08, 0x27, 0x34, 0x8d, 0x15, 0x37, 0x98, 0xbb, 0xe2, 0xfe, 0xb6, 0x05, 0x68, 0xc9, 0xf3, - 0x5d, 0x12, 0x1e, 0xc3, 0x69, 0xdb, 0xdf, 0x66, 0xf8, 0x13, 0xda, 0xb5, 0x60, 0xab, 0x1d, 0xf8, - 0xc4, 0x8f, 0x97, 0x02, 0xdf, 0xe5, 0x27, 0xf0, 0x27, 0xa0, 0x12, 0xd3, 0xa6, 0x78, 0xb7, 0x9e, - 0x94, 0xd3, 0x42, 0x1b, 0xd8, 0xdf, 0x9d, 0x3b, 0xd5, 0x5d, 0x83, 0x75, 0x81, 0xd5, 0x41, 0x1f, - 0x87, 0xc1, 0x28, 0x76, 0xe2, 0x4e, 0x24, 0x3a, 0xfa, 0x98, 0xec, 0x68, 0x83, 0x95, 0xee, 0xef, - 0xce, 0x4d, 0xa8, 0x6a, 0xbc, 0x08, 0x8b, 0x0a, 0xe8, 0x29, 0x18, 0xda, 0x22, 0x51, 0xe4, 0x6c, - 0x48, 0x9e, 0x38, 0x21, 0xea, 0x0e, 0x5d, 0xe3, 0xc5, 0x58, 0xc2, 0xd1, 0xe3, 0x30, 0x40, 0xc2, - 0x30, 0x08, 0xc5, 0x8a, 0x18, 0x13, 0x88, 0x03, 0xcb, 0xb4, 0x10, 0x73, 0x98, 0xfd, 0x5f, 0x2c, - 0x98, 0x50, 0x7d, 0xe5, 0x6d, 0x1d, 0xc3, 0x96, 0x77, 0x01, 0x9a, 0xf2, 0x03, 0x23, 0xb6, 0xd1, - 0xb4, 0x36, 0xb2, 0x97, 0x5f, 0xf7, 0x80, 0x26, 0x6d, 0xa8, 0xa2, 0x08, 0x6b, 0x74, 0xed, 0x7f, - 0x6b, 0xc1, 0x89, 0xd4, 0xb7, 0x5d, 0xf5, 0xa2, 0x18, 0xbd, 0xd1, 0xf5, 0x7d, 0xf3, 0xc5, 0xbe, - 0x8f, 0xd6, 0x66, 0x5f, 0xa7, 0xd6, 0x8b, 0x2c, 0xd1, 0xbe, 0x0d, 0xc3, 0x80, 0x17, 0x93, 0x2d, - 0xf9, 0x59, 0xcf, 0x16, 0xfc, 0x2c, 0xde, 0xbf, 0x64, 0x96, 0x56, 0x29, 0x0d, 0xcc, 0x49, 0xd9, - 0xff, 0xcb, 0x82, 0xea, 0x52, 0xe0, 0xaf, 0x7b, 0x1b, 0xd7, 0x9c, 0xf6, 0x31, 0xcc, 0x4f, 0x03, - 0x2a, 0x8c, 0x3a, 0xff, 0x84, 0x0b, 0x79, 0x9f, 0x20, 0x3a, 0x36, 0x4f, 0xcf, 0x3d, 0x2e, 0x5f, - 0x28, 0x36, 0x45, 0x8b, 0x30, 0x23, 0x36, 0xfb, 0x22, 0x54, 0x15, 0x02, 0x9a, 0x84, 0xf2, 0x5d, - 0xc2, 0x85, 0xcf, 0x2a, 0xa6, 0x3f, 0xd1, 0x34, 0x0c, 0x6c, 0x3b, 0xad, 0x8e, 0xd8, 0xbc, 0x98, - 0xff, 0xf9, 0x44, 0xe9, 0x25, 0xcb, 0xfe, 0x1e, 0xdb, 0x81, 0xa2, 0x91, 0x65, 0x7f, 0x5b, 0x30, - 0x87, 0xcf, 0x59, 0x30, 0xdd, 0xca, 0x60, 0x4a, 0x62, 0x4c, 0x0e, 0xc3, 0xce, 0x1e, 0x11, 0xdd, - 0x9e, 0xce, 0x82, 0xe2, 0xcc, 0xd6, 0x28, 0xaf, 0x0f, 0xda, 0x74, 0xc1, 0x39, 0x2d, 0xd6, 0x75, - 0x21, 0x36, 0xdc, 0x10, 0x65, 0x58, 0x41, 0xed, 0xbf, 0xb0, 0x60, 0x5a, 0x7d, 0xc7, 0x15, 0xb2, - 0xd3, 0x20, 0x2d, 0xd2, 0x8c, 0x83, 0xf0, 0x83, 0xf2, 0x25, 0x8f, 0xf2, 0x39, 0xe1, 0x3c, 0x69, - 0x44, 0x10, 0x28, 0x5f, 0x21, 0x3b, 0x7c, 0x82, 0xf4, 0x0f, 0x2d, 0x1f, 0xf8, 0xa1, 0xbf, 0x63, - 0xc1, 0x98, 0xfa, 0xd0, 0x63, 0xd8, 0x72, 0x57, 0xcd, 0x2d, 0xf7, 0x33, 0x05, 0xd7, 0x6b, 0x8f, - 0xcd, 0xf6, 0xb7, 0x4a, 0x94, 0x6d, 0x08, 0x9c, 0x7a, 0x18, 0xd0, 0x41, 0xa2, 0x1c, 0xff, 0x03, - 0x32, 0x4b, 0xfd, 0x7d, 0xec, 0x15, 0xb2, 0xb3, 0x16, 0x50, 0x69, 0x22, 0xfb, 0x63, 0x8d, 0x49, - 0xad, 0x1c, 0x38, 0xa9, 0x7f, 0x50, 0x82, 0x93, 0x6a, 0x58, 0x8c, 0x53, 0xfa, 0xa7, 0x72, 0x60, - 0x2e, 0xc0, 0x88, 0x4b, 0xd6, 0x9d, 0x4e, 0x2b, 0x56, 0x0a, 0xc8, 0x00, 0xd7, 0x4c, 0x6b, 0x49, - 0x31, 0xd6, 0x71, 0xfa, 0x18, 0xcb, 0xaf, 0x8c, 0x30, 0x7e, 0x1e, 0x3b, 0x74, 0xd5, 0x53, 0x09, - 0x4f, 0xd3, 0x28, 0x47, 0x75, 0x8d, 0x52, 0x68, 0x8f, 0x8f, 0xc3, 0x80, 0xb7, 0x45, 0xcf, 0xfc, - 0x92, 0x79, 0x94, 0xaf, 0xd2, 0x42, 0xcc, 0x61, 0xe8, 0x09, 0x18, 0x6a, 0x06, 0x5b, 0x5b, 0x8e, - 0xef, 0xce, 0x94, 0x99, 0xcc, 0x39, 0x42, 0xc5, 0x82, 0x25, 0x5e, 0x84, 0x25, 0x0c, 0x3d, 0x02, - 0x15, 0x27, 0xdc, 0x88, 0x66, 0x2a, 0x0c, 0x67, 0x98, 0xb6, 0xb4, 0x10, 0x6e, 0x44, 0x98, 0x95, - 0x52, 0x59, 0xf2, 0x5e, 0x10, 0xde, 0xf5, 0xfc, 0x8d, 0x9a, 0x17, 0x32, 0xc1, 0x50, 0x93, 0x25, - 0x6f, 0x2b, 0x08, 0xd6, 0xb0, 0x50, 0x1d, 0x06, 0xda, 0x41, 0x18, 0x47, 0x33, 0x83, 0x6c, 0xe0, - 0x9f, 0xc9, 0xdd, 0x7e, 0xfc, 0xbb, 0xeb, 0x41, 0x18, 0x27, 0x9f, 0x42, 0xff, 0x45, 0x98, 0x13, - 0x42, 0x4b, 0x50, 0x26, 0xfe, 0xf6, 0xcc, 0x10, 0xa3, 0xf7, 0x91, 0x83, 0xe9, 0x2d, 0xfb, 0xdb, - 0xb7, 0x9c, 0x30, 0xe1, 0x57, 0xcb, 0xfe, 0x36, 0xa6, 0xb5, 0x51, 0x13, 0xaa, 0xd2, 0x7e, 0x15, - 0xcd, 0x0c, 0x17, 0x59, 0x8a, 0x58, 0xa0, 0x63, 0xf2, 0x6e, 0xc7, 0x0b, 0xc9, 0x16, 0xf1, 0xe3, - 0x28, 0x51, 0xac, 0x24, 0x34, 0xc2, 0x09, 0x5d, 0xd4, 0x84, 0x51, 0x2e, 0x7f, 0x5e, 0x0b, 0x3a, - 0x7e, 0x1c, 0xcd, 0x54, 0x59, 0x97, 0x73, 0x8c, 0x1d, 0xb7, 0x92, 0x1a, 0x8b, 0xd3, 0x82, 0xfc, - 0xa8, 0x56, 0x18, 0x61, 0x83, 0x28, 0x7a, 0x03, 0xc6, 0x5a, 0xde, 0x36, 0xf1, 0x49, 0x14, 0xd5, - 0xc3, 0xe0, 0x0e, 0x99, 0x01, 0xf6, 0x35, 0x8f, 0xe7, 0x29, 0xfe, 0xc1, 0x1d, 0xb2, 0x38, 0xb5, - 0xb7, 0x3b, 0x37, 0x76, 0x55, 0xaf, 0x8d, 0x4d, 0x62, 0xe8, 0x2d, 0x18, 0xa7, 0xc2, 0xae, 0x97, - 0x90, 0x1f, 0x29, 0x4e, 0x1e, 0xed, 0xed, 0xce, 0x8d, 0x63, 0xa3, 0x3a, 0x4e, 0x91, 0x43, 0x6b, - 0x50, 0x6d, 0x79, 0xeb, 0xa4, 0xb9, 0xd3, 0x6c, 0x91, 0x99, 0x51, 0x46, 0x3b, 0x67, 0x73, 0x5e, - 0x95, 0xe8, 0x5c, 0xc1, 0x50, 0x7f, 0x71, 0x42, 0x08, 0xdd, 0x82, 0x53, 0x31, 0x09, 0xb7, 0x3c, - 0xdf, 0xa1, 0x9b, 0x4a, 0x48, 0xbf, 0xcc, 0xba, 0x32, 0xc6, 0x56, 0xed, 0x69, 0x31, 0xb0, 0xa7, - 0xd6, 0x32, 0xb1, 0x70, 0x8f, 0xda, 0xe8, 0x06, 0x4c, 0xb0, 0xfd, 0x54, 0xef, 0xb4, 0x5a, 0xf5, - 0xa0, 0xe5, 0x35, 0x77, 0x66, 0xc6, 0x19, 0xc1, 0x27, 0xa4, 0xcd, 0x64, 0xd5, 0x04, 0x53, 0xc5, - 0x30, 0xf9, 0x87, 0xd3, 0xb5, 0x51, 0x0b, 0x26, 0x22, 0xd2, 0xec, 0x84, 0x5e, 0xbc, 0x43, 0xd7, - 0x3e, 0xb9, 0x1f, 0xcf, 0x4c, 0x14, 0x51, 0x74, 0x1b, 0x66, 0x25, 0x6e, 0xb0, 0x4a, 0x15, 0xe2, - 0x34, 0x69, 0xca, 0x2a, 0xa2, 0xd8, 0xf5, 0xfc, 0x99, 0x49, 0xc6, 0x81, 0xd4, 0xfe, 0x6a, 0xd0, - 0x42, 0xcc, 0x61, 0xcc, 0x7e, 0x40, 0x7f, 0xdc, 0xa0, 0x5c, 0x7a, 0x8a, 0x21, 0x26, 0xf6, 0x03, - 0x09, 0xc0, 0x09, 0x0e, 0x15, 0x0d, 0xe2, 0x78, 0x67, 0x06, 0x31, 0x54, 0xb5, 0xd5, 0xd6, 0xd6, - 0x3e, 0x8d, 0x69, 0x39, 0xba, 0x05, 0x43, 0xc4, 0xdf, 0x5e, 0x09, 0x83, 0xad, 0x99, 0x13, 0x45, - 0x78, 0xc0, 0x32, 0x47, 0xe6, 0xe7, 0x47, 0xa2, 0xc2, 0x88, 0x62, 0x2c, 0x89, 0xa1, 0xfb, 0x30, - 0x93, 0x31, 0x4b, 0x7c, 0x52, 0xa6, 0xd9, 0xa4, 0x7c, 0x52, 0xd4, 0x9d, 0x59, 0xeb, 0x81, 0xb7, - 0x7f, 0x00, 0x0c, 0xf7, 0xa4, 0x6e, 0xdf, 0x81, 0x71, 0xc5, 0xa8, 0xd8, 0x7c, 0xa3, 0x39, 0x18, - 0xa0, 0xbc, 0x58, 0x2a, 0xf4, 0x55, 0x3a, 0xa8, 0x94, 0x45, 0x47, 0x98, 0x97, 0xb3, 0x41, 0xf5, - 0xde, 0x23, 0x8b, 0x3b, 0x31, 0xe1, 0x8a, 0x5d, 0x59, 0x1b, 0x54, 0x09, 0xc0, 0x09, 0x8e, 0xfd, - 0x7f, 0xb9, 0x98, 0x94, 0x70, 0xc3, 0x02, 0x27, 0xc1, 0x39, 0x18, 0xde, 0x0c, 0xa2, 0x98, 0x62, - 0xb3, 0x36, 0x06, 0x12, 0xc1, 0xe8, 0xb2, 0x28, 0xc7, 0x0a, 0x03, 0xbd, 0x0c, 0x63, 0x4d, 0xbd, - 0x01, 0x71, 0x8c, 0x9d, 0x14, 0x55, 0xcc, 0xd6, 0xb1, 0x89, 0x8b, 0x5e, 0x82, 0x61, 0x66, 0x18, - 0x6f, 0x06, 0x2d, 0xa1, 0x42, 0xca, 0x53, 0x79, 0xb8, 0x2e, 0xca, 0xf7, 0xb5, 0xdf, 0x58, 0x61, - 0x53, 0x45, 0x9c, 0x76, 0x61, 0xb5, 0x2e, 0x0e, 0x10, 0xa5, 0x88, 0x5f, 0x66, 0xa5, 0x58, 0x40, - 0xed, 0xdf, 0x2a, 0x69, 0xa3, 0x4c, 0x15, 0x20, 0x82, 0x5e, 0x87, 0xa1, 0x7b, 0x8e, 0x17, 0x7b, - 0xfe, 0x86, 0x90, 0x1e, 0x9e, 0x2b, 0x78, 0x9a, 0xb0, 0xea, 0xb7, 0x79, 0x55, 0x7e, 0xf2, 0x89, - 0x3f, 0x58, 0x12, 0xa4, 0xb4, 0xc3, 0x8e, 0xef, 0x53, 0xda, 0xa5, 0xfe, 0x69, 0x63, 0x5e, 0x95, - 0xd3, 0x16, 0x7f, 0xb0, 0x24, 0x88, 0xd6, 0x01, 0xe4, 0x5a, 0x22, 0xae, 0x30, 0x48, 0x7f, 0xac, - 0x1f, 0xf2, 0x6b, 0xaa, 0xf6, 0xe2, 0x38, 0x3d, 0x6b, 0x93, 0xff, 0x58, 0xa3, 0x6c, 0xc7, 0x4c, - 0x08, 0xeb, 0xee, 0x16, 0xfa, 0x0c, 0xdd, 0xd2, 0x4e, 0x18, 0x13, 0x77, 0x21, 0x4e, 0xdb, 0xf4, - 0x0f, 0x16, 0xb1, 0xd7, 0xbc, 0x2d, 0xa2, 0x6f, 0x7f, 0x41, 0x04, 0x27, 0xf4, 0xec, 0x6f, 0x95, - 0x61, 0xa6, 0x57, 0x77, 0xe9, 0x92, 0x24, 0xf7, 0xbd, 0x78, 0x89, 0x8a, 0x49, 0x96, 0xb9, 0x24, - 0x97, 0x45, 0x39, 0x56, 0x18, 0x74, 0x6d, 0x44, 0xde, 0x86, 0x54, 0x96, 0x06, 0x92, 0xb5, 0xd1, - 0x60, 0xa5, 0x58, 0x40, 0x29, 0x5e, 0x48, 0x9c, 0x48, 0xdc, 0x87, 0x68, 0x6b, 0x08, 0xb3, 0x52, - 0x2c, 0xa0, 0xba, 0x41, 0xa4, 0x92, 0x63, 0x10, 0x31, 0x86, 0x68, 0xe0, 0xc1, 0x0e, 0x11, 0x7a, - 0x13, 0x60, 0xdd, 0xf3, 0xbd, 0x68, 0x93, 0x51, 0x1f, 0xec, 0x9b, 0xba, 0x12, 0xb2, 0x56, 0x14, - 0x15, 0xac, 0x51, 0x44, 0x2f, 0xc0, 0x88, 0xda, 0x9e, 0xab, 0xb5, 0x99, 0x21, 0xd3, 0x86, 0x9e, - 0xf0, 0xaa, 0x1a, 0xd6, 0xf1, 0xec, 0x77, 0xd2, 0xeb, 0x45, 0xec, 0x0a, 0x6d, 0x7c, 0xad, 0xa2, - 0xe3, 0x5b, 0x3a, 0x78, 0x7c, 0xed, 0xff, 0x5c, 0x86, 0x09, 0xa3, 0xb1, 0x4e, 0x54, 0x80, 0xa3, - 0xbd, 0x4a, 0x0f, 0x2c, 0x27, 0x26, 0x62, 0x4f, 0x9e, 0xeb, 0x67, 0xd3, 0xe8, 0xc7, 0x1b, 0xdd, - 0x0b, 0x9c, 0x12, 0xda, 0x84, 0x6a, 0xcb, 0x89, 0x98, 0x49, 0x85, 0x88, 0xbd, 0xd8, 0x1f, 0xd9, - 0x44, 0xfd, 0x70, 0xa2, 0x58, 0x3b, 0x3d, 0x78, 0x2b, 0x09, 0x71, 0x7a, 0xda, 0x52, 0x61, 0x47, - 0x5e, 0xc2, 0xa9, 0xee, 0x50, 0x89, 0x68, 0x07, 0x73, 0x18, 0x7a, 0x09, 0x46, 0x43, 0xc2, 0x56, - 0xca, 0x12, 0x95, 0xe7, 0xd8, 0xd2, 0x1b, 0x48, 0x04, 0x3f, 0xac, 0xc1, 0xb0, 0x81, 0x99, 0xc8, - 0xfd, 0x83, 0x07, 0xc8, 0xfd, 0x4f, 0xc1, 0x10, 0xfb, 0xa1, 0x56, 0x85, 0x9a, 0xa1, 0x55, 0x5e, - 0x8c, 0x25, 0x3c, 0xbd, 0x88, 0x86, 0x0b, 0x2e, 0xa2, 0xa7, 0x61, 0xbc, 0xe6, 0x90, 0xad, 0xc0, - 0x5f, 0xf6, 0xdd, 0x76, 0xe0, 0xf9, 0x31, 0x9a, 0x81, 0x0a, 0x3b, 0x4f, 0xf8, 0x7e, 0xaf, 0x50, - 0x0a, 0xb8, 0x42, 0x65, 0x77, 0xfb, 0x4f, 0x4a, 0x30, 0x56, 0x23, 0x2d, 0x12, 0x13, 0xae, 0xf7, - 0x44, 0x68, 0x05, 0xd0, 0x46, 0xe8, 0x34, 0x49, 0x9d, 0x84, 0x5e, 0xe0, 0x36, 0x48, 0x33, 0xf0, - 0xd9, 0xdd, 0x15, 0x3d, 0x20, 0x4f, 0xed, 0xed, 0xce, 0xa1, 0x4b, 0x5d, 0x50, 0x9c, 0x51, 0x03, - 0xb9, 0x30, 0xd6, 0x0e, 0x89, 0x61, 0x37, 0xb4, 0xf2, 0x45, 0x8d, 0xba, 0x5e, 0x85, 0x4b, 0xc3, - 0x46, 0x11, 0x36, 0x89, 0xa2, 0x4f, 0xc1, 0x64, 0x10, 0xb6, 0x37, 0x1d, 0xbf, 0x46, 0xda, 0xc4, - 0x77, 0xa9, 0x0a, 0x20, 0xac, 0x1d, 0xd3, 0x7b, 0xbb, 0x73, 0x93, 0x37, 0x52, 0x30, 0xdc, 0x85, - 0x8d, 0x5e, 0x87, 0xa9, 0x76, 0x18, 0xb4, 0x9d, 0x0d, 0xb6, 0x64, 0x84, 0xb4, 0xc2, 0x79, 0xd3, - 0xb9, 0xbd, 0xdd, 0xb9, 0xa9, 0x7a, 0x1a, 0xb8, 0xbf, 0x3b, 0x77, 0x82, 0x0d, 0x19, 0x2d, 0x49, - 0x80, 0xb8, 0x9b, 0x8c, 0xfd, 0x2e, 0x9c, 0xac, 0x05, 0xf7, 0xfc, 0x7b, 0x4e, 0xe8, 0x2e, 0xd4, - 0x57, 0x35, 0xe3, 0xc4, 0x6b, 0x52, 0xf9, 0xe5, 0x77, 0x82, 0x39, 0x27, 0x9b, 0x46, 0x83, 0xab, - 0x1d, 0x2b, 0x5e, 0x8b, 0xf4, 0x30, 0x87, 0xfc, 0xe3, 0x92, 0xd1, 0x66, 0x82, 0xaf, 0xee, 0x2e, - 0xac, 0x9e, 0x77, 0x17, 0x9f, 0x81, 0xe1, 0x75, 0x8f, 0xb4, 0x5c, 0x4c, 0xd6, 0xc5, 0x6c, 0x5d, - 0x28, 0x72, 0xb9, 0xb3, 0x42, 0xeb, 0x48, 0xeb, 0x18, 0x57, 0xa2, 0x57, 0x04, 0x19, 0xac, 0x08, - 0xa2, 0x0e, 0x4c, 0x4a, 0x3d, 0x4c, 0x42, 0xc5, 0x66, 0x7f, 0xae, 0x98, 0x9a, 0x67, 0x36, 0xc3, - 0xa6, 0x17, 0xa7, 0x08, 0xe2, 0xae, 0x26, 0xa8, 0xfe, 0xbc, 0x45, 0x8f, 0xba, 0x0a, 0x5b, 0xfa, - 0x4c, 0x7f, 0x66, 0xa6, 0x00, 0x56, 0x6a, 0xff, 0xa6, 0x05, 0x0f, 0x75, 0x8d, 0x96, 0xb0, 0x93, - 0x1c, 0xd9, 0x1c, 0xa5, 0x8d, 0x15, 0xa5, 0x7c, 0x63, 0x85, 0xfd, 0x5b, 0x16, 0x4c, 0x2f, 0x6f, - 0xb5, 0xe3, 0x9d, 0x9a, 0x67, 0xde, 0xb9, 0xbc, 0x08, 0x83, 0x5b, 0xc4, 0xf5, 0x3a, 0x5b, 0x62, - 0x5e, 0xe7, 0xe4, 0xc1, 0x70, 0x8d, 0x95, 0xee, 0xef, 0xce, 0x8d, 0x35, 0xe2, 0x20, 0x74, 0x36, - 0x08, 0x2f, 0xc0, 0x02, 0x9d, 0x5d, 0x29, 0x79, 0xef, 0x91, 0xab, 0xde, 0x96, 0x27, 0xaf, 0xf2, - 0x0e, 0x34, 0xf2, 0xcd, 0xcb, 0xa1, 0x9d, 0x7f, 0xb5, 0xe3, 0xf8, 0xb1, 0x17, 0xef, 0x98, 0xf2, - 0x32, 0x23, 0x84, 0x13, 0x9a, 0xf6, 0x8f, 0x2c, 0x98, 0x90, 0x1c, 0x68, 0xc1, 0x75, 0x43, 0x12, - 0x45, 0x68, 0x16, 0x4a, 0x5e, 0x5b, 0xf4, 0x14, 0x44, 0xed, 0xd2, 0x6a, 0x1d, 0x97, 0xbc, 0x36, - 0x7a, 0x1d, 0xaa, 0xfc, 0x2e, 0x30, 0x59, 0x7e, 0x7d, 0xde, 0x2d, 0x32, 0xed, 0x73, 0x4d, 0xd2, - 0xc0, 0x09, 0x39, 0x29, 0x87, 0xb3, 0xb3, 0xad, 0x6c, 0xde, 0x4c, 0x5d, 0x16, 0xe5, 0x58, 0x61, - 0xa0, 0xb3, 0x30, 0xec, 0x07, 0x2e, 0xbf, 0xae, 0xe5, 0x9c, 0x80, 0x2d, 0xea, 0xeb, 0xa2, 0x0c, - 0x2b, 0xa8, 0xfd, 0x45, 0x0b, 0x46, 0xe5, 0x37, 0x16, 0x54, 0x09, 0xe8, 0x36, 0x4c, 0xd4, 0x81, - 0x64, 0x1b, 0x52, 0x91, 0x9e, 0x41, 0x0c, 0x49, 0xbe, 0xdc, 0x8f, 0x24, 0x6f, 0xff, 0x76, 0x09, - 0xc6, 0x65, 0x77, 0x1a, 0x9d, 0x3b, 0x11, 0xa1, 0x82, 0x4e, 0xd5, 0xe1, 0x83, 0x4f, 0xe4, 0x4a, - 0x7e, 0x36, 0x4f, 0xdb, 0x33, 0xe6, 0x2c, 0x99, 0xe5, 0x05, 0x49, 0x07, 0x27, 0x24, 0xd1, 0x36, - 0x4c, 0xf9, 0x41, 0xcc, 0x0e, 0x50, 0x05, 0x2f, 0x76, 0x97, 0x92, 0x6e, 0xe7, 0x61, 0xd1, 0xce, - 0xd4, 0xf5, 0x34, 0x3d, 0xdc, 0xdd, 0x04, 0xba, 0x21, 0xad, 0x58, 0x65, 0xd6, 0xd6, 0xd3, 0xc5, - 0xda, 0xea, 0x6d, 0xc4, 0xb2, 0x7f, 0xdf, 0x82, 0xaa, 0x44, 0x3b, 0x8e, 0x4b, 0xb5, 0xdb, 0x30, - 0x14, 0xb1, 0x29, 0x92, 0xc3, 0x75, 0xae, 0xd8, 0x27, 0xf0, 0x79, 0x4d, 0xa4, 0x06, 0xfe, 0x3f, - 0xc2, 0x92, 0x1a, 0x33, 0xe7, 0xab, 0x0f, 0xf9, 0xc0, 0x99, 0xf3, 0x55, 0xcf, 0x7a, 0xdf, 0x9d, - 0x8d, 0x19, 0xf6, 0x06, 0x2a, 0xfa, 0xb6, 0x43, 0xb2, 0xee, 0xdd, 0x4f, 0x8b, 0xbe, 0x75, 0x56, - 0x8a, 0x05, 0x14, 0xad, 0xc3, 0x68, 0x53, 0x1a, 0xbc, 0x13, 0x16, 0xf2, 0xd1, 0x82, 0xb7, 0x0b, - 0xea, 0xa2, 0x8a, 0xfb, 0x4b, 0x2d, 0x69, 0x94, 0xb0, 0x41, 0x97, 0xf2, 0xa9, 0xe4, 0x2e, 0xbe, - 0x5c, 0xd0, 0x34, 0x14, 0x92, 0x38, 0x69, 0xa1, 0xe7, 0x35, 0xbc, 0xfd, 0x55, 0x0b, 0x06, 0xb9, - 0x85, 0xb4, 0x98, 0x99, 0x59, 0xbb, 0x82, 0x4b, 0xc6, 0xf3, 0x16, 0x2d, 0x14, 0x37, 0x72, 0xe8, - 0x36, 0x54, 0xd9, 0x0f, 0x66, 0xed, 0x29, 0x17, 0x71, 0x1e, 0xe3, 0xed, 0xeb, 0x5d, 0xbd, 0x25, - 0x09, 0xe0, 0x84, 0x96, 0xfd, 0x9d, 0x32, 0x65, 0x7d, 0x09, 0xaa, 0x21, 0x3d, 0x58, 0xc7, 0x21, - 0x3d, 0x94, 0x8e, 0x5e, 0x7a, 0x78, 0x17, 0x26, 0x9a, 0xda, 0x15, 0x60, 0x32, 0xe3, 0x17, 0x0b, - 0x2e, 0x2b, 0xed, 0xde, 0x90, 0x5b, 0x04, 0x97, 0x4c, 0x72, 0x38, 0x4d, 0x1f, 0x11, 0x18, 0xe5, - 0xeb, 0x41, 0xb4, 0x57, 0x61, 0xed, 0x9d, 0x2f, 0xb2, 0xc2, 0xf4, 0xc6, 0xd8, 0x2a, 0x6e, 0x68, - 0x84, 0xb0, 0x41, 0xd6, 0xfe, 0xf5, 0x01, 0x18, 0x58, 0xde, 0x26, 0x7e, 0x7c, 0x0c, 0xac, 0x6e, - 0x0b, 0xc6, 0x3d, 0x7f, 0x3b, 0x68, 0x6d, 0x13, 0x97, 0xc3, 0x0f, 0x77, 0xbc, 0x9f, 0x12, 0x8d, - 0x8c, 0xaf, 0x1a, 0xc4, 0x70, 0x8a, 0xf8, 0x51, 0xd8, 0x22, 0x5e, 0x85, 0x41, 0xbe, 0x32, 0x84, - 0x21, 0x22, 0xe7, 0xc6, 0x80, 0x0d, 0xac, 0xd8, 0x41, 0x89, 0xc5, 0x84, 0x5f, 0x56, 0x08, 0x42, - 0xe8, 0x1d, 0x18, 0x5f, 0xf7, 0xc2, 0x28, 0x5e, 0xf3, 0xb6, 0xa8, 0x0e, 0xb9, 0xd5, 0x3e, 0x84, - 0x15, 0x42, 0x8d, 0xc8, 0x8a, 0x41, 0x09, 0xa7, 0x28, 0xa3, 0x0d, 0x18, 0xa3, 0x4a, 0x70, 0xd2, - 0xd4, 0x50, 0xdf, 0x4d, 0x29, 0x23, 0xe4, 0x55, 0x9d, 0x10, 0x36, 0xe9, 0x52, 0x96, 0xd4, 0x64, - 0x4a, 0xf3, 0x30, 0x93, 0x6e, 0x14, 0x4b, 0xe2, 0xda, 0x32, 0x87, 0x51, 0xce, 0xc6, 0x7c, 0x71, - 0xaa, 0x26, 0x67, 0x4b, 0x3c, 0x6e, 0xec, 0xaf, 0xd3, 0xb3, 0x98, 0x8e, 0xe1, 0x31, 0x1c, 0x5f, - 0x97, 0xcd, 0xe3, 0xeb, 0xf1, 0x02, 0x33, 0xdb, 0xe3, 0xe8, 0x7a, 0x1b, 0x46, 0xb4, 0x89, 0x47, - 0xe7, 0xa1, 0xda, 0x94, 0xee, 0x22, 0x82, 0x8b, 0x2b, 0x51, 0x4a, 0xf9, 0x91, 0xe0, 0x04, 0x87, - 0x8e, 0x0b, 0x15, 0x41, 0xd3, 0xce, 0x65, 0x54, 0x40, 0xc5, 0x0c, 0x62, 0x3f, 0x07, 0xb0, 0x7c, - 0x9f, 0x34, 0x17, 0xb8, 0x12, 0xa9, 0xdd, 0x20, 0x5a, 0xbd, 0x6f, 0x10, 0xed, 0xaf, 0x59, 0x30, - 0xbe, 0xb2, 0x64, 0x28, 0x0d, 0xf3, 0x00, 0x5c, 0x36, 0xbe, 0x7d, 0xfb, 0xba, 0xb4, 0x90, 0x73, - 0x33, 0xa6, 0x2a, 0xc5, 0x1a, 0x06, 0x7a, 0x18, 0xca, 0xad, 0x8e, 0x2f, 0x44, 0xd6, 0xa1, 0xbd, - 0xdd, 0xb9, 0xf2, 0xd5, 0x8e, 0x8f, 0x69, 0x99, 0xe6, 0xc5, 0x55, 0x2e, 0xec, 0xc5, 0x95, 0xef, - 0x02, 0xfd, 0xe5, 0x32, 0x4c, 0xae, 0xb4, 0xc8, 0x7d, 0xa3, 0xd7, 0x4f, 0xc2, 0xa0, 0x1b, 0x7a, - 0xdb, 0x24, 0x4c, 0x0b, 0x02, 0x35, 0x56, 0x8a, 0x05, 0xb4, 0xb0, 0x63, 0xd9, 0x5b, 0xdd, 0x07, - 0xf9, 0xd1, 0x39, 0xd5, 0xe5, 0x7e, 0x33, 0x5a, 0x87, 0x21, 0x7e, 0xe3, 0x1c, 0xcd, 0x0c, 0xb0, - 0xa5, 0xf8, 0xf2, 0xc1, 0x9d, 0x49, 0x8f, 0xcf, 0xbc, 0xb0, 0xe0, 0x70, 0x97, 0x1e, 0xc5, 0xcb, - 0x44, 0x29, 0x96, 0xc4, 0x67, 0x3f, 0x01, 0xa3, 0x3a, 0x66, 0x5f, 0xbe, 0x3d, 0x7f, 0xd5, 0x82, - 0x13, 0x2b, 0xad, 0xa0, 0x79, 0x37, 0xe5, 0xf9, 0xf7, 0x02, 0x8c, 0xd0, 0xcd, 0x14, 0x19, 0x6e, - 0xb1, 0x86, 0xcb, 0xb0, 0x00, 0x61, 0x1d, 0x4f, 0xab, 0x76, 0xf3, 0xe6, 0x6a, 0x2d, 0xcb, 0xd3, - 0x58, 0x80, 0xb0, 0x8e, 0x67, 0xff, 0xa1, 0x05, 0x8f, 0x5e, 0x5a, 0x5a, 0xae, 0x93, 0x30, 0xf2, - 0xa2, 0x98, 0xf8, 0x71, 0x97, 0xb3, 0x33, 0x95, 0x19, 0x5d, 0xad, 0x2b, 0x89, 0xcc, 0x58, 0x63, - 0xbd, 0x10, 0xd0, 0x0f, 0x8a, 0xc7, 0xff, 0x57, 0x2d, 0x38, 0x71, 0xc9, 0x8b, 0x31, 0x69, 0x07, - 0x69, 0x67, 0xe3, 0x90, 0xb4, 0x83, 0xc8, 0x8b, 0x83, 0x70, 0x27, 0xed, 0x6c, 0x8c, 0x15, 0x04, - 0x6b, 0x58, 0xbc, 0xe5, 0x6d, 0x2f, 0xa2, 0x3d, 0x2d, 0x99, 0xaa, 0x2e, 0x16, 0xe5, 0x58, 0x61, - 0xd0, 0x0f, 0x73, 0xbd, 0x90, 0x89, 0x0c, 0x3b, 0x62, 0x07, 0xab, 0x0f, 0xab, 0x49, 0x00, 0x4e, - 0x70, 0xec, 0xbf, 0x6b, 0xc1, 0xc9, 0x4b, 0xad, 0x4e, 0x14, 0x93, 0x70, 0x3d, 0x32, 0x3a, 0xfb, - 0x1c, 0x54, 0x89, 0x14, 0xee, 0x45, 0x5f, 0xd5, 0xa1, 0xa1, 0xa4, 0x7e, 0xee, 0xe9, 0xac, 0xf0, - 0x0a, 0x38, 0xd4, 0xf6, 0xe7, 0xfe, 0xf9, 0xbb, 0x25, 0x18, 0xbb, 0xbc, 0xb6, 0x56, 0xbf, 0x44, - 0x62, 0xc1, 0x25, 0xf3, 0xcd, 0x5e, 0x58, 0xd3, 0xc8, 0x0f, 0x12, 0x7e, 0x3a, 0xb1, 0xd7, 0x9a, - 0xe7, 0xd1, 0x28, 0xf3, 0xab, 0x7e, 0x7c, 0x23, 0x6c, 0xc4, 0xa1, 0xe7, 0x6f, 0x64, 0xea, 0xf0, - 0x92, 0x97, 0x97, 0x7b, 0xf1, 0x72, 0xf4, 0x1c, 0x0c, 0xb2, 0x70, 0x18, 0x29, 0x7c, 0x7c, 0x58, - 0xc9, 0x09, 0xac, 0x74, 0x7f, 0x77, 0xae, 0x7a, 0x13, 0xaf, 0xf2, 0x3f, 0x58, 0xa0, 0xa2, 0xb7, - 0x60, 0x64, 0x33, 0x8e, 0xdb, 0x97, 0x89, 0xe3, 0x92, 0x50, 0xf2, 0x89, 0xb3, 0x07, 0xf3, 0x09, - 0x3a, 0x1c, 0xbc, 0x42, 0xb2, 0xb5, 0x92, 0xb2, 0x08, 0xeb, 0x14, 0xed, 0x06, 0x40, 0x02, 0x7b, - 0x40, 0x3a, 0x88, 0xfd, 0xcb, 0x25, 0x18, 0xba, 0xec, 0xf8, 0x6e, 0x8b, 0x84, 0x68, 0x05, 0x2a, - 0xe4, 0x3e, 0x69, 0x8a, 0x83, 0x3c, 0xa7, 0xeb, 0xc9, 0x61, 0xc7, 0x2d, 0x77, 0xf4, 0x3f, 0x66, - 0xf5, 0x11, 0x86, 0x21, 0xda, 0xef, 0x4b, 0xca, 0x0f, 0xfd, 0x99, 0xfc, 0x51, 0x50, 0x8b, 0x82, - 0x9f, 0x94, 0xa2, 0x08, 0x4b, 0x42, 0xcc, 0x02, 0xd5, 0x6c, 0x37, 0x28, 0x7b, 0x8b, 0x8b, 0x69, - 0x76, 0x6b, 0x4b, 0x75, 0x8e, 0x2e, 0xe8, 0x72, 0x0b, 0x94, 0x2c, 0xc4, 0x09, 0x39, 0x7b, 0x0d, - 0xaa, 0x74, 0xf2, 0x17, 0x5a, 0x9e, 0x73, 0xb0, 0x19, 0xec, 0x19, 0xa8, 0x4a, 0x43, 0x54, 0x24, - 0x9c, 0xda, 0x19, 0x55, 0x69, 0xa7, 0x8a, 0x70, 0x02, 0xb7, 0x5f, 0x82, 0x69, 0x76, 0x8f, 0xec, - 0xc4, 0x9b, 0xc6, 0x5e, 0xcc, 0x5d, 0xf4, 0xf6, 0x37, 0x2a, 0x30, 0xb5, 0xda, 0x58, 0x6a, 0x98, - 0x36, 0xcf, 0x97, 0x60, 0x94, 0x1f, 0xfb, 0x74, 0x29, 0x3b, 0x2d, 0x51, 0x5f, 0xdd, 0x7d, 0xac, - 0x69, 0x30, 0x6c, 0x60, 0xa2, 0x47, 0xa1, 0xec, 0xbd, 0xeb, 0xa7, 0xbd, 0x11, 0x57, 0x5f, 0xbd, - 0x8e, 0x69, 0x39, 0x05, 0x53, 0x09, 0x82, 0xb3, 0x4e, 0x05, 0x56, 0x52, 0xc4, 0x2b, 0x30, 0xee, - 0x45, 0xcd, 0xc8, 0x5b, 0xf5, 0x29, 0x5f, 0x71, 0x9a, 0x72, 0x53, 0x24, 0x22, 0x3f, 0xed, 0xaa, - 0x82, 0xe2, 0x14, 0xb6, 0xc6, 0xc7, 0x07, 0x0a, 0x4b, 0x21, 0xb9, 0x6e, 0xee, 0x54, 0xc0, 0x6a, - 0xb3, 0xaf, 0x8b, 0x98, 0x6f, 0x93, 0x10, 0xb0, 0xf8, 0x07, 0x47, 0x58, 0xc2, 0xd0, 0x25, 0x98, - 0x6a, 0x6e, 0x3a, 0xed, 0x85, 0x4e, 0xbc, 0x59, 0xf3, 0xa2, 0x66, 0xb0, 0x4d, 0xc2, 0x1d, 0x26, - 0x00, 0x0f, 0x27, 0x36, 0x2d, 0x05, 0x58, 0xba, 0xbc, 0x50, 0xa7, 0x98, 0xb8, 0xbb, 0x8e, 0x29, - 0x90, 0xc0, 0x11, 0x08, 0x24, 0x0b, 0x30, 0x21, 0x5b, 0x6d, 0x90, 0x88, 0x1d, 0x11, 0x23, 0xac, - 0x9f, 0x2a, 0xc0, 0x48, 0x14, 0xab, 0x5e, 0xa6, 0xf1, 0xed, 0x77, 0xa0, 0xaa, 0x7c, 0xf1, 0xa4, - 0x0b, 0xaa, 0xd5, 0xc3, 0x05, 0x35, 0x9f, 0xb9, 0x4b, 0xeb, 0x7c, 0x39, 0xd3, 0x3a, 0xff, 0x4f, - 0x2d, 0x48, 0x9c, 0x89, 0x10, 0x86, 0x6a, 0x3b, 0x60, 0x37, 0x79, 0xa1, 0xbc, 0x32, 0x7f, 0x22, - 0x67, 0xcf, 0x73, 0x9e, 0xc3, 0x07, 0xa4, 0x2e, 0xeb, 0xe2, 0x84, 0x0c, 0xba, 0x0a, 0x43, 0xed, - 0x90, 0x34, 0x62, 0x16, 0x3f, 0xd2, 0x07, 0x45, 0xbe, 0x10, 0x78, 0x4d, 0x2c, 0x49, 0xd8, 0xff, - 0xd2, 0x02, 0xe0, 0x66, 0x70, 0xc7, 0xdf, 0x20, 0xc7, 0xa0, 0x58, 0x5f, 0x87, 0x4a, 0xd4, 0x26, - 0xcd, 0x62, 0x77, 0xb1, 0x49, 0xcf, 0x1a, 0x6d, 0xd2, 0x4c, 0xa6, 0x83, 0xfe, 0xc3, 0x8c, 0x8e, - 0xfd, 0x6d, 0x80, 0xf1, 0x04, 0x8d, 0x2a, 0x37, 0xe8, 0x59, 0x23, 0x70, 0xe2, 0xe1, 0x54, 0xe0, - 0x44, 0x95, 0x61, 0x6b, 0xb1, 0x12, 0x31, 0x94, 0xb7, 0x9c, 0xfb, 0x42, 0x97, 0x7a, 0xa1, 0x68, - 0x87, 0x68, 0x4b, 0xf3, 0xd7, 0x9c, 0xfb, 0x5c, 0x74, 0x7d, 0x46, 0x2e, 0xa4, 0x6b, 0xce, 0xfd, - 0x7d, 0x7e, 0xe3, 0xca, 0xb8, 0x13, 0x55, 0xde, 0x3e, 0xfb, 0x67, 0xc9, 0x7f, 0x76, 0x0c, 0xd1, - 0xe6, 0x58, 0xab, 0x9e, 0x2f, 0x4c, 0xc1, 0x7d, 0xb6, 0xea, 0xf9, 0xe9, 0x56, 0x3d, 0xbf, 0x40, - 0xab, 0x1e, 0xf3, 0x30, 0x1e, 0x12, 0x77, 0x34, 0xcc, 0x3d, 0x73, 0xe4, 0xe2, 0xc7, 0xfb, 0x6a, - 0x5a, 0x5c, 0xf6, 0xf0, 0xe6, 0xcf, 0x4b, 0x79, 0x5d, 0x94, 0xe6, 0x76, 0x41, 0x36, 0x8d, 0xfe, - 0x9e, 0x05, 0xe3, 0xe2, 0x37, 0x26, 0xef, 0x76, 0x48, 0x14, 0x0b, 0xb9, 0xe0, 0x53, 0x87, 0xe9, - 0x8d, 0x20, 0xc1, 0x3b, 0xf5, 0x31, 0xc9, 0x7e, 0x4d, 0x60, 0x6e, 0xdf, 0x52, 0xfd, 0x41, 0xdf, - 0xb6, 0x60, 0x7a, 0xcb, 0xb9, 0xcf, 0x5b, 0xe4, 0x65, 0xd8, 0x89, 0xbd, 0x40, 0xb8, 0xa0, 0xae, - 0xf4, 0xbb, 0x4e, 0xba, 0x08, 0xf1, 0xee, 0x4a, 0xef, 0xb2, 0xe9, 0x2c, 0x94, 0xdc, 0x4e, 0x67, - 0xf6, 0x70, 0x76, 0x1d, 0x86, 0xe5, 0xc2, 0xcc, 0xd0, 0x94, 0x6a, 0xba, 0xf8, 0xd3, 0xf7, 0x05, - 0x9a, 0xa6, 0x59, 0xb1, 0x76, 0xc4, 0x52, 0x3c, 0xd2, 0x76, 0xde, 0x81, 0x51, 0x7d, 0xdd, 0x1d, - 0x69, 0x5b, 0xef, 0xc2, 0x89, 0x8c, 0x55, 0x75, 0xa4, 0x4d, 0xde, 0x83, 0x87, 0x7b, 0xae, 0x8f, - 0xa3, 0x6c, 0xd8, 0xfe, 0x5d, 0x4b, 0x67, 0x9d, 0xc7, 0x60, 0xb7, 0xba, 0x66, 0xda, 0xad, 0xce, - 0x16, 0xdd, 0x43, 0x3d, 0x8c, 0x57, 0xeb, 0x7a, 0xf7, 0xe9, 0x91, 0x80, 0xd6, 0x60, 0xb0, 0x45, - 0x4b, 0xe4, 0xb5, 0xe1, 0xb9, 0x7e, 0x76, 0x69, 0x22, 0x81, 0xb1, 0xf2, 0x08, 0x0b, 0x5a, 0xf6, - 0xb7, 0x2d, 0xa8, 0xfc, 0x25, 0x86, 0x75, 0x75, 0x91, 0x16, 0xa9, 0x09, 0xe6, 0xb1, 0x73, 0x6f, - 0xf9, 0x7e, 0x4c, 0xfc, 0x88, 0x89, 0xf1, 0x99, 0x43, 0xf4, 0x7f, 0x4a, 0x30, 0x42, 0x9b, 0x92, - 0x9e, 0x32, 0x2f, 0xc3, 0x58, 0xcb, 0xb9, 0x43, 0x5a, 0xd2, 0xe6, 0x9e, 0x56, 0x7a, 0xaf, 0xea, - 0x40, 0x6c, 0xe2, 0xd2, 0xca, 0xeb, 0xfa, 0x95, 0x84, 0x10, 0x92, 0x54, 0x65, 0xe3, 0xbe, 0x02, - 0x9b, 0xb8, 0x54, 0xeb, 0xba, 0xe7, 0xc4, 0xcd, 0x4d, 0xa1, 0x10, 0xab, 0xee, 0xde, 0xa6, 0x85, - 0x98, 0xc3, 0xa8, 0xb0, 0x27, 0x57, 0xec, 0x2d, 0x12, 0x32, 0x61, 0x8f, 0x0b, 0xd5, 0x4a, 0xd8, - 0xc3, 0x26, 0x18, 0xa7, 0xf1, 0xd1, 0x27, 0x60, 0x9c, 0x0e, 0x4e, 0xd0, 0x89, 0xa5, 0x1f, 0xd0, - 0x00, 0xf3, 0x03, 0x62, 0x6e, 0xe4, 0x6b, 0x06, 0x04, 0xa7, 0x30, 0x51, 0x1d, 0xa6, 0x3d, 0xbf, - 0xd9, 0xea, 0xb8, 0xe4, 0xa6, 0xef, 0xf9, 0x5e, 0xec, 0x39, 0x2d, 0xef, 0x3d, 0xe2, 0x0a, 0xb1, - 0x5b, 0xb9, 0x6c, 0xad, 0x66, 0xe0, 0xe0, 0xcc, 0x9a, 0xf6, 0x5b, 0x70, 0xe2, 0x6a, 0xe0, 0xb8, - 0x8b, 0x4e, 0xcb, 0xf1, 0x9b, 0x24, 0x5c, 0xf5, 0x37, 0x72, 0x7d, 0x0a, 0xf4, 0x7b, 0xff, 0x52, - 0xde, 0xbd, 0xbf, 0x1d, 0x02, 0xd2, 0x1b, 0x10, 0x3e, 0x71, 0x6f, 0xc0, 0x90, 0xc7, 0x9b, 0x12, - 0x1b, 0xe1, 0x42, 0x9e, 0x4c, 0xde, 0xd5, 0x47, 0xcd, 0xc7, 0x8b, 0x17, 0x60, 0x49, 0x92, 0x6a, - 0x70, 0x59, 0x42, 0x7c, 0xbe, 0xea, 0x6d, 0xbf, 0x00, 0x53, 0xac, 0x66, 0x9f, 0x8a, 0xdf, 0x5f, - 0xb3, 0x60, 0xe2, 0x7a, 0x2a, 0x00, 0xfa, 0x49, 0x18, 0x8c, 0x48, 0x98, 0x61, 0x59, 0x6d, 0xb0, - 0x52, 0x2c, 0xa0, 0x0f, 0xdc, 0x5a, 0xf3, 0x6b, 0x25, 0xa8, 0x32, 0xa7, 0xec, 0x36, 0x55, 0xe2, - 0x8e, 0x5e, 0x5e, 0xbe, 0x66, 0xc8, 0xcb, 0x39, 0x16, 0x03, 0xd5, 0xb1, 0x5e, 0xe2, 0x32, 0xba, - 0xa9, 0x02, 0x83, 0x0b, 0x19, 0x0b, 0x12, 0x82, 0x3c, 0x78, 0x74, 0xdc, 0x8c, 0x23, 0x96, 0x41, - 0xc3, 0xec, 0x02, 0x5f, 0xe1, 0x7e, 0xe0, 0x2e, 0xf0, 0x55, 0xcf, 0x7a, 0x70, 0xc9, 0xba, 0xd6, - 0x79, 0x76, 0x8e, 0xfc, 0x1c, 0x73, 0xb5, 0x65, 0x7b, 0x58, 0xc5, 0xd7, 0xcf, 0x09, 0xd7, 0x59, - 0x51, 0xba, 0xcf, 0x18, 0x9e, 0xf8, 0xc7, 0xd3, 0x27, 0x24, 0x55, 0xec, 0xcb, 0x30, 0x91, 0x1a, - 0x3a, 0xf4, 0x02, 0x0c, 0xb4, 0x37, 0x9d, 0x88, 0xa4, 0x9c, 0x9e, 0x06, 0xea, 0xb4, 0x70, 0x7f, - 0x77, 0x6e, 0x5c, 0x55, 0x60, 0x25, 0x98, 0x63, 0xdb, 0x9f, 0x2b, 0x41, 0xe5, 0x7a, 0xe0, 0x1e, - 0xc7, 0x52, 0xbb, 0x6c, 0x2c, 0xb5, 0x27, 0xf3, 0xf3, 0xb5, 0xf4, 0x5c, 0x65, 0xf5, 0xd4, 0x2a, - 0x3b, 0x5b, 0x80, 0xd6, 0xc1, 0x0b, 0x6c, 0x0b, 0x46, 0x58, 0x3e, 0x18, 0xe1, 0x94, 0xf5, 0x9c, - 0xa1, 0xe2, 0xcd, 0xa5, 0x54, 0xbc, 0x09, 0x0d, 0x55, 0x53, 0xf4, 0x9e, 0x82, 0x21, 0xe1, 0x04, - 0x94, 0x76, 0x34, 0x16, 0xb8, 0x58, 0xc2, 0xed, 0x7f, 0x51, 0x06, 0x23, 0xff, 0x0c, 0xfa, 0x7d, - 0x0b, 0xe6, 0x43, 0x1e, 0xb4, 0xe5, 0xd6, 0x3a, 0xa1, 0xe7, 0x6f, 0x34, 0x9a, 0x9b, 0xc4, 0xed, - 0xb4, 0x3c, 0x7f, 0x63, 0x75, 0xc3, 0x0f, 0x54, 0xf1, 0xf2, 0x7d, 0xd2, 0xec, 0x30, 0x9b, 0x7b, - 0xe1, 0xb4, 0x37, 0xea, 0x02, 0xfc, 0xe2, 0xde, 0xee, 0xdc, 0x3c, 0xee, 0xab, 0x15, 0xdc, 0x67, - 0xaf, 0xd0, 0x0f, 0x2d, 0x38, 0xcf, 0x33, 0xb0, 0x14, 0xff, 0x92, 0x42, 0xaa, 0x71, 0x5d, 0x12, - 0x4d, 0xc8, 0xad, 0x91, 0x70, 0x6b, 0xf1, 0x45, 0x31, 0xc8, 0xe7, 0xeb, 0xfd, 0xb5, 0x8a, 0xfb, - 0xed, 0xa6, 0xfd, 0xaf, 0xcb, 0x30, 0x46, 0xc7, 0x33, 0x49, 0xa1, 0xf0, 0x82, 0xb1, 0x4c, 0x1e, - 0x4b, 0x2d, 0x93, 0x29, 0x03, 0xf9, 0xc1, 0x64, 0x4f, 0x88, 0x60, 0xaa, 0xe5, 0x44, 0xf1, 0x65, + 0x02, 0x02, 0x27, 0x80, 0x02, 0x03, 0x71, 0x94, 0xc4, 0xf9, 0x50, 0x04, 0x7d, 0x18, 0x96, 0x13, + 0xc4, 0x91, 0x1c, 0x39, 0x48, 0x1c, 0x01, 0x46, 0x62, 0x05, 0x86, 0xd7, 0xd6, 0x0a, 0xf1, 0x9f, + 0x00, 0xf9, 0x91, 0xfc, 0xdb, 0x7c, 0x20, 0xa8, 0xcf, 0xae, 0xea, 0xe9, 0xd9, 0xee, 0x59, 0xde, + 0xae, 0x29, 0x21, 0xff, 0x66, 0xde, 0x7b, 0xf5, 0xaa, 0xba, 0x3e, 0x5e, 0xbd, 0x7a, 0xf5, 0xde, + 0x2b, 0x38, 0x77, 0xf7, 0xa5, 0x68, 0xde, 0x0b, 0xce, 0xdf, 0xed, 0xdc, 0x21, 0xa1, 0x4f, 0x62, + 0x12, 0x9d, 0x6f, 0xdf, 0xdd, 0x38, 0xef, 0xb4, 0xbd, 0xf3, 0xdb, 0x17, 0xce, 0x6f, 0x10, 0x9f, + 0x84, 0x4e, 0x4c, 0xdc, 0xf9, 0x76, 0x18, 0xc4, 0x01, 0x7a, 0x84, 0x53, 0xcf, 0x27, 0xd4, 0xf3, + 0xed, 0xbb, 0x1b, 0xf3, 0x4e, 0xdb, 0x9b, 0xdf, 0xbe, 0x30, 0xfb, 0xec, 0x86, 0x17, 0x6f, 0x76, + 0xee, 0xcc, 0x37, 0x83, 0xad, 0xf3, 0x1b, 0xc1, 0x46, 0x70, 0x9e, 0x15, 0xba, 0xd3, 0x59, 0x67, + 0xff, 0xd8, 0x1f, 0xf6, 0x8b, 0x33, 0x9b, 0x7d, 0x5e, 0x54, 0xed, 0xb4, 0xbd, 0x2d, 0xa7, 0xb9, + 0xe9, 0xf9, 0x24, 0xdc, 0x51, 0x95, 0x87, 0x24, 0x0a, 0x3a, 0x61, 0x93, 0xa4, 0x9b, 0x70, 0x60, + 0xa9, 0xe8, 0xfc, 0x16, 0x89, 0x9d, 0x8c, 0x86, 0xcf, 0x9e, 0xef, 0x55, 0x2a, 0xec, 0xf8, 0xb1, + 0xb7, 0xd5, 0x5d, 0xcd, 0xc7, 0xf2, 0x0a, 0x44, 0xcd, 0x4d, 0xb2, 0xe5, 0x74, 0x95, 0x7b, 0xae, + 0x57, 0xb9, 0x4e, 0xec, 0xb5, 0xce, 0x7b, 0x7e, 0x1c, 0xc5, 0x61, 0xba, 0x90, 0xfd, 0xc7, 0x16, + 0x9c, 0x59, 0xb8, 0xdd, 0x58, 0x6e, 0x39, 0x51, 0xec, 0x35, 0x17, 0x5b, 0x41, 0xf3, 0x6e, 0x23, + 0x0e, 0x42, 0x72, 0x2b, 0x68, 0x75, 0xb6, 0x48, 0x83, 0x75, 0x04, 0x3a, 0x07, 0xc3, 0xdb, 0xec, + 0xff, 0x6a, 0x6d, 0xc6, 0x3a, 0x63, 0x9d, 0xad, 0x2e, 0x4e, 0x7e, 0x7f, 0x77, 0xee, 0x43, 0x7b, + 0xbb, 0x73, 0xc3, 0xb7, 0x04, 0x1c, 0x2b, 0x0a, 0xf4, 0x24, 0x0c, 0xae, 0x47, 0x6b, 0x3b, 0x6d, + 0x32, 0x53, 0x62, 0xb4, 0xe3, 0x82, 0x76, 0x70, 0xa5, 0x41, 0xa1, 0x58, 0x60, 0xd1, 0x79, 0xa8, + 0xb6, 0x9d, 0x30, 0xf6, 0x62, 0x2f, 0xf0, 0x67, 0xca, 0x67, 0xac, 0xb3, 0x03, 0x8b, 0x53, 0x82, + 0xb4, 0x5a, 0x97, 0x08, 0x9c, 0xd0, 0xd0, 0x66, 0x84, 0xc4, 0x71, 0x6f, 0xf8, 0xad, 0x9d, 0x99, + 0xca, 0x19, 0xeb, 0xec, 0x70, 0xd2, 0x0c, 0x2c, 0xe0, 0x58, 0x51, 0xd8, 0xdf, 0x2e, 0xc1, 0xf0, + 0xc2, 0xfa, 0xba, 0xe7, 0x7b, 0xf1, 0x0e, 0x7a, 0x1b, 0x46, 0xfd, 0xc0, 0x25, 0xf2, 0x3f, 0xfb, + 0x8a, 0x91, 0x8b, 0x4f, 0xcf, 0x1f, 0x34, 0xa9, 0xe6, 0xaf, 0x6b, 0x25, 0x16, 0x27, 0xf7, 0x76, + 0xe7, 0x46, 0x75, 0x08, 0x36, 0x38, 0xa2, 0x37, 0x60, 0xa4, 0x1d, 0xb8, 0xaa, 0x82, 0x12, 0xab, + 0xe0, 0xa9, 0x83, 0x2b, 0xa8, 0x27, 0x05, 0x16, 0x27, 0xf6, 0x76, 0xe7, 0x46, 0x34, 0x00, 0xd6, + 0xd9, 0xa1, 0x16, 0x4c, 0xd0, 0xbf, 0x7e, 0xec, 0xa9, 0x1a, 0xca, 0xac, 0x86, 0x67, 0xf3, 0x6b, + 0xd0, 0x0a, 0x2d, 0x9e, 0xd8, 0xdb, 0x9d, 0x9b, 0x48, 0x01, 0x71, 0x9a, 0xb5, 0xfd, 0x1e, 0x8c, + 0x2f, 0xc4, 0xb1, 0xd3, 0xdc, 0x24, 0x2e, 0x1f, 0x5f, 0xf4, 0x3c, 0x54, 0x7c, 0x67, 0x8b, 0x88, + 0xd1, 0x3f, 0x23, 0xba, 0xbd, 0x72, 0xdd, 0xd9, 0x22, 0xfb, 0xbb, 0x73, 0x93, 0x37, 0x7d, 0xef, + 0xdd, 0x8e, 0x98, 0x33, 0x14, 0x86, 0x19, 0x35, 0xba, 0x08, 0xe0, 0x92, 0x6d, 0xaf, 0x49, 0xea, + 0x4e, 0xbc, 0x29, 0x66, 0x03, 0x12, 0x65, 0xa1, 0xa6, 0x30, 0x58, 0xa3, 0xb2, 0x3f, 0x6b, 0x41, + 0x75, 0x61, 0x3b, 0xf0, 0xdc, 0x7a, 0xe0, 0x46, 0xa8, 0x03, 0x13, 0xed, 0x90, 0xac, 0x93, 0x50, + 0x81, 0x66, 0xac, 0x33, 0xe5, 0xb3, 0x23, 0x17, 0x2f, 0xe6, 0x7c, 0xb7, 0x59, 0x68, 0xd9, 0x8f, + 0xc3, 0x9d, 0xc5, 0x87, 0x44, 0xd5, 0x13, 0x29, 0x2c, 0x4e, 0xd7, 0x61, 0x7f, 0xb7, 0x04, 0x27, + 0x17, 0xde, 0xeb, 0x84, 0xa4, 0xe6, 0x45, 0x77, 0xd3, 0x4b, 0xc1, 0xf5, 0xa2, 0xbb, 0xd7, 0x93, + 0xce, 0x50, 0x73, 0xb0, 0x26, 0xe0, 0x58, 0x51, 0xa0, 0x67, 0x61, 0x88, 0xfe, 0xbe, 0x89, 0x57, + 0xc5, 0xd7, 0x9f, 0x10, 0xc4, 0x23, 0x35, 0x27, 0x76, 0x6a, 0x1c, 0x85, 0x25, 0x0d, 0xba, 0x06, + 0x23, 0x4d, 0xb6, 0x72, 0x37, 0xae, 0x05, 0x2e, 0x61, 0x23, 0x5c, 0x5d, 0x7c, 0x86, 0x92, 0x2f, + 0x25, 0xe0, 0xfd, 0xdd, 0xb9, 0x19, 0xde, 0x36, 0xc1, 0x42, 0xc3, 0x61, 0xbd, 0x3c, 0xb2, 0xd5, + 0x42, 0xac, 0x30, 0x4e, 0x90, 0xb1, 0x08, 0xcf, 0x6a, 0x6b, 0x6a, 0x80, 0xad, 0xa9, 0xd1, 0xec, + 0xf5, 0x84, 0x2e, 0x40, 0xe5, 0xae, 0xe7, 0xbb, 0x33, 0x83, 0x8c, 0xd7, 0xa3, 0x74, 0xf8, 0xaf, + 0x78, 0xbe, 0xbb, 0xbf, 0x3b, 0x37, 0x65, 0x34, 0x87, 0x02, 0x31, 0x23, 0xb5, 0xff, 0x91, 0x25, + 0xba, 0x71, 0xc5, 0x6b, 0x99, 0x12, 0xe5, 0x22, 0x40, 0x44, 0x9a, 0x21, 0x89, 0xb5, 0x8e, 0x54, + 0x33, 0xa3, 0xa1, 0x30, 0x58, 0xa3, 0xa2, 0xf2, 0x22, 0xda, 0x74, 0x42, 0x36, 0xc1, 0x44, 0x77, + 0x2a, 0x79, 0xd1, 0x90, 0x08, 0x9c, 0xd0, 0x18, 0xf2, 0xa2, 0x9c, 0x2b, 0x2f, 0x7e, 0xcf, 0x82, + 0xa1, 0x45, 0xcf, 0x77, 0x3d, 0x7f, 0x03, 0xbd, 0x0d, 0xc3, 0x54, 0x9c, 0xbb, 0x4e, 0xec, 0x08, + 0x51, 0xf1, 0x51, 0x39, 0xdf, 0x74, 0xe9, 0x2a, 0x67, 0x5c, 0x34, 0x4f, 0xa9, 0xe9, 0xbc, 0xbb, + 0x71, 0xe7, 0x1d, 0xd2, 0x8c, 0xaf, 0x91, 0xd8, 0x49, 0x3e, 0x27, 0x81, 0x61, 0xc5, 0x15, 0xdd, + 0x84, 0xc1, 0xd8, 0x09, 0x37, 0x48, 0x2c, 0x24, 0x45, 0xce, 0x3a, 0xe6, 0x3c, 0x30, 0x9d, 0xa5, + 0xc4, 0x6f, 0x92, 0x44, 0xa6, 0xae, 0x31, 0x26, 0x58, 0x30, 0xb3, 0x9b, 0x30, 0xba, 0xe4, 0xb4, + 0x9d, 0x3b, 0x5e, 0xcb, 0x8b, 0x3d, 0x12, 0xa1, 0x9f, 0x81, 0xb2, 0xe3, 0xba, 0x6c, 0xcd, 0x54, + 0x17, 0x4f, 0xee, 0xed, 0xce, 0x95, 0x17, 0x5c, 0x3a, 0x64, 0xa0, 0xa8, 0x76, 0x30, 0xa5, 0x40, + 0x4f, 0x43, 0xc5, 0x0d, 0x83, 0xf6, 0x4c, 0x89, 0x51, 0x9e, 0xa2, 0xa3, 0x5b, 0x0b, 0x83, 0x76, + 0x8a, 0x94, 0xd1, 0xd8, 0xdf, 0x2b, 0x01, 0x5a, 0x22, 0xed, 0xcd, 0x95, 0x86, 0x31, 0xa6, 0x67, + 0x61, 0x78, 0x2b, 0xf0, 0xbd, 0x38, 0x08, 0x23, 0x51, 0x21, 0x9b, 0x4a, 0xd7, 0x04, 0x0c, 0x2b, + 0x2c, 0x3a, 0x03, 0x95, 0x76, 0x22, 0x11, 0x46, 0xa5, 0x34, 0x61, 0xb2, 0x80, 0x61, 0x28, 0x45, + 0x27, 0x22, 0xa1, 0x58, 0x02, 0x8a, 0xe2, 0x66, 0x44, 0x42, 0xcc, 0x30, 0xc9, 0x0c, 0xa2, 0x73, + 0x4b, 0x4c, 0xf0, 0xd4, 0x0c, 0xa2, 0x18, 0xac, 0x51, 0xa1, 0xb7, 0xa0, 0xca, 0xff, 0x61, 0xb2, + 0xce, 0x66, 0x7b, 0xae, 0x1c, 0xb9, 0x1a, 0x34, 0x9d, 0x56, 0xba, 0xf3, 0xc7, 0xd8, 0x8c, 0x93, + 0x8c, 0x70, 0xc2, 0xd3, 0x98, 0x71, 0x83, 0xb9, 0x33, 0xee, 0x6f, 0x5b, 0x80, 0x96, 0x3c, 0xdf, + 0x25, 0xe1, 0x31, 0xec, 0xb6, 0xfd, 0x2d, 0x86, 0x3f, 0xa1, 0x4d, 0x0b, 0xb6, 0xda, 0x81, 0x4f, + 0xfc, 0x78, 0x29, 0xf0, 0x5d, 0xbe, 0x03, 0x7f, 0x02, 0x2a, 0x31, 0xad, 0x8a, 0x37, 0xeb, 0x49, + 0x39, 0x2c, 0xb4, 0x82, 0xfd, 0xdd, 0xb9, 0x53, 0xdd, 0x25, 0x58, 0x13, 0x58, 0x19, 0xf4, 0x71, + 0x18, 0x8c, 0x62, 0x27, 0xee, 0x44, 0xa2, 0xa1, 0x8f, 0xc9, 0x86, 0x36, 0x18, 0x74, 0x7f, 0x77, + 0x6e, 0x42, 0x15, 0xe3, 0x20, 0x2c, 0x0a, 0xa0, 0xa7, 0x60, 0x68, 0x8b, 0x44, 0x91, 0xb3, 0x21, + 0x65, 0xe2, 0x84, 0x28, 0x3b, 0x74, 0x8d, 0x83, 0xb1, 0xc4, 0xa3, 0xc7, 0x61, 0x80, 0x84, 0x61, + 0x10, 0x8a, 0x19, 0x31, 0x26, 0x08, 0x07, 0x96, 0x29, 0x10, 0x73, 0x9c, 0xfd, 0x5f, 0x2c, 0x98, + 0x50, 0x6d, 0xe5, 0x75, 0x1d, 0xc3, 0x92, 0x77, 0x01, 0x9a, 0xf2, 0x03, 0x23, 0xb6, 0xd0, 0xb4, + 0x3a, 0xb2, 0xa7, 0x5f, 0x77, 0x87, 0x26, 0x75, 0x28, 0x50, 0x84, 0x35, 0xbe, 0xf6, 0xbf, 0xb5, + 0xe0, 0x44, 0xea, 0xdb, 0xae, 0x7a, 0x51, 0x8c, 0xde, 0xe8, 0xfa, 0xbe, 0xf9, 0x62, 0xdf, 0x47, + 0x4b, 0xb3, 0xaf, 0x53, 0xf3, 0x45, 0x42, 0xb4, 0x6f, 0xc3, 0x30, 0xe0, 0xc5, 0x64, 0x4b, 0x7e, + 0xd6, 0xb3, 0x05, 0x3f, 0x8b, 0xb7, 0x2f, 0x19, 0xa5, 0x55, 0xca, 0x03, 0x73, 0x56, 0xf6, 0xff, + 0xb2, 0xa0, 0xba, 0x14, 0xf8, 0xeb, 0xde, 0xc6, 0x35, 0xa7, 0x7d, 0x0c, 0xe3, 0xd3, 0x80, 0x0a, + 0xe3, 0xce, 0x3f, 0xe1, 0x42, 0xde, 0x27, 0x88, 0x86, 0xcd, 0xd3, 0x7d, 0x8f, 0xeb, 0x17, 0x4a, + 0x4c, 0x51, 0x10, 0x66, 0xcc, 0x66, 0x5f, 0x84, 0xaa, 0x22, 0x40, 0x93, 0x50, 0xbe, 0x4b, 0xb8, + 0xf2, 0x59, 0xc5, 0xf4, 0x27, 0x9a, 0x86, 0x81, 0x6d, 0xa7, 0xd5, 0x11, 0x8b, 0x17, 0xf3, 0x3f, + 0x9f, 0x28, 0xbd, 0x64, 0xd9, 0xdf, 0x63, 0x2b, 0x50, 0x54, 0xb2, 0xec, 0x6f, 0x0b, 0xe1, 0xf0, + 0x39, 0x0b, 0xa6, 0x5b, 0x19, 0x42, 0x49, 0xf4, 0xc9, 0x61, 0xc4, 0xd9, 0x23, 0xa2, 0xd9, 0xd3, + 0x59, 0x58, 0x9c, 0x59, 0x1b, 0x95, 0xf5, 0x41, 0x9b, 0x4e, 0x38, 0xa7, 0xc5, 0x9a, 0x2e, 0xd4, + 0x86, 0x1b, 0x02, 0x86, 0x15, 0xd6, 0xfe, 0x0b, 0x0b, 0xa6, 0xd5, 0x77, 0x5c, 0x21, 0x3b, 0x0d, + 0xd2, 0x22, 0xcd, 0x38, 0x08, 0x3f, 0x28, 0x5f, 0xf2, 0x28, 0x1f, 0x13, 0x2e, 0x93, 0x46, 0x04, + 0x83, 0xf2, 0x15, 0xb2, 0xc3, 0x07, 0x48, 0xff, 0xd0, 0xf2, 0x81, 0x1f, 0xfa, 0x3b, 0x16, 0x8c, + 0xa9, 0x0f, 0x3d, 0x86, 0x25, 0x77, 0xd5, 0x5c, 0x72, 0x3f, 0x53, 0x70, 0xbe, 0xf6, 0x58, 0x6c, + 0x7f, 0xab, 0x44, 0xc5, 0x86, 0xa0, 0xa9, 0x87, 0x01, 0xed, 0x24, 0x2a, 0xf1, 0x3f, 0x20, 0xa3, + 0xd4, 0xdf, 0xc7, 0x5e, 0x21, 0x3b, 0x6b, 0x01, 0xd5, 0x26, 0xb2, 0x3f, 0xd6, 0x18, 0xd4, 0xca, + 0x81, 0x83, 0xfa, 0x07, 0x25, 0x38, 0xa9, 0xba, 0xc5, 0xd8, 0xa5, 0x7f, 0x2a, 0x3b, 0xe6, 0x02, + 0x8c, 0xb8, 0x64, 0xdd, 0xe9, 0xb4, 0x62, 0x75, 0x00, 0x19, 0xe0, 0x27, 0xd3, 0x5a, 0x02, 0xc6, + 0x3a, 0x4d, 0x1f, 0x7d, 0xf9, 0x95, 0x11, 0x26, 0xcf, 0x63, 0x87, 0xce, 0x7a, 0xaa, 0xe1, 0x69, + 0x27, 0xca, 0x51, 0xfd, 0x44, 0x29, 0x4e, 0x8f, 0x8f, 0xc3, 0x80, 0xb7, 0x45, 0xf7, 0xfc, 0x92, + 0xb9, 0x95, 0xaf, 0x52, 0x20, 0xe6, 0x38, 0xf4, 0x04, 0x0c, 0x35, 0x83, 0xad, 0x2d, 0xc7, 0x77, + 0x67, 0xca, 0x4c, 0xe7, 0x1c, 0xa1, 0x6a, 0xc1, 0x12, 0x07, 0x61, 0x89, 0x43, 0x8f, 0x40, 0xc5, + 0x09, 0x37, 0xa2, 0x99, 0x0a, 0xa3, 0x19, 0xa6, 0x35, 0x2d, 0x84, 0x1b, 0x11, 0x66, 0x50, 0xaa, + 0x4b, 0xde, 0x0b, 0xc2, 0xbb, 0x9e, 0xbf, 0x51, 0xf3, 0x42, 0xa6, 0x18, 0x6a, 0xba, 0xe4, 0x6d, + 0x85, 0xc1, 0x1a, 0x15, 0xaa, 0xc3, 0x40, 0x3b, 0x08, 0xe3, 0x68, 0x66, 0x90, 0x75, 0xfc, 0x33, + 0xb9, 0xcb, 0x8f, 0x7f, 0x77, 0x3d, 0x08, 0xe3, 0xe4, 0x53, 0xe8, 0xbf, 0x08, 0x73, 0x46, 0x68, + 0x09, 0xca, 0xc4, 0xdf, 0x9e, 0x19, 0x62, 0xfc, 0x3e, 0x72, 0x30, 0xbf, 0x65, 0x7f, 0xfb, 0x96, + 0x13, 0x26, 0xf2, 0x6a, 0xd9, 0xdf, 0xc6, 0xb4, 0x34, 0x6a, 0x42, 0x55, 0xda, 0xaf, 0xa2, 0x99, + 0xe1, 0x22, 0x53, 0x11, 0x0b, 0x72, 0x4c, 0xde, 0xed, 0x78, 0x21, 0xd9, 0x22, 0x7e, 0x1c, 0x25, + 0x07, 0x2b, 0x89, 0x8d, 0x70, 0xc2, 0x17, 0x35, 0x61, 0x94, 0xeb, 0x9f, 0xd7, 0x82, 0x8e, 0x1f, + 0x47, 0x33, 0x55, 0xd6, 0xe4, 0x1c, 0x63, 0xc7, 0xad, 0xa4, 0xc4, 0xe2, 0xb4, 0x60, 0x3f, 0xaa, + 0x01, 0x23, 0x6c, 0x30, 0x45, 0x6f, 0xc0, 0x58, 0xcb, 0xdb, 0x26, 0x3e, 0x89, 0xa2, 0x7a, 0x18, + 0xdc, 0x21, 0x33, 0xc0, 0xbe, 0xe6, 0xf1, 0xbc, 0x83, 0x7f, 0x70, 0x87, 0x2c, 0x4e, 0xed, 0xed, + 0xce, 0x8d, 0x5d, 0xd5, 0x4b, 0x63, 0x93, 0x19, 0x7a, 0x0b, 0xc6, 0xa9, 0xb2, 0xeb, 0x25, 0xec, + 0x47, 0x8a, 0xb3, 0x47, 0x7b, 0xbb, 0x73, 0xe3, 0xd8, 0x28, 0x8e, 0x53, 0xec, 0xd0, 0x1a, 0x54, + 0x5b, 0xde, 0x3a, 0x69, 0xee, 0x34, 0x5b, 0x64, 0x66, 0x94, 0xf1, 0xce, 0x59, 0x9c, 0x57, 0x25, + 0x39, 0x3f, 0x60, 0xa8, 0xbf, 0x38, 0x61, 0x84, 0x6e, 0xc1, 0xa9, 0x98, 0x84, 0x5b, 0x9e, 0xef, + 0xd0, 0x45, 0x25, 0xb4, 0x5f, 0x66, 0x5d, 0x19, 0x63, 0xb3, 0xf6, 0xb4, 0xe8, 0xd8, 0x53, 0x6b, + 0x99, 0x54, 0xb8, 0x47, 0x69, 0x74, 0x03, 0x26, 0xd8, 0x7a, 0xaa, 0x77, 0x5a, 0xad, 0x7a, 0xd0, + 0xf2, 0x9a, 0x3b, 0x33, 0xe3, 0x8c, 0xe1, 0x13, 0xd2, 0x66, 0xb2, 0x6a, 0xa2, 0xe9, 0xc1, 0x30, + 0xf9, 0x87, 0xd3, 0xa5, 0x51, 0x0b, 0x26, 0x22, 0xd2, 0xec, 0x84, 0x5e, 0xbc, 0x43, 0xe7, 0x3e, + 0xb9, 0x1f, 0xcf, 0x4c, 0x14, 0x39, 0xe8, 0x36, 0xcc, 0x42, 0xdc, 0x60, 0x95, 0x02, 0xe2, 0x34, + 0x6b, 0x2a, 0x2a, 0xa2, 0xd8, 0xf5, 0xfc, 0x99, 0x49, 0x26, 0x81, 0xd4, 0xfa, 0x6a, 0x50, 0x20, + 0xe6, 0x38, 0x66, 0x3f, 0xa0, 0x3f, 0x6e, 0x50, 0x29, 0x3d, 0xc5, 0x08, 0x13, 0xfb, 0x81, 0x44, + 0xe0, 0x84, 0x86, 0xaa, 0x06, 0x71, 0xbc, 0x33, 0x83, 0x18, 0xa9, 0x5a, 0x6a, 0x6b, 0x6b, 0x9f, + 0xc6, 0x14, 0x8e, 0x6e, 0xc1, 0x10, 0xf1, 0xb7, 0x57, 0xc2, 0x60, 0x6b, 0xe6, 0x44, 0x11, 0x19, + 0xb0, 0xcc, 0x89, 0xf9, 0xfe, 0x91, 0x1c, 0x61, 0x04, 0x18, 0x4b, 0x66, 0xe8, 0x3e, 0xcc, 0x64, + 0x8c, 0x12, 0x1f, 0x94, 0x69, 0x36, 0x28, 0x9f, 0x14, 0x65, 0x67, 0xd6, 0x7a, 0xd0, 0xed, 0x1f, + 0x80, 0xc3, 0x3d, 0xb9, 0xdb, 0x77, 0x60, 0x5c, 0x09, 0x2a, 0x36, 0xde, 0x68, 0x0e, 0x06, 0xa8, + 0x2c, 0x96, 0x07, 0xfa, 0x2a, 0xed, 0x54, 0x2a, 0xa2, 0x23, 0xcc, 0xe1, 0xac, 0x53, 0xbd, 0xf7, + 0xc8, 0xe2, 0x4e, 0x4c, 0xf8, 0xc1, 0xae, 0xac, 0x75, 0xaa, 0x44, 0xe0, 0x84, 0xc6, 0xfe, 0xbf, + 0x5c, 0x4d, 0x4a, 0xa4, 0x61, 0x81, 0x9d, 0xe0, 0x1c, 0x0c, 0x6f, 0x06, 0x51, 0x4c, 0xa9, 0x59, + 0x1d, 0x03, 0x89, 0x62, 0x74, 0x59, 0xc0, 0xb1, 0xa2, 0x40, 0x2f, 0xc3, 0x58, 0x53, 0xaf, 0x40, + 0x6c, 0x63, 0x27, 0x45, 0x11, 0xb3, 0x76, 0x6c, 0xd2, 0xa2, 0x97, 0x60, 0x98, 0x19, 0xc6, 0x9b, + 0x41, 0x4b, 0x1c, 0x21, 0xe5, 0xae, 0x3c, 0x5c, 0x17, 0xf0, 0x7d, 0xed, 0x37, 0x56, 0xd4, 0xf4, + 0x20, 0x4e, 0x9b, 0xb0, 0x5a, 0x17, 0x1b, 0x88, 0x3a, 0x88, 0x5f, 0x66, 0x50, 0x2c, 0xb0, 0xf6, + 0x3f, 0x2f, 0x69, 0xbd, 0x4c, 0x0f, 0x40, 0x04, 0xbd, 0x0e, 0x43, 0xf7, 0x1c, 0x2f, 0xf6, 0xfc, + 0x0d, 0xa1, 0x3d, 0x3c, 0x57, 0x70, 0x37, 0x61, 0xc5, 0x6f, 0xf3, 0xa2, 0x7c, 0xe7, 0x13, 0x7f, + 0xb0, 0x64, 0x48, 0x79, 0x87, 0x1d, 0xdf, 0xa7, 0xbc, 0x4b, 0xfd, 0xf3, 0xc6, 0xbc, 0x28, 0xe7, + 0x2d, 0xfe, 0x60, 0xc9, 0x10, 0xad, 0x03, 0xc8, 0xb9, 0x44, 0x5c, 0x61, 0x90, 0xfe, 0x58, 0x3f, + 0xec, 0xd7, 0x54, 0xe9, 0xc5, 0x71, 0xba, 0xd7, 0x26, 0xff, 0xb1, 0xc6, 0xd9, 0x8e, 0x99, 0x12, + 0xd6, 0xdd, 0x2c, 0xf4, 0x19, 0xba, 0xa4, 0x9d, 0x30, 0x26, 0xee, 0x42, 0x9c, 0xb6, 0xe9, 0x1f, + 0xac, 0x62, 0xaf, 0x79, 0x5b, 0x44, 0x5f, 0xfe, 0x82, 0x09, 0x4e, 0xf8, 0xd9, 0xdf, 0x2a, 0xc3, + 0x4c, 0xaf, 0xe6, 0xd2, 0x29, 0x49, 0xee, 0x7b, 0xf1, 0x12, 0x55, 0x93, 0x2c, 0x73, 0x4a, 0x2e, + 0x0b, 0x38, 0x56, 0x14, 0x74, 0x6e, 0x44, 0xde, 0x86, 0x3c, 0x2c, 0x0d, 0x24, 0x73, 0xa3, 0xc1, + 0xa0, 0x58, 0x60, 0x29, 0x5d, 0x48, 0x9c, 0x48, 0xdc, 0x87, 0x68, 0x73, 0x08, 0x33, 0x28, 0x16, + 0x58, 0xdd, 0x20, 0x52, 0xc9, 0x31, 0x88, 0x18, 0x5d, 0x34, 0xf0, 0x60, 0xbb, 0x08, 0xbd, 0x09, + 0xb0, 0xee, 0xf9, 0x5e, 0xb4, 0xc9, 0xb8, 0x0f, 0xf6, 0xcd, 0x5d, 0x29, 0x59, 0x2b, 0x8a, 0x0b, + 0xd6, 0x38, 0xa2, 0x17, 0x60, 0x44, 0x2d, 0xcf, 0xd5, 0xda, 0xcc, 0x90, 0x69, 0x43, 0x4f, 0x64, + 0x55, 0x0d, 0xeb, 0x74, 0xf6, 0x3b, 0xe9, 0xf9, 0x22, 0x56, 0x85, 0xd6, 0xbf, 0x56, 0xd1, 0xfe, + 0x2d, 0x1d, 0xdc, 0xbf, 0xf6, 0x7f, 0x2e, 0xc3, 0x84, 0x51, 0x59, 0x27, 0x2a, 0x20, 0xd1, 0x5e, + 0xa5, 0x1b, 0x96, 0x13, 0x13, 0xb1, 0x26, 0xcf, 0xf5, 0xb3, 0x68, 0xf4, 0xed, 0x8d, 0xae, 0x05, + 0xce, 0x09, 0x6d, 0x42, 0xb5, 0xe5, 0x44, 0xcc, 0xa4, 0x42, 0xc4, 0x5a, 0xec, 0x8f, 0x6d, 0x72, + 0xfc, 0x70, 0xa2, 0x58, 0xdb, 0x3d, 0x78, 0x2d, 0x09, 0x73, 0xba, 0xdb, 0x52, 0x65, 0x47, 0x5e, + 0xc2, 0xa9, 0xe6, 0x50, 0x8d, 0x68, 0x07, 0x73, 0x1c, 0x7a, 0x09, 0x46, 0x43, 0xc2, 0x66, 0xca, + 0x12, 0xd5, 0xe7, 0xd8, 0xd4, 0x1b, 0x48, 0x14, 0x3f, 0xac, 0xe1, 0xb0, 0x41, 0x99, 0xe8, 0xfd, + 0x83, 0x07, 0xe8, 0xfd, 0x4f, 0xc1, 0x10, 0xfb, 0xa1, 0x66, 0x85, 0x1a, 0xa1, 0x55, 0x0e, 0xc6, + 0x12, 0x9f, 0x9e, 0x44, 0xc3, 0x05, 0x27, 0xd1, 0xd3, 0x30, 0x5e, 0x73, 0xc8, 0x56, 0xe0, 0x2f, + 0xfb, 0x6e, 0x3b, 0xf0, 0xfc, 0x18, 0xcd, 0x40, 0x85, 0xed, 0x27, 0x7c, 0xbd, 0x57, 0x28, 0x07, + 0x5c, 0xa1, 0xba, 0xbb, 0xfd, 0x27, 0x25, 0x18, 0xab, 0x91, 0x16, 0x89, 0x09, 0x3f, 0xf7, 0x44, + 0x68, 0x05, 0xd0, 0x46, 0xe8, 0x34, 0x49, 0x9d, 0x84, 0x5e, 0xe0, 0x36, 0x48, 0x33, 0xf0, 0xd9, + 0xdd, 0x15, 0xdd, 0x20, 0x4f, 0xed, 0xed, 0xce, 0xa1, 0x4b, 0x5d, 0x58, 0x9c, 0x51, 0x02, 0xb9, + 0x30, 0xd6, 0x0e, 0x89, 0x61, 0x37, 0xb4, 0xf2, 0x55, 0x8d, 0xba, 0x5e, 0x84, 0x6b, 0xc3, 0x06, + 0x08, 0x9b, 0x4c, 0xd1, 0xa7, 0x60, 0x32, 0x08, 0xdb, 0x9b, 0x8e, 0x5f, 0x23, 0x6d, 0xe2, 0xbb, + 0xf4, 0x08, 0x20, 0xac, 0x1d, 0xd3, 0x7b, 0xbb, 0x73, 0x93, 0x37, 0x52, 0x38, 0xdc, 0x45, 0x8d, + 0x5e, 0x87, 0xa9, 0x76, 0x18, 0xb4, 0x9d, 0x0d, 0x36, 0x65, 0x84, 0xb6, 0xc2, 0x65, 0xd3, 0xb9, + 0xbd, 0xdd, 0xb9, 0xa9, 0x7a, 0x1a, 0xb9, 0xbf, 0x3b, 0x77, 0x82, 0x75, 0x19, 0x85, 0x24, 0x48, + 0xdc, 0xcd, 0xc6, 0x7e, 0x17, 0x4e, 0xd6, 0x82, 0x7b, 0xfe, 0x3d, 0x27, 0x74, 0x17, 0xea, 0xab, + 0x9a, 0x71, 0xe2, 0x35, 0x79, 0xf8, 0xe5, 0x77, 0x82, 0x39, 0x3b, 0x9b, 0xc6, 0x83, 0x1f, 0x3b, + 0x56, 0xbc, 0x16, 0xe9, 0x61, 0x0e, 0xf9, 0xc7, 0x25, 0xa3, 0xce, 0x84, 0x5e, 0xdd, 0x5d, 0x58, + 0x3d, 0xef, 0x2e, 0x3e, 0x03, 0xc3, 0xeb, 0x1e, 0x69, 0xb9, 0x98, 0xac, 0x8b, 0xd1, 0xba, 0x50, + 0xe4, 0x72, 0x67, 0x85, 0x96, 0x91, 0xd6, 0x31, 0x7e, 0x88, 0x5e, 0x11, 0x6c, 0xb0, 0x62, 0x88, + 0x3a, 0x30, 0x29, 0xcf, 0x61, 0x12, 0x2b, 0x16, 0xfb, 0x73, 0xc5, 0x8e, 0x79, 0x66, 0x35, 0x6c, + 0x78, 0x71, 0x8a, 0x21, 0xee, 0xaa, 0x82, 0x9e, 0x9f, 0xb7, 0xe8, 0x56, 0x57, 0x61, 0x53, 0x9f, + 0x9d, 0x9f, 0x99, 0x29, 0x80, 0x41, 0xed, 0xdf, 0xb4, 0xe0, 0xa1, 0xae, 0xde, 0x12, 0x76, 0x92, + 0x23, 0x1b, 0xa3, 0xb4, 0xb1, 0xa2, 0x94, 0x6f, 0xac, 0xb0, 0x7f, 0xcb, 0x82, 0xe9, 0xe5, 0xad, + 0x76, 0xbc, 0x53, 0xf3, 0xcc, 0x3b, 0x97, 0x17, 0x61, 0x70, 0x8b, 0xb8, 0x5e, 0x67, 0x4b, 0x8c, + 0xeb, 0x9c, 0xdc, 0x18, 0xae, 0x31, 0xe8, 0xfe, 0xee, 0xdc, 0x58, 0x23, 0x0e, 0x42, 0x67, 0x83, + 0x70, 0x00, 0x16, 0xe4, 0x6c, 0x7b, 0xf5, 0xde, 0x23, 0x57, 0xbd, 0x2d, 0x4f, 0x5e, 0xe5, 0x1d, + 0x68, 0xe4, 0x9b, 0x97, 0x5d, 0x3b, 0xff, 0x6a, 0xc7, 0xf1, 0x63, 0x2f, 0xde, 0x11, 0xd7, 0x49, + 0x92, 0x09, 0x4e, 0xf8, 0xd9, 0x3f, 0xb2, 0x60, 0x42, 0x4a, 0x9f, 0x05, 0xd7, 0x0d, 0x49, 0x14, + 0xa1, 0x59, 0x28, 0x79, 0x6d, 0xd1, 0x4a, 0x10, 0xad, 0x2c, 0xad, 0xd6, 0x71, 0xc9, 0x6b, 0xa3, + 0xd7, 0xa1, 0xca, 0xef, 0x01, 0x93, 0xa9, 0xd7, 0xe7, 0xbd, 0x22, 0x6b, 0xcb, 0x9a, 0xe4, 0x81, + 0x13, 0x76, 0x52, 0x07, 0x67, 0xfb, 0x5a, 0xd9, 0xbc, 0x95, 0xba, 0x2c, 0xe0, 0x58, 0x51, 0xa0, + 0xb3, 0x30, 0xec, 0x07, 0x2e, 0xbf, 0xaa, 0xe5, 0x52, 0x80, 0x4d, 0xe8, 0xeb, 0x02, 0x86, 0x15, + 0xd6, 0xfe, 0xa2, 0x05, 0xa3, 0xf2, 0x1b, 0x0b, 0x1e, 0x07, 0xe8, 0x12, 0x4c, 0x8e, 0x02, 0xc9, + 0x12, 0xa4, 0xea, 0x3c, 0xc3, 0x18, 0x5a, 0x7c, 0xb9, 0x1f, 0x2d, 0xde, 0xfe, 0xed, 0x12, 0x8c, + 0xcb, 0xe6, 0x34, 0x3a, 0x77, 0x22, 0x42, 0x95, 0x9c, 0xaa, 0xc3, 0x3b, 0x9f, 0xc8, 0x59, 0xfc, + 0x6c, 0xde, 0x49, 0xcf, 0x18, 0xb3, 0x44, 0x89, 0x5a, 0x90, 0x7c, 0x70, 0xc2, 0x12, 0x6d, 0xc3, + 0x94, 0x1f, 0xc4, 0x6c, 0xf3, 0x54, 0xf8, 0x62, 0xf7, 0x28, 0xe9, 0x7a, 0x1e, 0x16, 0xf5, 0x4c, + 0x5d, 0x4f, 0xf3, 0xc3, 0xdd, 0x55, 0xa0, 0x1b, 0xd2, 0x82, 0x55, 0x66, 0x75, 0x3d, 0x5d, 0xac, + 0xae, 0xde, 0x06, 0x2c, 0xfb, 0xf7, 0x2d, 0xa8, 0x4a, 0xb2, 0xe3, 0xb8, 0x50, 0xbb, 0x0d, 0x43, + 0x11, 0x1b, 0x22, 0xd9, 0x5d, 0xe7, 0x8a, 0x7d, 0x02, 0x1f, 0xd7, 0x44, 0x63, 0xe0, 0xff, 0x23, + 0x2c, 0xb9, 0x31, 0x53, 0xbe, 0xfa, 0x90, 0x0f, 0x9c, 0x29, 0x5f, 0xb5, 0xac, 0xf7, 0xbd, 0xd9, + 0x98, 0x61, 0x6b, 0xa0, 0x6a, 0x6f, 0x3b, 0x24, 0xeb, 0xde, 0xfd, 0xb4, 0xda, 0x5b, 0x67, 0x50, + 0x2c, 0xb0, 0x68, 0x1d, 0x46, 0x9b, 0xd2, 0xd8, 0x9d, 0x88, 0x90, 0x8f, 0x16, 0xbc, 0x59, 0x50, + 0x97, 0x54, 0xdc, 0x57, 0x6a, 0x49, 0xe3, 0x84, 0x0d, 0xbe, 0x54, 0x4e, 0x25, 0xf7, 0xf0, 0xe5, + 0x82, 0x66, 0xa1, 0x90, 0xc4, 0x49, 0x0d, 0x3d, 0xaf, 0xe0, 0xed, 0xaf, 0x5a, 0x30, 0xc8, 0xad, + 0xa3, 0xc5, 0x4c, 0xcc, 0xda, 0xf5, 0x5b, 0xd2, 0x9f, 0xb7, 0x28, 0x50, 0xdc, 0xc6, 0xa1, 0xdb, + 0x50, 0x65, 0x3f, 0x98, 0xa5, 0xa7, 0x5c, 0xc4, 0x71, 0x8c, 0xd7, 0xaf, 0x37, 0xf5, 0x96, 0x64, + 0x80, 0x13, 0x5e, 0xf6, 0x77, 0xca, 0x54, 0xf4, 0x25, 0xa4, 0x86, 0xe6, 0x60, 0x1d, 0x87, 0xe6, + 0x50, 0x3a, 0x7a, 0xcd, 0xe1, 0x5d, 0x98, 0x68, 0x6a, 0xd7, 0x7f, 0xc9, 0x88, 0x5f, 0x2c, 0x38, + 0xad, 0xb4, 0x3b, 0x43, 0x6e, 0x0d, 0x5c, 0x32, 0xd9, 0xe1, 0x34, 0x7f, 0x44, 0x60, 0x94, 0xcf, + 0x07, 0x51, 0x5f, 0x85, 0xd5, 0x77, 0xbe, 0xc8, 0x0c, 0xd3, 0x2b, 0x63, 0xb3, 0xb8, 0xa1, 0x31, + 0xc2, 0x06, 0x5b, 0xfb, 0xd7, 0x07, 0x60, 0x60, 0x79, 0x9b, 0xf8, 0xf1, 0x31, 0x88, 0xba, 0x2d, + 0x18, 0xf7, 0xfc, 0xed, 0xa0, 0xb5, 0x4d, 0x5c, 0x8e, 0x3f, 0xdc, 0xf6, 0x7e, 0x4a, 0x54, 0x32, + 0xbe, 0x6a, 0x30, 0xc3, 0x29, 0xe6, 0x47, 0x61, 0x87, 0x78, 0x15, 0x06, 0xf9, 0xcc, 0x10, 0x46, + 0x88, 0x9c, 0xdb, 0x02, 0xd6, 0xb1, 0x62, 0x05, 0x25, 0xd6, 0x12, 0x7e, 0x51, 0x21, 0x18, 0xa1, + 0x77, 0x60, 0x7c, 0xdd, 0x0b, 0xa3, 0x78, 0xcd, 0xdb, 0xa2, 0xe7, 0xc7, 0xad, 0xf6, 0x21, 0x2c, + 0x10, 0xaa, 0x47, 0x56, 0x0c, 0x4e, 0x38, 0xc5, 0x19, 0x6d, 0xc0, 0x18, 0x3d, 0x00, 0x27, 0x55, + 0x0d, 0xf5, 0x5d, 0x95, 0x32, 0x40, 0x5e, 0xd5, 0x19, 0x61, 0x93, 0x2f, 0x15, 0x49, 0x4d, 0x76, + 0x60, 0x1e, 0x66, 0xda, 0x8d, 0x12, 0x49, 0xfc, 0xa4, 0xcc, 0x71, 0x54, 0xb2, 0x31, 0x3f, 0x9c, + 0xaa, 0x29, 0xd9, 0x12, 0x6f, 0x1b, 0xfb, 0xeb, 0x74, 0x2f, 0xa6, 0x7d, 0x78, 0x0c, 0xdb, 0xd7, + 0x65, 0x73, 0xfb, 0x7a, 0xbc, 0xc0, 0xc8, 0xf6, 0xd8, 0xba, 0xde, 0x86, 0x11, 0x6d, 0xe0, 0xd1, + 0x79, 0xa8, 0x36, 0xa5, 0xab, 0x88, 0x90, 0xe2, 0x4a, 0x95, 0x52, 0x3e, 0x24, 0x38, 0xa1, 0xa1, + 0xfd, 0x42, 0x55, 0xd0, 0xb4, 0x63, 0x19, 0x55, 0x50, 0x31, 0xc3, 0xd8, 0xcf, 0x01, 0x2c, 0xdf, + 0x27, 0xcd, 0x05, 0x7e, 0x80, 0xd4, 0x6e, 0x0f, 0xad, 0xde, 0xb7, 0x87, 0xf6, 0xd7, 0x2c, 0x18, + 0x5f, 0x59, 0x32, 0x0e, 0x0c, 0xf3, 0x00, 0x5c, 0x37, 0xbe, 0x7d, 0xfb, 0xba, 0xb4, 0x8e, 0x73, + 0x13, 0xa6, 0x82, 0x62, 0x8d, 0x02, 0x3d, 0x0c, 0xe5, 0x56, 0xc7, 0x17, 0x2a, 0xeb, 0xd0, 0xde, + 0xee, 0x5c, 0xf9, 0x6a, 0xc7, 0xc7, 0x14, 0xa6, 0x79, 0x70, 0x95, 0x0b, 0x7b, 0x70, 0xe5, 0xbb, + 0x3f, 0x7f, 0xb9, 0x0c, 0x93, 0x2b, 0x2d, 0x72, 0xdf, 0x68, 0xf5, 0x93, 0x30, 0xe8, 0x86, 0xde, + 0x36, 0x09, 0xd3, 0x8a, 0x40, 0x8d, 0x41, 0xb1, 0xc0, 0x16, 0x76, 0x2a, 0x7b, 0xab, 0x7b, 0x23, + 0x3f, 0x3a, 0x87, 0xba, 0xdc, 0x6f, 0x46, 0xeb, 0x30, 0xc4, 0x6f, 0x9b, 0xa3, 0x99, 0x01, 0x36, + 0x15, 0x5f, 0x3e, 0xb8, 0x31, 0xe9, 0xfe, 0x99, 0x17, 0xd6, 0x1b, 0xee, 0xce, 0xa3, 0x64, 0x99, + 0x80, 0x62, 0xc9, 0x7c, 0xf6, 0x13, 0x30, 0xaa, 0x53, 0xf6, 0xe5, 0xd7, 0xf3, 0x57, 0x2d, 0x38, + 0xb1, 0xd2, 0x0a, 0x9a, 0x77, 0x53, 0x5e, 0x7f, 0x2f, 0xc0, 0x08, 0x5d, 0x4c, 0x91, 0xe1, 0x12, + 0x6b, 0xb8, 0x0b, 0x0b, 0x14, 0xd6, 0xe9, 0xb4, 0x62, 0x37, 0x6f, 0xae, 0xd6, 0xb2, 0xbc, 0x8c, + 0x05, 0x0a, 0xeb, 0x74, 0xf6, 0x1f, 0x5a, 0xf0, 0xe8, 0xa5, 0xa5, 0xe5, 0x3a, 0x09, 0x23, 0x2f, + 0x8a, 0x89, 0x1f, 0x77, 0x39, 0x3a, 0x53, 0x9d, 0xd1, 0xd5, 0x9a, 0x92, 0xe8, 0x8c, 0x35, 0xd6, + 0x0a, 0x81, 0xfd, 0xa0, 0x78, 0xfb, 0x7f, 0xd5, 0x82, 0x13, 0x97, 0xbc, 0x18, 0x93, 0x76, 0x90, + 0x76, 0x34, 0x0e, 0x49, 0x3b, 0x88, 0xbc, 0x38, 0x08, 0x77, 0xd2, 0x8e, 0xc6, 0x58, 0x61, 0xb0, + 0x46, 0xc5, 0x6b, 0xde, 0xf6, 0x22, 0xda, 0xd2, 0x92, 0x79, 0xd4, 0xc5, 0x02, 0x8e, 0x15, 0x05, + 0xfd, 0x30, 0xd7, 0x0b, 0x99, 0xca, 0xb0, 0x23, 0x56, 0xb0, 0xfa, 0xb0, 0x9a, 0x44, 0xe0, 0x84, + 0xc6, 0xfe, 0xbb, 0x16, 0x9c, 0xbc, 0xd4, 0xea, 0x44, 0x31, 0x09, 0xd7, 0x23, 0xa3, 0xb1, 0xcf, + 0x41, 0x95, 0x48, 0xe5, 0x5e, 0xb4, 0x55, 0x6d, 0x1a, 0x4a, 0xeb, 0xe7, 0x5e, 0xce, 0x8a, 0xae, + 0x80, 0x33, 0x6d, 0x7f, 0xae, 0x9f, 0xbf, 0x5b, 0x82, 0xb1, 0xcb, 0x6b, 0x6b, 0xf5, 0x4b, 0x24, + 0x16, 0x52, 0x32, 0xdf, 0xe4, 0x85, 0xb5, 0x13, 0xf9, 0x41, 0xca, 0x4f, 0x27, 0xf6, 0x5a, 0xf3, + 0x3c, 0x12, 0x65, 0x7e, 0xd5, 0x8f, 0x6f, 0x84, 0x8d, 0x38, 0xf4, 0xfc, 0x8d, 0xcc, 0x33, 0xbc, + 0x94, 0xe5, 0xe5, 0x5e, 0xb2, 0x1c, 0x3d, 0x07, 0x83, 0x2c, 0x14, 0x46, 0x2a, 0x1f, 0x1f, 0x56, + 0x7a, 0x02, 0x83, 0xee, 0xef, 0xce, 0x55, 0x6f, 0xe2, 0x55, 0xfe, 0x07, 0x0b, 0x52, 0xf4, 0x16, + 0x8c, 0x6c, 0xc6, 0x71, 0xfb, 0x32, 0x71, 0x5c, 0x12, 0x4a, 0x39, 0x71, 0xf6, 0x60, 0x39, 0x41, + 0xbb, 0x83, 0x17, 0x48, 0x96, 0x56, 0x02, 0x8b, 0xb0, 0xce, 0xd1, 0x6e, 0x00, 0x24, 0xb8, 0x07, + 0x74, 0x06, 0xb1, 0x7f, 0xb9, 0x04, 0x43, 0x97, 0x1d, 0xdf, 0x6d, 0x91, 0x10, 0xad, 0x40, 0x85, + 0xdc, 0x27, 0x4d, 0xb1, 0x91, 0xe7, 0x34, 0x3d, 0xd9, 0xec, 0xb8, 0xd5, 0x8e, 0xfe, 0xc7, 0xac, + 0x3c, 0xc2, 0x30, 0x44, 0xdb, 0x7d, 0x49, 0xf9, 0xa0, 0x3f, 0x93, 0xdf, 0x0b, 0x6a, 0x52, 0xf0, + 0x9d, 0x52, 0x80, 0xb0, 0x64, 0xc4, 0x2c, 0x50, 0xcd, 0x76, 0x83, 0x8a, 0xb7, 0xb8, 0xd8, 0xc9, + 0x6e, 0x6d, 0xa9, 0xce, 0xc9, 0x05, 0x5f, 0x6e, 0x81, 0x92, 0x40, 0x9c, 0xb0, 0xb3, 0xd7, 0xa0, + 0x4a, 0x07, 0x7f, 0xa1, 0xe5, 0x39, 0x07, 0x9b, 0xc1, 0x9e, 0x81, 0xaa, 0x34, 0x44, 0x45, 0xc2, + 0xa1, 0x9d, 0x71, 0x95, 0x76, 0xaa, 0x08, 0x27, 0x78, 0xfb, 0x25, 0x98, 0x66, 0x77, 0xc8, 0x4e, + 0xbc, 0x69, 0xac, 0xc5, 0xdc, 0x49, 0x6f, 0x7f, 0xa3, 0x02, 0x53, 0xab, 0x8d, 0xa5, 0x86, 0x69, + 0xef, 0x7c, 0x09, 0x46, 0xf9, 0xb6, 0x4f, 0xa7, 0xb2, 0xd3, 0x12, 0xe5, 0xd5, 0xbd, 0xc7, 0x9a, + 0x86, 0xc3, 0x06, 0x25, 0x7a, 0x14, 0xca, 0xde, 0xbb, 0x7e, 0xda, 0x13, 0x71, 0xf5, 0xd5, 0xeb, + 0x98, 0xc2, 0x29, 0x9a, 0x6a, 0x10, 0x5c, 0x74, 0x2a, 0xb4, 0xd2, 0x22, 0x5e, 0x81, 0x71, 0x2f, + 0x6a, 0x46, 0xde, 0xaa, 0x4f, 0xe5, 0x8a, 0xd3, 0x94, 0x8b, 0x22, 0x51, 0xf9, 0x69, 0x53, 0x15, + 0x16, 0xa7, 0xa8, 0x35, 0x39, 0x3e, 0x50, 0x58, 0x0b, 0xc9, 0x75, 0x71, 0xa7, 0x0a, 0x56, 0x9b, + 0x7d, 0x5d, 0xc4, 0xfc, 0x9a, 0x84, 0x82, 0xc5, 0x3f, 0x38, 0xc2, 0x12, 0x87, 0x2e, 0xc1, 0x54, + 0x73, 0xd3, 0x69, 0x2f, 0x74, 0xe2, 0xcd, 0x9a, 0x17, 0x35, 0x83, 0x6d, 0x12, 0xee, 0x30, 0x05, + 0x78, 0x38, 0xb1, 0x69, 0x29, 0xc4, 0xd2, 0xe5, 0x85, 0x3a, 0xa5, 0xc4, 0xdd, 0x65, 0x4c, 0x85, + 0x04, 0x8e, 0x40, 0x21, 0x59, 0x80, 0x09, 0x59, 0x6b, 0x83, 0x44, 0x6c, 0x8b, 0x18, 0x61, 0xed, + 0x54, 0xc1, 0x45, 0x02, 0xac, 0x5a, 0x99, 0xa6, 0xb7, 0xdf, 0x81, 0xaa, 0xf2, 0xc3, 0x93, 0xee, + 0xa7, 0x56, 0x0f, 0xf7, 0xd3, 0x7c, 0xe1, 0x2e, 0x2d, 0xf3, 0xe5, 0x4c, 0xcb, 0xfc, 0x3f, 0xb1, + 0x20, 0x71, 0x24, 0x42, 0x18, 0xaa, 0xed, 0x80, 0xdd, 0xe2, 0x85, 0xf2, 0xba, 0xfc, 0x89, 0x9c, + 0x35, 0xcf, 0x65, 0x0e, 0xef, 0x90, 0xba, 0x2c, 0x8b, 0x13, 0x36, 0xe8, 0x2a, 0x0c, 0xb5, 0x43, + 0xd2, 0x88, 0x59, 0xec, 0x48, 0x1f, 0x1c, 0xf9, 0x44, 0xe0, 0x25, 0xb1, 0x64, 0x61, 0xff, 0x4b, + 0x0b, 0x80, 0x9b, 0xc1, 0x1d, 0x7f, 0x83, 0x1c, 0xc3, 0xc1, 0xfa, 0x3a, 0x54, 0xa2, 0x36, 0x69, + 0x16, 0xbb, 0x87, 0x4d, 0x5a, 0xd6, 0x68, 0x93, 0x66, 0x32, 0x1c, 0xf4, 0x1f, 0x66, 0x7c, 0xec, + 0x6f, 0x03, 0x8c, 0x27, 0x64, 0xf4, 0x70, 0x83, 0x9e, 0x35, 0x82, 0x26, 0x1e, 0x4e, 0x05, 0x4d, + 0x54, 0x19, 0xb5, 0x16, 0x27, 0x11, 0x43, 0x79, 0xcb, 0xb9, 0x2f, 0xce, 0x52, 0x2f, 0x14, 0x6d, + 0x10, 0xad, 0x69, 0xfe, 0x9a, 0x73, 0x9f, 0xab, 0xae, 0xcf, 0xc8, 0x89, 0x74, 0xcd, 0xb9, 0xbf, + 0xcf, 0x6f, 0x5b, 0x99, 0x74, 0xa2, 0x87, 0xb7, 0xcf, 0xfe, 0x59, 0xf2, 0x9f, 0x6d, 0x43, 0xb4, + 0x3a, 0x56, 0xab, 0xe7, 0x0b, 0x53, 0x70, 0x9f, 0xb5, 0x7a, 0x7e, 0xba, 0x56, 0xcf, 0x2f, 0x50, + 0xab, 0xc7, 0xbc, 0x8b, 0x87, 0xc4, 0xfd, 0x0c, 0x73, 0xcd, 0x1c, 0xb9, 0xf8, 0xf1, 0xbe, 0xaa, + 0x16, 0x17, 0x3d, 0xbc, 0xfa, 0xf3, 0x52, 0x5f, 0x17, 0xd0, 0xdc, 0x26, 0xc8, 0xaa, 0xd1, 0xdf, + 0xb3, 0x60, 0x5c, 0xfc, 0xc6, 0xe4, 0xdd, 0x0e, 0x89, 0x62, 0xa1, 0x17, 0x7c, 0xea, 0x30, 0xad, + 0x11, 0x2c, 0x78, 0xa3, 0x3e, 0x26, 0xc5, 0xaf, 0x89, 0xcc, 0x6d, 0x5b, 0xaa, 0x3d, 0xe8, 0xdb, + 0x16, 0x4c, 0x6f, 0x39, 0xf7, 0x79, 0x8d, 0x1c, 0x86, 0x9d, 0xd8, 0x0b, 0x84, 0xfb, 0xe9, 0x4a, + 0xbf, 0xf3, 0xa4, 0x8b, 0x11, 0x6f, 0xae, 0xf4, 0x2c, 0x9b, 0xce, 0x22, 0xc9, 0x6d, 0x74, 0x66, + 0x0b, 0x67, 0xd7, 0x61, 0x58, 0x4e, 0xcc, 0x8c, 0x93, 0x52, 0x4d, 0x57, 0x7f, 0xfa, 0xbe, 0x3c, + 0xd3, 0x4e, 0x56, 0xac, 0x1e, 0x31, 0x15, 0x8f, 0xb4, 0x9e, 0x77, 0x60, 0x54, 0x9f, 0x77, 0x47, + 0x5a, 0xd7, 0xbb, 0x70, 0x22, 0x63, 0x56, 0x1d, 0x69, 0x95, 0xf7, 0xe0, 0xe1, 0x9e, 0xf3, 0xe3, + 0x28, 0x2b, 0xb6, 0x7f, 0xd7, 0xd2, 0x45, 0xe7, 0x31, 0xd8, 0xad, 0xae, 0x99, 0x76, 0xab, 0xb3, + 0x45, 0xd7, 0x50, 0x0f, 0xe3, 0xd5, 0xba, 0xde, 0x7c, 0xba, 0x25, 0xa0, 0x35, 0x18, 0x6c, 0x51, + 0x88, 0xbc, 0x36, 0x3c, 0xd7, 0xcf, 0x2a, 0x4d, 0x34, 0x30, 0x06, 0x8f, 0xb0, 0xe0, 0x65, 0x7f, + 0xdb, 0x82, 0xca, 0x5f, 0x62, 0x48, 0x57, 0x17, 0x6b, 0x91, 0x96, 0x60, 0x1e, 0x3b, 0xf7, 0x96, + 0xef, 0xc7, 0xc4, 0x8f, 0x98, 0x1a, 0x9f, 0xd9, 0x45, 0xff, 0xa7, 0x04, 0x23, 0xb4, 0x2a, 0xe9, + 0x25, 0xf3, 0x32, 0x8c, 0xb5, 0x9c, 0x3b, 0xa4, 0x25, 0x6d, 0xee, 0xe9, 0x43, 0xef, 0x55, 0x1d, + 0x89, 0x4d, 0x5a, 0x5a, 0x78, 0x5d, 0xbf, 0x92, 0x10, 0x4a, 0x92, 0x2a, 0x6c, 0xdc, 0x57, 0x60, + 0x93, 0x96, 0x9e, 0xba, 0xee, 0x39, 0x71, 0x73, 0x53, 0x1c, 0x88, 0x55, 0x73, 0x6f, 0x53, 0x20, + 0xe6, 0x38, 0xaa, 0xec, 0xc9, 0x19, 0x7b, 0x8b, 0x84, 0x4c, 0xd9, 0xe3, 0x4a, 0xb5, 0x52, 0xf6, + 0xb0, 0x89, 0xc6, 0x69, 0x7a, 0xf4, 0x09, 0x18, 0xa7, 0x9d, 0x13, 0x74, 0x62, 0xe9, 0x03, 0x34, + 0xc0, 0x7c, 0x80, 0x98, 0x0b, 0xf9, 0x9a, 0x81, 0xc1, 0x29, 0x4a, 0x54, 0x87, 0x69, 0xcf, 0x6f, + 0xb6, 0x3a, 0x2e, 0xb9, 0xe9, 0x7b, 0xbe, 0x17, 0x7b, 0x4e, 0xcb, 0x7b, 0x8f, 0xb8, 0x42, 0xed, + 0x56, 0xee, 0x5a, 0xab, 0x19, 0x34, 0x38, 0xb3, 0xa4, 0xfd, 0x16, 0x9c, 0xb8, 0x1a, 0x38, 0xee, + 0xa2, 0xd3, 0x72, 0xfc, 0x26, 0x09, 0x57, 0xfd, 0x8d, 0x5c, 0x9f, 0x02, 0xfd, 0xde, 0xbf, 0x94, + 0x77, 0xef, 0x6f, 0x87, 0x80, 0xf4, 0x0a, 0x84, 0x3f, 0xdc, 0x1b, 0x30, 0xe4, 0xf1, 0xaa, 0xc4, + 0x42, 0xb8, 0x90, 0xa7, 0x93, 0x77, 0xb5, 0x51, 0xf3, 0xef, 0xe2, 0x00, 0x2c, 0x59, 0xd2, 0x13, + 0x5c, 0x96, 0x12, 0x9f, 0x7f, 0xf4, 0xb6, 0x5f, 0x80, 0x29, 0x56, 0xb2, 0xcf, 0x83, 0xdf, 0x5f, + 0xb3, 0x60, 0xe2, 0x7a, 0x2a, 0xf8, 0xf9, 0x49, 0x18, 0x8c, 0x48, 0x98, 0x61, 0x59, 0x6d, 0x30, + 0x28, 0x16, 0xd8, 0x07, 0x6e, 0xad, 0xf9, 0xb5, 0x12, 0x54, 0x99, 0x43, 0x76, 0x9b, 0x1e, 0xe2, + 0x8e, 0x5e, 0x5f, 0xbe, 0x66, 0xe8, 0xcb, 0x39, 0x16, 0x03, 0xd5, 0xb0, 0x5e, 0xea, 0x32, 0xba, + 0xa9, 0x82, 0x82, 0x0b, 0x19, 0x0b, 0x12, 0x86, 0x3c, 0x70, 0x74, 0xdc, 0x8c, 0x21, 0x96, 0x01, + 0xc3, 0xec, 0x02, 0x5f, 0xd1, 0x7e, 0xe0, 0x2e, 0xf0, 0x55, 0xcb, 0x7a, 0x48, 0xc9, 0xba, 0xd6, + 0x78, 0xb6, 0x8f, 0xfc, 0x1c, 0x73, 0xb3, 0x65, 0x6b, 0x58, 0xc5, 0xd6, 0xcf, 0x09, 0xb7, 0x59, + 0x01, 0xdd, 0x67, 0x02, 0x4f, 0xfc, 0xe3, 0xa9, 0x13, 0x92, 0x22, 0xf6, 0x65, 0x98, 0x48, 0x75, + 0x1d, 0x7a, 0x01, 0x06, 0xda, 0x9b, 0x4e, 0x44, 0x52, 0x0e, 0x4f, 0x03, 0x75, 0x0a, 0xdc, 0xdf, + 0x9d, 0x1b, 0x57, 0x05, 0x18, 0x04, 0x73, 0x6a, 0xfb, 0x73, 0x25, 0xa8, 0x5c, 0x0f, 0xdc, 0xe3, + 0x98, 0x6a, 0x97, 0x8d, 0xa9, 0xf6, 0x64, 0x7e, 0xae, 0x96, 0x9e, 0xb3, 0xac, 0x9e, 0x9a, 0x65, + 0x67, 0x0b, 0xf0, 0x3a, 0x78, 0x82, 0x6d, 0xc1, 0x08, 0xcb, 0x05, 0x23, 0x9c, 0xb2, 0x9e, 0x33, + 0x8e, 0x78, 0x73, 0xa9, 0x23, 0xde, 0x84, 0x46, 0xaa, 0x1d, 0xf4, 0x9e, 0x82, 0x21, 0xe1, 0x04, + 0x94, 0x76, 0x32, 0x16, 0xb4, 0x58, 0xe2, 0xed, 0x7f, 0x51, 0x06, 0x23, 0xf7, 0x0c, 0xfa, 0x7d, + 0x0b, 0xe6, 0x43, 0x1e, 0xb0, 0xe5, 0xd6, 0x3a, 0xa1, 0xe7, 0x6f, 0x34, 0x9a, 0x9b, 0xc4, 0xed, + 0xb4, 0x3c, 0x7f, 0x63, 0x75, 0xc3, 0x0f, 0x14, 0x78, 0xf9, 0x3e, 0x69, 0x76, 0x98, 0xcd, 0xbd, + 0x70, 0xca, 0x1b, 0x75, 0x01, 0x7e, 0x71, 0x6f, 0x77, 0x6e, 0x1e, 0xf7, 0x55, 0x0b, 0xee, 0xb3, + 0x55, 0xe8, 0x87, 0x16, 0x9c, 0xe7, 0xd9, 0x57, 0x8a, 0x7f, 0x49, 0xa1, 0xa3, 0x71, 0x5d, 0x32, + 0x4d, 0xd8, 0xad, 0x91, 0x70, 0x6b, 0xf1, 0x45, 0xd1, 0xc9, 0xe7, 0xeb, 0xfd, 0xd5, 0x8a, 0xfb, + 0x6d, 0xa6, 0xfd, 0xaf, 0xcb, 0x30, 0x46, 0xfb, 0x33, 0x49, 0x9f, 0xf0, 0x82, 0x31, 0x4d, 0x1e, + 0x4b, 0x4d, 0x93, 0x29, 0x83, 0xf8, 0xc1, 0x64, 0x4e, 0x88, 0x60, 0xaa, 0xe5, 0x44, 0xf1, 0x65, 0xe2, 0x84, 0xf1, 0x1d, 0xe2, 0xb0, 0x7b, 0xe6, 0xb4, 0x0f, 0x4b, 0x81, 0xab, 0x6b, 0x65, 0x84, - 0xbb, 0x9a, 0x26, 0x86, 0xbb, 0xe9, 0xa3, 0x6d, 0x40, 0xec, 0x4e, 0x3b, 0x74, 0xfc, 0x88, 0x7f, - 0x8b, 0x27, 0x6c, 0xf4, 0xfd, 0xb5, 0x3a, 0x2b, 0x5a, 0x45, 0x57, 0xbb, 0xa8, 0xe1, 0x8c, 0x16, - 0x34, 0xaf, 0x85, 0x81, 0xa2, 0x5e, 0x0b, 0x83, 0x39, 0x1e, 0xfe, 0xbf, 0x62, 0xc1, 0x09, 0x3a, - 0x2d, 0xa6, 0x37, 0x78, 0x84, 0x02, 0x98, 0xa0, 0xcb, 0xae, 0x45, 0x62, 0x59, 0x26, 0xf6, 0x57, - 0x8e, 0x88, 0x6f, 0xd2, 0x49, 0xe4, 0xc8, 0x2b, 0x26, 0x31, 0x9c, 0xa6, 0x6e, 0x7f, 0xcd, 0x02, - 0xe6, 0x3d, 0x79, 0x0c, 0x87, 0xd9, 0x25, 0xf3, 0x30, 0xb3, 0xf3, 0x39, 0x46, 0x8f, 0x73, 0xec, - 0x79, 0x98, 0xa4, 0xd0, 0x7a, 0x18, 0xdc, 0xdf, 0x91, 0x12, 0x7f, 0xbe, 0x74, 0xf5, 0x2b, 0x25, - 0xbe, 0x6d, 0x54, 0xf4, 0x29, 0xfa, 0xbc, 0x05, 0xc3, 0x4d, 0xa7, 0xed, 0x34, 0x79, 0xf6, 0xae, - 0x02, 0x66, 0x22, 0xa3, 0xfe, 0xfc, 0x92, 0xa8, 0xcb, 0x4d, 0x1c, 0x1f, 0x95, 0x9f, 0x2e, 0x8b, - 0x73, 0xcd, 0x1a, 0xaa, 0xf1, 0xd9, 0xbb, 0x30, 0x66, 0x10, 0x3b, 0x52, 0x7d, 0xf8, 0xf3, 0x16, - 0x67, 0xfa, 0x4a, 0x67, 0xb9, 0x07, 0x53, 0xbe, 0xf6, 0x9f, 0xb2, 0x33, 0x29, 0x50, 0xcf, 0x17, - 0x67, 0xeb, 0x8c, 0x0b, 0x6a, 0x9e, 0xa2, 0x29, 0x82, 0xb8, 0xbb, 0x0d, 0xfb, 0x37, 0x2c, 0x78, - 0x48, 0x47, 0xd4, 0xc2, 0x85, 0xf3, 0x0c, 0xd8, 0x35, 0x18, 0x0e, 0xda, 0x24, 0x74, 0x12, 0xfd, - 0xec, 0xac, 0x1c, 0xff, 0x1b, 0xa2, 0x7c, 0x7f, 0x77, 0x6e, 0x5a, 0xa7, 0x2e, 0xcb, 0xb1, 0xaa, - 0x89, 0x6c, 0x18, 0x64, 0xe3, 0x12, 0x89, 0x40, 0x6f, 0x96, 0xcd, 0x8a, 0x5d, 0x90, 0x45, 0x58, - 0x40, 0xec, 0xbf, 0x69, 0xf1, 0xe5, 0xa6, 0x77, 0x1d, 0xfd, 0x02, 0x4c, 0x6e, 0x51, 0x55, 0x6e, - 0xf9, 0x7e, 0x3b, 0xe4, 0xe6, 0x77, 0x39, 0x62, 0x2f, 0x14, 0x1f, 0x31, 0xed, 0x73, 0x17, 0x67, - 0x44, 0xef, 0x27, 0xaf, 0xa5, 0xc8, 0xe2, 0xae, 0x86, 0xec, 0x7f, 0x50, 0xe2, 0x7b, 0x96, 0xc9, - 0x70, 0x4f, 0xc1, 0x50, 0x3b, 0x70, 0x97, 0x56, 0x6b, 0x58, 0x8c, 0x95, 0x62, 0x3a, 0x75, 0x5e, - 0x8c, 0x25, 0x1c, 0x5d, 0x04, 0x20, 0xf7, 0x63, 0x12, 0xfa, 0x4e, 0x4b, 0x5d, 0xe9, 0x2b, 0x51, - 0x69, 0x59, 0x41, 0xb0, 0x86, 0x45, 0xeb, 0xb4, 0xc3, 0x60, 0xdb, 0x73, 0x59, 0x9c, 0x4b, 0xd9, - 0xac, 0x53, 0x57, 0x10, 0xac, 0x61, 0x51, 0x05, 0xba, 0xe3, 0x47, 0xfc, 0x18, 0x73, 0xee, 0x88, - 0x4c, 0x4a, 0xc3, 0x89, 0x02, 0x7d, 0x53, 0x07, 0x62, 0x13, 0x17, 0x5d, 0x81, 0xc1, 0xd8, 0x61, - 0x17, 0xd5, 0x03, 0x45, 0xbc, 0x7e, 0xd6, 0x28, 0xae, 0x9e, 0xba, 0x8a, 0x56, 0xc5, 0x82, 0x84, - 0xfd, 0x9f, 0xaa, 0x00, 0x89, 0xd4, 0x85, 0x3e, 0xd7, 0xbd, 0xe1, 0x3f, 0x56, 0x54, 0x64, 0x7b, - 0x70, 0xbb, 0x1d, 0x7d, 0xc9, 0x82, 0x11, 0xa7, 0xd5, 0x0a, 0x9a, 0x4e, 0xcc, 0x86, 0xa7, 0x54, - 0x94, 0xf5, 0x88, 0x9e, 0x2c, 0x24, 0x75, 0x79, 0x67, 0x9e, 0x93, 0x97, 0xc7, 0x1a, 0x24, 0xb7, - 0x3f, 0x7a, 0x17, 0xd0, 0x47, 0xa5, 0xd4, 0xce, 0x67, 0x78, 0x36, 0x2d, 0xb5, 0x57, 0x19, 0xc3, - 0xd5, 0x04, 0x76, 0xf4, 0x96, 0x91, 0x79, 0xa8, 0x52, 0x24, 0x58, 0xd9, 0x90, 0x43, 0xf2, 0x92, - 0x0e, 0xa1, 0xd7, 0x75, 0xf7, 0xf8, 0x81, 0x22, 0xd9, 0x00, 0x34, 0x71, 0x38, 0xc7, 0x35, 0x3e, - 0x86, 0x09, 0xd7, 0x3c, 0x79, 0x85, 0x8b, 0xdf, 0x85, 0xfc, 0x16, 0x52, 0x47, 0x76, 0x72, 0xd6, - 0xa6, 0x00, 0x38, 0xdd, 0x04, 0x7a, 0x9d, 0x07, 0x2f, 0xac, 0xfa, 0xeb, 0x81, 0x70, 0xf3, 0x3b, - 0x57, 0x60, 0xce, 0x77, 0xa2, 0x98, 0x6c, 0xd1, 0x3a, 0xc9, 0xe1, 0x7a, 0x5d, 0x50, 0xc1, 0x8a, - 0x1e, 0x5a, 0x83, 0x41, 0x16, 0x9b, 0x16, 0xcd, 0x0c, 0x17, 0x31, 0x09, 0x9a, 0x21, 0xd9, 0xc9, - 0xfe, 0x61, 0x7f, 0x23, 0x2c, 0x68, 0xa1, 0xcb, 0x32, 0x29, 0x43, 0xb4, 0xea, 0xdf, 0x8c, 0x08, - 0x4b, 0xca, 0x50, 0x5d, 0xfc, 0x48, 0x92, 0x65, 0x81, 0x97, 0x67, 0xa6, 0x6b, 0x34, 0x6a, 0x52, - 0xc1, 0x46, 0xfc, 0x97, 0x59, 0x20, 0x67, 0xa0, 0x48, 0x47, 0xcd, 0x9c, 0x91, 0xc9, 0x60, 0xdf, - 0x32, 0x89, 0xe1, 0x34, 0xf5, 0x63, 0x3d, 0x52, 0x67, 0x7d, 0x98, 0x4c, 0x6f, 0xca, 0x23, 0x3d, - 0xc2, 0x7f, 0x5c, 0x81, 0x71, 0x73, 0x71, 0xa0, 0xf3, 0x50, 0x15, 0x44, 0x54, 0x8a, 0x37, 0xb5, - 0x07, 0xae, 0x49, 0x00, 0x4e, 0x70, 0x58, 0xb2, 0x3b, 0x56, 0x5d, 0x73, 0xf0, 0x4a, 0x92, 0xdd, - 0x29, 0x08, 0xd6, 0xb0, 0xa8, 0x24, 0x7c, 0x27, 0x08, 0x62, 0x75, 0x12, 0xa8, 0x75, 0xb3, 0xc8, - 0x4a, 0xb1, 0x80, 0xd2, 0x13, 0xe0, 0x2e, 0x9d, 0xcc, 0x96, 0x69, 0xde, 0x54, 0x27, 0xc0, 0x15, - 0x1d, 0x88, 0x4d, 0x5c, 0x7a, 0xa2, 0x05, 0x11, 0x5b, 0x88, 0x42, 0xde, 0x4e, 0x1c, 0xe6, 0x1a, - 0x3c, 0x5e, 0x53, 0xc2, 0xd1, 0xa7, 0xe1, 0x21, 0x15, 0x5e, 0x89, 0xb9, 0xb9, 0x58, 0xb6, 0x38, - 0x68, 0xa8, 0xcc, 0x0f, 0x2d, 0x65, 0xa3, 0xe1, 0x5e, 0xf5, 0xd1, 0x2b, 0x30, 0x2e, 0x64, 0x65, - 0x49, 0x71, 0xc8, 0xf4, 0x7b, 0xb8, 0x62, 0x40, 0x71, 0x0a, 0x1b, 0xd5, 0x60, 0x92, 0x96, 0x30, - 0x21, 0x55, 0x52, 0xe0, 0x61, 0xa2, 0xea, 0xa8, 0xbf, 0x92, 0x82, 0xe3, 0xae, 0x1a, 0x68, 0x01, - 0x26, 0xb8, 0xb0, 0x42, 0x15, 0x43, 0x36, 0x0f, 0xc2, 0x37, 0x57, 0x6d, 0x84, 0x1b, 0x26, 0x18, - 0xa7, 0xf1, 0xd1, 0x4b, 0x30, 0xea, 0x84, 0xcd, 0x4d, 0x2f, 0x26, 0xcd, 0xb8, 0x13, 0xf2, 0x94, - 0x27, 0x9a, 0xe3, 0xc8, 0x82, 0x06, 0xc3, 0x06, 0xa6, 0xfd, 0x1e, 0x9c, 0xc8, 0x08, 0x04, 0xa0, - 0x0b, 0xc7, 0x69, 0x7b, 0xf2, 0x9b, 0x52, 0xae, 0x6f, 0x0b, 0xf5, 0x55, 0xf9, 0x35, 0x1a, 0x16, - 0x5d, 0x9d, 0xcc, 0x4e, 0xae, 0x25, 0x6d, 0x55, 0xab, 0x73, 0x45, 0x02, 0x70, 0x82, 0x63, 0xff, - 0x29, 0x80, 0x66, 0xbd, 0x29, 0xe0, 0xee, 0xf4, 0x12, 0x8c, 0xca, 0x3c, 0xc4, 0x5a, 0x32, 0x4f, - 0xf5, 0x99, 0x97, 0x34, 0x18, 0x36, 0x30, 0x69, 0xdf, 0x7c, 0x69, 0x93, 0x4a, 0x3b, 0xda, 0x29, - 0x63, 0x15, 0x4e, 0x70, 0xd0, 0x39, 0x18, 0x8e, 0x48, 0x6b, 0xfd, 0xaa, 0xe7, 0xdf, 0x15, 0x0b, - 0x5b, 0x71, 0xe6, 0x86, 0x28, 0xc7, 0x0a, 0x03, 0x2d, 0x42, 0xb9, 0xe3, 0xb9, 0x62, 0x29, 0x4b, - 0xb1, 0xa1, 0x7c, 0x73, 0xb5, 0xb6, 0xbf, 0x3b, 0xf7, 0x58, 0xaf, 0xf4, 0xca, 0x54, 0x3f, 0x8f, - 0xe6, 0xe9, 0xf6, 0xa3, 0x95, 0xb3, 0x2e, 0x0c, 0x06, 0xfb, 0xbc, 0x30, 0xb8, 0x08, 0x20, 0xbe, - 0x5a, 0xae, 0xe5, 0x72, 0x32, 0x6b, 0x97, 0x14, 0x04, 0x6b, 0x58, 0x54, 0xcb, 0x6f, 0x86, 0xc4, - 0x91, 0x8a, 0x30, 0x77, 0x50, 0x1f, 0x3e, 0xbc, 0x96, 0xbf, 0x94, 0x26, 0x86, 0xbb, 0xe9, 0xa3, - 0x00, 0xa6, 0x5c, 0x11, 0xc3, 0x9b, 0x34, 0x5a, 0xed, 0xdf, 0x2b, 0x9e, 0xf9, 0xf6, 0xa4, 0x09, - 0xe1, 0x6e, 0xda, 0xe8, 0x4d, 0x98, 0x95, 0x85, 0xdd, 0x01, 0xd4, 0x6c, 0xbb, 0x94, 0x17, 0x4f, - 0xef, 0xed, 0xce, 0xcd, 0xd6, 0x7a, 0x62, 0xe1, 0x03, 0x28, 0xa0, 0x37, 0x60, 0x90, 0x5d, 0x30, - 0x45, 0x33, 0x23, 0xec, 0xc4, 0x7b, 0xbe, 0x48, 0x6c, 0x05, 0x5d, 0xf5, 0xf3, 0xec, 0x9a, 0x4a, - 0x78, 0x0d, 0x27, 0xb7, 0x76, 0xac, 0x10, 0x0b, 0x9a, 0xa8, 0x0d, 0x23, 0x8e, 0xef, 0x07, 0xb1, - 0xc3, 0x05, 0xb1, 0xd1, 0x22, 0xb2, 0xa4, 0xd6, 0xc4, 0x42, 0x52, 0x97, 0xb7, 0xa3, 0x1c, 0x11, - 0x35, 0x08, 0xd6, 0x9b, 0x40, 0xf7, 0x60, 0x22, 0xb8, 0x47, 0x19, 0xa6, 0xbc, 0x11, 0x89, 0x66, - 0xc6, 0xcc, 0x0f, 0xcb, 0x31, 0xd4, 0x1a, 0x95, 0x35, 0x4e, 0x66, 0x12, 0xc5, 0xe9, 0x56, 0xd0, - 0xbc, 0x61, 0xae, 0x1e, 0x4f, 0x7c, 0xe3, 0x13, 0x73, 0xb5, 0x6e, 0x9d, 0x66, 0x41, 0xfa, 0xdc, - 0x1f, 0x96, 0x71, 0x84, 0x89, 0x54, 0x90, 0x7e, 0x02, 0xc2, 0x3a, 0x1e, 0xda, 0x84, 0xd1, 0xe4, - 0x6e, 0x2b, 0x8c, 0x58, 0xfe, 0x1f, 0xcd, 0xdd, 0xeb, 0xe0, 0x8f, 0x5b, 0xd5, 0x6a, 0xf2, 0x48, - 0x1f, 0xbd, 0x04, 0x1b, 0x94, 0x67, 0x3f, 0x0e, 0x23, 0xda, 0x14, 0xf7, 0xe3, 0xee, 0x3d, 0xfb, - 0x0a, 0x4c, 0xa6, 0xa7, 0xae, 0x2f, 0x77, 0xf1, 0xff, 0x51, 0x82, 0x89, 0x8c, 0x8b, 0x2d, 0x96, - 0x8d, 0x39, 0xc5, 0x64, 0x93, 0xe4, 0xcb, 0x26, 0xab, 0x2c, 0x15, 0x60, 0x95, 0x92, 0x6f, 0x97, - 0x7b, 0xf2, 0x6d, 0xc1, 0x1e, 0x2b, 0xef, 0x87, 0x3d, 0x9a, 0x27, 0xd2, 0x40, 0xa1, 0x13, 0xe9, - 0x01, 0xb0, 0x54, 0xe3, 0x50, 0x1b, 0x2a, 0x70, 0xa8, 0x7d, 0xb5, 0x04, 0x93, 0x89, 0x6b, 0xbc, - 0x48, 0x83, 0x7e, 0xf4, 0x17, 0x1e, 0x6b, 0xc6, 0x85, 0x47, 0x5e, 0x96, 0xf3, 0x54, 0xff, 0x7a, - 0x5e, 0x7e, 0xbc, 0x91, 0xba, 0xfc, 0x78, 0xbe, 0x4f, 0xba, 0x07, 0x5f, 0x84, 0x7c, 0xab, 0x04, - 0x27, 0xd3, 0x55, 0x96, 0x5a, 0x8e, 0xb7, 0x75, 0x0c, 0xe3, 0xf5, 0x69, 0x63, 0xbc, 0x5e, 0xec, - 0xef, 0xbb, 0x58, 0x27, 0x7b, 0x0e, 0x9a, 0x93, 0x1a, 0xb4, 0x8f, 0x1f, 0x86, 0xf8, 0xc1, 0x23, - 0xf7, 0x47, 0x16, 0x3c, 0x9c, 0x59, 0xef, 0x18, 0x4c, 0xbc, 0xaf, 0x99, 0x26, 0xde, 0xe7, 0x0e, + 0xbb, 0x9a, 0x66, 0x86, 0xbb, 0xf9, 0xa3, 0x6d, 0x40, 0xec, 0x4e, 0x3b, 0x74, 0xfc, 0x88, 0x7f, + 0x8b, 0x27, 0x6c, 0xf4, 0xfd, 0xd5, 0x3a, 0x2b, 0x6a, 0x45, 0x57, 0xbb, 0xb8, 0xe1, 0x8c, 0x1a, + 0x34, 0xaf, 0x85, 0x81, 0xa2, 0x5e, 0x0b, 0x83, 0x39, 0xde, 0xfd, 0xbf, 0x62, 0xc1, 0x09, 0x3a, + 0x2c, 0xa6, 0x27, 0x78, 0x84, 0x02, 0x98, 0xa0, 0xd3, 0xae, 0x45, 0x62, 0x09, 0x13, 0xeb, 0x2b, + 0x47, 0xc5, 0x37, 0xf9, 0x24, 0x7a, 0xe4, 0x15, 0x93, 0x19, 0x4e, 0x73, 0xb7, 0xbf, 0x66, 0x01, + 0xf3, 0x9e, 0x3c, 0x86, 0xcd, 0xec, 0x92, 0xb9, 0x99, 0xd9, 0xf9, 0x12, 0xa3, 0xc7, 0x3e, 0xf6, + 0x3c, 0x4c, 0x52, 0x6c, 0x3d, 0x0c, 0xee, 0xef, 0x48, 0x8d, 0x3f, 0x5f, 0xbb, 0xfa, 0x95, 0x12, + 0x5f, 0x36, 0x2a, 0xf2, 0x14, 0x7d, 0xde, 0x82, 0xe1, 0xa6, 0xd3, 0x76, 0x9a, 0x3c, 0x73, 0x57, + 0x01, 0x33, 0x91, 0x51, 0x7e, 0x7e, 0x49, 0x94, 0xe5, 0x26, 0x8e, 0x8f, 0xca, 0x4f, 0x97, 0xe0, + 0x5c, 0xb3, 0x86, 0xaa, 0x7c, 0xf6, 0x2e, 0x8c, 0x19, 0xcc, 0x8e, 0xf4, 0x3c, 0xfc, 0x79, 0x8b, + 0x0b, 0x7d, 0x75, 0x66, 0xb9, 0x07, 0x53, 0xbe, 0xf6, 0x9f, 0x8a, 0x33, 0xa9, 0x50, 0xcf, 0x17, + 0x17, 0xeb, 0x4c, 0x0a, 0x6a, 0x9e, 0xa2, 0x29, 0x86, 0xb8, 0xbb, 0x0e, 0xfb, 0x37, 0x2c, 0x78, + 0x48, 0x27, 0xd4, 0x42, 0x85, 0xf3, 0x0c, 0xd8, 0x35, 0x18, 0x0e, 0xda, 0x24, 0x74, 0x92, 0xf3, + 0xd9, 0x59, 0xd9, 0xff, 0x37, 0x04, 0x7c, 0x7f, 0x77, 0x6e, 0x5a, 0xe7, 0x2e, 0xe1, 0x58, 0x95, + 0x44, 0x36, 0x0c, 0xb2, 0x7e, 0x89, 0x44, 0x90, 0x37, 0xcb, 0x64, 0xc5, 0x2e, 0xc8, 0x22, 0x2c, + 0x30, 0xf6, 0xdf, 0xb4, 0xf8, 0x74, 0xd3, 0x9b, 0x8e, 0x7e, 0x01, 0x26, 0xb7, 0xe8, 0x51, 0x6e, + 0xf9, 0x7e, 0x3b, 0xe4, 0xe6, 0x77, 0xd9, 0x63, 0x2f, 0x14, 0xef, 0x31, 0xed, 0x73, 0x17, 0x67, + 0x44, 0xeb, 0x27, 0xaf, 0xa5, 0xd8, 0xe2, 0xae, 0x8a, 0xec, 0x7f, 0x50, 0xe2, 0x6b, 0x96, 0xe9, + 0x70, 0x4f, 0xc1, 0x50, 0x3b, 0x70, 0x97, 0x56, 0x6b, 0x58, 0xf4, 0x95, 0x12, 0x3a, 0x75, 0x0e, + 0xc6, 0x12, 0x8f, 0x2e, 0x02, 0x90, 0xfb, 0x31, 0x09, 0x7d, 0xa7, 0xa5, 0xae, 0xf4, 0x95, 0xaa, + 0xb4, 0xac, 0x30, 0x58, 0xa3, 0xa2, 0x65, 0xda, 0x61, 0xb0, 0xed, 0xb9, 0x2c, 0xc6, 0xa5, 0x6c, + 0x96, 0xa9, 0x2b, 0x0c, 0xd6, 0xa8, 0xe8, 0x01, 0xba, 0xe3, 0x47, 0x7c, 0x1b, 0x73, 0xee, 0x88, + 0x2c, 0x4a, 0xc3, 0xc9, 0x01, 0xfa, 0xa6, 0x8e, 0xc4, 0x26, 0x2d, 0xba, 0x02, 0x83, 0xb1, 0xc3, + 0x2e, 0xaa, 0x07, 0x8a, 0x78, 0xfd, 0xac, 0x51, 0x5a, 0x3d, 0x6d, 0x15, 0x2d, 0x8a, 0x05, 0x0b, + 0xfb, 0x3f, 0x55, 0x01, 0x12, 0xad, 0x0b, 0x7d, 0xae, 0x7b, 0xc1, 0x7f, 0xac, 0xa8, 0xca, 0xf6, + 0xe0, 0x56, 0x3b, 0xfa, 0x92, 0x05, 0x23, 0x4e, 0xab, 0x15, 0x34, 0x9d, 0x98, 0x75, 0x4f, 0xa9, + 0xa8, 0xe8, 0x11, 0x2d, 0x59, 0x48, 0xca, 0xf2, 0xc6, 0x3c, 0x27, 0x2f, 0x8f, 0x35, 0x4c, 0x6e, + 0x7b, 0xf4, 0x26, 0xa0, 0x8f, 0x4a, 0xad, 0x9d, 0x8f, 0xf0, 0x6c, 0x5a, 0x6b, 0xaf, 0x32, 0x81, + 0xab, 0x29, 0xec, 0xe8, 0x2d, 0x23, 0xeb, 0x50, 0xa5, 0x48, 0xa0, 0xb2, 0xa1, 0x87, 0xe4, 0x25, + 0x1c, 0x42, 0xaf, 0xeb, 0xee, 0xf1, 0x03, 0x45, 0x32, 0x01, 0x68, 0xea, 0x70, 0x8e, 0x6b, 0x7c, + 0x0c, 0x13, 0xae, 0xb9, 0xf3, 0x0a, 0x17, 0xbf, 0x0b, 0xf9, 0x35, 0xa4, 0xb6, 0xec, 0x64, 0xaf, + 0x4d, 0x21, 0x70, 0xba, 0x0a, 0xf4, 0x3a, 0x0f, 0x5e, 0x58, 0xf5, 0xd7, 0x03, 0xe1, 0xe6, 0x77, + 0xae, 0xc0, 0x98, 0xef, 0x44, 0x31, 0xd9, 0xa2, 0x65, 0x92, 0xcd, 0xf5, 0xba, 0xe0, 0x82, 0x15, + 0x3f, 0xb4, 0x06, 0x83, 0x2c, 0x2e, 0x2d, 0x9a, 0x19, 0x2e, 0x62, 0x12, 0x34, 0xc3, 0xb1, 0x93, + 0xf5, 0xc3, 0xfe, 0x46, 0x58, 0xf0, 0x42, 0x97, 0x65, 0x42, 0x86, 0x68, 0xd5, 0xbf, 0x19, 0x11, + 0x96, 0x90, 0xa1, 0xba, 0xf8, 0x91, 0x24, 0xc3, 0x02, 0x87, 0x67, 0xa6, 0x6a, 0x34, 0x4a, 0x52, + 0xc5, 0x46, 0xfc, 0x97, 0x19, 0x20, 0x67, 0xa0, 0x48, 0x43, 0xcd, 0x7c, 0x91, 0x49, 0x67, 0xdf, + 0x32, 0x99, 0xe1, 0x34, 0xf7, 0x63, 0xdd, 0x52, 0x67, 0x7d, 0x98, 0x4c, 0x2f, 0xca, 0x23, 0xdd, + 0xc2, 0x7f, 0x5c, 0x81, 0x71, 0x73, 0x72, 0xa0, 0xf3, 0x50, 0x15, 0x4c, 0x54, 0x7a, 0x37, 0xb5, + 0x06, 0xae, 0x49, 0x04, 0x4e, 0x68, 0x58, 0xa2, 0x3b, 0x56, 0x5c, 0x73, 0xf0, 0x4a, 0x12, 0xdd, + 0x29, 0x0c, 0xd6, 0xa8, 0xa8, 0x26, 0x7c, 0x27, 0x08, 0x62, 0xb5, 0x13, 0xa8, 0x79, 0xb3, 0xc8, + 0xa0, 0x58, 0x60, 0xe9, 0x0e, 0x70, 0x97, 0x0e, 0x66, 0xcb, 0x34, 0x6f, 0xaa, 0x1d, 0xe0, 0x8a, + 0x8e, 0xc4, 0x26, 0x2d, 0xdd, 0xd1, 0x82, 0x88, 0x4d, 0x44, 0xa1, 0x6f, 0x27, 0x0e, 0x73, 0x0d, + 0x1e, 0xab, 0x29, 0xf1, 0xe8, 0xd3, 0xf0, 0x90, 0x0a, 0xad, 0xc4, 0xdc, 0x5c, 0x2c, 0x6b, 0x1c, + 0x34, 0x8e, 0xcc, 0x0f, 0x2d, 0x65, 0x93, 0xe1, 0x5e, 0xe5, 0xd1, 0x2b, 0x30, 0x2e, 0x74, 0x65, + 0xc9, 0x71, 0xc8, 0xf4, 0x7b, 0xb8, 0x62, 0x60, 0x71, 0x8a, 0x1a, 0xd5, 0x60, 0x92, 0x42, 0x98, + 0x92, 0x2a, 0x39, 0xf0, 0x10, 0x51, 0xb5, 0xd5, 0x5f, 0x49, 0xe1, 0x71, 0x57, 0x09, 0xb4, 0x00, + 0x13, 0x5c, 0x59, 0xa1, 0x07, 0x43, 0x36, 0x0e, 0xc2, 0x37, 0x57, 0x2d, 0x84, 0x1b, 0x26, 0x1a, + 0xa7, 0xe9, 0xd1, 0x4b, 0x30, 0xea, 0x84, 0xcd, 0x4d, 0x2f, 0x26, 0xcd, 0xb8, 0x13, 0xf2, 0x74, + 0x27, 0x9a, 0xe3, 0xc8, 0x82, 0x86, 0xc3, 0x06, 0xa5, 0xfd, 0x1e, 0x9c, 0xc8, 0x08, 0x04, 0xa0, + 0x13, 0xc7, 0x69, 0x7b, 0xf2, 0x9b, 0x52, 0xae, 0x6f, 0x0b, 0xf5, 0x55, 0xf9, 0x35, 0x1a, 0x15, + 0x9d, 0x9d, 0xcc, 0x4e, 0xae, 0x25, 0x6c, 0x55, 0xb3, 0x73, 0x45, 0x22, 0x70, 0x42, 0x63, 0xff, + 0x29, 0x80, 0x66, 0xbd, 0x29, 0xe0, 0xee, 0xf4, 0x12, 0x8c, 0xca, 0x1c, 0xc4, 0x5a, 0x22, 0x4f, + 0xf5, 0x99, 0x97, 0x34, 0x1c, 0x36, 0x28, 0x69, 0xdb, 0x7c, 0x69, 0x93, 0x4a, 0x3b, 0xda, 0x29, + 0x63, 0x15, 0x4e, 0x68, 0xd0, 0x39, 0x18, 0x8e, 0x48, 0x6b, 0xfd, 0xaa, 0xe7, 0xdf, 0x15, 0x13, + 0x5b, 0x49, 0xe6, 0x86, 0x80, 0x63, 0x45, 0x81, 0x16, 0xa1, 0xdc, 0xf1, 0x5c, 0x31, 0x95, 0xa5, + 0xda, 0x50, 0xbe, 0xb9, 0x5a, 0xdb, 0xdf, 0x9d, 0x7b, 0xac, 0x57, 0x6a, 0x65, 0x7a, 0x3e, 0x8f, + 0xe6, 0xe9, 0xf2, 0xa3, 0x85, 0xb3, 0x2e, 0x0c, 0x06, 0xfb, 0xbc, 0x30, 0xb8, 0x08, 0x20, 0xbe, + 0x5a, 0xce, 0xe5, 0x72, 0x32, 0x6a, 0x97, 0x14, 0x06, 0x6b, 0x54, 0xf4, 0x94, 0xdf, 0x0c, 0x89, + 0x23, 0x0f, 0xc2, 0xdc, 0x41, 0x7d, 0xf8, 0xf0, 0xa7, 0xfc, 0xa5, 0x34, 0x33, 0xdc, 0xcd, 0x1f, + 0x05, 0x30, 0xe5, 0x8a, 0xf8, 0xdd, 0xa4, 0xd2, 0x6a, 0xff, 0x5e, 0xf1, 0xcc, 0xb7, 0x27, 0xcd, + 0x08, 0x77, 0xf3, 0x46, 0x6f, 0xc2, 0xac, 0x04, 0x76, 0x07, 0x4f, 0xb3, 0xe5, 0x52, 0x5e, 0x3c, + 0xbd, 0xb7, 0x3b, 0x37, 0x5b, 0xeb, 0x49, 0x85, 0x0f, 0xe0, 0x80, 0xde, 0x80, 0x41, 0x76, 0xc1, + 0x14, 0xcd, 0x8c, 0xb0, 0x1d, 0xef, 0xf9, 0x22, 0xb1, 0x15, 0x74, 0xd6, 0xcf, 0xb3, 0x6b, 0x2a, + 0xe1, 0x35, 0x9c, 0xdc, 0xda, 0x31, 0x20, 0x16, 0x3c, 0x51, 0x1b, 0x46, 0x1c, 0xdf, 0x0f, 0x62, + 0x87, 0x2b, 0x62, 0xa3, 0x45, 0x74, 0x49, 0xad, 0x8a, 0x85, 0xa4, 0x2c, 0xaf, 0x47, 0x39, 0x22, + 0x6a, 0x18, 0xac, 0x57, 0x81, 0xee, 0xc1, 0x44, 0x70, 0x8f, 0x0a, 0x4c, 0x79, 0x23, 0x12, 0xcd, + 0x8c, 0x99, 0x1f, 0x96, 0x63, 0xa8, 0x35, 0x0a, 0x6b, 0x92, 0xcc, 0x64, 0x8a, 0xd3, 0xb5, 0xa0, + 0x79, 0xc3, 0x5c, 0x3d, 0x9e, 0xf8, 0xc6, 0x27, 0xe6, 0x6a, 0xdd, 0x3a, 0xcd, 0x02, 0xf4, 0xb9, + 0x3f, 0x2c, 0x93, 0x08, 0x13, 0xa9, 0x00, 0xfd, 0x04, 0x85, 0x75, 0x3a, 0xb4, 0x09, 0xa3, 0xc9, + 0xdd, 0x56, 0x18, 0xb1, 0xdc, 0x3f, 0x9a, 0xbb, 0xd7, 0xc1, 0x1f, 0xb7, 0xaa, 0x95, 0xe4, 0x91, + 0x3e, 0x3a, 0x04, 0x1b, 0x9c, 0x67, 0x3f, 0x0e, 0x23, 0xda, 0x10, 0xf7, 0xe3, 0xee, 0x3d, 0xfb, + 0x0a, 0x4c, 0xa6, 0x87, 0xae, 0x2f, 0x77, 0xf1, 0xff, 0x51, 0x82, 0x89, 0x8c, 0x8b, 0x2d, 0x96, + 0x89, 0x39, 0x25, 0x64, 0x93, 0xc4, 0xcb, 0xa6, 0xa8, 0x2c, 0x15, 0x10, 0x95, 0x52, 0x6e, 0x97, + 0x7b, 0xca, 0x6d, 0x21, 0x1e, 0x2b, 0xef, 0x47, 0x3c, 0x9a, 0x3b, 0xd2, 0x40, 0xa1, 0x1d, 0xe9, + 0x01, 0x88, 0x54, 0x63, 0x53, 0x1b, 0x2a, 0xb0, 0xa9, 0x7d, 0xb5, 0x04, 0x93, 0x89, 0x6b, 0xbc, + 0x48, 0x81, 0x7e, 0xf4, 0x17, 0x1e, 0x6b, 0xc6, 0x85, 0x47, 0x5e, 0x86, 0xf3, 0x54, 0xfb, 0x7a, + 0x5e, 0x7e, 0xbc, 0x91, 0xba, 0xfc, 0x78, 0xbe, 0x4f, 0xbe, 0x07, 0x5f, 0x84, 0x7c, 0xab, 0x04, + 0x27, 0xd3, 0x45, 0x96, 0x5a, 0x8e, 0xb7, 0x75, 0x0c, 0xfd, 0xf5, 0x69, 0xa3, 0xbf, 0x5e, 0xec, + 0xef, 0xbb, 0x58, 0x23, 0x7b, 0x76, 0x9a, 0x93, 0xea, 0xb4, 0x8f, 0x1f, 0x86, 0xf9, 0xc1, 0x3d, + 0xf7, 0x47, 0x16, 0x3c, 0x9c, 0x59, 0xee, 0x18, 0x4c, 0xbc, 0xaf, 0x99, 0x26, 0xde, 0xe7, 0x0e, 0xf1, 0x75, 0x3d, 0x6c, 0xbe, 0xbf, 0x59, 0xee, 0xf1, 0x55, 0xcc, 0x08, 0x76, 0x03, 0x46, 0x9c, - 0x66, 0x93, 0x44, 0xd1, 0xb5, 0xc0, 0x55, 0x89, 0xc5, 0x9e, 0x65, 0xa7, 0x58, 0x52, 0xbc, 0xbf, - 0x3b, 0x37, 0x9b, 0x26, 0x91, 0x80, 0xb1, 0x4e, 0xc1, 0x4c, 0x79, 0x58, 0x3a, 0xa2, 0x94, 0x87, - 0x17, 0x01, 0xb6, 0x95, 0xbe, 0x9c, 0xb6, 0xad, 0x69, 0x9a, 0xb4, 0x86, 0x85, 0xfe, 0x0a, 0x93, - 0x3d, 0xb9, 0x5f, 0x4a, 0xc5, 0x8c, 0xb2, 0xcd, 0x99, 0x3f, 0xdd, 0xc7, 0x85, 0x07, 0xf3, 0x2a, - 0x3b, 0xa4, 0x22, 0x89, 0x3e, 0x05, 0x93, 0x11, 0xcf, 0x49, 0xb1, 0xd4, 0x72, 0x22, 0x16, 0x13, - 0x22, 0xf8, 0x29, 0x8b, 0xcb, 0x6d, 0xa4, 0x60, 0xb8, 0x0b, 0xdb, 0xfe, 0x66, 0x19, 0x3e, 0x7c, - 0xc0, 0xb2, 0x45, 0x0b, 0xe6, 0xfd, 0xf0, 0x33, 0x69, 0x4b, 0xd3, 0x6c, 0x66, 0x65, 0xc3, 0xf4, - 0x94, 0x9a, 0xed, 0xd2, 0xfb, 0x9e, 0xed, 0x2f, 0xeb, 0x76, 0x41, 0xee, 0xaa, 0x7a, 0xe9, 0xd0, - 0x1b, 0xf3, 0x27, 0xf5, 0x5a, 0xe0, 0xb3, 0x16, 0x3c, 0x96, 0xf9, 0x59, 0x86, 0x3f, 0xca, 0x79, - 0xa8, 0x36, 0x69, 0xa1, 0x16, 0xc1, 0x95, 0x84, 0x4e, 0x4a, 0x00, 0x4e, 0x70, 0x0c, 0xb7, 0x93, - 0x52, 0xae, 0xdb, 0xc9, 0x1f, 0x58, 0x30, 0x9d, 0xee, 0xc4, 0x31, 0xf0, 0xad, 0x86, 0xc9, 0xb7, - 0xe6, 0xfb, 0x9b, 0xfc, 0x1e, 0x2c, 0xeb, 0xab, 0x93, 0x70, 0xaa, 0xeb, 0xd4, 0xe3, 0xa3, 0xf8, - 0x4b, 0x16, 0x4c, 0x6d, 0x30, 0x3d, 0x41, 0x0b, 0x93, 0x13, 0xdf, 0x95, 0x13, 0x5b, 0x78, 0x60, - 0x74, 0x1d, 0xd7, 0x7a, 0xba, 0x50, 0x70, 0x77, 0x63, 0xe8, 0x8b, 0x16, 0x4c, 0x3b, 0xf7, 0xa2, - 0xae, 0x47, 0x7a, 0xc4, 0x42, 0x7a, 0x25, 0xc7, 0x2c, 0x97, 0xf3, 0xbc, 0xcf, 0xe2, 0xcc, 0xde, - 0xee, 0xdc, 0x74, 0x16, 0x16, 0xce, 0x6c, 0x95, 0xce, 0xef, 0xa6, 0x08, 0x97, 0x29, 0x16, 0xf0, - 0x99, 0x15, 0x5c, 0xc3, 0xd9, 0x9a, 0x84, 0x60, 0x45, 0x11, 0xbd, 0x0d, 0xd5, 0x0d, 0x19, 0x19, - 0x97, 0x66, 0x9b, 0x3d, 0x86, 0x39, 0x2b, 0x90, 0x8e, 0x87, 0x2b, 0x28, 0x10, 0x4e, 0x88, 0xa2, - 0xcb, 0x50, 0xf6, 0xd7, 0x23, 0x11, 0x83, 0x9e, 0xe7, 0x6d, 0x64, 0xfa, 0x78, 0xf1, 0xb0, 0xdd, - 0xeb, 0x2b, 0x0d, 0x4c, 0x49, 0x50, 0x4a, 0xe1, 0x1d, 0x57, 0xd8, 0xa3, 0x73, 0x28, 0xe1, 0xc5, - 0x5a, 0x37, 0x25, 0xbc, 0x58, 0xc3, 0x94, 0x04, 0xaa, 0xc3, 0x00, 0x0b, 0xc6, 0x11, 0xc6, 0xe6, - 0x9c, 0x44, 0x05, 0x5d, 0x21, 0x47, 0x3c, 0x33, 0x27, 0x2b, 0xc6, 0x9c, 0x10, 0x5a, 0x83, 0xc1, - 0x26, 0x7b, 0x5c, 0x42, 0x58, 0x01, 0xf2, 0x52, 0x78, 0x74, 0x3d, 0x44, 0xc1, 0x6f, 0xd8, 0x78, - 0x39, 0x16, 0xb4, 0x18, 0x55, 0xd2, 0xde, 0x5c, 0x8f, 0x84, 0x9a, 0x9f, 0x47, 0xb5, 0xeb, 0x99, - 0x10, 0x41, 0x95, 0x95, 0x63, 0x41, 0x0b, 0xd5, 0xa0, 0xb4, 0xde, 0x14, 0xb1, 0x3a, 0x39, 0x46, + 0x66, 0x93, 0x44, 0xd1, 0xb5, 0xc0, 0x55, 0x49, 0xc5, 0x9e, 0x65, 0xbb, 0x58, 0x02, 0xde, 0xdf, + 0x9d, 0x9b, 0x4d, 0xb3, 0x48, 0xd0, 0x58, 0xe7, 0x60, 0xa6, 0x3b, 0x2c, 0x1d, 0x51, 0xba, 0xc3, + 0x8b, 0x00, 0xdb, 0xea, 0xbc, 0x9c, 0xb6, 0xad, 0x69, 0x27, 0x69, 0x8d, 0x0a, 0xfd, 0x15, 0xa6, + 0x7b, 0x72, 0xbf, 0x94, 0x8a, 0x19, 0x65, 0x9b, 0x33, 0x7e, 0xba, 0x8f, 0x0b, 0x0f, 0xe6, 0x55, + 0x76, 0x48, 0xc5, 0x12, 0x7d, 0x0a, 0x26, 0x23, 0x9e, 0x8f, 0x62, 0xa9, 0xe5, 0x44, 0x2c, 0x26, + 0x44, 0xc8, 0x53, 0x16, 0x97, 0xdb, 0x48, 0xe1, 0x70, 0x17, 0xb5, 0xfd, 0xcd, 0x32, 0x7c, 0xf8, + 0x80, 0x69, 0x8b, 0x16, 0xcc, 0xfb, 0xe1, 0x67, 0xd2, 0x96, 0xa6, 0xd9, 0xcc, 0xc2, 0x86, 0xe9, + 0x29, 0x35, 0xda, 0xa5, 0xf7, 0x3d, 0xda, 0x5f, 0xd6, 0xed, 0x82, 0xdc, 0x55, 0xf5, 0xd2, 0xa1, + 0x17, 0xe6, 0x4f, 0xea, 0xb5, 0xc0, 0x67, 0x2d, 0x78, 0x2c, 0xf3, 0xb3, 0x0c, 0x7f, 0x94, 0xf3, + 0x50, 0x6d, 0x52, 0xa0, 0x16, 0xc1, 0x95, 0x84, 0x4e, 0x4a, 0x04, 0x4e, 0x68, 0x0c, 0xb7, 0x93, + 0x52, 0xae, 0xdb, 0xc9, 0x1f, 0x58, 0x30, 0x9d, 0x6e, 0xc4, 0x31, 0xc8, 0xad, 0x86, 0x29, 0xb7, + 0xe6, 0xfb, 0x1b, 0xfc, 0x1e, 0x22, 0xeb, 0xab, 0x93, 0x70, 0xaa, 0x6b, 0xd7, 0xe3, 0xbd, 0xf8, + 0x4b, 0x16, 0x4c, 0x6d, 0xb0, 0x73, 0x82, 0x16, 0x26, 0x27, 0xbe, 0x2b, 0x27, 0xb6, 0xf0, 0xc0, + 0xe8, 0x3a, 0x7e, 0xea, 0xe9, 0x22, 0xc1, 0xdd, 0x95, 0xa1, 0x2f, 0x5a, 0x30, 0xed, 0xdc, 0x8b, + 0xba, 0x1e, 0xe8, 0x11, 0x13, 0xe9, 0x95, 0x1c, 0xb3, 0x5c, 0xce, 0xd3, 0x3e, 0x8b, 0x33, 0x7b, + 0xbb, 0x73, 0xd3, 0x59, 0x54, 0x38, 0xb3, 0x56, 0x3a, 0xbe, 0x9b, 0x22, 0x5c, 0xa6, 0x58, 0xc0, + 0x67, 0x56, 0x70, 0x0d, 0x17, 0x6b, 0x12, 0x83, 0x15, 0x47, 0xf4, 0x36, 0x54, 0x37, 0x64, 0x64, + 0x5c, 0x5a, 0x6c, 0xf6, 0xe8, 0xe6, 0xac, 0x40, 0x3a, 0x1e, 0xae, 0xa0, 0x50, 0x38, 0x61, 0x8a, + 0x2e, 0x43, 0xd9, 0x5f, 0x8f, 0x44, 0x0c, 0x7a, 0x9e, 0xb7, 0x91, 0xe9, 0xe3, 0xc5, 0xc3, 0x76, + 0xaf, 0xaf, 0x34, 0x30, 0x65, 0x41, 0x39, 0x85, 0x77, 0x5c, 0x61, 0x8f, 0xce, 0xe1, 0x84, 0x17, + 0x6b, 0xdd, 0x9c, 0xf0, 0x62, 0x0d, 0x53, 0x16, 0xa8, 0x0e, 0x03, 0x2c, 0x18, 0x47, 0x18, 0x9b, + 0x73, 0x12, 0x15, 0x74, 0x85, 0x1c, 0xf1, 0xac, 0x9c, 0x0c, 0x8c, 0x39, 0x23, 0xb4, 0x06, 0x83, + 0x4d, 0xf6, 0xb0, 0x84, 0xb0, 0x02, 0xe4, 0xa5, 0xf0, 0xe8, 0x7a, 0x84, 0x82, 0xdf, 0xb0, 0x71, + 0x38, 0x16, 0xbc, 0x18, 0x57, 0xd2, 0xde, 0x5c, 0x8f, 0xc4, 0x31, 0x3f, 0x8f, 0x6b, 0xd7, 0x13, + 0x21, 0x82, 0x2b, 0x83, 0x63, 0xc1, 0x0b, 0xd5, 0xa0, 0xb4, 0xde, 0x14, 0xb1, 0x3a, 0x39, 0x46, 0x66, 0x33, 0x06, 0x7b, 0x71, 0x70, 0x6f, 0x77, 0xae, 0xb4, 0xb2, 0x84, 0x4b, 0xeb, 0x4d, 0xf4, - 0x1a, 0x0c, 0xad, 0xf3, 0xa8, 0x5a, 0x91, 0xcc, 0xf7, 0x42, 0x5e, 0xe8, 0x6f, 0x57, 0x08, 0x2e, - 0x0f, 0x49, 0x11, 0x00, 0x2c, 0xc9, 0xb1, 0x3c, 0x87, 0x2a, 0x4e, 0x58, 0x64, 0xf3, 0x9d, 0xef, - 0x2f, 0xae, 0x58, 0x68, 0xbf, 0xaa, 0x14, 0x6b, 0x14, 0xe9, 0x9a, 0x77, 0xe4, 0x3b, 0x39, 0x2c, - 0x93, 0x6f, 0xee, 0x9a, 0xcf, 0x7c, 0x56, 0x87, 0xaf, 0x79, 0x05, 0xc2, 0x09, 0x51, 0xd4, 0x81, - 0xb1, 0xed, 0xa8, 0xbd, 0x49, 0xe4, 0xd6, 0x67, 0xe9, 0x7d, 0x47, 0x2e, 0x7e, 0x32, 0x27, 0x67, - 0xb3, 0xa8, 0xe2, 0x85, 0x71, 0xc7, 0x69, 0x75, 0x71, 0x30, 0x96, 0x58, 0xee, 0x96, 0x4e, 0x16, - 0x9b, 0xad, 0xd0, 0x29, 0x79, 0xb7, 0x13, 0xdc, 0xd9, 0x89, 0x89, 0x48, 0xff, 0x9b, 0x33, 0x25, - 0xaf, 0x72, 0xe4, 0xee, 0x29, 0x11, 0x00, 0x2c, 0xc9, 0xa9, 0x21, 0x63, 0xdc, 0x78, 0xb2, 0xf0, - 0x90, 0x75, 0x7d, 0x43, 0x32, 0x64, 0x8c, 0xfb, 0x26, 0x44, 0x19, 0xd7, 0x6d, 0x6f, 0x06, 0x71, - 0xe0, 0xa7, 0x78, 0xff, 0x54, 0x11, 0xae, 0x5b, 0xcf, 0xa8, 0xd9, 0xcd, 0x75, 0xb3, 0xb0, 0x70, - 0x66, 0xab, 0xc8, 0x87, 0xf1, 0x76, 0x10, 0xc6, 0xf7, 0x82, 0x50, 0xae, 0x43, 0x54, 0x48, 0x47, - 0x34, 0xea, 0x88, 0xb6, 0x99, 0xe7, 0xb1, 0x09, 0xc1, 0x29, 0xea, 0x74, 0xea, 0xa2, 0xa6, 0xd3, - 0x22, 0xab, 0x37, 0x66, 0x4e, 0x14, 0x99, 0xba, 0x06, 0x47, 0xee, 0x9e, 0x3a, 0x01, 0xc0, 0x92, - 0x1c, 0xe5, 0x75, 0x2c, 0x97, 0x3d, 0xcb, 0x66, 0x9c, 0xcb, 0xeb, 0xba, 0xbc, 0x73, 0x39, 0xaf, - 0x63, 0xc5, 0x98, 0x13, 0x42, 0xef, 0x40, 0x55, 0x08, 0xb7, 0x41, 0x34, 0x73, 0x92, 0x51, 0xfd, - 0xd9, 0x9c, 0xde, 0x72, 0xf4, 0x1b, 0x8d, 0xec, 0x53, 0x5f, 0x44, 0xff, 0x49, 0x24, 0x9c, 0x90, - 0xb7, 0x7f, 0x63, 0xb0, 0x5b, 0xec, 0x61, 0x8a, 0xcd, 0xdf, 0xe8, 0xbe, 0xb1, 0xfe, 0x54, 0xff, - 0xfa, 0xfb, 0x03, 0xbc, 0xbb, 0xfe, 0xa2, 0x05, 0xa7, 0xda, 0x99, 0x9f, 0x27, 0x04, 0x87, 0x7e, - 0xcd, 0x00, 0x7c, 0x68, 0x54, 0x8e, 0xf1, 0x6c, 0x38, 0xee, 0xd1, 0x66, 0x5a, 0x15, 0x28, 0xbf, - 0x6f, 0x55, 0xe0, 0x36, 0x0c, 0x33, 0xd9, 0x35, 0xc9, 0xef, 0xd3, 0x67, 0x2a, 0x1c, 0x26, 0x82, - 0x2c, 0x09, 0x12, 0x58, 0x11, 0xa3, 0x03, 0xf7, 0x68, 0xfa, 0x23, 0x30, 0x61, 0x60, 0x91, 0xd9, - 0x92, 0xeb, 0x59, 0x2b, 0x62, 0x24, 0x1e, 0xad, 0x1f, 0x84, 0xbc, 0x9f, 0x87, 0x80, 0x0f, 0x6e, - 0x0c, 0xd5, 0x32, 0x14, 0xbd, 0x41, 0xf3, 0x7a, 0x2a, 0x5f, 0xd9, 0x3b, 0x5e, 0x05, 0xe5, 0x1f, - 0x5a, 0x19, 0xf2, 0x34, 0x57, 0x2a, 0x3f, 0x69, 0x2a, 0x95, 0x4f, 0xa6, 0x95, 0xca, 0x2e, 0x53, - 0x92, 0xa1, 0x4f, 0x16, 0xcf, 0xcc, 0x5b, 0x34, 0x81, 0x91, 0xdd, 0x82, 0x33, 0x79, 0xcc, 0x9a, - 0xb9, 0xac, 0xb9, 0xea, 0xb2, 0x36, 0x71, 0x59, 0x73, 0x57, 0x6b, 0x98, 0x41, 0x8a, 0xe6, 0xc0, - 0xb0, 0x7f, 0xb9, 0x04, 0xe5, 0x7a, 0xe0, 0x1e, 0x83, 0x69, 0xec, 0x92, 0x61, 0x1a, 0x7b, 0x22, - 0xf7, 0xa1, 0xc8, 0x9e, 0x86, 0xb0, 0x1b, 0x29, 0x43, 0xd8, 0xcf, 0xe4, 0x93, 0x3a, 0xd8, 0xec, - 0xf5, 0xed, 0x32, 0xe8, 0x4f, 0x5d, 0xa2, 0xff, 0x70, 0x18, 0x4f, 0xe6, 0x72, 0xb1, 0xd7, 0x2f, - 0x45, 0x1b, 0xcc, 0xe3, 0x4d, 0x06, 0x62, 0xfe, 0xc4, 0x3a, 0x34, 0xdf, 0x26, 0xde, 0xc6, 0x66, - 0x4c, 0xdc, 0xf4, 0x87, 0x1d, 0x9f, 0x43, 0xf3, 0x5f, 0x58, 0x30, 0x91, 0x6a, 0x1d, 0xb5, 0xb2, - 0x22, 0xb8, 0x0e, 0x69, 0xec, 0x9a, 0xca, 0x0d, 0xf9, 0x9a, 0x07, 0x50, 0x77, 0x16, 0xd2, 0xa0, - 0xc4, 0x64, 0x6b, 0x75, 0xa9, 0x11, 0x61, 0x0d, 0x03, 0xbd, 0x00, 0x23, 0x71, 0xd0, 0x0e, 0x5a, - 0xc1, 0xc6, 0xce, 0x15, 0x22, 0xb3, 0xb3, 0xa8, 0x9b, 0xa5, 0xb5, 0x04, 0x84, 0x75, 0x3c, 0xfb, - 0x3b, 0x65, 0x48, 0x3f, 0x94, 0xfa, 0xff, 0xd7, 0xe9, 0x4f, 0xce, 0x3a, 0xfd, 0x63, 0x0b, 0x26, - 0x69, 0xeb, 0xcc, 0xc5, 0x48, 0x3a, 0x1e, 0xab, 0x67, 0x42, 0xac, 0x03, 0x9e, 0x09, 0x79, 0x92, - 0x72, 0x3b, 0x37, 0xe8, 0xc4, 0xc2, 0x04, 0xa6, 0x31, 0x31, 0x5a, 0x8a, 0x05, 0x54, 0xe0, 0x91, - 0x30, 0x14, 0x11, 0x5a, 0x3a, 0x1e, 0x09, 0x43, 0x2c, 0xa0, 0xf2, 0x15, 0x91, 0x4a, 0x8f, 0x57, - 0x44, 0x58, 0x7e, 0x33, 0xe1, 0xd6, 0x22, 0xc4, 0x0a, 0x2d, 0xbf, 0x99, 0xf4, 0x77, 0x49, 0x70, - 0xec, 0xaf, 0x97, 0x61, 0xb4, 0x1e, 0xb8, 0x49, 0x44, 0xc1, 0xf3, 0x46, 0x44, 0xc1, 0x99, 0x54, - 0x44, 0xc1, 0xa4, 0x8e, 0xfb, 0x60, 0x02, 0x0a, 0x44, 0x1e, 0x3c, 0xf6, 0xce, 0xcd, 0x21, 0x83, - 0x09, 0x8c, 0x3c, 0x78, 0x8a, 0x10, 0x36, 0xe9, 0xfe, 0x34, 0x05, 0x11, 0xfc, 0x6f, 0x0b, 0xc6, - 0xeb, 0x81, 0x4b, 0x17, 0xe8, 0x4f, 0xd3, 0x6a, 0xd4, 0xb3, 0xe7, 0x0d, 0x1e, 0x90, 0x3d, 0xef, - 0x9f, 0x5b, 0x30, 0x54, 0x0f, 0xdc, 0x63, 0x30, 0x0f, 0xaf, 0x98, 0xe6, 0xe1, 0xc7, 0x72, 0x39, - 0x6f, 0x0f, 0x8b, 0xf0, 0x37, 0xcb, 0x30, 0x46, 0x7b, 0x1c, 0x6c, 0xc8, 0xf9, 0x32, 0xc6, 0xc6, - 0x2a, 0x30, 0x36, 0x54, 0x24, 0x0c, 0x5a, 0xad, 0xe0, 0x5e, 0x7a, 0xee, 0x56, 0x58, 0x29, 0x16, - 0x50, 0x74, 0x0e, 0x86, 0xdb, 0x21, 0xd9, 0xf6, 0x82, 0x4e, 0x94, 0x8e, 0xf6, 0xac, 0x8b, 0x72, - 0xac, 0x30, 0xd0, 0xf3, 0x30, 0x1a, 0x79, 0x7e, 0x93, 0x48, 0xa7, 0x97, 0x0a, 0x73, 0x7a, 0xe1, - 0x89, 0x4a, 0xb5, 0x72, 0x6c, 0x60, 0xa1, 0xdb, 0x50, 0x65, 0xff, 0xd9, 0x0e, 0xea, 0xff, 0x19, - 0x10, 0xae, 0x0e, 0x4b, 0x02, 0x38, 0xa1, 0x85, 0x2e, 0x02, 0xc4, 0xd2, 0x3d, 0x27, 0x12, 0x61, - 0xc9, 0x4a, 0x2e, 0x55, 0x8e, 0x3b, 0x11, 0xd6, 0xb0, 0xd0, 0x33, 0x50, 0x8d, 0x1d, 0xaf, 0x75, - 0xd5, 0xf3, 0x49, 0x24, 0xdc, 0x9b, 0x44, 0xd2, 0x71, 0x51, 0x88, 0x13, 0x38, 0x3d, 0xef, 0x59, - 0xd0, 0x3b, 0x7f, 0x62, 0x68, 0x98, 0x61, 0xb3, 0xf3, 0xfe, 0xaa, 0x2a, 0xc5, 0x1a, 0x86, 0xfd, - 0x12, 0x9c, 0xac, 0x07, 0x6e, 0x3d, 0x08, 0xe3, 0x95, 0x20, 0xbc, 0xe7, 0x84, 0xae, 0x9c, 0xbf, - 0x39, 0x99, 0xeb, 0x9a, 0x9e, 0xc9, 0x03, 0xdc, 0x8a, 0x60, 0xe4, 0xae, 0x7e, 0x8e, 0x9d, 0xf8, - 0x7d, 0x86, 0xaa, 0xfc, 0xa0, 0x04, 0xa8, 0xce, 0x1c, 0x88, 0x8c, 0x17, 0xa9, 0x36, 0x61, 0x3c, - 0x22, 0x57, 0x3d, 0xbf, 0x73, 0x5f, 0x90, 0x2a, 0x16, 0x1b, 0xd4, 0x58, 0xd6, 0xeb, 0x70, 0x3b, - 0x8d, 0x59, 0x86, 0x53, 0x74, 0xe9, 0x60, 0x86, 0x1d, 0x7f, 0x21, 0xba, 0x19, 0x91, 0x50, 0xbc, - 0xc0, 0xc4, 0x06, 0x13, 0xcb, 0x42, 0x9c, 0xc0, 0xe9, 0xe2, 0x61, 0x7f, 0xae, 0x07, 0x3e, 0x0e, - 0x82, 0x58, 0x2e, 0x37, 0xf6, 0x22, 0x87, 0x56, 0x8e, 0x0d, 0x2c, 0xb4, 0x02, 0x28, 0xea, 0xb4, - 0xdb, 0x2d, 0x76, 0x53, 0xea, 0xb4, 0x2e, 0x85, 0x41, 0xa7, 0xcd, 0xfd, 0xc8, 0xc5, 0x63, 0x16, - 0x8d, 0x2e, 0x28, 0xce, 0xa8, 0x41, 0x99, 0xc5, 0x7a, 0xc4, 0x7e, 0x8b, 0x08, 0x78, 0x6e, 0x6d, - 0x6d, 0xb0, 0x22, 0x2c, 0x61, 0xf6, 0x2f, 0xb2, 0x03, 0x8e, 0x3d, 0x8d, 0x13, 0x77, 0x42, 0x82, - 0xb6, 0x60, 0xac, 0xcd, 0x0e, 0xb1, 0x38, 0x0c, 0x5a, 0x2d, 0x22, 0xe5, 0xcb, 0xc3, 0xb9, 0x30, - 0xf1, 0xc7, 0x30, 0x74, 0x72, 0xd8, 0xa4, 0x6e, 0xff, 0xb7, 0x71, 0xc6, 0xab, 0xc4, 0x65, 0xf5, - 0x90, 0x70, 0x56, 0x16, 0x92, 0xdc, 0x47, 0x8a, 0x3c, 0x72, 0x97, 0x9c, 0x03, 0xc2, 0xf5, 0x19, - 0x4b, 0x2a, 0xe8, 0x33, 0xcc, 0x15, 0x9f, 0x33, 0x88, 0xe2, 0x4f, 0x77, 0x72, 0x7c, 0xc3, 0x0d, - 0x5f, 0x90, 0xc0, 0x1a, 0x39, 0x74, 0x15, 0xc6, 0xc4, 0x4b, 0x2a, 0xc2, 0x4c, 0x51, 0x36, 0x54, - 0xec, 0x31, 0xac, 0x03, 0xf7, 0xd3, 0x05, 0xd8, 0xac, 0x8c, 0x36, 0xe0, 0x51, 0xed, 0xa5, 0xb0, - 0x0c, 0x77, 0x3b, 0xce, 0x79, 0x1e, 0xdb, 0xdb, 0x9d, 0x7b, 0x74, 0xed, 0x20, 0x44, 0x7c, 0x30, - 0x1d, 0x74, 0x03, 0x4e, 0x3a, 0xcd, 0xd8, 0xdb, 0x26, 0x35, 0xe2, 0xb8, 0x2d, 0xcf, 0x27, 0x66, - 0x9a, 0x84, 0x87, 0xf7, 0x76, 0xe7, 0x4e, 0x2e, 0x64, 0x21, 0xe0, 0xec, 0x7a, 0xe8, 0x93, 0x50, - 0x75, 0xfd, 0x48, 0x8c, 0xc1, 0xa0, 0xf1, 0x30, 0x5e, 0xb5, 0x76, 0xbd, 0xa1, 0xbe, 0x3f, 0xf9, - 0x83, 0x93, 0x0a, 0xe8, 0x5d, 0x18, 0xd5, 0xc3, 0x9f, 0xc4, 0x83, 0x8c, 0x2f, 0x16, 0xd2, 0x9f, - 0x8d, 0x98, 0x21, 0x6e, 0xc1, 0x53, 0x6e, 0xad, 0x46, 0x38, 0x91, 0xd1, 0x04, 0xfa, 0x79, 0x40, - 0x11, 0x09, 0xb7, 0xbd, 0x26, 0x59, 0x68, 0xb2, 0xec, 0xbe, 0xcc, 0xc6, 0x33, 0x6c, 0xc4, 0x77, - 0xa0, 0x46, 0x17, 0x06, 0xce, 0xa8, 0x85, 0x2e, 0x53, 0xce, 0xa3, 0x97, 0x0a, 0x2f, 0x64, 0x29, - 0x18, 0xce, 0xd4, 0x48, 0x3b, 0x24, 0x4d, 0x27, 0x26, 0xae, 0x49, 0x11, 0xa7, 0xea, 0xd1, 0x73, - 0x49, 0x3d, 0xe0, 0x00, 0xa6, 0xef, 0x6c, 0xf7, 0x23, 0x0e, 0x54, 0xcf, 0xda, 0x0c, 0xa2, 0xf8, - 0x3a, 0x89, 0xef, 0x05, 0xe1, 0x5d, 0x91, 0x11, 0x2d, 0x49, 0x95, 0x98, 0x80, 0xb0, 0x8e, 0x47, - 0x65, 0x28, 0x76, 0xf5, 0xb7, 0x5a, 0x63, 0xf7, 0x2a, 0xc3, 0xc9, 0xde, 0xb9, 0xcc, 0x8b, 0xb1, - 0x84, 0x4b, 0xd4, 0xd5, 0xfa, 0x12, 0xbb, 0x23, 0x49, 0xa1, 0xae, 0xd6, 0x97, 0xb0, 0x84, 0xa3, - 0xa0, 0xfb, 0xf9, 0xc1, 0xf1, 0x22, 0xf7, 0x55, 0xdd, 0x9c, 0xbc, 0xe0, 0x0b, 0x84, 0xf7, 0x61, - 0x52, 0x3d, 0x81, 0xc8, 0x93, 0xc6, 0x45, 0x33, 0x13, 0x6c, 0xe1, 0x1c, 0x26, 0xf7, 0x9c, 0xb2, - 0xeb, 0xad, 0xa6, 0x68, 0xe2, 0xae, 0x56, 0x8c, 0xe4, 0x1c, 0x93, 0xb9, 0x8f, 0x72, 0x9c, 0x87, - 0x6a, 0xd4, 0xb9, 0xe3, 0x06, 0x5b, 0x8e, 0xe7, 0xb3, 0x8b, 0x0c, 0x4d, 0x88, 0x69, 0x48, 0x00, - 0x4e, 0x70, 0x50, 0x1d, 0x86, 0x1d, 0xa1, 0xc2, 0x89, 0x0b, 0x87, 0x9c, 0x28, 0x7c, 0xa9, 0xf0, - 0x71, 0xeb, 0xaa, 0xfc, 0x87, 0x15, 0x15, 0xf4, 0x32, 0x8c, 0x89, 0x20, 0x32, 0xe1, 0xec, 0x79, - 0xc2, 0x0c, 0x38, 0x68, 0xe8, 0x40, 0x6c, 0xe2, 0xa2, 0x0d, 0x18, 0xa7, 0x54, 0x12, 0x06, 0x38, - 0x33, 0xdd, 0x1f, 0x0f, 0xd5, 0xd2, 0x9f, 0xeb, 0x64, 0x70, 0x8a, 0x2c, 0x72, 0xe1, 0x11, 0xa7, - 0x13, 0x07, 0x5b, 0x74, 0x27, 0x98, 0xfb, 0x64, 0x2d, 0xb8, 0x4b, 0x7c, 0x76, 0xcb, 0x30, 0xbc, - 0x78, 0x66, 0x6f, 0x77, 0xee, 0x91, 0x85, 0x03, 0xf0, 0xf0, 0x81, 0x54, 0xd0, 0x5b, 0x30, 0x12, - 0x07, 0x2d, 0xe1, 0xc3, 0x1d, 0xcd, 0x9c, 0x2a, 0x92, 0x84, 0x68, 0x4d, 0x55, 0xd0, 0xcd, 0x18, - 0x8a, 0x08, 0xd6, 0x29, 0xa2, 0x37, 0xf9, 0xae, 0x64, 0x09, 0x33, 0x49, 0x34, 0xf3, 0x50, 0x91, - 0xc1, 0x52, 0x19, 0x36, 0xcd, 0xed, 0x2b, 0x68, 0x60, 0x9d, 0xe0, 0xec, 0xcf, 0xc1, 0x54, 0x17, - 0xcb, 0xeb, 0xcb, 0xb9, 0xf5, 0x3f, 0x0e, 0x40, 0x55, 0x59, 0x0c, 0xd1, 0x79, 0xd3, 0x38, 0xfc, - 0x70, 0xda, 0x38, 0x3c, 0x4c, 0x05, 0x34, 0xdd, 0x1e, 0xfc, 0x66, 0xc6, 0xa3, 0xfa, 0x4f, 0xe7, - 0xee, 0xf1, 0xe2, 0x91, 0x6d, 0x9a, 0x8a, 0x57, 0x2e, 0x6c, 0x6f, 0xae, 0x1c, 0xa8, 0x35, 0x16, - 0x7c, 0x28, 0x92, 0xea, 0x87, 0xed, 0xc0, 0x5d, 0xad, 0xa7, 0xdf, 0x41, 0xab, 0xd3, 0x42, 0xcc, - 0x61, 0x4c, 0xae, 0xa7, 0x67, 0x36, 0x93, 0xeb, 0x87, 0x0e, 0x29, 0xd7, 0x4b, 0x02, 0x38, 0xa1, - 0x85, 0xb6, 0x61, 0xaa, 0x69, 0x3e, 0x6b, 0xa7, 0xe2, 0xd5, 0x9e, 0xed, 0xe3, 0x59, 0xb9, 0x8e, - 0xf6, 0x22, 0xcd, 0x52, 0x9a, 0x1e, 0xee, 0x6e, 0x02, 0xbd, 0x0c, 0xc3, 0xef, 0x06, 0x11, 0xbb, - 0xb6, 0x10, 0x07, 0x97, 0x8c, 0x0b, 0x1a, 0x7e, 0xf5, 0x46, 0x83, 0x95, 0xef, 0xef, 0xce, 0x8d, - 0xd4, 0x03, 0x57, 0xfe, 0xc5, 0xaa, 0x02, 0xfa, 0xac, 0x05, 0x27, 0x8d, 0x7d, 0xac, 0x7a, 0x0e, - 0x87, 0xe9, 0xf9, 0xa3, 0xa2, 0xe5, 0x93, 0xab, 0x59, 0x34, 0x71, 0x76, 0x53, 0xf6, 0x77, 0xb9, - 0x89, 0x54, 0x18, 0x4d, 0x48, 0xd4, 0x69, 0x1d, 0xc7, 0xeb, 0x10, 0x37, 0x0c, 0x7b, 0xce, 0x03, - 0x30, 0xd2, 0xff, 0x7b, 0x8b, 0x19, 0xe9, 0xd7, 0xc8, 0x56, 0xbb, 0xe5, 0xc4, 0xc7, 0xe1, 0xfb, - 0xfc, 0x19, 0x18, 0x8e, 0x45, 0x6b, 0xc5, 0x9e, 0xb6, 0xd0, 0xba, 0xc7, 0x2e, 0x2f, 0xd4, 0xc1, - 0x27, 0x4b, 0xb1, 0x22, 0x68, 0xff, 0x2b, 0x3e, 0x2b, 0x12, 0x72, 0x0c, 0x96, 0x88, 0xeb, 0xa6, - 0x25, 0xe2, 0xa9, 0xc2, 0xdf, 0xd2, 0xc3, 0x22, 0xf1, 0x1d, 0xf3, 0x0b, 0x98, 0x7e, 0xf2, 0x93, - 0x73, 0x8b, 0x64, 0xff, 0xba, 0x05, 0xd3, 0x59, 0xce, 0x08, 0x54, 0x80, 0xe1, 0xda, 0x91, 0xba, - 0x5f, 0x53, 0xa3, 0x7a, 0x4b, 0x94, 0x63, 0x85, 0x51, 0x38, 0xd7, 0x7c, 0x7f, 0x29, 0xb4, 0x6e, - 0x80, 0xf9, 0x40, 0x22, 0x7a, 0x85, 0x87, 0x3a, 0x58, 0xea, 0x05, 0xc3, 0xfe, 0xc2, 0x1c, 0xec, - 0x6f, 0x94, 0x60, 0x9a, 0x1b, 0xb9, 0x17, 0xb6, 0x03, 0xcf, 0xad, 0x07, 0xae, 0x08, 0xfc, 0x70, - 0x61, 0xb4, 0xad, 0x29, 0xb7, 0xc5, 0x52, 0xf2, 0xe8, 0xea, 0x70, 0xa2, 0x50, 0xe8, 0xa5, 0xd8, - 0xa0, 0x4a, 0x5b, 0x21, 0xdb, 0x5e, 0x53, 0xd9, 0x4c, 0x4b, 0x7d, 0x9f, 0x0c, 0xaa, 0x95, 0x65, - 0x8d, 0x0e, 0x36, 0xa8, 0x1e, 0xc1, 0x13, 0x31, 0xf6, 0xdf, 0xb7, 0xe0, 0xa1, 0x1e, 0x69, 0x7b, - 0x68, 0x73, 0xf7, 0xd8, 0xc5, 0x82, 0x78, 0x81, 0x53, 0x35, 0xc7, 0xaf, 0x1b, 0xb0, 0x80, 0xa2, - 0x3b, 0x00, 0xfc, 0xba, 0x80, 0xca, 0xd2, 0xe9, 0xbb, 0xec, 0x82, 0xc9, 0x31, 0xb4, 0xbc, 0x09, - 0x92, 0x12, 0xd6, 0xa8, 0xda, 0x5f, 0x2b, 0xc3, 0x00, 0x7f, 0xe8, 0xbd, 0x0e, 0x43, 0x9b, 0x3c, - 0x9f, 0x71, 0x7f, 0xe9, 0x94, 0x13, 0xe5, 0x85, 0x17, 0x60, 0x49, 0x06, 0x5d, 0x83, 0x13, 0x22, - 0xf4, 0xa8, 0x46, 0x5a, 0xce, 0x8e, 0xd4, 0x86, 0xf9, 0xbb, 0x21, 0x32, 0xc1, 0xfd, 0x89, 0xd5, - 0x6e, 0x14, 0x9c, 0x55, 0x0f, 0xbd, 0xd2, 0x95, 0x7e, 0x90, 0xe7, 0x89, 0x56, 0x92, 0x70, 0x4e, - 0x0a, 0xc2, 0x97, 0x61, 0xac, 0xdd, 0xa5, 0xf7, 0x6b, 0xef, 0x69, 0x9b, 0xba, 0xbe, 0x89, 0xcb, - 0x7c, 0x17, 0x3a, 0xcc, 0x67, 0x63, 0x6d, 0x33, 0x24, 0xd1, 0x66, 0xd0, 0x72, 0xc5, 0x53, 0xb0, - 0x89, 0xef, 0x42, 0x0a, 0x8e, 0xbb, 0x6a, 0x50, 0x2a, 0xeb, 0x8e, 0xd7, 0xea, 0x84, 0x24, 0xa1, - 0x32, 0x68, 0x52, 0x59, 0x49, 0xc1, 0x71, 0x57, 0x0d, 0xba, 0xb6, 0x4e, 0x8a, 0xd7, 0x43, 0x65, - 0x90, 0xba, 0x60, 0x41, 0x9f, 0x86, 0x21, 0x19, 0x40, 0x50, 0x28, 0x97, 0x8a, 0x70, 0x4c, 0x50, - 0x2f, 0x91, 0x6a, 0xef, 0xc8, 0x89, 0xd0, 0x01, 0x49, 0xef, 0x30, 0xaf, 0x54, 0xfe, 0xb9, 0x05, - 0x27, 0x32, 0x1c, 0xe1, 0x38, 0x4b, 0xdb, 0xf0, 0xa2, 0x58, 0xbd, 0x62, 0xa1, 0xb1, 0x34, 0x5e, - 0x8e, 0x15, 0x06, 0xdd, 0x2d, 0x9c, 0x69, 0xa6, 0x19, 0xa5, 0x70, 0x31, 0x11, 0xd0, 0xfe, 0x18, - 0x25, 0x3a, 0x03, 0x95, 0x4e, 0x44, 0x42, 0xf9, 0xa0, 0xa3, 0xe4, 0xf3, 0xcc, 0xce, 0xc8, 0x20, - 0x54, 0x6c, 0xdd, 0x50, 0x26, 0x3e, 0x4d, 0x6c, 0xe5, 0x46, 0x3e, 0x0e, 0xb3, 0xbf, 0x5c, 0x86, - 0x89, 0x94, 0x43, 0x2c, 0xed, 0xc8, 0x56, 0xe0, 0x7b, 0x71, 0xa0, 0xf2, 0xdb, 0xf1, 0x37, 0xe4, - 0x48, 0x7b, 0xf3, 0x9a, 0x28, 0xc7, 0x0a, 0x03, 0x3d, 0x29, 0x5f, 0x09, 0x4e, 0xbf, 0xce, 0xb1, - 0x58, 0x33, 0x1e, 0x0a, 0x2e, 0xfa, 0xb2, 0xce, 0xe3, 0x50, 0x69, 0x07, 0xea, 0xd1, 0x77, 0x35, - 0x9f, 0x78, 0xb1, 0x56, 0x0f, 0x82, 0x16, 0x66, 0x40, 0xf4, 0x84, 0xf8, 0xfa, 0xd4, 0xcd, 0x08, - 0x76, 0xdc, 0x20, 0xd2, 0x86, 0xe0, 0x29, 0x18, 0xba, 0x4b, 0x76, 0x42, 0xcf, 0xdf, 0x48, 0xdf, - 0x0b, 0x5d, 0xe1, 0xc5, 0x58, 0xc2, 0xcd, 0x64, 0xf5, 0x43, 0x47, 0xfc, 0x7a, 0xce, 0x70, 0xee, - 0x39, 0xf8, 0x4d, 0x0b, 0x26, 0x58, 0xf6, 0x59, 0x91, 0x22, 0xc1, 0x0b, 0xfc, 0x63, 0x90, 0x31, - 0x1e, 0x87, 0x81, 0x90, 0x36, 0x9a, 0x7e, 0xfe, 0x82, 0xf5, 0x04, 0x73, 0x18, 0x7a, 0x04, 0x2a, - 0xac, 0x0b, 0x74, 0x1a, 0x47, 0x79, 0x92, 0xfb, 0x9a, 0x13, 0x3b, 0x98, 0x95, 0xb2, 0x18, 0x34, - 0x4c, 0xda, 0x2d, 0x8f, 0x77, 0x3a, 0x31, 0xe7, 0x7e, 0xd0, 0x62, 0xd0, 0x32, 0x3b, 0xf9, 0xa0, - 0x62, 0xd0, 0xb2, 0x89, 0x1f, 0x2c, 0xe7, 0xff, 0xf7, 0x12, 0x9c, 0xce, 0xac, 0x97, 0xdc, 0x30, - 0xaf, 0x18, 0x37, 0xcc, 0x17, 0x53, 0x37, 0xcc, 0xf6, 0xc1, 0xb5, 0x1f, 0xcc, 0x9d, 0x73, 0xf6, - 0x55, 0x70, 0xf9, 0x18, 0xaf, 0x82, 0x2b, 0x45, 0x45, 0x9c, 0x81, 0x1c, 0x11, 0xe7, 0x8f, 0x2c, - 0x78, 0x38, 0x73, 0xc8, 0x3e, 0x70, 0x41, 0x7f, 0x99, 0xbd, 0xec, 0xa1, 0x9d, 0xfc, 0x5a, 0xb9, - 0xc7, 0x57, 0x31, 0x3d, 0xe5, 0x2c, 0xe5, 0x42, 0x0c, 0x18, 0x09, 0xe1, 0x6d, 0x94, 0x73, 0x20, - 0x5e, 0x86, 0x15, 0x14, 0x45, 0x5a, 0xd0, 0x1c, 0xef, 0xe4, 0xf2, 0x21, 0x37, 0xd4, 0xbc, 0x69, - 0x87, 0xd7, 0xf3, 0x3e, 0xa4, 0x43, 0xe9, 0x6e, 0x6b, 0x9a, 0x67, 0xf9, 0x30, 0x9a, 0xe7, 0x68, - 0xb6, 0xd6, 0x89, 0x16, 0x60, 0x62, 0xcb, 0xf3, 0xd9, 0xa3, 0xbb, 0xa6, 0xf4, 0xa4, 0x22, 0x97, - 0xaf, 0x99, 0x60, 0x9c, 0xc6, 0x9f, 0x7d, 0x19, 0xc6, 0x0e, 0x6f, 0x5d, 0xfb, 0x51, 0x19, 0x3e, - 0x7c, 0x00, 0x53, 0xe0, 0xa7, 0x83, 0x31, 0x2f, 0xda, 0xe9, 0xd0, 0x35, 0x37, 0x75, 0x98, 0x5e, - 0xef, 0xb4, 0x5a, 0x3b, 0xcc, 0x3f, 0x8b, 0xb8, 0x12, 0x43, 0x08, 0x35, 0x2a, 0x19, 0xf5, 0x4a, - 0x06, 0x0e, 0xce, 0xac, 0x89, 0x7e, 0x1e, 0x50, 0x70, 0x87, 0xa5, 0x45, 0x76, 0x93, 0xbc, 0x16, - 0x6c, 0x0a, 0xca, 0xc9, 0x56, 0xbd, 0xd1, 0x85, 0x81, 0x33, 0x6a, 0x51, 0x39, 0x95, 0x9e, 0x63, - 0x3b, 0xaa, 0x5b, 0x29, 0x39, 0x15, 0xeb, 0x40, 0x6c, 0xe2, 0xa2, 0x4b, 0x30, 0xe5, 0x6c, 0x3b, - 0x1e, 0x4f, 0x73, 0x26, 0x09, 0x70, 0x41, 0x55, 0xd9, 0xaf, 0x16, 0xd2, 0x08, 0xb8, 0xbb, 0x0e, - 0x6a, 0x1b, 0x06, 0x49, 0xfe, 0x32, 0xc3, 0x27, 0x0f, 0xb1, 0x82, 0x0b, 0x9b, 0x28, 0xed, 0x3f, - 0xb5, 0xe8, 0xd1, 0x97, 0xf1, 0x3e, 0x2b, 0x1d, 0x11, 0x65, 0x60, 0xd3, 0x82, 0x00, 0xd5, 0x88, - 0x2c, 0xe9, 0x40, 0x6c, 0xe2, 0xf2, 0xa5, 0x11, 0x25, 0xee, 0xe2, 0x86, 0xb4, 0x29, 0xe2, 0x67, - 0x15, 0x06, 0x95, 0xa0, 0x5d, 0x6f, 0xdb, 0x8b, 0x82, 0x50, 0x6c, 0xa0, 0x7e, 0x5f, 0x41, 0x57, - 0xfc, 0xb2, 0xc6, 0xc9, 0x60, 0x49, 0xcf, 0xfe, 0x4a, 0x09, 0xc6, 0x64, 0x8b, 0xaf, 0x76, 0x82, - 0xd8, 0x39, 0x86, 0x23, 0xfd, 0x55, 0xe3, 0x48, 0x3f, 0x5f, 0x2c, 0x9c, 0x98, 0x75, 0xae, 0xe7, - 0x51, 0xfe, 0xe9, 0xd4, 0x51, 0x7e, 0xa1, 0x1f, 0xa2, 0x07, 0x1f, 0xe1, 0xff, 0xc6, 0x82, 0x29, - 0x03, 0xff, 0x18, 0x4e, 0x92, 0xba, 0x79, 0x92, 0x3c, 0xd3, 0xc7, 0xd7, 0xf4, 0x38, 0x41, 0xbe, - 0x5e, 0x4a, 0x7d, 0x05, 0x3b, 0x39, 0x7e, 0x01, 0x2a, 0x9b, 0x4e, 0xe8, 0x16, 0xcb, 0xf9, 0xd9, - 0x55, 0x7d, 0xfe, 0xb2, 0x13, 0xba, 0x9c, 0xff, 0x9f, 0x53, 0xaf, 0xc7, 0x39, 0xa1, 0x9b, 0x1b, - 0x45, 0xc1, 0x1a, 0x45, 0x2f, 0xc1, 0x60, 0xd4, 0x0c, 0xda, 0xca, 0xcf, 0xf4, 0x0c, 0x7f, 0x59, - 0x8e, 0x96, 0xec, 0xef, 0xce, 0x21, 0xb3, 0x39, 0x5a, 0x8c, 0x05, 0xfe, 0xec, 0x06, 0x54, 0x55, - 0xd3, 0x47, 0xea, 0x69, 0xff, 0x5f, 0xcb, 0x70, 0x22, 0x63, 0xad, 0xa0, 0x5f, 0x34, 0xc6, 0xed, - 0xe5, 0xbe, 0x17, 0xdb, 0xfb, 0x1c, 0xb9, 0x5f, 0x64, 0x9a, 0x92, 0x2b, 0x56, 0xc7, 0x21, 0x9a, - 0xbf, 0x19, 0x91, 0x74, 0xf3, 0xb4, 0x28, 0xbf, 0x79, 0xda, 0xec, 0xb1, 0x0d, 0x3f, 0x6d, 0x48, - 0xf5, 0xf4, 0x48, 0xe7, 0xf9, 0x0b, 0x15, 0x98, 0xce, 0xca, 0x5b, 0x80, 0x7e, 0xc5, 0x4a, 0xbd, - 0x30, 0xf2, 0x4a, 0xff, 0xc9, 0x0f, 0xf8, 0xb3, 0x23, 0x22, 0xab, 0xd0, 0xbc, 0xf9, 0xe6, 0x48, - 0xee, 0x88, 0x8b, 0xd6, 0x59, 0xfc, 0x53, 0xc8, 0x5f, 0x8b, 0x91, 0x5c, 0xe1, 0x53, 0x87, 0xe8, - 0x8a, 0x78, 0x70, 0x26, 0x4a, 0xc5, 0x3f, 0xc9, 0xe2, 0xfc, 0xf8, 0x27, 0xd9, 0x87, 0x59, 0x0f, - 0x46, 0xb4, 0xef, 0x3a, 0xd2, 0x65, 0x70, 0x97, 0x1e, 0x51, 0x5a, 0xbf, 0x8f, 0x74, 0x29, 0xfc, - 0x1d, 0x0b, 0x52, 0x4e, 0x61, 0xca, 0x2c, 0x63, 0xf5, 0x34, 0xcb, 0x9c, 0x81, 0x4a, 0x18, 0xb4, - 0x48, 0xfa, 0xd1, 0x09, 0x1c, 0xb4, 0x08, 0x66, 0x10, 0xf5, 0xa0, 0x74, 0xb9, 0xd7, 0x83, 0xd2, - 0x54, 0x4f, 0x6f, 0x91, 0x6d, 0x22, 0x8d, 0x24, 0x8a, 0x8d, 0x5f, 0xa5, 0x85, 0x98, 0xc3, 0xec, - 0xdf, 0xa9, 0xc0, 0x89, 0x8c, 0x58, 0x40, 0xaa, 0x21, 0x6d, 0x38, 0x31, 0xb9, 0xe7, 0xec, 0xa4, - 0x93, 0xdf, 0x5e, 0xe2, 0xc5, 0x58, 0xc2, 0x99, 0x33, 0x2b, 0x4f, 0xa0, 0x97, 0x32, 0x5d, 0x89, - 0xbc, 0x79, 0x02, 0x7a, 0xf4, 0x4f, 0x0f, 0x5f, 0x04, 0x88, 0xa2, 0xd6, 0xb2, 0x4f, 0x25, 0x3c, - 0x57, 0x38, 0xcd, 0x26, 0x79, 0x17, 0x1b, 0x57, 0x05, 0x04, 0x6b, 0x58, 0xa8, 0x06, 0x93, 0xed, - 0x30, 0x88, 0xb9, 0x61, 0xb0, 0xc6, 0x1d, 0x2d, 0x06, 0xcc, 0x68, 0xad, 0x7a, 0x0a, 0x8e, 0xbb, - 0x6a, 0xa0, 0x17, 0x60, 0x44, 0x44, 0x70, 0xd5, 0x83, 0xa0, 0x25, 0xcc, 0x48, 0xea, 0x3a, 0xbe, - 0x91, 0x80, 0xb0, 0x8e, 0xa7, 0x55, 0x63, 0xd6, 0xc6, 0xa1, 0xcc, 0x6a, 0xdc, 0xe2, 0xa8, 0xe1, - 0xa5, 0xb2, 0x9b, 0x0c, 0x17, 0xca, 0x6e, 0x92, 0x18, 0xd6, 0xaa, 0x85, 0x2f, 0x62, 0x20, 0xd7, - 0x00, 0xf5, 0x87, 0x65, 0x18, 0xe4, 0x53, 0x71, 0x0c, 0x52, 0x5e, 0x5d, 0x98, 0x94, 0x0a, 0x65, - 0x92, 0xe0, 0xbd, 0x9a, 0xaf, 0x39, 0xb1, 0xc3, 0x59, 0x93, 0xda, 0x21, 0x89, 0x19, 0x0a, 0xcd, - 0x1b, 0x7b, 0x68, 0x36, 0x65, 0x29, 0x01, 0x4e, 0x43, 0xdb, 0x51, 0x9b, 0x00, 0x11, 0x7b, 0xfe, - 0x96, 0xd2, 0x10, 0x99, 0x79, 0x9f, 0x2f, 0xd4, 0x8f, 0x86, 0xaa, 0xc6, 0x7b, 0x93, 0x2c, 0x4b, - 0x05, 0xc0, 0x1a, 0xed, 0xd9, 0x17, 0xa1, 0xaa, 0x90, 0xf3, 0x54, 0xc8, 0x51, 0x9d, 0xb5, 0xfd, - 0x2c, 0x4c, 0xa4, 0xda, 0xea, 0x4b, 0x03, 0xfd, 0x3d, 0x0b, 0x26, 0x78, 0x97, 0x97, 0xfd, 0x6d, - 0xc1, 0x0a, 0x3e, 0x67, 0xc1, 0x74, 0x2b, 0x63, 0x27, 0x8a, 0x69, 0x3e, 0xcc, 0x1e, 0x56, 0xca, - 0x67, 0x16, 0x14, 0x67, 0xb6, 0x86, 0xce, 0xc2, 0x30, 0x7f, 0xcd, 0xdb, 0x69, 0x09, 0x0f, 0xed, - 0x51, 0x9e, 0x93, 0x9c, 0x97, 0x61, 0x05, 0xb5, 0x7f, 0x6c, 0xc1, 0x14, 0xff, 0x88, 0x2b, 0x64, - 0x47, 0xa9, 0x57, 0x1f, 0x90, 0xcf, 0x10, 0xd9, 0xd7, 0x4b, 0x3d, 0xb2, 0xaf, 0xeb, 0x5f, 0x59, - 0x3e, 0xf0, 0x2b, 0xbf, 0x61, 0x81, 0x58, 0xa1, 0xc7, 0xa0, 0x3f, 0xac, 0x9a, 0xfa, 0xc3, 0x47, - 0x8a, 0x2c, 0xfa, 0x1e, 0x8a, 0xc3, 0xaf, 0x96, 0x60, 0x92, 0x23, 0x24, 0x37, 0x32, 0x1f, 0x94, - 0xc9, 0xe9, 0xef, 0x55, 0x20, 0xf5, 0x26, 0x6c, 0xf6, 0x97, 0x1a, 0x73, 0x59, 0x39, 0x70, 0x2e, - 0xff, 0xa7, 0x05, 0x88, 0x8f, 0x49, 0xfa, 0x29, 0x74, 0x7e, 0xba, 0x69, 0xe6, 0x80, 0x84, 0x73, - 0x28, 0x08, 0xd6, 0xb0, 0x1e, 0xf0, 0x27, 0xa4, 0xee, 0xc3, 0xca, 0xf9, 0xf7, 0x61, 0x7d, 0x7c, - 0xf5, 0x77, 0xcb, 0x90, 0x76, 0xd5, 0x44, 0x6f, 0xc3, 0x68, 0xd3, 0x69, 0x3b, 0x77, 0xbc, 0x96, - 0x17, 0x7b, 0x24, 0x2a, 0x76, 0xe1, 0xbe, 0xa4, 0xd5, 0x10, 0xd7, 0x50, 0x5a, 0x09, 0x36, 0x28, - 0xa2, 0x79, 0x80, 0x76, 0xe8, 0x6d, 0x7b, 0x2d, 0xb2, 0xc1, 0x34, 0x1e, 0x16, 0xeb, 0xc1, 0xef, - 0x8e, 0x65, 0x29, 0xd6, 0x30, 0x32, 0x62, 0x03, 0xca, 0xc7, 0x11, 0x1b, 0x50, 0xe9, 0x33, 0x36, - 0x60, 0xa0, 0x50, 0x6c, 0x00, 0x86, 0x53, 0xf2, 0xf0, 0xa6, 0xff, 0x57, 0xbc, 0x16, 0x11, 0xb2, - 0x1b, 0x8f, 0x05, 0x99, 0xdd, 0xdb, 0x9d, 0x3b, 0x85, 0x33, 0x31, 0x70, 0x8f, 0x9a, 0x76, 0x07, - 0x4e, 0x34, 0x48, 0x28, 0x9f, 0xb1, 0x53, 0x7b, 0xe9, 0x4d, 0xa8, 0x86, 0xa9, 0x6d, 0xdc, 0x67, - 0xc0, 0xbf, 0x96, 0xe3, 0x4d, 0x6e, 0xdb, 0x84, 0xa4, 0xfd, 0xd7, 0x4b, 0x30, 0x24, 0x9c, 0x34, - 0x8f, 0x41, 0xf8, 0xb8, 0x62, 0x98, 0x98, 0x9e, 0xca, 0xe3, 0x7f, 0xac, 0x5b, 0x3d, 0x8d, 0x4b, - 0x8d, 0x94, 0x71, 0xe9, 0x99, 0x62, 0xe4, 0x0e, 0x36, 0x2b, 0xfd, 0x93, 0x32, 0x8c, 0x9b, 0x4e, - 0xab, 0xc7, 0x30, 0x2c, 0xaf, 0xc1, 0x50, 0x24, 0xfc, 0xa7, 0x4b, 0x45, 0x7c, 0xf6, 0xd2, 0x53, - 0x9c, 0xdc, 0xc4, 0x0b, 0x8f, 0x69, 0x49, 0x2e, 0xd3, 0x45, 0xbb, 0x7c, 0x2c, 0x2e, 0xda, 0x79, - 0xbe, 0xc4, 0x95, 0x07, 0xe1, 0x4b, 0x6c, 0x7f, 0x8f, 0xb1, 0x7c, 0xbd, 0xfc, 0x18, 0x8e, 0xf1, - 0x57, 0xcd, 0xc3, 0xe1, 0x5c, 0xa1, 0x75, 0x27, 0xba, 0xd7, 0xe3, 0x38, 0xff, 0x96, 0x05, 0x23, - 0x02, 0xf1, 0x18, 0x3e, 0xe0, 0xe7, 0xcd, 0x0f, 0x78, 0xa2, 0xd0, 0x07, 0xf4, 0xe8, 0xf9, 0x57, - 0x4a, 0xaa, 0xe7, 0xf5, 0x20, 0x8c, 0x0b, 0x65, 0x42, 0x1f, 0xa6, 0xaa, 0x5f, 0xd0, 0x0c, 0x5a, - 0x42, 0x80, 0x7b, 0x24, 0x09, 0xfd, 0xe3, 0xe5, 0xfb, 0xda, 0x6f, 0xac, 0xb0, 0x59, 0x64, 0x5a, - 0x10, 0xc6, 0xe2, 0x00, 0x4d, 0x22, 0xd3, 0x82, 0x30, 0xc6, 0x0c, 0x82, 0x5c, 0x80, 0xd8, 0x09, - 0x37, 0x48, 0x4c, 0xcb, 0x44, 0xd4, 0x6c, 0xef, 0xdd, 0xda, 0x89, 0xbd, 0xd6, 0xbc, 0xe7, 0xc7, - 0x51, 0x1c, 0xce, 0xaf, 0xfa, 0xf1, 0x8d, 0x90, 0x0b, 0xfd, 0x5a, 0x2c, 0x9f, 0xa2, 0x85, 0x35, - 0xba, 0x32, 0x48, 0x84, 0xb5, 0x31, 0x60, 0xde, 0x20, 0x5d, 0x17, 0xe5, 0x58, 0x61, 0xd8, 0x2f, - 0x32, 0xce, 0xce, 0x06, 0xa8, 0xbf, 0x30, 0xbb, 0x2f, 0x0c, 0xa9, 0xa1, 0x65, 0x66, 0xe1, 0xeb, - 0x7a, 0x30, 0x5f, 0x51, 0xf6, 0x49, 0xbb, 0xa0, 0xfb, 0x51, 0x27, 0xb1, 0x7f, 0x88, 0x74, 0x5d, - 0x3b, 0xbe, 0x58, 0x98, 0x23, 0xf7, 0x71, 0xd1, 0xc8, 0x52, 0x32, 0xb2, 0x3c, 0x74, 0xab, 0xf5, - 0x74, 0xfe, 0xfa, 0x25, 0x09, 0xc0, 0x09, 0x0e, 0x3a, 0x2f, 0x14, 0x4a, 0x6e, 0x71, 0xf9, 0x70, - 0x4a, 0xa1, 0x94, 0x43, 0xa2, 0x69, 0x94, 0x17, 0x60, 0x44, 0x3d, 0x09, 0x54, 0xe7, 0x8f, 0xb1, - 0x54, 0xb9, 0x7c, 0xb5, 0x9c, 0x14, 0x63, 0x1d, 0x07, 0xad, 0xc1, 0x44, 0xc4, 0xdf, 0x2b, 0x92, - 0xd1, 0x1a, 0xc2, 0x70, 0xf0, 0xb4, 0xbc, 0xa4, 0x6c, 0x98, 0xe0, 0x7d, 0x56, 0xc4, 0xb7, 0xb2, - 0x8c, 0xef, 0x48, 0x93, 0x40, 0xaf, 0xc0, 0x78, 0x4b, 0x7f, 0xc3, 0xb5, 0x2e, 0xec, 0x0a, 0xca, - 0xed, 0xcc, 0x78, 0xe1, 0xb5, 0x8e, 0x53, 0xd8, 0xe8, 0x35, 0x98, 0xd1, 0x4b, 0x44, 0x72, 0x21, - 0xc7, 0xdf, 0x20, 0x91, 0x78, 0xdb, 0xe4, 0x91, 0xbd, 0xdd, 0xb9, 0x99, 0xab, 0x3d, 0x70, 0x70, - 0xcf, 0xda, 0xe8, 0x25, 0x18, 0x95, 0x9f, 0xaf, 0xc5, 0x36, 0x25, 0x0e, 0x8f, 0x1a, 0x0c, 0x1b, - 0x98, 0xe8, 0x1e, 0x9c, 0x94, 0xff, 0xd7, 0x42, 0x67, 0x7d, 0xdd, 0x6b, 0x8a, 0x20, 0xb3, 0x11, - 0x46, 0x62, 0x41, 0xfa, 0x8b, 0x2f, 0x67, 0x21, 0xed, 0xef, 0xce, 0x9d, 0x11, 0xa3, 0x96, 0x09, - 0x67, 0x93, 0x98, 0x4d, 0x1f, 0x5d, 0x83, 0x13, 0x9b, 0xc4, 0x69, 0xc5, 0x9b, 0x4b, 0x9b, 0xa4, - 0x79, 0x57, 0x6e, 0x2c, 0x16, 0x31, 0xa5, 0xb9, 0x04, 0x5e, 0xee, 0x46, 0xc1, 0x59, 0xf5, 0xde, - 0xdf, 0x9d, 0xf2, 0x2f, 0xd0, 0xca, 0x9a, 0xfc, 0x80, 0xde, 0x81, 0x51, 0x7d, 0xac, 0xd3, 0x82, - 0x41, 0xfe, 0xfb, 0xbe, 0x42, 0x0e, 0x51, 0x33, 0xa0, 0xc3, 0xb0, 0x41, 0xdb, 0xfe, 0x77, 0x25, - 0x98, 0xcb, 0xc9, 0xdd, 0x95, 0xb2, 0x66, 0x59, 0x85, 0xac, 0x59, 0x0b, 0xf2, 0xcd, 0x9b, 0xeb, - 0xa9, 0x9c, 0xe9, 0xa9, 0x57, 0x6c, 0x92, 0xcc, 0xe9, 0x69, 0xfc, 0xc2, 0x9e, 0x66, 0xba, 0x41, - 0xac, 0x92, 0xeb, 0x70, 0xf7, 0xba, 0x6e, 0xe3, 0x1c, 0x38, 0x8c, 0xd0, 0xdb, 0xd3, 0xbc, 0x69, - 0x7f, 0xaf, 0x04, 0x27, 0xd5, 0x60, 0xfe, 0xf4, 0x0e, 0xe1, 0x5b, 0xdd, 0x43, 0xf8, 0x40, 0xcd, - 0xc4, 0xf6, 0x0d, 0x18, 0x6c, 0xec, 0x44, 0xcd, 0xb8, 0x55, 0xe0, 0xc4, 0x7f, 0xdc, 0xd8, 0x57, - 0xc9, 0x69, 0xc4, 0x5e, 0xb2, 0x13, 0xdb, 0xcc, 0xfe, 0xbc, 0x05, 0x13, 0x6b, 0x4b, 0xf5, 0x46, - 0xd0, 0xbc, 0x4b, 0xe2, 0x05, 0x6e, 0xd0, 0xc0, 0xe2, 0xc0, 0xb7, 0x0e, 0x79, 0x90, 0x67, 0x89, - 0x08, 0x67, 0xa0, 0xb2, 0x19, 0x44, 0x71, 0xfa, 0x52, 0xe0, 0x72, 0x10, 0xc5, 0x98, 0x41, 0xec, - 0x3f, 0xb3, 0x60, 0x80, 0x3d, 0xd4, 0x96, 0xf7, 0xc8, 0x5f, 0x91, 0xef, 0x42, 0x2f, 0xc0, 0x20, - 0x59, 0x5f, 0x27, 0xcd, 0x58, 0xcc, 0xaf, 0x0c, 0xb0, 0x19, 0x5c, 0x66, 0xa5, 0xf4, 0x44, 0x63, - 0x8d, 0xf1, 0xbf, 0x58, 0x20, 0xa3, 0xcf, 0x40, 0x35, 0xf6, 0xb6, 0xc8, 0x82, 0xeb, 0x0a, 0x2b, - 0x7c, 0x7f, 0x3e, 0x5f, 0xea, 0x84, 0x5d, 0x93, 0x44, 0x70, 0x42, 0xcf, 0xfe, 0x52, 0x09, 0x20, - 0x09, 0x9f, 0xcb, 0xfb, 0xcc, 0xc5, 0xae, 0xb7, 0x0c, 0x9f, 0xcc, 0x78, 0xcb, 0x10, 0x25, 0x04, - 0x33, 0x5e, 0x32, 0x54, 0x43, 0x55, 0x2e, 0x34, 0x54, 0x95, 0x7e, 0x86, 0x6a, 0x09, 0xa6, 0x92, - 0xf0, 0x3f, 0x33, 0x8e, 0x9a, 0xe5, 0x1b, 0x5e, 0x4b, 0x03, 0x71, 0x37, 0xbe, 0xfd, 0x25, 0x0b, - 0x84, 0x97, 0x70, 0x81, 0x05, 0xed, 0xca, 0x77, 0xc7, 0x8c, 0xd4, 0x82, 0x4f, 0x17, 0x71, 0xa0, - 0x16, 0x09, 0x05, 0x15, 0xdf, 0x37, 0xd2, 0x08, 0x1a, 0x54, 0xed, 0xdf, 0xb6, 0x60, 0x84, 0x83, - 0xaf, 0x31, 0x45, 0x34, 0xbf, 0x5f, 0x7d, 0x25, 0xb3, 0x66, 0x4f, 0x72, 0x51, 0xc2, 0x2a, 0xa9, - 0xb1, 0xfe, 0x24, 0x97, 0x04, 0xe0, 0x04, 0x07, 0x3d, 0x05, 0x43, 0x51, 0xe7, 0x0e, 0x43, 0x4f, - 0xb9, 0x0c, 0x37, 0x78, 0x31, 0x96, 0x70, 0xfb, 0x9f, 0x95, 0x60, 0x32, 0xed, 0x31, 0x8e, 0x30, - 0x0c, 0x72, 0x06, 0x92, 0xd6, 0x69, 0x0e, 0x32, 0x80, 0x6a, 0x1e, 0xe7, 0xc0, 0x1f, 0x96, 0x67, - 0x2c, 0x48, 0x50, 0x42, 0xeb, 0x30, 0xe2, 0x06, 0xf7, 0xfc, 0x7b, 0x4e, 0xe8, 0x2e, 0xd4, 0x57, - 0xc5, 0x4c, 0xe4, 0xf8, 0xf8, 0xd5, 0x92, 0x0a, 0xba, 0x3f, 0x3b, 0x33, 0xc8, 0x25, 0x20, 0xac, - 0x13, 0x46, 0x6f, 0xb2, 0x4c, 0x28, 0xeb, 0xde, 0xc6, 0x35, 0xa7, 0x5d, 0xcc, 0x9b, 0x65, 0x49, - 0xa2, 0x6b, 0x6d, 0x8c, 0x89, 0xc4, 0x29, 0x1c, 0x80, 0x13, 0x92, 0xf6, 0xaf, 0x9e, 0x04, 0x63, - 0x2d, 0x18, 0x19, 0xa7, 0xad, 0x07, 0x9e, 0x71, 0xfa, 0x0d, 0x18, 0x26, 0x5b, 0xed, 0x78, 0xa7, - 0xe6, 0x85, 0xc5, 0xde, 0x0f, 0x58, 0x16, 0xd8, 0xdd, 0xd4, 0x25, 0x04, 0x2b, 0x8a, 0x3d, 0xf2, - 0x87, 0x97, 0x3f, 0x10, 0xf9, 0xc3, 0x2b, 0x7f, 0x29, 0xf9, 0xc3, 0x5f, 0x83, 0xa1, 0x0d, 0x2f, - 0xc6, 0xa4, 0x1d, 0x88, 0xd3, 0x38, 0x67, 0xf1, 0x5c, 0xe2, 0xc8, 0xdd, 0x99, 0x65, 0x05, 0x00, - 0x4b, 0x72, 0x68, 0x4d, 0x6d, 0xaa, 0xc1, 0x22, 0x32, 0x68, 0xb7, 0x81, 0x3c, 0x73, 0x5b, 0x89, - 0x7c, 0xe1, 0x43, 0xef, 0x3f, 0x5f, 0xb8, 0xca, 0xf2, 0x3d, 0xfc, 0xa0, 0xb2, 0x7c, 0x1b, 0xd9, - 0xd2, 0xab, 0x47, 0x91, 0x2d, 0xfd, 0x4b, 0x16, 0x9c, 0x6c, 0x67, 0xbd, 0x35, 0x20, 0xf2, 0x75, - 0xff, 0xdc, 0x21, 0x5e, 0x5f, 0x30, 0x9a, 0x66, 0xf9, 0x3d, 0x32, 0xd1, 0x70, 0x76, 0xc3, 0x32, - 0xed, 0xfa, 0xc8, 0xfb, 0x4f, 0xbb, 0x7e, 0xd4, 0x89, 0xbd, 0x93, 0x24, 0xec, 0x63, 0x47, 0x92, - 0x84, 0x7d, 0xfc, 0x01, 0x26, 0x61, 0xd7, 0xd2, 0xa7, 0x4f, 0x3c, 0xd8, 0xf4, 0xe9, 0x9b, 0xe6, - 0xb9, 0xc4, 0xb3, 0x75, 0xbf, 0x50, 0xf8, 0x5c, 0x32, 0x5a, 0x38, 0xf8, 0x64, 0xe2, 0x89, 0xe4, - 0xa7, 0xde, 0x67, 0x22, 0x79, 0x23, 0x1d, 0x3b, 0x3a, 0x8a, 0x74, 0xec, 0x6f, 0xeb, 0x27, 0xe8, - 0x89, 0x22, 0x2d, 0xa8, 0x83, 0xb2, 0xbb, 0x85, 0xac, 0x33, 0xb4, 0x3b, 0xe1, 0xfb, 0xf4, 0x71, - 0x27, 0x7c, 0x3f, 0x79, 0x84, 0x09, 0xdf, 0x4f, 0x1d, 0x6b, 0xc2, 0xf7, 0x87, 0x3e, 0x20, 0x09, - 0xdf, 0x67, 0x8e, 0x2b, 0xe1, 0xfb, 0xc3, 0x0f, 0x36, 0xe1, 0xfb, 0xdb, 0x50, 0x6d, 0xcb, 0xb8, - 0xcb, 0x99, 0xd9, 0x22, 0x53, 0x97, 0x19, 0xa6, 0xc9, 0xa7, 0x4e, 0x81, 0x70, 0x42, 0x94, 0xb6, - 0x90, 0x24, 0x80, 0xff, 0x70, 0x91, 0x16, 0x32, 0xed, 0x1e, 0x07, 0xa4, 0x7d, 0xff, 0x42, 0x09, - 0x4e, 0x1f, 0xbc, 0x3b, 0x12, 0xa3, 0x49, 0x3d, 0xb1, 0x65, 0xa7, 0x8c, 0x26, 0x4c, 0xf2, 0xd4, - 0xb0, 0x0a, 0x87, 0xb3, 0x5f, 0x82, 0x29, 0xe5, 0xe7, 0xd5, 0xf2, 0x9a, 0x3b, 0xda, 0x33, 0x54, - 0x2a, 0x3e, 0xa1, 0x91, 0x46, 0xc0, 0xdd, 0x75, 0xd0, 0x02, 0x4c, 0x18, 0x85, 0xab, 0x35, 0xa1, - 0xbf, 0x28, 0x2b, 0x4d, 0xc3, 0x04, 0xe3, 0x34, 0xbe, 0xfd, 0x75, 0x0b, 0x1e, 0xea, 0x91, 0xe1, - 0xb5, 0x70, 0x8c, 0x76, 0x1b, 0x26, 0xda, 0x66, 0xd5, 0xc2, 0x29, 0x1f, 0x8c, 0x8c, 0xb2, 0xaa, - 0xd7, 0x29, 0x00, 0x4e, 0x93, 0x5f, 0x3c, 0xfb, 0xfd, 0x1f, 0x9d, 0xfe, 0xd0, 0x0f, 0x7e, 0x74, - 0xfa, 0x43, 0x3f, 0xfc, 0xd1, 0xe9, 0x0f, 0xfd, 0xd2, 0xde, 0x69, 0xeb, 0xfb, 0x7b, 0xa7, 0xad, - 0x1f, 0xec, 0x9d, 0xb6, 0x7e, 0xb8, 0x77, 0xda, 0xfa, 0xf3, 0xbd, 0xd3, 0xd6, 0x97, 0x7e, 0x7c, - 0xfa, 0x43, 0xaf, 0x97, 0xb6, 0x2f, 0xfc, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0xe5, 0xd7, - 0x49, 0x99, 0xd0, 0x00, 0x00, + 0x1a, 0x0c, 0xad, 0xf3, 0xa8, 0x5a, 0x91, 0xc8, 0xf7, 0x42, 0x5e, 0xe8, 0x6f, 0x57, 0x08, 0x2e, + 0x0f, 0x49, 0x11, 0x08, 0x2c, 0xd9, 0xb1, 0x1c, 0x87, 0x2a, 0x4e, 0x58, 0x64, 0xf2, 0x9d, 0xef, + 0x2f, 0xae, 0x58, 0x9c, 0x7e, 0x15, 0x14, 0x6b, 0x1c, 0xe9, 0x9c, 0x77, 0xe4, 0x1b, 0x39, 0x2c, + 0x8b, 0x6f, 0xee, 0x9c, 0xcf, 0x7c, 0x52, 0x87, 0xcf, 0x79, 0x85, 0xc2, 0x09, 0x53, 0xd4, 0x81, + 0xb1, 0xed, 0xa8, 0xbd, 0x49, 0xe4, 0xd2, 0x67, 0xa9, 0x7d, 0x47, 0x2e, 0x7e, 0x32, 0x27, 0x5f, + 0xb3, 0x28, 0xe2, 0x85, 0x71, 0xc7, 0x69, 0x75, 0x49, 0x30, 0x96, 0x54, 0xee, 0x96, 0xce, 0x16, + 0x9b, 0xb5, 0xd0, 0x21, 0x79, 0xb7, 0x13, 0xdc, 0xd9, 0x89, 0x89, 0x48, 0xfd, 0x9b, 0x33, 0x24, + 0xaf, 0x72, 0xe2, 0xee, 0x21, 0x11, 0x08, 0x2c, 0xd9, 0xa9, 0x2e, 0x63, 0xd2, 0x78, 0xb2, 0x70, + 0x97, 0x75, 0x7d, 0x43, 0xd2, 0x65, 0x4c, 0xfa, 0x26, 0x4c, 0x99, 0xd4, 0x6d, 0x6f, 0x06, 0x71, + 0xe0, 0xa7, 0x64, 0xff, 0x54, 0x11, 0xa9, 0x5b, 0xcf, 0x28, 0xd9, 0x2d, 0x75, 0xb3, 0xa8, 0x70, + 0x66, 0xad, 0xc8, 0x87, 0xf1, 0x76, 0x10, 0xc6, 0xf7, 0x82, 0x50, 0xce, 0x43, 0x54, 0xe8, 0x8c, + 0x68, 0x94, 0x11, 0x75, 0x33, 0xcf, 0x63, 0x13, 0x83, 0x53, 0xdc, 0xe9, 0xd0, 0x45, 0x4d, 0xa7, + 0x45, 0x56, 0x6f, 0xcc, 0x9c, 0x28, 0x32, 0x74, 0x0d, 0x4e, 0xdc, 0x3d, 0x74, 0x02, 0x81, 0x25, + 0x3b, 0x2a, 0xeb, 0x58, 0x1e, 0x7b, 0x96, 0xc9, 0x38, 0x57, 0xd6, 0x75, 0x79, 0xe7, 0x72, 0x59, + 0xc7, 0xc0, 0x98, 0x33, 0x42, 0xef, 0x40, 0x55, 0x28, 0xb7, 0x41, 0x34, 0x73, 0x92, 0x71, 0xfd, + 0xd9, 0x9c, 0xd6, 0x72, 0xf2, 0x1b, 0x8d, 0xec, 0x5d, 0x5f, 0x44, 0xff, 0x49, 0x22, 0x9c, 0xb0, + 0xb7, 0x7f, 0x63, 0xb0, 0x5b, 0xed, 0x61, 0x07, 0x9b, 0xbf, 0xd1, 0x7d, 0x63, 0xfd, 0xa9, 0xfe, + 0xcf, 0xef, 0x0f, 0xf0, 0xee, 0xfa, 0x8b, 0x16, 0x9c, 0x6a, 0x67, 0x7e, 0x9e, 0x50, 0x1c, 0xfa, + 0x35, 0x03, 0xf0, 0xae, 0x51, 0xf9, 0xc5, 0xb3, 0xf1, 0xb8, 0x47, 0x9d, 0xe9, 0xa3, 0x40, 0xf9, + 0x7d, 0x1f, 0x05, 0x6e, 0xc3, 0x30, 0xd3, 0x5d, 0x93, 0xfc, 0x3e, 0x7d, 0xa6, 0xc2, 0x61, 0x2a, + 0xc8, 0x92, 0x60, 0x81, 0x15, 0x33, 0xda, 0x71, 0x8f, 0xa6, 0x3f, 0x02, 0x13, 0x86, 0x16, 0x59, + 0x2d, 0xf9, 0x39, 0x6b, 0x45, 0xf4, 0xc4, 0xa3, 0xf5, 0x83, 0x88, 0xf7, 0xf3, 0x08, 0xf0, 0xc1, + 0x95, 0xa1, 0x5a, 0xc6, 0x41, 0x6f, 0xd0, 0xbc, 0x9e, 0xca, 0x3f, 0xec, 0x1d, 0xef, 0x01, 0xe5, + 0x1f, 0x5a, 0x19, 0xfa, 0x34, 0x3f, 0x54, 0x7e, 0xd2, 0x3c, 0x54, 0x3e, 0x99, 0x3e, 0x54, 0x76, + 0x99, 0x92, 0x8c, 0xf3, 0x64, 0xf1, 0xac, 0xbc, 0x45, 0x13, 0x18, 0xd9, 0x2d, 0x38, 0x93, 0x27, + 0xac, 0x99, 0xcb, 0x9a, 0xab, 0x2e, 0x6b, 0x13, 0x97, 0x35, 0x77, 0xb5, 0x86, 0x19, 0xa6, 0x68, + 0x0e, 0x0c, 0xfb, 0x97, 0x4b, 0x50, 0xae, 0x07, 0xee, 0x31, 0x98, 0xc6, 0x2e, 0x19, 0xa6, 0xb1, + 0x27, 0x72, 0x1f, 0x89, 0xec, 0x69, 0x08, 0xbb, 0x91, 0x32, 0x84, 0xfd, 0x4c, 0x3e, 0xab, 0x83, + 0xcd, 0x5e, 0xdf, 0x2e, 0x83, 0xfe, 0xcc, 0x25, 0xfa, 0x0f, 0x87, 0xf1, 0x64, 0x2e, 0x17, 0x7b, + 0xf9, 0x52, 0xd4, 0xc1, 0x3c, 0xde, 0x64, 0x20, 0xe6, 0x4f, 0xac, 0x43, 0xf3, 0x6d, 0xe2, 0x6d, + 0x6c, 0xc6, 0xc4, 0x4d, 0x7f, 0xd8, 0xf1, 0x39, 0x34, 0xff, 0x85, 0x05, 0x13, 0xa9, 0xda, 0x51, + 0x2b, 0x2b, 0x82, 0xeb, 0x90, 0xc6, 0xae, 0xa9, 0xdc, 0x90, 0xaf, 0x79, 0x00, 0x75, 0x67, 0x21, + 0x0d, 0x4a, 0x4c, 0xb7, 0x56, 0x97, 0x1a, 0x11, 0xd6, 0x28, 0xd0, 0x0b, 0x30, 0x12, 0x07, 0xed, + 0xa0, 0x15, 0x6c, 0xec, 0x5c, 0x21, 0x32, 0x3b, 0x8b, 0xba, 0x59, 0x5a, 0x4b, 0x50, 0x58, 0xa7, + 0xb3, 0xbf, 0x53, 0x86, 0xf4, 0x23, 0xa9, 0xff, 0x7f, 0x9e, 0xfe, 0xe4, 0xcc, 0xd3, 0x3f, 0xb6, + 0x60, 0x92, 0xd6, 0xce, 0x5c, 0x8c, 0xa4, 0xe3, 0xb1, 0x7a, 0x22, 0xc4, 0x3a, 0xe0, 0x89, 0x90, + 0x27, 0xa9, 0xb4, 0x73, 0x83, 0x4e, 0x2c, 0x4c, 0x60, 0x9a, 0x10, 0xa3, 0x50, 0x2c, 0xb0, 0x82, + 0x8e, 0x84, 0xa1, 0x88, 0xd0, 0xd2, 0xe9, 0x48, 0x18, 0x62, 0x81, 0x95, 0x2f, 0x88, 0x54, 0x7a, + 0xbc, 0x20, 0xc2, 0xf2, 0x9b, 0x09, 0xb7, 0x16, 0xa1, 0x56, 0x68, 0xf9, 0xcd, 0xa4, 0xbf, 0x4b, + 0x42, 0x63, 0x7f, 0xbd, 0x0c, 0xa3, 0xf5, 0xc0, 0x4d, 0x22, 0x0a, 0x9e, 0x37, 0x22, 0x0a, 0xce, + 0xa4, 0x22, 0x0a, 0x26, 0x75, 0xda, 0x07, 0x13, 0x50, 0x20, 0xf2, 0xe0, 0xb1, 0x37, 0x6e, 0x0e, + 0x19, 0x4c, 0x60, 0xe4, 0xc1, 0x53, 0x8c, 0xb0, 0xc9, 0xf7, 0xa7, 0x29, 0x88, 0xe0, 0x7f, 0x5b, + 0x30, 0x5e, 0x0f, 0x5c, 0x3a, 0x41, 0x7f, 0x9a, 0x66, 0xa3, 0x9e, 0x3d, 0x6f, 0xf0, 0x80, 0xec, + 0x79, 0xff, 0xcc, 0x82, 0xa1, 0x7a, 0xe0, 0x1e, 0x83, 0x79, 0x78, 0xc5, 0x34, 0x0f, 0x3f, 0x96, + 0x2b, 0x79, 0x7b, 0x58, 0x84, 0xbf, 0x59, 0x86, 0x31, 0xda, 0xe2, 0x60, 0x43, 0x8e, 0x97, 0xd1, + 0x37, 0x56, 0x81, 0xbe, 0xa1, 0x2a, 0x61, 0xd0, 0x6a, 0x05, 0xf7, 0xd2, 0x63, 0xb7, 0xc2, 0xa0, + 0x58, 0x60, 0xd1, 0x39, 0x18, 0x6e, 0x87, 0x64, 0xdb, 0x0b, 0x3a, 0x51, 0x3a, 0xda, 0xb3, 0x2e, + 0xe0, 0x58, 0x51, 0xa0, 0xe7, 0x61, 0x34, 0xf2, 0xfc, 0x26, 0x91, 0x4e, 0x2f, 0x15, 0xe6, 0xf4, + 0xc2, 0x13, 0x95, 0x6a, 0x70, 0x6c, 0x50, 0xa1, 0xdb, 0x50, 0x65, 0xff, 0xd9, 0x0a, 0xea, 0xff, + 0x09, 0x10, 0x91, 0x9f, 0x5c, 0x30, 0xc0, 0x09, 0x2f, 0x74, 0x11, 0x20, 0x96, 0xee, 0x39, 0x91, + 0x08, 0x4b, 0x56, 0x7a, 0xa9, 0x72, 0xdc, 0x89, 0xb0, 0x46, 0x85, 0x9e, 0x81, 0x6a, 0xec, 0x78, + 0xad, 0xab, 0x9e, 0x4f, 0x22, 0xe1, 0xde, 0x24, 0x92, 0x8e, 0x0b, 0x20, 0x4e, 0xf0, 0x74, 0xbf, + 0x67, 0x41, 0xef, 0xfc, 0x79, 0xa1, 0x61, 0x46, 0xcd, 0xf6, 0xfb, 0xab, 0x0a, 0x8a, 0x35, 0x0a, + 0xfb, 0x25, 0x38, 0x59, 0x0f, 0xdc, 0x7a, 0x10, 0xc6, 0x2b, 0x41, 0x78, 0xcf, 0x09, 0x5d, 0x39, + 0x7e, 0x73, 0x32, 0xd7, 0x35, 0xdd, 0x93, 0x07, 0xb8, 0x15, 0xc1, 0xc8, 0x5d, 0xfd, 0x1c, 0xdb, + 0xf1, 0xfb, 0x0c, 0x55, 0xf9, 0x41, 0x09, 0x50, 0x9d, 0x39, 0x10, 0x19, 0xaf, 0x51, 0x6d, 0xc2, + 0x78, 0x44, 0xae, 0x7a, 0x7e, 0xe7, 0xbe, 0x60, 0x55, 0x2c, 0x36, 0xa8, 0xb1, 0xac, 0x97, 0xe1, + 0x76, 0x1a, 0x13, 0x86, 0x53, 0x7c, 0x69, 0x67, 0x86, 0x1d, 0x7f, 0x21, 0xba, 0x19, 0x91, 0x50, + 0xbc, 0xbe, 0xc4, 0x3a, 0x13, 0x4b, 0x20, 0x4e, 0xf0, 0x74, 0xf2, 0xb0, 0x3f, 0xd7, 0x03, 0x1f, + 0x07, 0x41, 0x2c, 0xa7, 0x1b, 0x7b, 0x8d, 0x43, 0x83, 0x63, 0x83, 0x0a, 0xad, 0x00, 0x8a, 0x3a, + 0xed, 0x76, 0x8b, 0xdd, 0x94, 0x3a, 0xad, 0x4b, 0x61, 0xd0, 0x69, 0x73, 0x3f, 0x72, 0xf1, 0x90, + 0x45, 0xa3, 0x0b, 0x8b, 0x33, 0x4a, 0x50, 0x61, 0xb1, 0x1e, 0xb1, 0xdf, 0x22, 0x02, 0x9e, 0x5b, + 0x5b, 0x1b, 0x0c, 0x84, 0x25, 0xce, 0xfe, 0x45, 0xb6, 0xc1, 0xb1, 0x67, 0x71, 0xe2, 0x4e, 0x48, + 0xd0, 0x16, 0x8c, 0xb5, 0xd9, 0x26, 0x16, 0x87, 0x41, 0xab, 0x45, 0xa4, 0x7e, 0x79, 0x38, 0x17, + 0x26, 0xfe, 0x10, 0x86, 0xce, 0x0e, 0x9b, 0xdc, 0xed, 0xff, 0x36, 0xce, 0x64, 0x95, 0xb8, 0xac, + 0x1e, 0x12, 0xce, 0xca, 0x42, 0x93, 0xfb, 0x48, 0x91, 0x07, 0xee, 0x92, 0x7d, 0x40, 0xb8, 0x3e, + 0x63, 0xc9, 0x05, 0x7d, 0x86, 0xb9, 0xe2, 0x73, 0x01, 0x51, 0xfc, 0xd9, 0x4e, 0x4e, 0x6f, 0xb8, + 0xe1, 0x0b, 0x16, 0x58, 0x63, 0x87, 0xae, 0xc2, 0x98, 0x78, 0x45, 0x45, 0x98, 0x29, 0xca, 0xc6, + 0x11, 0x7b, 0x0c, 0xeb, 0xc8, 0xfd, 0x34, 0x00, 0x9b, 0x85, 0xd1, 0x06, 0x3c, 0xaa, 0xbd, 0x12, + 0x96, 0xe1, 0x6e, 0xc7, 0x25, 0xcf, 0x63, 0x7b, 0xbb, 0x73, 0x8f, 0xae, 0x1d, 0x44, 0x88, 0x0f, + 0xe6, 0x83, 0x6e, 0xc0, 0x49, 0xa7, 0x19, 0x7b, 0xdb, 0xa4, 0x46, 0x1c, 0xb7, 0xe5, 0xf9, 0xc4, + 0x4c, 0x93, 0xf0, 0xf0, 0xde, 0xee, 0xdc, 0xc9, 0x85, 0x2c, 0x02, 0x9c, 0x5d, 0x0e, 0x7d, 0x12, + 0xaa, 0xae, 0x1f, 0x89, 0x3e, 0x18, 0x34, 0x1e, 0xc5, 0xab, 0xd6, 0xae, 0x37, 0xd4, 0xf7, 0x27, + 0x7f, 0x70, 0x52, 0x00, 0xbd, 0x0b, 0xa3, 0x7a, 0xf8, 0x93, 0x78, 0x8c, 0xf1, 0xc5, 0x42, 0xe7, + 0x67, 0x23, 0x66, 0x88, 0x5b, 0xf0, 0x94, 0x5b, 0xab, 0x11, 0x4e, 0x64, 0x54, 0x81, 0x7e, 0x1e, + 0x50, 0x44, 0xc2, 0x6d, 0xaf, 0x49, 0x16, 0x9a, 0x2c, 0xbb, 0x2f, 0xb3, 0xf1, 0x0c, 0x1b, 0xf1, + 0x1d, 0xa8, 0xd1, 0x45, 0x81, 0x33, 0x4a, 0xa1, 0xcb, 0x54, 0xf2, 0xe8, 0x50, 0xe1, 0x85, 0x2c, + 0x15, 0xc3, 0x99, 0x1a, 0x69, 0x87, 0xa4, 0xe9, 0xc4, 0xc4, 0x35, 0x39, 0xe2, 0x54, 0x39, 0xba, + 0x2f, 0xa9, 0x07, 0x1c, 0xc0, 0xf4, 0x9d, 0xed, 0x7e, 0xc4, 0x81, 0x9e, 0xb3, 0x36, 0x83, 0x28, + 0xbe, 0x4e, 0xe2, 0x7b, 0x41, 0x78, 0x57, 0x64, 0x44, 0x4b, 0x52, 0x25, 0x26, 0x28, 0xac, 0xd3, + 0x51, 0x1d, 0x8a, 0x5d, 0xfd, 0xad, 0xd6, 0xd8, 0xbd, 0xca, 0x70, 0xb2, 0x76, 0x2e, 0x73, 0x30, + 0x96, 0x78, 0x49, 0xba, 0x5a, 0x5f, 0x62, 0x77, 0x24, 0x29, 0xd2, 0xd5, 0xfa, 0x12, 0x96, 0x78, + 0x14, 0x74, 0x3f, 0x3d, 0x38, 0x5e, 0xe4, 0xbe, 0xaa, 0x5b, 0x92, 0x17, 0x7c, 0x7d, 0xf0, 0x3e, + 0x4c, 0xaa, 0xe7, 0x0f, 0x79, 0xd2, 0xb8, 0x68, 0x66, 0x82, 0x4d, 0x9c, 0xc3, 0xe4, 0x9e, 0x53, + 0x76, 0xbd, 0xd5, 0x14, 0x4f, 0xdc, 0x55, 0x8b, 0x91, 0x9c, 0x63, 0x32, 0xf7, 0x51, 0x8e, 0xf3, + 0x50, 0x8d, 0x3a, 0x77, 0xdc, 0x60, 0xcb, 0xf1, 0x7c, 0x76, 0x91, 0xa1, 0x29, 0x31, 0x0d, 0x89, + 0xc0, 0x09, 0x0d, 0xaa, 0xc3, 0xb0, 0x23, 0x8e, 0x70, 0xe2, 0xc2, 0x21, 0x27, 0x0a, 0x5f, 0x1e, + 0xf8, 0xb8, 0x75, 0x55, 0xfe, 0xc3, 0x8a, 0x0b, 0x7a, 0x19, 0xc6, 0x44, 0x10, 0x99, 0x70, 0xf6, + 0x3c, 0x61, 0x06, 0x1c, 0x34, 0x74, 0x24, 0x36, 0x69, 0xd1, 0x06, 0x8c, 0x53, 0x2e, 0x89, 0x00, + 0x9c, 0x99, 0xee, 0x4f, 0x86, 0x6a, 0xe9, 0xcf, 0x75, 0x36, 0x38, 0xc5, 0x16, 0xb9, 0xf0, 0x88, + 0xd3, 0x89, 0x83, 0x2d, 0xba, 0x12, 0xcc, 0x75, 0xb2, 0x16, 0xdc, 0x25, 0x3e, 0xbb, 0x65, 0x18, + 0x5e, 0x3c, 0xb3, 0xb7, 0x3b, 0xf7, 0xc8, 0xc2, 0x01, 0x74, 0xf8, 0x40, 0x2e, 0xe8, 0x2d, 0x18, + 0x89, 0x83, 0x96, 0xf0, 0xe1, 0x8e, 0x66, 0x4e, 0x15, 0x49, 0x42, 0xb4, 0xa6, 0x0a, 0xe8, 0x66, + 0x0c, 0xc5, 0x04, 0xeb, 0x1c, 0xd1, 0x9b, 0x7c, 0x55, 0xb2, 0x84, 0x99, 0x24, 0x9a, 0x79, 0xa8, + 0x48, 0x67, 0xa9, 0x0c, 0x9b, 0xe6, 0xf2, 0x15, 0x3c, 0xb0, 0xce, 0x70, 0xf6, 0xe7, 0x60, 0xaa, + 0x4b, 0xe4, 0xf5, 0xe5, 0xdc, 0xfa, 0x1f, 0x07, 0xa0, 0xaa, 0x2c, 0x86, 0xe8, 0xbc, 0x69, 0x1c, + 0x7e, 0x38, 0x6d, 0x1c, 0x1e, 0xa6, 0x0a, 0x9a, 0x6e, 0x0f, 0x7e, 0x33, 0xe3, 0x41, 0xfd, 0xa7, + 0x73, 0xd7, 0x78, 0xf1, 0xc8, 0x36, 0xed, 0x88, 0x57, 0x2e, 0x6c, 0x6f, 0xae, 0x1c, 0x78, 0x6a, + 0x2c, 0xf8, 0x48, 0x24, 0x3d, 0x1f, 0xb6, 0x03, 0x77, 0xb5, 0x9e, 0x7e, 0x03, 0xad, 0x4e, 0x81, + 0x98, 0xe3, 0x98, 0x5e, 0x4f, 0xf7, 0x6c, 0xa6, 0xd7, 0x0f, 0x1d, 0x52, 0xaf, 0x97, 0x0c, 0x70, + 0xc2, 0x0b, 0x6d, 0xc3, 0x54, 0xd3, 0x7c, 0xd2, 0x4e, 0xc5, 0xab, 0x3d, 0xdb, 0xc7, 0x93, 0x72, + 0x1d, 0xed, 0x45, 0x9a, 0xa5, 0x34, 0x3f, 0xdc, 0x5d, 0x05, 0x7a, 0x19, 0x86, 0xdf, 0x0d, 0x22, + 0x76, 0x6d, 0x21, 0x36, 0x2e, 0x19, 0x17, 0x34, 0xfc, 0xea, 0x8d, 0x06, 0x83, 0xef, 0xef, 0xce, + 0x8d, 0xd4, 0x03, 0x57, 0xfe, 0xc5, 0xaa, 0x00, 0xfa, 0xac, 0x05, 0x27, 0x8d, 0x75, 0xac, 0x5a, + 0x0e, 0x87, 0x69, 0xf9, 0xa3, 0xa2, 0xe6, 0x93, 0xab, 0x59, 0x3c, 0x71, 0x76, 0x55, 0xf6, 0x77, + 0xb9, 0x89, 0x54, 0x18, 0x4d, 0x48, 0xd4, 0x69, 0x1d, 0xc7, 0xeb, 0x10, 0x37, 0x0c, 0x7b, 0xce, + 0x03, 0x30, 0xd2, 0xff, 0x7b, 0x8b, 0x19, 0xe9, 0xd7, 0xc8, 0x56, 0xbb, 0xe5, 0xc4, 0xc7, 0xe1, + 0xfb, 0xfc, 0x19, 0x18, 0x8e, 0x45, 0x6d, 0xc5, 0x9e, 0xb6, 0xd0, 0x9a, 0xc7, 0x2e, 0x2f, 0xd4, + 0xc6, 0x27, 0xa1, 0x58, 0x31, 0xb4, 0xff, 0x15, 0x1f, 0x15, 0x89, 0x39, 0x06, 0x4b, 0xc4, 0x75, + 0xd3, 0x12, 0xf1, 0x54, 0xe1, 0x6f, 0xe9, 0x61, 0x91, 0xf8, 0x8e, 0xf9, 0x05, 0xec, 0x7c, 0xf2, + 0x93, 0x73, 0x8b, 0x64, 0xff, 0xba, 0x05, 0xd3, 0x59, 0xce, 0x08, 0x54, 0x81, 0xe1, 0xa7, 0x23, + 0x75, 0xbf, 0xa6, 0x7a, 0xf5, 0x96, 0x80, 0x63, 0x45, 0x51, 0x38, 0xd7, 0x7c, 0x7f, 0x29, 0xb4, + 0x6e, 0x80, 0xf9, 0x38, 0x22, 0x7a, 0x85, 0x87, 0x3a, 0x58, 0xea, 0xf5, 0xc2, 0xfe, 0xc2, 0x1c, + 0xec, 0x6f, 0x94, 0x60, 0x9a, 0x1b, 0xb9, 0x17, 0xb6, 0x03, 0xcf, 0xad, 0x07, 0xae, 0x08, 0xfc, + 0x70, 0x61, 0xb4, 0xad, 0x1d, 0x6e, 0x8b, 0xa5, 0xe4, 0xd1, 0x8f, 0xc3, 0xc9, 0x81, 0x42, 0x87, + 0x62, 0x83, 0x2b, 0xad, 0x85, 0x6c, 0x7b, 0x4d, 0x65, 0x33, 0x2d, 0xf5, 0xbd, 0x33, 0xa8, 0x5a, + 0x96, 0x35, 0x3e, 0xd8, 0xe0, 0x7a, 0x04, 0x4f, 0xc4, 0xd8, 0x7f, 0xdf, 0x82, 0x87, 0x7a, 0xa4, + 0xed, 0xa1, 0xd5, 0xdd, 0x63, 0x17, 0x0b, 0xe2, 0xf5, 0x4d, 0x55, 0x1d, 0xbf, 0x6e, 0xc0, 0x02, + 0x8b, 0xee, 0x00, 0xf0, 0xeb, 0x02, 0xaa, 0x4b, 0xa7, 0xef, 0xb2, 0x0b, 0x26, 0xc7, 0xd0, 0xf2, + 0x26, 0x48, 0x4e, 0x58, 0xe3, 0x6a, 0x7f, 0xad, 0x0c, 0x03, 0xfc, 0x91, 0xf7, 0x3a, 0x0c, 0x6d, + 0xf2, 0x7c, 0xc6, 0xfd, 0xa5, 0x53, 0x4e, 0x0e, 0x2f, 0x1c, 0x80, 0x25, 0x1b, 0x74, 0x0d, 0x4e, + 0x88, 0xd0, 0xa3, 0x1a, 0x69, 0x39, 0x3b, 0xf2, 0x34, 0xcc, 0xdf, 0x0d, 0x91, 0x09, 0xee, 0x4f, + 0xac, 0x76, 0x93, 0xe0, 0xac, 0x72, 0xe8, 0x95, 0xae, 0xf4, 0x83, 0x3c, 0x4f, 0xb4, 0xd2, 0x84, + 0x73, 0x52, 0x10, 0xbe, 0x0c, 0x63, 0xed, 0xae, 0x73, 0xbf, 0xf6, 0x96, 0xb6, 0x79, 0xd6, 0x37, + 0x69, 0x99, 0xef, 0x42, 0x87, 0xf9, 0x6c, 0xac, 0x6d, 0x86, 0x24, 0xda, 0x0c, 0x5a, 0xae, 0x78, + 0x06, 0x36, 0xf1, 0x5d, 0x48, 0xe1, 0x71, 0x57, 0x09, 0xca, 0x65, 0xdd, 0xf1, 0x5a, 0x9d, 0x90, + 0x24, 0x5c, 0x06, 0x4d, 0x2e, 0x2b, 0x29, 0x3c, 0xee, 0x2a, 0x41, 0xe7, 0xd6, 0x49, 0xf1, 0x72, + 0xa8, 0x0c, 0x52, 0x17, 0x22, 0xe8, 0xd3, 0x30, 0x24, 0x03, 0x08, 0x0a, 0xe5, 0x52, 0x11, 0x8e, + 0x09, 0xea, 0x15, 0x52, 0xed, 0x1d, 0x39, 0x11, 0x3a, 0x20, 0xf9, 0x1d, 0xe6, 0x85, 0xca, 0x3f, + 0xb7, 0xe0, 0x44, 0x86, 0x23, 0x1c, 0x17, 0x69, 0x1b, 0x5e, 0x14, 0xab, 0x57, 0x2c, 0x34, 0x91, + 0xc6, 0xe1, 0x58, 0x51, 0xd0, 0xd5, 0xc2, 0x85, 0x66, 0x5a, 0x50, 0x0a, 0x17, 0x13, 0x81, 0xed, + 0x4f, 0x50, 0xa2, 0x33, 0x50, 0xe9, 0x44, 0x24, 0x94, 0x0f, 0x3a, 0x4a, 0x39, 0xcf, 0xec, 0x8c, + 0x0c, 0x43, 0xd5, 0xd6, 0x0d, 0x65, 0xe2, 0xd3, 0xd4, 0x56, 0x6e, 0xe4, 0xe3, 0x38, 0xfb, 0xcb, + 0x65, 0x98, 0x48, 0x39, 0xc4, 0xd2, 0x86, 0x6c, 0x05, 0xbe, 0x17, 0x07, 0x2a, 0xbf, 0x1d, 0x7f, + 0x43, 0x8e, 0xb4, 0x37, 0xaf, 0x09, 0x38, 0x56, 0x14, 0xe8, 0x49, 0xf9, 0x42, 0x70, 0xfa, 0x75, + 0x8e, 0xc5, 0x9a, 0xf1, 0x48, 0x70, 0xd1, 0x97, 0x75, 0x1e, 0x87, 0x4a, 0x3b, 0x50, 0x0f, 0xbe, + 0xab, 0xf1, 0xc4, 0x8b, 0xb5, 0x7a, 0x10, 0xb4, 0x30, 0x43, 0xa2, 0x27, 0xc4, 0xd7, 0xa7, 0x6e, + 0x46, 0xb0, 0xe3, 0x06, 0x91, 0xd6, 0x05, 0x4f, 0xc1, 0xd0, 0x5d, 0xb2, 0x13, 0x7a, 0xfe, 0x46, + 0xfa, 0x5e, 0xe8, 0x0a, 0x07, 0x63, 0x89, 0x37, 0x93, 0xd5, 0x0f, 0x1d, 0xf1, 0xeb, 0x39, 0xc3, + 0xb9, 0xfb, 0xe0, 0x37, 0x2d, 0x98, 0x60, 0xd9, 0x67, 0x45, 0x8a, 0x04, 0x2f, 0xf0, 0x8f, 0x41, + 0xc7, 0x78, 0x1c, 0x06, 0x42, 0x5a, 0x69, 0xfa, 0xf9, 0x0b, 0xd6, 0x12, 0xcc, 0x71, 0xe8, 0x11, + 0xa8, 0xb0, 0x26, 0xd0, 0x61, 0x1c, 0xe5, 0x49, 0xee, 0x6b, 0x4e, 0xec, 0x60, 0x06, 0x65, 0x31, + 0x68, 0x98, 0xb4, 0x5b, 0x1e, 0x6f, 0x74, 0x62, 0xce, 0xfd, 0xa0, 0xc5, 0xa0, 0x65, 0x36, 0xf2, + 0x41, 0xc5, 0xa0, 0x65, 0x33, 0x3f, 0x58, 0xcf, 0xff, 0xef, 0x25, 0x38, 0x9d, 0x59, 0x2e, 0xb9, + 0x61, 0x5e, 0x31, 0x6e, 0x98, 0x2f, 0xa6, 0x6e, 0x98, 0xed, 0x83, 0x4b, 0x3f, 0x98, 0x3b, 0xe7, + 0xec, 0xab, 0xe0, 0xf2, 0x31, 0x5e, 0x05, 0x57, 0x8a, 0xaa, 0x38, 0x03, 0x39, 0x2a, 0xce, 0x1f, + 0x59, 0xf0, 0x70, 0x66, 0x97, 0x7d, 0xe0, 0x82, 0xfe, 0x32, 0x5b, 0xd9, 0xe3, 0x74, 0xf2, 0x6b, + 0xe5, 0x1e, 0x5f, 0xc5, 0xce, 0x29, 0x67, 0xa9, 0x14, 0x62, 0xc8, 0x48, 0x28, 0x6f, 0xa3, 0x5c, + 0x02, 0x71, 0x18, 0x56, 0x58, 0x14, 0x69, 0x41, 0x73, 0xbc, 0x91, 0xcb, 0x87, 0x5c, 0x50, 0xf3, + 0xa6, 0x1d, 0x5e, 0xcf, 0xfb, 0x90, 0x0e, 0xa5, 0xbb, 0xad, 0x9d, 0x3c, 0xcb, 0x87, 0x39, 0x79, + 0x8e, 0x66, 0x9f, 0x3a, 0xd1, 0x02, 0x4c, 0x6c, 0x79, 0x3e, 0x7b, 0x74, 0xd7, 0xd4, 0x9e, 0x54, + 0xe4, 0xf2, 0x35, 0x13, 0x8d, 0xd3, 0xf4, 0xb3, 0x2f, 0xc3, 0xd8, 0xe1, 0xad, 0x6b, 0x3f, 0x2a, + 0xc3, 0x87, 0x0f, 0x10, 0x0a, 0x7c, 0x77, 0x30, 0xc6, 0x45, 0xdb, 0x1d, 0xba, 0xc6, 0xa6, 0x0e, + 0xd3, 0xeb, 0x9d, 0x56, 0x6b, 0x87, 0xf9, 0x67, 0x11, 0x57, 0x52, 0x08, 0xa5, 0x46, 0x25, 0xa3, + 0x5e, 0xc9, 0xa0, 0xc1, 0x99, 0x25, 0xd1, 0xcf, 0x03, 0x0a, 0xee, 0xb0, 0xb4, 0xc8, 0x6e, 0x92, + 0xd7, 0x82, 0x0d, 0x41, 0x39, 0x59, 0xaa, 0x37, 0xba, 0x28, 0x70, 0x46, 0x29, 0xaa, 0xa7, 0xd2, + 0x7d, 0x6c, 0x47, 0x35, 0x2b, 0xa5, 0xa7, 0x62, 0x1d, 0x89, 0x4d, 0x5a, 0x74, 0x09, 0xa6, 0x9c, + 0x6d, 0xc7, 0xe3, 0x69, 0xce, 0x24, 0x03, 0xae, 0xa8, 0x2a, 0xfb, 0xd5, 0x42, 0x9a, 0x00, 0x77, + 0x97, 0x41, 0x6d, 0xc3, 0x20, 0xc9, 0x5f, 0x66, 0xf8, 0xe4, 0x21, 0x66, 0x70, 0x61, 0x13, 0xa5, + 0xfd, 0xa7, 0x16, 0xdd, 0xfa, 0x32, 0xde, 0x67, 0xa5, 0x3d, 0xa2, 0x0c, 0x6c, 0x5a, 0x10, 0xa0, + 0xea, 0x91, 0x25, 0x1d, 0x89, 0x4d, 0x5a, 0x3e, 0x35, 0xa2, 0xc4, 0x5d, 0xdc, 0xd0, 0x36, 0x45, + 0xfc, 0xac, 0xa2, 0xa0, 0x1a, 0xb4, 0xeb, 0x6d, 0x7b, 0x51, 0x10, 0x8a, 0x05, 0xd4, 0xef, 0x0b, + 0xe8, 0x4a, 0x5e, 0xd6, 0x38, 0x1b, 0x2c, 0xf9, 0xd9, 0x5f, 0x29, 0xc1, 0x98, 0xac, 0xf1, 0xd5, + 0x4e, 0x10, 0x3b, 0xc7, 0xb0, 0xa5, 0xbf, 0x6a, 0x6c, 0xe9, 0xe7, 0x8b, 0x85, 0x13, 0xb3, 0xc6, + 0xf5, 0xdc, 0xca, 0x3f, 0x9d, 0xda, 0xca, 0x2f, 0xf4, 0xc3, 0xf4, 0xe0, 0x2d, 0xfc, 0xdf, 0x58, + 0x30, 0x65, 0xd0, 0x1f, 0xc3, 0x4e, 0x52, 0x37, 0x77, 0x92, 0x67, 0xfa, 0xf8, 0x9a, 0x1e, 0x3b, + 0xc8, 0xd7, 0x4b, 0xa9, 0xaf, 0x60, 0x3b, 0xc7, 0x2f, 0x40, 0x65, 0xd3, 0x09, 0xdd, 0x62, 0x39, + 0x3f, 0xbb, 0x8a, 0xcf, 0x5f, 0x76, 0x42, 0x97, 0xcb, 0xff, 0x73, 0xea, 0xf5, 0x38, 0x27, 0x74, + 0x73, 0xa3, 0x28, 0x58, 0xa5, 0xe8, 0x25, 0x18, 0x8c, 0x9a, 0x41, 0x5b, 0xf9, 0x99, 0x9e, 0xe1, + 0x2f, 0xcb, 0x51, 0xc8, 0xfe, 0xee, 0x1c, 0x32, 0xab, 0xa3, 0x60, 0x2c, 0xe8, 0x67, 0x37, 0xa0, + 0xaa, 0xaa, 0x3e, 0x52, 0x4f, 0xfb, 0xff, 0x5a, 0x86, 0x13, 0x19, 0x73, 0x05, 0xfd, 0xa2, 0xd1, + 0x6f, 0x2f, 0xf7, 0x3d, 0xd9, 0xde, 0x67, 0xcf, 0xfd, 0x22, 0x3b, 0x29, 0xb9, 0x62, 0x76, 0x1c, + 0xa2, 0xfa, 0x9b, 0x11, 0x49, 0x57, 0x4f, 0x41, 0xf9, 0xd5, 0xd3, 0x6a, 0x8f, 0xad, 0xfb, 0x69, + 0x45, 0xaa, 0xa5, 0x47, 0x3a, 0xce, 0x5f, 0xa8, 0xc0, 0x74, 0x56, 0xde, 0x02, 0xf4, 0x2b, 0x56, + 0xea, 0x85, 0x91, 0x57, 0xfa, 0x4f, 0x7e, 0xc0, 0x9f, 0x1d, 0x11, 0x59, 0x85, 0xe6, 0xcd, 0x37, + 0x47, 0x72, 0x7b, 0x5c, 0xd4, 0xce, 0xe2, 0x9f, 0x42, 0xfe, 0x5a, 0x8c, 0x94, 0x0a, 0x9f, 0x3a, + 0x44, 0x53, 0xc4, 0x83, 0x33, 0x51, 0x2a, 0xfe, 0x49, 0x82, 0xf3, 0xe3, 0x9f, 0x64, 0x1b, 0x66, + 0x3d, 0x18, 0xd1, 0xbe, 0xeb, 0x48, 0xa7, 0xc1, 0x5d, 0xba, 0x45, 0x69, 0xed, 0x3e, 0xd2, 0xa9, + 0xf0, 0x77, 0x2c, 0x48, 0x39, 0x85, 0x29, 0xb3, 0x8c, 0xd5, 0xd3, 0x2c, 0x73, 0x06, 0x2a, 0x61, + 0xd0, 0x22, 0xe9, 0x47, 0x27, 0x70, 0xd0, 0x22, 0x98, 0x61, 0xd4, 0x83, 0xd2, 0xe5, 0x5e, 0x0f, + 0x4a, 0xd3, 0x73, 0x7a, 0x8b, 0x6c, 0x13, 0x69, 0x24, 0x51, 0x62, 0xfc, 0x2a, 0x05, 0x62, 0x8e, + 0xb3, 0x7f, 0xa7, 0x02, 0x27, 0x32, 0x62, 0x01, 0xe9, 0x09, 0x69, 0xc3, 0x89, 0xc9, 0x3d, 0x67, + 0x27, 0x9d, 0xfc, 0xf6, 0x12, 0x07, 0x63, 0x89, 0x67, 0xce, 0xac, 0x3c, 0x81, 0x5e, 0xca, 0x74, + 0x25, 0xf2, 0xe6, 0x09, 0xec, 0xd1, 0x3f, 0x3d, 0x7c, 0x11, 0x20, 0x8a, 0x5a, 0xcb, 0x3e, 0xd5, + 0xf0, 0x5c, 0xe1, 0x34, 0x9b, 0xe4, 0x5d, 0x6c, 0x5c, 0x15, 0x18, 0xac, 0x51, 0xa1, 0x1a, 0x4c, + 0xb6, 0xc3, 0x20, 0xe6, 0x86, 0xc1, 0x1a, 0x77, 0xb4, 0x18, 0x30, 0xa3, 0xb5, 0xea, 0x29, 0x3c, + 0xee, 0x2a, 0x81, 0x5e, 0x80, 0x11, 0x11, 0xc1, 0x55, 0x0f, 0x82, 0x96, 0x30, 0x23, 0xa9, 0xeb, + 0xf8, 0x46, 0x82, 0xc2, 0x3a, 0x9d, 0x56, 0x8c, 0x59, 0x1b, 0x87, 0x32, 0x8b, 0x71, 0x8b, 0xa3, + 0x46, 0x97, 0xca, 0x6e, 0x32, 0x5c, 0x28, 0xbb, 0x49, 0x62, 0x58, 0xab, 0x16, 0xbe, 0x88, 0x81, + 0x5c, 0x03, 0xd4, 0x1f, 0x96, 0x61, 0x90, 0x0f, 0xc5, 0x31, 0x68, 0x79, 0x75, 0x61, 0x52, 0x2a, + 0x94, 0x49, 0x82, 0xb7, 0x6a, 0xbe, 0xe6, 0xc4, 0x0e, 0x17, 0x4d, 0x6a, 0x85, 0x24, 0x66, 0x28, + 0x34, 0x6f, 0xac, 0xa1, 0xd9, 0x94, 0xa5, 0x04, 0x38, 0x0f, 0x6d, 0x45, 0x6d, 0x02, 0x44, 0xec, + 0xf9, 0x5b, 0xca, 0x43, 0x64, 0xe6, 0x7d, 0xbe, 0x50, 0x3b, 0x1a, 0xaa, 0x18, 0x6f, 0x4d, 0x32, + 0x2d, 0x15, 0x02, 0x6b, 0xbc, 0x67, 0x5f, 0x84, 0xaa, 0x22, 0xce, 0x3b, 0x42, 0x8e, 0xea, 0xa2, + 0xed, 0x67, 0x61, 0x22, 0x55, 0x57, 0x5f, 0x27, 0xd0, 0xdf, 0xb3, 0x60, 0x82, 0x37, 0x79, 0xd9, + 0xdf, 0x16, 0xa2, 0xe0, 0x73, 0x16, 0x4c, 0xb7, 0x32, 0x56, 0xa2, 0x18, 0xe6, 0xc3, 0xac, 0x61, + 0x75, 0xf8, 0xcc, 0xc2, 0xe2, 0xcc, 0xda, 0xd0, 0x59, 0x18, 0xe6, 0xaf, 0x79, 0x3b, 0x2d, 0xe1, + 0xa1, 0x3d, 0xca, 0x73, 0x92, 0x73, 0x18, 0x56, 0x58, 0xfb, 0xc7, 0x16, 0x4c, 0xf1, 0x8f, 0xb8, + 0x42, 0x76, 0xd4, 0xf1, 0xea, 0x03, 0xf2, 0x19, 0x22, 0xfb, 0x7a, 0xa9, 0x47, 0xf6, 0x75, 0xfd, + 0x2b, 0xcb, 0x07, 0x7e, 0xe5, 0x37, 0x2c, 0x10, 0x33, 0xf4, 0x18, 0xce, 0x0f, 0xab, 0xe6, 0xf9, + 0xe1, 0x23, 0x45, 0x26, 0x7d, 0x8f, 0x83, 0xc3, 0xaf, 0x96, 0x60, 0x92, 0x13, 0x24, 0x37, 0x32, + 0x1f, 0x94, 0xc1, 0xe9, 0xef, 0x55, 0x20, 0xf5, 0x26, 0x6c, 0xf6, 0x97, 0x1a, 0x63, 0x59, 0x39, + 0x70, 0x2c, 0xff, 0xa7, 0x05, 0x88, 0xf7, 0x49, 0xfa, 0x29, 0x74, 0xbe, 0xbb, 0x69, 0xe6, 0x80, + 0x44, 0x72, 0x28, 0x0c, 0xd6, 0xa8, 0x1e, 0xf0, 0x27, 0xa4, 0xee, 0xc3, 0xca, 0xf9, 0xf7, 0x61, + 0x7d, 0x7c, 0xf5, 0x77, 0xcb, 0x90, 0x76, 0xd5, 0x44, 0x6f, 0xc3, 0x68, 0xd3, 0x69, 0x3b, 0x77, + 0xbc, 0x96, 0x17, 0x7b, 0x24, 0x2a, 0x76, 0xe1, 0xbe, 0xa4, 0x95, 0x10, 0xd7, 0x50, 0x1a, 0x04, + 0x1b, 0x1c, 0xd1, 0x3c, 0x40, 0x3b, 0xf4, 0xb6, 0xbd, 0x16, 0xd9, 0x60, 0x27, 0x1e, 0x16, 0xeb, + 0xc1, 0xef, 0x8e, 0x25, 0x14, 0x6b, 0x14, 0x19, 0xb1, 0x01, 0xe5, 0xe3, 0x88, 0x0d, 0xa8, 0xf4, + 0x19, 0x1b, 0x30, 0x50, 0x28, 0x36, 0x00, 0xc3, 0x29, 0xb9, 0x79, 0xd3, 0xff, 0x2b, 0x5e, 0x8b, + 0x08, 0xdd, 0x8d, 0xc7, 0x82, 0xcc, 0xee, 0xed, 0xce, 0x9d, 0xc2, 0x99, 0x14, 0xb8, 0x47, 0x49, + 0xbb, 0x03, 0x27, 0x1a, 0x24, 0x94, 0xcf, 0xd8, 0xa9, 0xb5, 0xf4, 0x26, 0x54, 0xc3, 0xd4, 0x32, + 0xee, 0x33, 0xe0, 0x5f, 0xcb, 0xf1, 0x26, 0x97, 0x6d, 0xc2, 0xd2, 0xfe, 0xeb, 0x25, 0x18, 0x12, + 0x4e, 0x9a, 0xc7, 0xa0, 0x7c, 0x5c, 0x31, 0x4c, 0x4c, 0x4f, 0xe5, 0xc9, 0x3f, 0xd6, 0xac, 0x9e, + 0xc6, 0xa5, 0x46, 0xca, 0xb8, 0xf4, 0x4c, 0x31, 0x76, 0x07, 0x9b, 0x95, 0x7e, 0xab, 0x0c, 0xe3, + 0xa6, 0xd3, 0xea, 0x31, 0x74, 0xcb, 0x6b, 0x30, 0x14, 0x09, 0xff, 0xe9, 0x52, 0x11, 0x9f, 0xbd, + 0xf4, 0x10, 0x27, 0x37, 0xf1, 0xc2, 0x63, 0x5a, 0xb2, 0xcb, 0x74, 0xd1, 0x2e, 0x1f, 0x8b, 0x8b, + 0x76, 0x9e, 0x2f, 0x71, 0xe5, 0x41, 0xf8, 0x12, 0xdb, 0xdf, 0x63, 0x22, 0x5f, 0x87, 0x1f, 0xc3, + 0x36, 0xfe, 0xaa, 0xb9, 0x39, 0x9c, 0x2b, 0x34, 0xef, 0x44, 0xf3, 0x7a, 0x6c, 0xe7, 0xdf, 0xb2, + 0x60, 0x44, 0x10, 0x1e, 0xc3, 0x07, 0xfc, 0xbc, 0xf9, 0x01, 0x4f, 0x14, 0xfa, 0x80, 0x1e, 0x2d, + 0xff, 0x4a, 0x49, 0xb5, 0xbc, 0x1e, 0x84, 0x71, 0xa1, 0x4c, 0xe8, 0xc3, 0xf4, 0xe8, 0x17, 0x34, + 0x83, 0x96, 0x50, 0xe0, 0x1e, 0x49, 0x42, 0xff, 0x38, 0x7c, 0x5f, 0xfb, 0x8d, 0x15, 0x35, 0x8b, + 0x4c, 0x0b, 0xc2, 0x58, 0x6c, 0xa0, 0x49, 0x64, 0x5a, 0x10, 0xc6, 0x98, 0x61, 0x90, 0x0b, 0x10, + 0x3b, 0xe1, 0x06, 0x89, 0x29, 0x4c, 0x44, 0xcd, 0xf6, 0x5e, 0xad, 0x9d, 0xd8, 0x6b, 0xcd, 0x7b, + 0x7e, 0x1c, 0xc5, 0xe1, 0xfc, 0xaa, 0x1f, 0xdf, 0x08, 0xb9, 0xd2, 0xaf, 0xc5, 0xf2, 0x29, 0x5e, + 0x58, 0xe3, 0x2b, 0x83, 0x44, 0x58, 0x1d, 0x03, 0xe6, 0x0d, 0xd2, 0x75, 0x01, 0xc7, 0x8a, 0xc2, + 0x7e, 0x91, 0x49, 0x76, 0xd6, 0x41, 0xfd, 0x85, 0xd9, 0x7d, 0x61, 0x48, 0x75, 0x2d, 0x33, 0x0b, + 0x5f, 0xd7, 0x83, 0xf9, 0x8a, 0x8a, 0x4f, 0xda, 0x04, 0xdd, 0x8f, 0x3a, 0x89, 0xfd, 0x43, 0xa4, + 0xeb, 0xda, 0xf1, 0xc5, 0xc2, 0x12, 0xb9, 0x8f, 0x8b, 0x46, 0x96, 0x92, 0x91, 0xe5, 0xa1, 0x5b, + 0xad, 0xa7, 0xf3, 0xd7, 0x2f, 0x49, 0x04, 0x4e, 0x68, 0xd0, 0x79, 0x71, 0xa0, 0xe4, 0x16, 0x97, + 0x0f, 0xa7, 0x0e, 0x94, 0xb2, 0x4b, 0xb4, 0x13, 0xe5, 0x05, 0x18, 0x51, 0x4f, 0x02, 0xd5, 0xf9, + 0x63, 0x2c, 0x55, 0xae, 0x5f, 0x2d, 0x27, 0x60, 0xac, 0xd3, 0xa0, 0x35, 0x98, 0x88, 0xf8, 0x7b, + 0x45, 0x32, 0x5a, 0x43, 0x18, 0x0e, 0x9e, 0x96, 0x97, 0x94, 0x0d, 0x13, 0xbd, 0xcf, 0x40, 0x7c, + 0x29, 0xcb, 0xf8, 0x8e, 0x34, 0x0b, 0xf4, 0x0a, 0x8c, 0xb7, 0xf4, 0x37, 0x5c, 0xeb, 0xc2, 0xae, + 0xa0, 0xdc, 0xce, 0x8c, 0x17, 0x5e, 0xeb, 0x38, 0x45, 0x8d, 0x5e, 0x83, 0x19, 0x1d, 0x22, 0x92, + 0x0b, 0x39, 0xfe, 0x06, 0x89, 0xc4, 0xdb, 0x26, 0x8f, 0xec, 0xed, 0xce, 0xcd, 0x5c, 0xed, 0x41, + 0x83, 0x7b, 0x96, 0x46, 0x2f, 0xc1, 0xa8, 0xfc, 0x7c, 0x2d, 0xb6, 0x29, 0x71, 0x78, 0xd4, 0x70, + 0xd8, 0xa0, 0x44, 0xf7, 0xe0, 0xa4, 0xfc, 0xbf, 0x16, 0x3a, 0xeb, 0xeb, 0x5e, 0x53, 0x04, 0x99, + 0x8d, 0x30, 0x16, 0x0b, 0xd2, 0x5f, 0x7c, 0x39, 0x8b, 0x68, 0x7f, 0x77, 0xee, 0x8c, 0xe8, 0xb5, + 0x4c, 0x3c, 0x1b, 0xc4, 0x6c, 0xfe, 0xe8, 0x1a, 0x9c, 0xd8, 0x24, 0x4e, 0x2b, 0xde, 0x5c, 0xda, + 0x24, 0xcd, 0xbb, 0x72, 0x61, 0xb1, 0x88, 0x29, 0xcd, 0x25, 0xf0, 0x72, 0x37, 0x09, 0xce, 0x2a, + 0xf7, 0xfe, 0xee, 0x94, 0x7f, 0x81, 0x16, 0xd6, 0xf4, 0x07, 0xf4, 0x0e, 0x8c, 0xea, 0x7d, 0x9d, + 0x56, 0x0c, 0xf2, 0xdf, 0xf7, 0x15, 0x7a, 0x88, 0x1a, 0x01, 0x1d, 0x87, 0x0d, 0xde, 0xf6, 0xbf, + 0x2b, 0xc1, 0x5c, 0x4e, 0xee, 0xae, 0x94, 0x35, 0xcb, 0x2a, 0x64, 0xcd, 0x5a, 0x90, 0x6f, 0xde, + 0x5c, 0x4f, 0xe5, 0x4c, 0x4f, 0xbd, 0x62, 0x93, 0x64, 0x4e, 0x4f, 0xd3, 0x17, 0xf6, 0x34, 0xd3, + 0x0d, 0x62, 0x95, 0x5c, 0x87, 0xbb, 0xd7, 0x75, 0x1b, 0xe7, 0xc0, 0x61, 0x94, 0xde, 0x9e, 0xe6, + 0x4d, 0xfb, 0x7b, 0x25, 0x38, 0xa9, 0x3a, 0xf3, 0xa7, 0xb7, 0x0b, 0xdf, 0xea, 0xee, 0xc2, 0x07, + 0x6a, 0x26, 0xb6, 0x6f, 0xc0, 0x60, 0x63, 0x27, 0x6a, 0xc6, 0xad, 0x02, 0x3b, 0xfe, 0xe3, 0xc6, + 0xba, 0x4a, 0x76, 0x23, 0xf6, 0x92, 0x9d, 0x58, 0x66, 0xf6, 0xe7, 0x2d, 0x98, 0x58, 0x5b, 0xaa, + 0x37, 0x82, 0xe6, 0x5d, 0x12, 0x2f, 0x70, 0x83, 0x06, 0x16, 0x1b, 0xbe, 0x75, 0xc8, 0x8d, 0x3c, + 0x4b, 0x45, 0x38, 0x03, 0x95, 0xcd, 0x20, 0x8a, 0xd3, 0x97, 0x02, 0x97, 0x83, 0x28, 0xc6, 0x0c, + 0x63, 0xff, 0x99, 0x05, 0x03, 0xec, 0xa1, 0xb6, 0xbc, 0x47, 0xfe, 0x8a, 0x7c, 0x17, 0x7a, 0x01, + 0x06, 0xc9, 0xfa, 0x3a, 0x69, 0xc6, 0x62, 0x7c, 0x65, 0x80, 0xcd, 0xe0, 0x32, 0x83, 0xd2, 0x1d, + 0x8d, 0x55, 0xc6, 0xff, 0x62, 0x41, 0x8c, 0x3e, 0x03, 0xd5, 0xd8, 0xdb, 0x22, 0x0b, 0xae, 0x2b, + 0xac, 0xf0, 0xfd, 0xf9, 0x7c, 0xa9, 0x1d, 0x76, 0x4d, 0x32, 0xc1, 0x09, 0x3f, 0xfb, 0x4b, 0x25, + 0x80, 0x24, 0x7c, 0x2e, 0xef, 0x33, 0x17, 0xbb, 0xde, 0x32, 0x7c, 0x32, 0xe3, 0x2d, 0x43, 0x94, + 0x30, 0xcc, 0x78, 0xc9, 0x50, 0x75, 0x55, 0xb9, 0x50, 0x57, 0x55, 0xfa, 0xe9, 0xaa, 0x25, 0x98, + 0x4a, 0xc2, 0xff, 0xcc, 0x38, 0x6a, 0x96, 0x6f, 0x78, 0x2d, 0x8d, 0xc4, 0xdd, 0xf4, 0xf6, 0x97, + 0x2c, 0x10, 0x5e, 0xc2, 0x05, 0x26, 0xb4, 0x2b, 0xdf, 0x1d, 0x33, 0x52, 0x0b, 0x3e, 0x5d, 0xc4, + 0x81, 0x5a, 0x24, 0x14, 0x54, 0x72, 0xdf, 0x48, 0x23, 0x68, 0x70, 0xb5, 0x7f, 0xdb, 0x82, 0x11, + 0x8e, 0xbe, 0xc6, 0x0e, 0xa2, 0xf9, 0xed, 0xea, 0x2b, 0x99, 0x35, 0x7b, 0x92, 0x8b, 0x32, 0x56, + 0x49, 0x8d, 0xf5, 0x27, 0xb9, 0x24, 0x02, 0x27, 0x34, 0xe8, 0x29, 0x18, 0x8a, 0x3a, 0x77, 0x18, + 0x79, 0xca, 0x65, 0xb8, 0xc1, 0xc1, 0x58, 0xe2, 0xed, 0x7f, 0x5a, 0x82, 0xc9, 0xb4, 0xc7, 0x38, + 0xc2, 0x30, 0xc8, 0x05, 0x48, 0xfa, 0x4c, 0x73, 0x90, 0x01, 0x54, 0xf3, 0x38, 0x07, 0xfe, 0xb0, + 0x3c, 0x13, 0x41, 0x82, 0x13, 0x5a, 0x87, 0x11, 0x37, 0xb8, 0xe7, 0xdf, 0x73, 0x42, 0x77, 0xa1, + 0xbe, 0x2a, 0x46, 0x22, 0xc7, 0xc7, 0xaf, 0x96, 0x14, 0xd0, 0xfd, 0xd9, 0x99, 0x41, 0x2e, 0x41, + 0x61, 0x9d, 0x31, 0x7a, 0x93, 0x65, 0x42, 0x59, 0xf7, 0x36, 0xae, 0x39, 0xed, 0x62, 0xde, 0x2c, + 0x4b, 0x92, 0x5c, 0xab, 0x63, 0x4c, 0x24, 0x4e, 0xe1, 0x08, 0x9c, 0xb0, 0xb4, 0x7f, 0xf5, 0x24, + 0x18, 0x73, 0xc1, 0xc8, 0x38, 0x6d, 0x3d, 0xf0, 0x8c, 0xd3, 0x6f, 0xc0, 0x30, 0xd9, 0x6a, 0xc7, + 0x3b, 0x35, 0x2f, 0x2c, 0xf6, 0x7e, 0xc0, 0xb2, 0xa0, 0xee, 0xe6, 0x2e, 0x31, 0x58, 0x71, 0xec, + 0x91, 0x3f, 0xbc, 0xfc, 0x81, 0xc8, 0x1f, 0x5e, 0xf9, 0x4b, 0xc9, 0x1f, 0xfe, 0x1a, 0x0c, 0x6d, + 0x78, 0x31, 0x26, 0xed, 0x40, 0xec, 0xc6, 0x39, 0x93, 0xe7, 0x12, 0x27, 0xee, 0xce, 0x2c, 0x2b, + 0x10, 0x58, 0xb2, 0x43, 0x6b, 0x6a, 0x51, 0x0d, 0x16, 0xd1, 0x41, 0xbb, 0x0d, 0xe4, 0x99, 0xcb, + 0x4a, 0xe4, 0x0b, 0x1f, 0x7a, 0xff, 0xf9, 0xc2, 0x55, 0x96, 0xef, 0xe1, 0x07, 0x95, 0xe5, 0xdb, + 0xc8, 0x96, 0x5e, 0x3d, 0x8a, 0x6c, 0xe9, 0x5f, 0xb2, 0xe0, 0x64, 0x3b, 0xeb, 0xad, 0x01, 0x91, + 0xaf, 0xfb, 0xe7, 0x0e, 0xf1, 0xfa, 0x82, 0x51, 0x35, 0xcb, 0xef, 0x91, 0x49, 0x86, 0xb3, 0x2b, + 0x96, 0x69, 0xd7, 0x47, 0xde, 0x7f, 0xda, 0xf5, 0xa3, 0x4e, 0xec, 0x9d, 0x24, 0x61, 0x1f, 0x3b, + 0x92, 0x24, 0xec, 0xe3, 0x0f, 0x30, 0x09, 0xbb, 0x96, 0x3e, 0x7d, 0xe2, 0xc1, 0xa6, 0x4f, 0xdf, + 0x34, 0xf7, 0x25, 0x9e, 0xad, 0xfb, 0x85, 0xc2, 0xfb, 0x92, 0x51, 0xc3, 0xc1, 0x3b, 0x13, 0x4f, + 0x24, 0x3f, 0xf5, 0x3e, 0x13, 0xc9, 0x1b, 0xe9, 0xd8, 0xd1, 0x51, 0xa4, 0x63, 0x7f, 0x5b, 0xdf, + 0x41, 0x4f, 0x14, 0xa9, 0x41, 0x6d, 0x94, 0xdd, 0x35, 0x64, 0xed, 0xa1, 0xdd, 0x09, 0xdf, 0xa7, + 0x8f, 0x3b, 0xe1, 0xfb, 0xc9, 0x23, 0x4c, 0xf8, 0x7e, 0xea, 0x58, 0x13, 0xbe, 0x3f, 0xf4, 0x01, + 0x49, 0xf8, 0x3e, 0x73, 0x5c, 0x09, 0xdf, 0x1f, 0x7e, 0xb0, 0x09, 0xdf, 0xdf, 0x86, 0x6a, 0x5b, + 0xc6, 0x5d, 0xce, 0xcc, 0x16, 0x19, 0xba, 0xcc, 0x30, 0x4d, 0x3e, 0x74, 0x0a, 0x85, 0x13, 0xa6, + 0xb4, 0x86, 0x24, 0x01, 0xfc, 0x87, 0x8b, 0xd4, 0x90, 0x69, 0xf7, 0x38, 0x20, 0xed, 0xfb, 0x17, + 0x4a, 0x70, 0xfa, 0xe0, 0xd5, 0x91, 0x18, 0x4d, 0xea, 0x89, 0x2d, 0x3b, 0x65, 0x34, 0x61, 0x9a, + 0xa7, 0x46, 0x55, 0x38, 0x9c, 0xfd, 0x12, 0x4c, 0x29, 0x3f, 0xaf, 0x96, 0xd7, 0xdc, 0xd1, 0x9e, + 0xa1, 0x52, 0xf1, 0x09, 0x8d, 0x34, 0x01, 0xee, 0x2e, 0x83, 0x16, 0x60, 0xc2, 0x00, 0xae, 0xd6, + 0xc4, 0xf9, 0x45, 0x59, 0x69, 0x1a, 0x26, 0x1a, 0xa7, 0xe9, 0xed, 0xaf, 0x5b, 0xf0, 0x50, 0x8f, + 0x0c, 0xaf, 0x85, 0x63, 0xb4, 0xdb, 0x30, 0xd1, 0x36, 0x8b, 0x16, 0x4e, 0xf9, 0x60, 0x64, 0x94, + 0x55, 0xad, 0x4e, 0x21, 0x70, 0x9a, 0xfd, 0xe2, 0xd9, 0xef, 0xff, 0xe8, 0xf4, 0x87, 0x7e, 0xf0, + 0xa3, 0xd3, 0x1f, 0xfa, 0xe1, 0x8f, 0x4e, 0x7f, 0xe8, 0x97, 0xf6, 0x4e, 0x5b, 0xdf, 0xdf, 0x3b, + 0x6d, 0xfd, 0x60, 0xef, 0xb4, 0xf5, 0xc3, 0xbd, 0xd3, 0xd6, 0x9f, 0xef, 0x9d, 0xb6, 0xbe, 0xf4, + 0xe3, 0xd3, 0x1f, 0x7a, 0xbd, 0xb4, 0x7d, 0xe1, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x1c, + 0xd0, 0x1f, 0x95, 0xd0, 0x00, 0x00, } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.generated.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.generated.go index 9bd5aa8456..e289f199bb 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.generated.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.generated.go @@ -11488,7 +11488,7 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { _, _, _ = yysep2, yyq2, yy2arr2 const yyr2 bool = false yyq2[0] = x.Medium != "" - yyq2[1] = true + yyq2[1] = x.SizeLimit != nil var yynn2 int if yyr2 || yy2arr2 { r.EncodeArrayStart(2) @@ -11520,15 +11520,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { if yyr2 || yy2arr2 { z.EncSendContainerState(codecSelfer_containerArrayElem1234) if yyq2[1] { - yy7 := &x.SizeLimit - yym8 := z.EncBinary() - _ = yym8 - if false { - } else if z.HasExtensions() && z.EncExt(yy7) { - } else if !yym8 && z.IsJSONHandle() { - z.EncJSONMarshal(yy7) + if x.SizeLimit == nil { + r.EncodeNil() } else { - z.EncFallback(yy7) + yym7 := z.EncBinary() + _ = yym7 + if false { + } else if z.HasExtensions() && z.EncExt(x.SizeLimit) { + } else if !yym7 && z.IsJSONHandle() { + z.EncJSONMarshal(x.SizeLimit) + } else { + z.EncFallback(x.SizeLimit) + } } } else { r.EncodeNil() @@ -11538,15 +11541,18 @@ func (x *EmptyDirVolumeSource) CodecEncodeSelf(e *codec1978.Encoder) { z.EncSendContainerState(codecSelfer_containerMapKey1234) r.EncodeString(codecSelferC_UTF81234, string("sizeLimit")) z.EncSendContainerState(codecSelfer_containerMapValue1234) - yy9 := &x.SizeLimit - yym10 := z.EncBinary() - _ = yym10 - if false { - } else if z.HasExtensions() && z.EncExt(yy9) { - } else if !yym10 && z.IsJSONHandle() { - z.EncJSONMarshal(yy9) + if x.SizeLimit == nil { + r.EncodeNil() } else { - z.EncFallback(yy9) + yym8 := z.EncBinary() + _ = yym8 + if false { + } else if z.HasExtensions() && z.EncExt(x.SizeLimit) { + } else if !yym8 && z.IsJSONHandle() { + z.EncJSONMarshal(x.SizeLimit) + } else { + z.EncFallback(x.SizeLimit) + } } } } @@ -11620,17 +11626,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromMap(l int, d *codec1978.Decode } case "sizeLimit": if r.TryDecodeAsNil() { - x.SizeLimit = pkg3_resource.Quantity{} + if x.SizeLimit != nil { + x.SizeLimit = nil + } } else { - yyv5 := &x.SizeLimit + if x.SizeLimit == nil { + x.SizeLimit = new(pkg3_resource.Quantity) + } yym6 := z.DecBinary() _ = yym6 if false { - } else if z.HasExtensions() && z.DecExt(yyv5) { + } else if z.HasExtensions() && z.DecExt(x.SizeLimit) { } else if !yym6 && z.IsJSONHandle() { - z.DecJSONUnmarshal(yyv5) + z.DecJSONUnmarshal(x.SizeLimit) } else { - z.DecFallback(yyv5, false) + z.DecFallback(x.SizeLimit, false) } } default: @@ -11676,17 +11686,21 @@ func (x *EmptyDirVolumeSource) codecDecodeSelfFromArray(l int, d *codec1978.Deco } z.DecSendContainerState(codecSelfer_containerArrayElem1234) if r.TryDecodeAsNil() { - x.SizeLimit = pkg3_resource.Quantity{} + if x.SizeLimit != nil { + x.SizeLimit = nil + } } else { - yyv9 := &x.SizeLimit + if x.SizeLimit == nil { + x.SizeLimit = new(pkg3_resource.Quantity) + } yym10 := z.DecBinary() _ = yym10 if false { - } else if z.HasExtensions() && z.DecExt(yyv9) { + } else if z.HasExtensions() && z.DecExt(x.SizeLimit) { } else if !yym10 && z.IsJSONHandle() { - z.DecJSONUnmarshal(yyv9) + z.DecJSONUnmarshal(x.SizeLimit) } else { - z.DecFallback(yyv9, false) + z.DecFallback(x.SizeLimit, false) } } for { diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.go index cdb0088c46..940f0e3254 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/types.go @@ -700,7 +700,7 @@ type EmptyDirVolumeSource struct { // The default is nil which means that the limit is undefined. // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir // +optional - SizeLimit resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"` + SizeLimit *resource.Quantity `json:"sizeLimit,omitempty" protobuf:"bytes,2,opt,name=sizeLimit"` } // Represents a Glusterfs mount that lasts the lifetime of a pod. diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.conversion.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.conversion.go index 1832c432bc..e0258772ff 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.conversion.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.conversion.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + resource "k8s.io/apimachinery/pkg/api/resource" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" @@ -1240,7 +1241,7 @@ func Convert_api_DownwardAPIVolumeSource_To_v1_DownwardAPIVolumeSource(in *api.D func autoConvert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVolumeSource, out *api.EmptyDirVolumeSource, s conversion.Scope) error { out.Medium = api.StorageMedium(in.Medium) - out.SizeLimit = in.SizeLimit + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) return nil } @@ -1251,7 +1252,7 @@ func Convert_v1_EmptyDirVolumeSource_To_api_EmptyDirVolumeSource(in *EmptyDirVol func autoConvert_api_EmptyDirVolumeSource_To_v1_EmptyDirVolumeSource(in *api.EmptyDirVolumeSource, out *EmptyDirVolumeSource, s conversion.Scope) error { out.Medium = StorageMedium(in.Medium) - out.SizeLimit = in.SizeLimit + out.SizeLimit = (*resource.Quantity)(unsafe.Pointer(in.SizeLimit)) return nil } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.deepcopy.go index b909d9b332..18cd4311e8 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/v1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + resource "k8s.io/apimachinery/pkg/api/resource" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" @@ -858,7 +859,11 @@ func DeepCopy_v1_EmptyDirVolumeSource(in interface{}, out interface{}, c *conver in := in.(*EmptyDirVolumeSource) out := out.(*EmptyDirVolumeSource) *out = *in - out.SizeLimit = in.SizeLimit.DeepCopy() + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + *out = new(resource.Quantity) + **out = (*in).DeepCopy() + } return nil } } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/zz_generated.deepcopy.go index cc111561b7..0aa95e1071 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/zz_generated.deepcopy.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/api/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package api import ( + resource "k8s.io/apimachinery/pkg/api/resource" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" fields "k8s.io/apimachinery/pkg/fields" @@ -860,7 +861,11 @@ func DeepCopy_api_EmptyDirVolumeSource(in interface{}, out interface{}, c *conve in := in.(*EmptyDirVolumeSource) out := out.(*EmptyDirVolumeSource) *out = *in - out.SizeLimit = in.SizeLimit.DeepCopy() + if in.SizeLimit != nil { + in, out := &in.SizeLimit, &out.SizeLimit + *out = new(resource.Quantity) + **out = (*in).DeepCopy() + } return nil } } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.pb.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.pb.go index 47fb3d5f19..26588f9c87 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.pb.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.pb.go @@ -3314,89 +3314,88 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 1331 bytes of a gzipped FileDescriptorProto + // 1323 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0x5b, 0x6f, 0x1b, 0x45, - 0x1b, 0xce, 0x3a, 0x4e, 0x9a, 0x6f, 0x9c, 0x26, 0xfd, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56, - 0x08, 0xb5, 0x08, 0x76, 0xa9, 0x29, 0x88, 0x0a, 0x01, 0x8a, 0xcd, 0xa1, 0x15, 0x71, 0x0f, 0xd3, - 0x50, 0x21, 0x40, 0x82, 0xc9, 0x7a, 0xea, 0x0c, 0xf1, 0x1e, 0xb4, 0x33, 0xb6, 0x48, 0xa5, 0x4a, - 0xdc, 0x70, 0x87, 0x04, 0x37, 0xfc, 0x04, 0x24, 0xfe, 0x01, 0xd7, 0x20, 0x21, 0xf5, 0xb2, 0x97, - 0xe5, 0xc6, 0xa2, 0xee, 0x1d, 0x3f, 0x21, 0x12, 0x07, 0xcd, 0x61, 0x4f, 0x5e, 0x6f, 0x1a, 0x87, - 0xb4, 0x82, 0x3b, 0x7b, 0xe6, 0x7d, 0x9f, 0xe7, 0x3d, 0x3c, 0xf3, 0xce, 0x2c, 0x78, 0x6b, 0xfb, - 0x35, 0x66, 0x51, 0xdf, 0xde, 0xee, 0x6f, 0x92, 0xd0, 0x23, 0x9c, 0x30, 0x3b, 0xd8, 0xee, 0xda, - 0x38, 0xa0, 0xcc, 0xc6, 0x7d, 0xee, 0x33, 0x07, 0xf7, 0xa8, 0xd7, 0xb5, 0x07, 0x0d, 0xdc, 0x0b, - 0xb6, 0xf0, 0x05, 0xbb, 0x4b, 0x3c, 0x12, 0x62, 0x4e, 0x3a, 0x56, 0x10, 0xfa, 0xdc, 0x87, 0xb6, - 0x02, 0xb0, 0x12, 0x00, 0x2b, 0xd8, 0xee, 0x5a, 0x02, 0xc0, 0x4a, 0x01, 0x58, 0x11, 0xc0, 0xca, - 0x8b, 0x5d, 0xca, 0xb7, 0xfa, 0x9b, 0x96, 0xe3, 0xbb, 0x76, 0xd7, 0xef, 0xfa, 0xb6, 0xc4, 0xd9, - 0xec, 0xdf, 0x96, 0xff, 0xe4, 0x1f, 0xf9, 0x4b, 0xe1, 0xaf, 0x5c, 0xd4, 0x01, 0xe2, 0x80, 0xba, - 0xd8, 0xd9, 0xa2, 0x1e, 0x09, 0x77, 0xa2, 0x10, 0xed, 0x90, 0x30, 0xbf, 0x1f, 0x3a, 0x64, 0x3c, - 0xaa, 0x3d, 0xbd, 0x98, 0xed, 0x12, 0x8e, 0xed, 0x41, 0x2e, 0x97, 0x15, 0xbb, 0xc8, 0x2b, 0xec, - 0x7b, 0x9c, 0xba, 0x79, 0x9a, 0x57, 0x1f, 0xe7, 0xc0, 0x9c, 0x2d, 0xe2, 0xe2, 0x9c, 0xdf, 0xcb, - 0x45, 0x7e, 0x7d, 0x4e, 0x7b, 0x36, 0xf5, 0x38, 0xe3, 0x61, 0xce, 0xe9, 0x85, 0xc2, 0x56, 0x4d, - 0xca, 0xe5, 0xd2, 0x7e, 0x1b, 0x9b, 0x73, 0x35, 0xbf, 0x33, 0xc0, 0x99, 0x56, 0xe8, 0x33, 0x76, - 0x8b, 0x84, 0x8c, 0xfa, 0xde, 0xb5, 0xcd, 0xcf, 0x89, 0xc3, 0x11, 0xb9, 0x4d, 0x42, 0xe2, 0x39, - 0x04, 0xae, 0x82, 0xf2, 0x36, 0xf5, 0x3a, 0x55, 0x63, 0xd5, 0x38, 0xf7, 0xbf, 0xe6, 0xe2, 0xbd, - 0x61, 0x7d, 0x66, 0x34, 0xac, 0x97, 0xdf, 0xa7, 0x5e, 0x07, 0xc9, 0x1d, 0x61, 0xe1, 0x61, 0x97, - 0x54, 0x4b, 0x59, 0x8b, 0xab, 0xd8, 0x25, 0x48, 0xee, 0xc0, 0x06, 0x00, 0x38, 0xa0, 0x9a, 0xa0, - 0x3a, 0x2b, 0xed, 0xa0, 0xb6, 0x03, 0x6b, 0xd7, 0xaf, 0xe8, 0x1d, 0x94, 0xb2, 0x32, 0x1f, 0x95, - 0xc0, 0xa9, 0xcb, 0x7e, 0x48, 0xef, 0xf8, 0x1e, 0xc7, 0xbd, 0xeb, 0x7e, 0x67, 0x4d, 0xe7, 0x41, - 0x42, 0xf8, 0x19, 0x58, 0x10, 0x5d, 0xed, 0x60, 0x8e, 0x65, 0x5c, 0x95, 0xc6, 0x4b, 0x96, 0x56, - 0x66, 0xba, 0xc8, 0x89, 0x36, 0x85, 0xb5, 0x35, 0xb8, 0x60, 0xa9, 0xe4, 0xda, 0x84, 0xe3, 0x84, - 0x3f, 0x59, 0x43, 0x31, 0x2a, 0xf4, 0x40, 0x99, 0x05, 0xc4, 0x91, 0x39, 0x55, 0x1a, 0xeb, 0xd6, - 0x94, 0xba, 0xb7, 0x0a, 0x22, 0xbf, 0x19, 0x10, 0x27, 0xa9, 0x90, 0xf8, 0x87, 0x24, 0x0f, 0x1c, - 0x80, 0x79, 0xc6, 0x31, 0xef, 0x33, 0x59, 0x9d, 0x4a, 0xe3, 0xea, 0xa1, 0x31, 0x4a, 0xd4, 0xe6, - 0x92, 0xe6, 0x9c, 0x57, 0xff, 0x91, 0x66, 0x33, 0xbf, 0x99, 0x05, 0xab, 0x05, 0x9e, 0x2d, 0xdf, - 0xeb, 0x50, 0x4e, 0x7d, 0x0f, 0x5e, 0x06, 0x65, 0xbe, 0x13, 0x10, 0x2d, 0x81, 0x8b, 0x51, 0xf8, - 0x1b, 0x3b, 0x01, 0xd9, 0x1d, 0xd6, 0x9f, 0x7d, 0x9c, 0xbf, 0xb0, 0x43, 0x12, 0x01, 0xde, 0x8a, - 0xd3, 0x54, 0x62, 0x79, 0x33, 0x1b, 0xd6, 0xee, 0xb0, 0xbe, 0xa7, 0xee, 0xad, 0x18, 0x33, 0x9b, - 0x06, 0x1c, 0x00, 0xd8, 0xc3, 0x8c, 0x6f, 0x84, 0xd8, 0x63, 0x8a, 0x93, 0xba, 0x44, 0x97, 0xf2, - 0xf9, 0xfd, 0x49, 0x43, 0x78, 0x34, 0x57, 0x74, 0x3c, 0x70, 0x3d, 0x87, 0x86, 0x26, 0x30, 0xc0, - 0xe7, 0xc0, 0x7c, 0x48, 0x30, 0xf3, 0xbd, 0x6a, 0x59, 0xe6, 0x13, 0x97, 0x19, 0xc9, 0x55, 0xa4, - 0x77, 0xe1, 0x79, 0x70, 0xc4, 0x25, 0x8c, 0xe1, 0x2e, 0xa9, 0xce, 0x49, 0xc3, 0x65, 0x6d, 0x78, - 0xa4, 0xad, 0x96, 0x51, 0xb4, 0x6f, 0xfe, 0x6e, 0x80, 0x33, 0x05, 0x15, 0x5d, 0xa7, 0x8c, 0xc3, - 0x4f, 0x72, 0xda, 0xb7, 0xf6, 0x97, 0xa0, 0xf0, 0x96, 0xca, 0x3f, 0xa6, 0xb9, 0x17, 0xa2, 0x95, - 0x94, 0xee, 0x5d, 0x30, 0x47, 0x39, 0x71, 0x45, 0x7f, 0x66, 0xcf, 0x55, 0x1a, 0x97, 0x0f, 0x4b, - 0x86, 0xcd, 0xa3, 0x9a, 0x74, 0xee, 0x8a, 0x80, 0x47, 0x8a, 0xc5, 0xfc, 0xb3, 0x54, 0x98, 0xac, - 0x38, 0x1c, 0xf0, 0x6b, 0x03, 0x2c, 0xc9, 0xbf, 0x1b, 0x38, 0xec, 0x12, 0x31, 0x95, 0x74, 0xce, - 0xd3, 0x9f, 0xc8, 0x3d, 0x66, 0x5c, 0xf3, 0xa4, 0x0e, 0x6e, 0xe9, 0x66, 0x86, 0x0b, 0x8d, 0x71, - 0xc3, 0x0b, 0xa0, 0xe2, 0x52, 0x0f, 0x91, 0xa0, 0x47, 0x1d, 0xac, 0x34, 0x3c, 0xd7, 0x5c, 0x1e, - 0x0d, 0xeb, 0x95, 0x76, 0xb2, 0x8c, 0xd2, 0x36, 0xf0, 0x15, 0x50, 0x71, 0xf1, 0x17, 0xb1, 0xcb, - 0xac, 0x74, 0x39, 0xae, 0xf9, 0x2a, 0xed, 0x64, 0x0b, 0xa5, 0xed, 0xe0, 0x6d, 0x21, 0x18, 0x1e, - 0x52, 0x87, 0x55, 0xcb, 0xb2, 0x13, 0xaf, 0x4f, 0x9d, 0x70, 0x5b, 0xfa, 0xcb, 0x89, 0x93, 0x52, - 0x9b, 0xc4, 0x44, 0x11, 0xb8, 0xf9, 0x6b, 0x19, 0x9c, 0xdd, 0x73, 0x72, 0xc0, 0x77, 0x01, 0xf4, - 0x37, 0x19, 0x09, 0x07, 0xa4, 0xf3, 0x9e, 0xba, 0x3a, 0xc4, 0x0c, 0x17, 0x5d, 0x98, 0x6d, 0x9e, - 0x14, 0x47, 0xe5, 0x5a, 0x6e, 0x17, 0x4d, 0xf0, 0x80, 0x0e, 0x38, 0x2a, 0x0e, 0x90, 0xaa, 0x30, - 0xd5, 0xd7, 0xc5, 0x74, 0xa7, 0xf3, 0xff, 0xa3, 0x61, 0xfd, 0xe8, 0x7a, 0x1a, 0x04, 0x65, 0x31, - 0xe1, 0x1a, 0x58, 0x76, 0xfa, 0x61, 0x48, 0x3c, 0x3e, 0x56, 0xf1, 0x53, 0xba, 0x02, 0xcb, 0xad, - 0xec, 0x36, 0x1a, 0xb7, 0x17, 0x10, 0x1d, 0xc2, 0x68, 0x48, 0x3a, 0x31, 0x44, 0x39, 0x0b, 0xf1, - 0x76, 0x76, 0x1b, 0x8d, 0xdb, 0xc3, 0xbb, 0x60, 0x49, 0xa3, 0xea, 0x7a, 0x57, 0xe7, 0x64, 0x0f, - 0xdf, 0x38, 0x68, 0x0f, 0xd5, 0x0c, 0x8f, 0x55, 0xda, 0xca, 0x80, 0xa3, 0x31, 0x32, 0xf8, 0x95, - 0x01, 0x80, 0x13, 0x0d, 0x4a, 0x56, 0x9d, 0x97, 0xdc, 0x37, 0x0e, 0xeb, 0x24, 0xc7, 0x23, 0x38, - 0xb9, 0x41, 0xe3, 0x25, 0x86, 0x52, 0xc4, 0xe6, 0x1f, 0x25, 0x00, 0x12, 0x11, 0xc2, 0x8b, 0x99, - 0x5b, 0x64, 0x75, 0xec, 0x16, 0x39, 0xa6, 0x2d, 0xe5, 0x0b, 0x2f, 0x75, 0x63, 0x74, 0xc1, 0xbc, - 0x2f, 0x4f, 0xab, 0xd6, 0x4b, 0x6b, 0xea, 0x3c, 0xe2, 0xfb, 0x3d, 0x86, 0x6f, 0x02, 0x31, 0xa2, - 0xf5, 0x10, 0xd0, 0xf0, 0xf0, 0x53, 0x50, 0x0e, 0xfc, 0x4e, 0x74, 0xff, 0xae, 0x4d, 0x4d, 0x73, - 0xdd, 0xef, 0xb0, 0x0c, 0xc9, 0x82, 0xc8, 0x4e, 0xac, 0x22, 0x09, 0x0c, 0x7d, 0xb0, 0x10, 0xbd, - 0x60, 0xa5, 0xa2, 0x2a, 0x8d, 0x77, 0xa6, 0x26, 0x41, 0x1a, 0x20, 0x43, 0xb4, 0x28, 0x66, 0x79, - 0xb4, 0x83, 0x62, 0x12, 0xf3, 0xaf, 0x12, 0x58, 0x4c, 0x0b, 0xe8, 0xdf, 0xd1, 0x01, 0xa5, 0xe5, - 0x27, 0xdc, 0x01, 0x45, 0xf2, 0x14, 0x3a, 0xa0, 0x88, 0x8a, 0x3a, 0xf0, 0x7d, 0x09, 0xc0, 0xbc, - 0xfc, 0x20, 0x07, 0xf3, 0x5c, 0xde, 0x29, 0x4f, 0xe4, 0x32, 0x8b, 0xdf, 0x20, 0xfa, 0xde, 0xd2, - 0x5c, 0xe2, 0x11, 0xae, 0xa6, 0xfe, 0xd5, 0xe4, 0xb1, 0x1e, 0x1f, 0xe1, 0x76, 0xbc, 0x83, 0x52, - 0x56, 0x90, 0x80, 0x8a, 0xf2, 0xbe, 0x85, 0x7b, 0xfd, 0xe8, 0x41, 0xb5, 0xe7, 0x7b, 0xc3, 0x8a, - 0x92, 0xb7, 0x6e, 0xf4, 0xb1, 0xc7, 0x29, 0xdf, 0x49, 0x6e, 0xbb, 0x8d, 0x04, 0x0a, 0xa5, 0x71, - 0xcd, 0x1f, 0xc6, 0xeb, 0xa4, 0xf4, 0xfa, 0xdf, 0xa9, 0xd3, 0x16, 0x58, 0xd4, 0x43, 0xf8, 0x9f, - 0x14, 0xea, 0x84, 0x66, 0x59, 0x6c, 0xa5, 0xb0, 0x50, 0x06, 0xd9, 0xfc, 0xd9, 0x00, 0xc7, 0xc6, - 0x47, 0xcd, 0x58, 0xc8, 0xc6, 0xbe, 0x42, 0xbe, 0x03, 0xa0, 0x4a, 0x78, 0x6d, 0x40, 0x42, 0xdc, - 0x25, 0x2a, 0xf0, 0xd2, 0x81, 0x02, 0x8f, 0x9f, 0xcd, 0x1b, 0x39, 0x44, 0x34, 0x81, 0xc5, 0xfc, - 0x25, 0x9b, 0x84, 0xea, 0xf6, 0x41, 0x92, 0xb8, 0x0b, 0x8e, 0xeb, 0xea, 0x1c, 0x42, 0x16, 0x67, - 0x34, 0xd9, 0xf1, 0x56, 0x1e, 0x12, 0x4d, 0xe2, 0x31, 0x7f, 0x2c, 0x81, 0x13, 0x93, 0x46, 0x32, - 0x6c, 0xeb, 0x4f, 0x62, 0x95, 0xc5, 0xa5, 0xf4, 0x27, 0xf1, 0xee, 0xb0, 0x7e, 0x7e, 0xcf, 0x6f, - 0x9c, 0x08, 0x30, 0xf5, 0xfd, 0xfc, 0x21, 0xa8, 0x66, 0xaa, 0xf8, 0x01, 0xa7, 0x3d, 0x7a, 0x47, - 0xbd, 0xc4, 0xd4, 0x23, 0xf4, 0x99, 0xd1, 0xb0, 0x5e, 0xdd, 0x28, 0xb0, 0x41, 0x85, 0xde, 0xe2, - 0xc3, 0x69, 0x82, 0x0a, 0x0e, 0x26, 0xdf, 0x93, 0x53, 0x28, 0xe0, 0xa7, 0x7c, 0xe5, 0x94, 0x0a, - 0x0e, 0xb9, 0x72, 0x1f, 0x83, 0xd3, 0xd9, 0xc6, 0xe5, 0x4b, 0x77, 0x76, 0x34, 0xac, 0x9f, 0x6e, - 0x15, 0x19, 0xa1, 0x62, 0xff, 0x22, 0xf5, 0xcd, 0x3e, 0x1d, 0xf5, 0x35, 0xad, 0x7b, 0x0f, 0x6b, - 0x33, 0xf7, 0x1f, 0xd6, 0x66, 0x1e, 0x3c, 0xac, 0xcd, 0x7c, 0x39, 0xaa, 0x19, 0xf7, 0x46, 0x35, - 0xe3, 0xfe, 0xa8, 0x66, 0x3c, 0x18, 0xd5, 0x8c, 0xdf, 0x46, 0x35, 0xe3, 0xdb, 0x47, 0xb5, 0x99, - 0x8f, 0x16, 0xa2, 0x61, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xa9, 0x91, 0xe9, 0xfe, - 0x13, 0x00, 0x00, + 0x14, 0xce, 0x3a, 0x4e, 0x1a, 0xc6, 0x69, 0x52, 0xa6, 0x55, 0xeb, 0xa6, 0xd4, 0x8e, 0x56, 0x08, + 0xb5, 0x08, 0x76, 0xa9, 0x29, 0x08, 0x84, 0x00, 0xc5, 0xe6, 0xd2, 0x8a, 0xb8, 0x97, 0x69, 0xa8, + 0x10, 0x20, 0xc1, 0x64, 0x3d, 0x75, 0x86, 0x78, 0x2f, 0xda, 0x19, 0x5b, 0xa4, 0x52, 0x25, 0x5e, + 0x78, 0x43, 0x82, 0x17, 0x7e, 0x02, 0x12, 0xff, 0x80, 0x67, 0x90, 0x90, 0xfa, 0xd8, 0xc7, 0xf2, + 0x62, 0x51, 0xf7, 0x8d, 0x9f, 0x50, 0x89, 0x8b, 0xe6, 0xb2, 0x37, 0xaf, 0xd7, 0xad, 0x43, 0x5a, + 0xc1, 0x9b, 0x3d, 0x73, 0xce, 0xf7, 0x9d, 0xcb, 0x37, 0x67, 0x66, 0xc1, 0xdb, 0xbb, 0xaf, 0x31, + 0x8b, 0xfa, 0xf6, 0x6e, 0x7f, 0x9b, 0x84, 0x1e, 0xe1, 0x84, 0xd9, 0xc1, 0x6e, 0xd7, 0xc6, 0x01, + 0x65, 0x36, 0xee, 0x73, 0x9f, 0x39, 0xb8, 0x47, 0xbd, 0xae, 0x3d, 0x68, 0xe0, 0x5e, 0xb0, 0x83, + 0xcf, 0xd9, 0x5d, 0xe2, 0x91, 0x10, 0x73, 0xd2, 0xb1, 0x82, 0xd0, 0xe7, 0x3e, 0xb4, 0x15, 0x80, + 0x95, 0x00, 0x58, 0xc1, 0x6e, 0xd7, 0x12, 0x00, 0x56, 0x0a, 0xc0, 0x8a, 0x00, 0xd6, 0x5e, 0xec, + 0x52, 0xbe, 0xd3, 0xdf, 0xb6, 0x1c, 0xdf, 0xb5, 0xbb, 0x7e, 0xd7, 0xb7, 0x25, 0xce, 0x76, 0xff, + 0x86, 0xfc, 0x27, 0xff, 0xc8, 0x5f, 0x0a, 0x7f, 0xed, 0xbc, 0x0e, 0x10, 0x07, 0xd4, 0xc5, 0xce, + 0x0e, 0xf5, 0x48, 0xb8, 0x17, 0x85, 0x68, 0x87, 0x84, 0xf9, 0xfd, 0xd0, 0x21, 0xe3, 0x51, 0x4d, + 0xf5, 0x62, 0xb6, 0x4b, 0x38, 0xb6, 0x07, 0xb9, 0x5c, 0xd6, 0xec, 0x22, 0xaf, 0xb0, 0xef, 0x71, + 0xea, 0xe6, 0x69, 0x5e, 0x7d, 0x98, 0x03, 0x73, 0x76, 0x88, 0x8b, 0x73, 0x7e, 0x2f, 0x17, 0xf9, + 0xf5, 0x39, 0xed, 0xd9, 0xd4, 0xe3, 0x8c, 0x87, 0x39, 0xa7, 0x17, 0x0a, 0x5b, 0x35, 0x21, 0x17, + 0xf3, 0x7b, 0x03, 0x9c, 0x6a, 0x85, 0x3e, 0x63, 0xd7, 0x49, 0xc8, 0xa8, 0xef, 0x5d, 0xde, 0xfe, + 0x82, 0x38, 0x1c, 0x91, 0x1b, 0x24, 0x24, 0x9e, 0x43, 0xe0, 0x3a, 0x28, 0xef, 0x52, 0xaf, 0x53, + 0x35, 0xd6, 0x8d, 0x33, 0x4f, 0x35, 0x97, 0x6f, 0x0f, 0xeb, 0x73, 0xa3, 0x61, 0xbd, 0xfc, 0x01, + 0xf5, 0x3a, 0x48, 0xee, 0x08, 0x0b, 0x0f, 0xbb, 0xa4, 0x5a, 0xca, 0x5a, 0x5c, 0xc2, 0x2e, 0x41, + 0x72, 0x07, 0x36, 0x00, 0xc0, 0x01, 0xd5, 0x04, 0xd5, 0x79, 0x69, 0x07, 0xb5, 0x1d, 0xd8, 0xb8, + 0x72, 0x51, 0xef, 0xa0, 0x94, 0x95, 0x79, 0xbf, 0x04, 0x4e, 0x5c, 0xf0, 0x43, 0x7a, 0xd3, 0xf7, + 0x38, 0xee, 0x5d, 0xf1, 0x3b, 0x1b, 0x5a, 0x24, 0x24, 0x84, 0x9f, 0x83, 0x25, 0xd1, 0x9a, 0x0e, + 0xe6, 0x58, 0xc6, 0x55, 0x69, 0xbc, 0x64, 0x69, 0x79, 0xa5, 0x2b, 0x95, 0x08, 0x4c, 0x58, 0x5b, + 0x83, 0x73, 0x96, 0x4a, 0xae, 0x4d, 0x38, 0x4e, 0xf8, 0x93, 0x35, 0x14, 0xa3, 0x42, 0x0f, 0x94, + 0x59, 0x40, 0x1c, 0x99, 0x53, 0xa5, 0xb1, 0x69, 0xcd, 0x28, 0x5e, 0xab, 0x20, 0xf2, 0x6b, 0x01, + 0x71, 0x92, 0x0a, 0x89, 0x7f, 0x48, 0xf2, 0xc0, 0x01, 0x58, 0x64, 0x1c, 0xf3, 0x3e, 0x93, 0xd5, + 0xa9, 0x34, 0x2e, 0x1d, 0x18, 0xa3, 0x44, 0x6d, 0xae, 0x68, 0xce, 0x45, 0xf5, 0x1f, 0x69, 0x36, + 0xf3, 0xdb, 0x79, 0xb0, 0x5e, 0xe0, 0xd9, 0xf2, 0xbd, 0x0e, 0xe5, 0xd4, 0xf7, 0xe0, 0x05, 0x50, + 0xe6, 0x7b, 0x01, 0xd1, 0x12, 0x38, 0x1f, 0x85, 0xbf, 0xb5, 0x17, 0x90, 0x07, 0xc3, 0xfa, 0xb3, + 0x0f, 0xf3, 0x17, 0x76, 0x48, 0x22, 0xc0, 0xeb, 0x71, 0x9a, 0x4a, 0x2c, 0x6f, 0x65, 0xc3, 0x7a, + 0x30, 0xac, 0x4f, 0x15, 0xaf, 0x15, 0x63, 0x66, 0xd3, 0x80, 0x03, 0x00, 0x7b, 0x98, 0xf1, 0xad, + 0x10, 0x7b, 0x4c, 0x71, 0x52, 0x97, 0xe8, 0x52, 0x3e, 0xff, 0x68, 0xd2, 0x10, 0x1e, 0xcd, 0x35, + 0x1d, 0x0f, 0xdc, 0xcc, 0xa1, 0xa1, 0x09, 0x0c, 0xf0, 0x39, 0xb0, 0x18, 0x12, 0xcc, 0x7c, 0xaf, + 0x5a, 0x96, 0xf9, 0xc4, 0x65, 0x46, 0x72, 0x15, 0xe9, 0x5d, 0x78, 0x16, 0x1c, 0x72, 0x09, 0x63, + 0xb8, 0x4b, 0xaa, 0x0b, 0xd2, 0x70, 0x55, 0x1b, 0x1e, 0x6a, 0xab, 0x65, 0x14, 0xed, 0x9b, 0x7f, + 0x18, 0xe0, 0x54, 0x41, 0x45, 0x37, 0x29, 0xe3, 0xf0, 0xd3, 0x9c, 0xf6, 0xad, 0x47, 0x4b, 0x50, + 0x78, 0x4b, 0xe5, 0x1f, 0xd1, 0xdc, 0x4b, 0xd1, 0x4a, 0x4a, 0xf7, 0x2e, 0x58, 0xa0, 0x9c, 0xb8, + 0xa2, 0x3f, 0xf3, 0x67, 0x2a, 0x8d, 0x0b, 0x07, 0x25, 0xc3, 0xe6, 0x61, 0x4d, 0xba, 0x70, 0x51, + 0xc0, 0x23, 0xc5, 0x62, 0xfe, 0x55, 0x2a, 0x4c, 0x56, 0x1c, 0x0e, 0xf8, 0x8d, 0x01, 0x56, 0xe4, + 0xdf, 0x2d, 0x1c, 0x76, 0x89, 0x98, 0x4a, 0x3a, 0xe7, 0xd9, 0x4f, 0xe4, 0x94, 0x19, 0xd7, 0x3c, + 0xae, 0x83, 0x5b, 0xb9, 0x96, 0xe1, 0x42, 0x63, 0xdc, 0xf0, 0x1c, 0xa8, 0xb8, 0xd4, 0x43, 0x24, + 0xe8, 0x51, 0x07, 0x2b, 0x0d, 0x2f, 0x34, 0x57, 0x47, 0xc3, 0x7a, 0xa5, 0x9d, 0x2c, 0xa3, 0xb4, + 0x0d, 0x7c, 0x05, 0x54, 0x5c, 0xfc, 0x65, 0xec, 0x32, 0x2f, 0x5d, 0x8e, 0x6a, 0xbe, 0x4a, 0x3b, + 0xd9, 0x42, 0x69, 0x3b, 0x78, 0x43, 0x08, 0x86, 0x87, 0xd4, 0x61, 0xd5, 0xb2, 0xec, 0xc4, 0x1b, + 0x33, 0x27, 0xdc, 0x96, 0xfe, 0x72, 0xe2, 0xa4, 0xd4, 0x26, 0x31, 0x51, 0x04, 0x6e, 0xfe, 0x56, + 0x06, 0xa7, 0xa7, 0x4e, 0x0e, 0xf8, 0x1e, 0x80, 0xfe, 0x36, 0x23, 0xe1, 0x80, 0x74, 0xde, 0x57, + 0x57, 0x87, 0x98, 0xe1, 0xa2, 0x0b, 0xf3, 0xcd, 0xe3, 0xe2, 0xa8, 0x5c, 0xce, 0xed, 0xa2, 0x09, + 0x1e, 0xd0, 0x01, 0x87, 0xc5, 0x01, 0x52, 0x15, 0xa6, 0xfa, 0xba, 0x98, 0xed, 0x74, 0x3e, 0x3d, + 0x1a, 0xd6, 0x0f, 0x6f, 0xa6, 0x41, 0x50, 0x16, 0x13, 0x6e, 0x80, 0x55, 0xa7, 0x1f, 0x86, 0xc4, + 0xe3, 0x63, 0x15, 0x3f, 0xa1, 0x2b, 0xb0, 0xda, 0xca, 0x6e, 0xa3, 0x71, 0x7b, 0x01, 0xd1, 0x21, + 0x8c, 0x86, 0xa4, 0x13, 0x43, 0x94, 0xb3, 0x10, 0xef, 0x64, 0xb7, 0xd1, 0xb8, 0x3d, 0xbc, 0x05, + 0x56, 0x34, 0xaa, 0xae, 0x77, 0x75, 0x41, 0xf6, 0xf0, 0xcd, 0xfd, 0xf6, 0x50, 0xcd, 0xf0, 0x58, + 0xa5, 0xad, 0x0c, 0x38, 0x1a, 0x23, 0x83, 0x5f, 0x1b, 0x00, 0x38, 0xd1, 0xa0, 0x64, 0xd5, 0x45, + 0xc9, 0x7d, 0xf5, 0xa0, 0x4e, 0x72, 0x3c, 0x82, 0x93, 0x1b, 0x34, 0x5e, 0x62, 0x28, 0x45, 0x6c, + 0xfe, 0x59, 0x02, 0x20, 0x11, 0x21, 0x3c, 0x9f, 0xb9, 0x45, 0xd6, 0xc7, 0x6e, 0x91, 0x23, 0xda, + 0x52, 0x3e, 0xd3, 0x52, 0x37, 0x46, 0x17, 0x2c, 0xfa, 0xf2, 0xb4, 0x6a, 0xbd, 0xb4, 0x66, 0xce, + 0x23, 0xbe, 0xdf, 0x63, 0xf8, 0x26, 0x10, 0x23, 0x5a, 0x0f, 0x01, 0x0d, 0x0f, 0x3f, 0x03, 0xe5, + 0xc0, 0xef, 0x44, 0xf7, 0xef, 0xc6, 0xcc, 0x34, 0x57, 0xfc, 0x0e, 0xcb, 0x90, 0x2c, 0x89, 0xec, + 0xc4, 0x2a, 0x92, 0xc0, 0xd0, 0x07, 0x4b, 0xd1, 0x33, 0x54, 0x2a, 0xaa, 0xd2, 0x78, 0x77, 0x66, + 0x12, 0xa4, 0x01, 0x32, 0x44, 0xcb, 0x62, 0x96, 0x47, 0x3b, 0x28, 0x26, 0x31, 0xff, 0x2e, 0x81, + 0xe5, 0xb4, 0x80, 0xfe, 0x1b, 0x1d, 0x50, 0x5a, 0x7e, 0xcc, 0x1d, 0x50, 0x24, 0x4f, 0xa0, 0x03, + 0x8a, 0xa8, 0xa8, 0x03, 0x3f, 0x94, 0x00, 0xcc, 0xcb, 0x0f, 0x72, 0xb0, 0xc8, 0xe5, 0x9d, 0xf2, + 0x58, 0x2e, 0xb3, 0xf8, 0x0d, 0xa2, 0xef, 0x2d, 0xcd, 0x25, 0x1e, 0xe1, 0x6a, 0xea, 0x5f, 0x4a, + 0x1e, 0xeb, 0xf1, 0x11, 0x6e, 0xc7, 0x3b, 0x28, 0x65, 0x05, 0x09, 0xa8, 0x28, 0xef, 0xeb, 0xb8, + 0xd7, 0x8f, 0x1e, 0x54, 0x53, 0xdf, 0x1b, 0x56, 0x94, 0xbc, 0x75, 0xb5, 0x8f, 0x3d, 0x4e, 0xf9, + 0x5e, 0x72, 0xdb, 0x6d, 0x25, 0x50, 0x28, 0x8d, 0x6b, 0xfe, 0x38, 0x5e, 0x27, 0xa5, 0xd7, 0xff, + 0x4f, 0x9d, 0x76, 0xc0, 0xb2, 0x1e, 0xc2, 0xff, 0xa6, 0x50, 0xc7, 0x34, 0xcb, 0x72, 0x2b, 0x85, + 0x85, 0x32, 0xc8, 0xe6, 0x2f, 0x06, 0x38, 0x32, 0x3e, 0x6a, 0xc6, 0x42, 0x36, 0x1e, 0x29, 0xe4, + 0x9b, 0x00, 0xaa, 0x84, 0x37, 0x06, 0x24, 0xc4, 0x5d, 0xa2, 0x02, 0x2f, 0xed, 0x2b, 0xf0, 0xf8, + 0xd9, 0xbc, 0x95, 0x43, 0x44, 0x13, 0x58, 0xcc, 0x5f, 0xb3, 0x49, 0xa8, 0x6e, 0xef, 0x27, 0x89, + 0x5b, 0xe0, 0xa8, 0xae, 0xce, 0x01, 0x64, 0x71, 0x4a, 0x93, 0x1d, 0x6d, 0xe5, 0x21, 0xd1, 0x24, + 0x1e, 0xf3, 0xa7, 0x12, 0x38, 0x36, 0x69, 0x24, 0xc3, 0xb6, 0xfe, 0x24, 0x56, 0x59, 0xbc, 0x9e, + 0xfe, 0x24, 0x7e, 0x30, 0xac, 0x9f, 0x9d, 0xfa, 0x8d, 0x13, 0x01, 0xa6, 0xbe, 0x9f, 0x3f, 0x02, + 0xd5, 0x4c, 0x15, 0x3f, 0xe4, 0xb4, 0x47, 0x6f, 0xaa, 0x97, 0x98, 0x7a, 0x84, 0x3e, 0x33, 0x1a, + 0xd6, 0xab, 0x5b, 0x05, 0x36, 0xa8, 0xd0, 0x5b, 0x7c, 0x38, 0x4d, 0x50, 0xc1, 0xfe, 0xe4, 0x7b, + 0x7c, 0x06, 0x05, 0xfc, 0x9c, 0xaf, 0x9c, 0x52, 0xc1, 0x01, 0x57, 0xee, 0x13, 0x70, 0x32, 0xdb, + 0xb8, 0x7c, 0xe9, 0x4e, 0x8f, 0x86, 0xf5, 0x93, 0xad, 0x22, 0x23, 0x54, 0xec, 0x5f, 0xa4, 0xbe, + 0xf9, 0x27, 0xa3, 0xbe, 0xa6, 0x75, 0xfb, 0x5e, 0x6d, 0xee, 0xce, 0xbd, 0xda, 0xdc, 0xdd, 0x7b, + 0xb5, 0xb9, 0xaf, 0x46, 0x35, 0xe3, 0xf6, 0xa8, 0x66, 0xdc, 0x19, 0xd5, 0x8c, 0xbb, 0xa3, 0x9a, + 0xf1, 0xfb, 0xa8, 0x66, 0x7c, 0x77, 0xbf, 0x36, 0xf7, 0xf1, 0x52, 0x34, 0x0c, 0xff, 0x09, 0x00, + 0x00, 0xff, 0xff, 0x88, 0x5a, 0x1f, 0xc3, 0xc3, 0x13, 0x00, 0x00, } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.proto b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.proto index 21d9ea6f62..2f84faf161 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.proto +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/apis/autoscaling/v2alpha1/generated.proto @@ -27,7 +27,6 @@ import "k8s.io/apimachinery/pkg/runtime/generated.proto"; import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; import "k8s.io/kubernetes/pkg/api/v1/generated.proto"; -import "k8s.io/kubernetes/pkg/apis/autoscaling/v1/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v2alpha1"; diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/util/util.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/util/util.go index 356b295a3e..389e145e84 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/util/util.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/util/util.go @@ -84,6 +84,15 @@ func FileExists(filename string) (bool, error) { return true, nil } +func FileOrSymlinkExists(filename string) (bool, error) { + if _, err := os.Lstat(filename); os.IsNotExist(err) { + return false, nil + } else if err != nil { + return false, err + } + return true, nil +} + // ReadDirNoStat returns a string of files/directories contained // in dirname without calling lstat on them. func ReadDirNoStat(dirname string) ([]string, error) { diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/version/base.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/version/base.go index 0762697303..311b63d01c 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/version/base.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/pkg/version/base.go @@ -39,8 +39,8 @@ var ( // them irrelevant. (Next we'll take it out, which may muck with // scripts consuming the kubectl version output - but most of // these should be looking at gitVersion already anyways.) - gitMajor string = "1" // major version, always numeric - gitMinor string = "7+" // minor version, numeric possibly followed by "+" + gitMajor string = "1" // major version, always numeric + gitMinor string = "7" // minor version, numeric possibly followed by "+" // semantic version, derived by build scripts (see // https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md @@ -51,7 +51,7 @@ var ( // semantic version is a git hash, but the version itself is no // longer the direct output of "git describe", but a slight // translation to be semver compliant. - gitVersion string = "v1.7.1-beta.0+$Format:%h$" + gitVersion string = "v1.7.6+$Format:%h$" gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD) gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty" diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD index 0c8f309549..00c96d666d 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/BUILD @@ -13,7 +13,7 @@ go_test( srcs = ["azure_test.go"], library = ":go_default_library", tags = ["automanaged"], - deps = ["//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library"], + deps = ["//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library"], ) go_library( @@ -22,6 +22,7 @@ go_library( tags = ["automanaged"], deps = [ "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/adal:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go index 342fbb78f5..06744e7424 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure.go @@ -24,6 +24,7 @@ import ( "sync" "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" "github.com/Azure/go-autorest/autorest/azure" "github.com/golang/glog" @@ -137,7 +138,7 @@ func (r *azureRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) } type azureToken struct { - token azure.Token + token adal.Token clientID string tenantID string apiserverID string @@ -234,7 +235,7 @@ func (ts *azureTokenSource) retrieveTokenFromCfg() (*azureToken, error) { } return &azureToken{ - token: azure.Token{ + token: adal.Token{ AccessToken: accessToken, RefreshToken: refreshToken, ExpiresIn: expiresIn, @@ -268,15 +269,15 @@ func (ts *azureTokenSource) storeTokenInCfg(token *azureToken) error { } func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error) { - oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(token.tenantID) + oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, token.tenantID) if err != nil { return nil, fmt.Errorf("building the OAuth configuration for token refresh: %v", err) } - callback := func(t azure.Token) error { + callback := func(t adal.Token) error { return nil } - spt, err := azure.NewServicePrincipalTokenFromManualToken( + spt, err := adal.NewServicePrincipalTokenFromManualToken( *oauthConfig, token.clientID, token.apiserverID, @@ -324,12 +325,12 @@ func newAzureTokenSourceDeviceCode(environment azure.Environment, clientID strin } func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) { - oauthConfig, err := ts.environment.OAuthConfigForTenant(ts.tenantID) + oauthConfig, err := adal.NewOAuthConfig(ts.environment.ActiveDirectoryEndpoint, ts.tenantID) if err != nil { return nil, fmt.Errorf("building the OAuth configuration for device code authentication: %v", err) } client := &autorest.Client{} - deviceCode, err := azure.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID) + deviceCode, err := adal.InitiateDeviceAuth(client, *oauthConfig, ts.clientID, ts.apiserverID) if err != nil { return nil, fmt.Errorf("initialing the device code authentication: %v", err) } @@ -339,7 +340,7 @@ func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) { return nil, fmt.Errorf("prompting the device code message: %v", err) } - token, err := azure.WaitForUserCompletion(client, deviceCode) + token, err := adal.WaitForUserCompletion(client, deviceCode) if err != nil { return nil, fmt.Errorf("waiting for device code authentication to complete: %v", err) } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go index 78d28b6e2f..b420712bc1 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/client-go/plugin/pkg/client/auth/azure/azure_test.go @@ -23,7 +23,7 @@ import ( "testing" "time" - "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/adal" ) func TestAzureTokenSource(t *testing.T) { @@ -120,8 +120,8 @@ func token2Cfg(token *azureToken) map[string]string { return cfg } -func newFackeAzureToken(accessToken string, expiresOn string) azure.Token { - return azure.Token{ +func newFackeAzureToken(accessToken string, expiresOn string) adal.Token { + return adal.Token{ AccessToken: accessToken, RefreshToken: "fake", ExpiresIn: "3600", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/helpers.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/helpers.go index 1f6790b32e..5e36e7db26 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/helpers.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/helpers.go @@ -20,6 +20,7 @@ import ( "sort" "strings" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -85,6 +86,17 @@ func APIServiceNameToGroupVersion(apiServiceName string) schema.GroupVersion { return schema.GroupVersion{Group: tokens[1], Version: tokens[0]} } +// NewLocalAvailableAPIServiceCondition returns a condition for an available local APIService. +func NewLocalAvailableAPIServiceCondition() APIServiceCondition { + return APIServiceCondition{ + Type: Available, + Status: ConditionTrue, + LastTransitionTime: metav1.Now(), + Reason: "Local", + Message: "Local APIServices are always available", + } +} + // SetAPIServiceCondition sets the status condition. It either overwrites the existing one or // creates a new one func SetAPIServiceCondition(apiService *APIService, newCondition APIServiceCondition) { diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/BUILD b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/BUILD index bea2e5baf3..3fc28a7878 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/BUILD +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/BUILD @@ -17,6 +17,7 @@ go_test( library = ":go_default_library", tags = ["automanaged"], deps = [ + "//vendor/golang.org/x/net/websocket:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/handler_proxy_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/handler_proxy_test.go index 482c971ed8..11e4c8fa8b 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/handler_proxy_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/apiserver/handler_proxy_test.go @@ -17,21 +17,24 @@ limitations under the License. package apiserver import ( + "crypto/tls" "io/ioutil" "net/http" "net/http/httptest" "net/http/httputil" + "net/url" "reflect" "strings" + "sync/atomic" "testing" + "golang.org/x/net/websocket" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/user" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/kube-aggregator/pkg/apis/apiregistration" - "net/url" ) type targetHTTPHandler struct { @@ -92,7 +95,13 @@ func (r *mockedRouter) ResolveEndpoint(namespace, name string) (*url.URL, error) func TestProxyHandler(t *testing.T) { target := &targetHTTPHandler{} - targetServer := httptest.NewTLSServer(target) + targetServer := httptest.NewUnstartedServer(target) + if cert, err := tls.X509KeyPair(svcCrt, svcKey); err != nil { + t.Fatal(err) + } else { + targetServer.TLS = &tls.Config{Certificates: []tls.Certificate{cert}} + } + targetServer.StartTLS() defer targetServer.Close() tests := map[string]struct { @@ -120,7 +129,7 @@ func TestProxyHandler(t *testing.T) { expectedStatusCode: http.StatusInternalServerError, expectedBody: "missing user", }, - "proxy with user": { + "proxy with user, insecure": { user: &user.DefaultInfo{ Name: "username", Groups: []string{"one", "two"}, @@ -147,6 +156,33 @@ func TestProxyHandler(t *testing.T) { "X-Remote-Group": {"one", "two"}, }, }, + "proxy with user, cabundle": { + user: &user.DefaultInfo{ + Name: "username", + Groups: []string{"one", "two"}, + }, + path: "/request/path", + apiService: &apiregistration.APIService{ + ObjectMeta: metav1.ObjectMeta{Name: "v1.foo"}, + Spec: apiregistration.APIServiceSpec{ + Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns"}, + Group: "foo", + Version: "v1", + CABundle: testCACrt, + }, + }, + expectedStatusCode: http.StatusOK, + expectedCalled: true, + expectedHeaders: map[string][]string{ + "X-Forwarded-Proto": {"https"}, + "X-Forwarded-Uri": {"/request/path"}, + "X-Forwarded-For": {"127.0.0.1"}, + "X-Remote-User": {"username"}, + "User-Agent": {"Go-http-client/1.1"}, + "Accept-Encoding": {"gzip"}, + "X-Remote-Group": {"one", "two"}, + }, + }, "fail on bad serving cert": { user: &user.DefaultInfo{ Name: "username", @@ -218,3 +254,188 @@ func TestProxyHandler(t *testing.T) { }() } } + +func TestProxyUpgrade(t *testing.T) { + testcases := map[string]struct { + APIService *apiregistration.APIService + ExpectError bool + ExpectCalled bool + }{ + "valid hostname + CABundle": { + APIService: &apiregistration.APIService{ + Spec: apiregistration.APIServiceSpec{ + CABundle: testCACrt, + Group: "mygroup", + Version: "v1", + Service: &apiregistration.ServiceReference{Name: "test-service", Namespace: "test-ns"}, + }, + }, + ExpectError: false, + ExpectCalled: true, + }, + "invalid hostname + insecure": { + APIService: &apiregistration.APIService{ + Spec: apiregistration.APIServiceSpec{ + InsecureSkipTLSVerify: true, + Group: "mygroup", + Version: "v1", + Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns"}, + }, + }, + ExpectError: false, + ExpectCalled: true, + }, + "invalid hostname + CABundle": { + APIService: &apiregistration.APIService{ + Spec: apiregistration.APIServiceSpec{ + CABundle: testCACrt, + Group: "mygroup", + Version: "v1", + Service: &apiregistration.ServiceReference{Name: "invalid-service", Namespace: "invalid-ns"}, + }, + }, + ExpectError: true, + ExpectCalled: false, + }, + } + + for k, tc := range testcases { + tcName := k + path := "/apis/" + tc.APIService.Spec.Group + "/" + tc.APIService.Spec.Version + "/foo" + timesCalled := int32(0) + + func() { // Cleanup after each test case. + backendHandler := http.NewServeMux() + backendHandler.Handle(path, websocket.Handler(func(ws *websocket.Conn) { + atomic.AddInt32(×Called, 1) + defer ws.Close() + body := make([]byte, 5) + ws.Read(body) + ws.Write([]byte("hello " + string(body))) + })) + + backendServer := httptest.NewUnstartedServer(backendHandler) + if cert, err := tls.X509KeyPair(svcCrt, svcKey); err != nil { + t.Errorf("https (valid hostname): %v", err) + return + } else { + backendServer.TLS = &tls.Config{Certificates: []tls.Certificate{cert}} + } + backendServer.StartTLS() + defer backendServer.Close() + + defer func() { + if called := atomic.LoadInt32(×Called) > 0; called != tc.ExpectCalled { + t.Errorf("%s: expected called=%v, got %v", tcName, tc.ExpectCalled, called) + } + }() + + serverURL, _ := url.Parse(backendServer.URL) + proxyHandler := &proxyHandler{ + contextMapper: &fakeRequestContextMapper{user: &user.DefaultInfo{Name: "username"}}, + serviceResolver: &mockedRouter{destinationHost: serverURL.Host}, + proxyTransport: &http.Transport{}, + } + proxyHandler.updateAPIService(tc.APIService) + aggregator := httptest.NewServer(proxyHandler) + defer aggregator.Close() + + ws, err := websocket.Dial("ws://"+aggregator.Listener.Addr().String()+path, "", "http://127.0.0.1/") + if err != nil { + if !tc.ExpectError { + t.Errorf("%s: websocket dial err: %s", tcName, err) + } + return + } + defer ws.Close() + if tc.ExpectError { + t.Errorf("%s: expected websocket error, got none", tcName) + return + } + + if _, err := ws.Write([]byte("world")); err != nil { + t.Errorf("%s: write err: %s", tcName, err) + return + } + + response := make([]byte, 20) + n, err := ws.Read(response) + if err != nil { + t.Errorf("%s: read err: %s", tcName, err) + return + } + if e, a := "hello world", string(response[0:n]); e != a { + t.Errorf("%s: expected '%#v', got '%#v'", tcName, e, a) + return + } + }() + } +} + +var testCACrt = []byte(`-----BEGIN CERTIFICATE----- +MIICxDCCAaygAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0 +LWNhMCAXDTE3MDcyMDIxMTc1MloYDzIxMTcwNjI2MjExNzUzWjASMRAwDgYDVQQD +Ewd0ZXN0LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuv/sT2xH +VS1/uXVNAEIwvEb2yTMbXwP6FD38LWkc37Ri7YMB9xiXEDBrbr6K1JThsqyitBxU +22QIl53LUm6I7c/vej1tdYtE2rDVuviiiRgy6omR8imVSv9vU024rgDe+nC9zTT1 +3aNKR03olCG6fkygdcZOghzlyQLhyh8LG75XdnLNksnakum2dNxQ5QIFmBKAuev3 +A069oRMNjudot+t/nFP9UDZ8dL80PNTNPF22bPsnxiau7KLZ4I0Lf7gt6yHlNcue +Fd5sqzqsw/LUFJR5Xuo1+0e7NV3SwCH5CymG6hkboM4Rf5S3EDDyXTxPbXzbQHf1 +7ksW6gjAxh4x/wIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAqQwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATgmDrW1BjFp+Vmw6T+ojVK4lJuIoerGw +TCCqabHs6O1iWkNi5KsY6vV86tofBIEXsf6S3mV2jcBn87+CIbNHlHFKrXwmcydA +WOc0LWVqqoeqIvEcMNoWQskzmOOUDTanX9mXkirm8d8BljC351TH17rSjLGzFuNh +Cy48xyKFM7kPauNZGfCyaZsGbNJP3Keeu35dOLZMDdBJw7ZvYEUqX7MLOO+d7vlO +JGNA5jsU2uBnSo6qsjxfsbGemk2uRO0nLhplWurw+4qzA79D0lKNLtH9yTn12KZb +/kUpsOSCtLomjWwp67lQyA/yFXf897pSKMXbnIfZfIlDg51CI3U2Sw== +-----END CERTIFICATE-----`) + +// valid for hostname test-service.test-ns.svc +// signed by testCACrt +var svcCrt = []byte(`-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIBBDANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0 +LWNhMCAXDTE3MDcyMDIxMjAzN1oYDzIxMTcwNjI2MjEyMDM4WjAjMSEwHwYDVQQD +Exh0ZXN0LXNlcnZpY2UudGVzdC1ucy5zdmMwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDOKgoTmlVeDhImiBLBccxdniKkS+FZSaoAEtoTvJG1wjk0ewzF +vKhjbHolJ+/qEANiQ6CpTz4hU3m/Iad6IrnmKd1jnkh9yKEaU32B2Xbh6VaV7Sca +Hv4cKWTe50sBvufZinTT8hlFcGufFlJIOLXya5t6HH1Ld7Xf2qwNqusHdmFlJko7 +0By8jhTtD7+2OAJsIPQDWfAsXxFa6LeQ/lqS2DCFnp45DirTNetXoIH8ZJvTBjak +bQuAAA3H+61gRm1blIu8/JjHYTDOcUe5pFyrFLFPgA+eIcpIbzTD61UTNhVlusV2 +eRrBr5BlRM13Zj6ZMcWp0Iiw5QI/W9QU7O4jAgMBAAGjWjBYMA4GA1UdDwEB/wQE +AwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMCMGA1UdEQQc +MBqCGHRlc3Qtc2VydmljZS50ZXN0LW5zLnN2YzANBgkqhkiG9w0BAQsFAAOCAQEA +kpULlml6Ct0cjOuHgDKUnTboFTUm2FHJY27p4NXUvXUMoipg/eSxk0r5JynzXrPa +jaJfY2bC45ixLjJv9irp9ER/lGYUcBQ8OHouXy+uKtA5YKHI3wYf8ITZrQwzRpsK +C5v7qDW+iyb9dn4T6qgpZvylKtkH5cH31hQooNgjZd5aEq3JSFnCM12IVqs/5kjL +NnbPXzeBQ9CHbC+mx7Mm6eSQVtGcQOy4yXFrh2/vrIB2t4gNeWaI1b+7l4MaJjV/ +kRrOirhZaJ90ow/PdYrILtEAdpeC/2Varpr3l4rIKhkkop4gfPwaFeWhG38shH3E +eG5PW2waPpxJzEnGBoAWxQ== +-----END CERTIFICATE-----`) + +var svcKey = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAzioKE5pVXg4SJogSwXHMXZ4ipEvhWUmqABLaE7yRtcI5NHsM +xbyoY2x6JSfv6hADYkOgqU8+IVN5vyGneiK55indY55IfcihGlN9gdl24elWle0n +Gh7+HClk3udLAb7n2Yp00/IZRXBrnxZSSDi18mubehx9S3e139qsDarrB3ZhZSZK +O9AcvI4U7Q+/tjgCbCD0A1nwLF8RWui3kP5aktgwhZ6eOQ4q0zXrV6CB/GSb0wY2 +pG0LgAANx/utYEZtW5SLvPyYx2EwznFHuaRcqxSxT4APniHKSG80w+tVEzYVZbrF +dnkawa+QZUTNd2Y+mTHFqdCIsOUCP1vUFOzuIwIDAQABAoIBABiX9z/DZ2+i6hNi +pCojcyev154V1zoZiYgct5snIZK3Kq/SBgIIsWW66Q9Jplsbseuk+aN46oZ7OMjO +MPZm8ho84EYj+a3XozBKyWwWDxKADW4xLjr1e4bMgVX97Xq11V6kH6+w78bS1GPT ++9jVuw7CO3fjsiawjye3JFM1Enh/NeRLEpT/oaQoWIV8b0IQB0VyqrdxWOO0rQhd +xA5w39tAZPDQ79MbMQyNWtPgBy0FuulP0GB12PrEbE+SXxsFhWViEwdB5Qx6Gqsx +KGn9vB1oaeSuuKIAjyBV0rXszrGektorDchsOY9UQi1mQsPSvvRFTM9T3qqSFIpu +oPNQLvECgYEA3ox3WJGjEve6VI4RMRt0l6ZFswNbNaHcTMPVsayqsl9KfebG+uyn +Z7TyyoCRzZZQa+3Z9jjW3hAGM9e7MG8jkeHbZpJpZv9X7eB3dgq3eZ1Zt5dyoDrU +PTdIPA2efFAf6V1ejyqH9h6RPQMeAb4uFU9nbI4rPagMxRdp5qIveIUCgYEA7Scb +0zWplDit4EUo+Fq80wzItwJZv64my8KIkEPpW3Fu6UPQvY74qyhE2fCSCwHqRpYJ +jVylyE0GIMx42kjwBgOpi4yEg8M3uMTal+Iy9SgrxZ5cPetaFpEF3Wk7/tz6ppr+ +wnZQTO2WH3YLzv7JIWVrOKuBNVfNEbguVFWw4IcCgYB54mp2uoSancySBKDLyWKo +r6raqQrqK7TQ4iyGO6/dMy1EGQF/ad8hgEu8tn+kHh/7jG/kVyruwc3z1MIze5r6 +ib00xxktDMnmgRpMLwBffdsmHq7rrGyS/lT0du0G3ocrszRXqo5+MC2RQcTMZZEt +oKhfHtn10bT0uKcKZmcjVQKBgEls2WWccMOuhM8yOowic+IYTDC1bpo1Tle6BFQ+ +YoroZQGd+IwoLv+3ORINNPppfmKaY5y7+aw5hNM025oiCQajraPCPukY0TDI6jEq +XMKgzGSkMkUNkFf6UMmLooK3Yneg94232gbnbJqTDvbo1dccMoVaPGgKpjh9QQLl +gR0TAoGACFOvhl8txfbkwLeuNeunyOPL7J4nIccthgd2ioFOr3HTou6wzN++vYTa +a3OF9jH5Z7m6X1rrwn6J1+Gw9sBme38/GeGXHigsBI/8WaTvyuppyVIXOVPoTvVf +VYsTwo5YgV1HzDkV+BNmBCw1GYcGXAElhJI+dCsgQuuU6TKzgl8= +-----END RSA PRIVATE KEY-----`) diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/BUILD b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/BUILD index 389bb26260..ca2525555d 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/BUILD +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/BUILD @@ -32,6 +32,7 @@ go_library( "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library", diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller.go index f606d51c24..e9f7e0739d 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller.go @@ -26,6 +26,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/labels" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" @@ -40,6 +41,11 @@ import ( const ( AutoRegisterManagedLabel = "kube-aggregator.kubernetes.io/automanaged" + + // manageOnStart is a value for the AutoRegisterManagedLabel that indicates the APIService wants to be synced one time when the controller starts. + manageOnStart = "onstart" + // manageContinuously is a value for the AutoRegisterManagedLabel that indicates the APIService wants to be synced continuously. + manageContinuously = "true" ) var ( @@ -49,7 +55,9 @@ var ( // AutoAPIServiceRegistration is an interface which callers can re-declare locally and properly cast to for // adding and removing APIServices type AutoAPIServiceRegistration interface { - // AddAPIServiceToSync adds an API service to auto-register. + // AddAPIServiceToSyncOnStart adds an API service to sync on start. + AddAPIServiceToSyncOnStart(in *apiregistration.APIService) + // AddAPIServiceToSync adds an API service to sync continuously. AddAPIServiceToSync(in *apiregistration.APIService) // RemoveAPIServiceToSync removes an API service to auto-register. RemoveAPIServiceToSync(name string) @@ -67,6 +75,13 @@ type autoRegisterController struct { syncHandler func(apiServiceName string) error + // track which services we have synced + syncedSuccessfullyLock *sync.RWMutex + syncedSuccessfully map[string]bool + + // remember names of services that existed when we started + apiServicesAtStart map[string]bool + // queue is where incoming work is placed to de-dup and to allow "easy" rate limited requeues on errors queue workqueue.RateLimitingInterface } @@ -77,7 +92,13 @@ func NewAutoRegisterController(apiServiceInformer informers.APIServiceInformer, apiServiceSynced: apiServiceInformer.Informer().HasSynced, apiServiceClient: apiServiceClient, apiServicesToSync: map[string]*apiregistration.APIService{}, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "autoregister"), + + apiServicesAtStart: map[string]bool{}, + + syncedSuccessfullyLock: &sync.RWMutex{}, + syncedSuccessfully: map[string]bool{}, + + queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "autoregister"), } c.syncHandler = c.checkAPIService @@ -125,6 +146,13 @@ func (c *autoRegisterController) Run(threadiness int, stopCh <-chan struct{}) { return } + // record APIService objects that existed when we started + if services, err := c.apiServiceLister.List(labels.Everything()); err == nil { + for _, service := range services { + c.apiServicesAtStart[service.Name] = true + } + } + // start up your worker threads based on threadiness. Some controllers have multiple kinds of workers for i := 0; i < threadiness; i++ { // runWorker will loop until "something bad" happens. The .Until will then rekick the worker @@ -174,29 +202,61 @@ func (c *autoRegisterController) processNextWorkItem() bool { return true } -func (c *autoRegisterController) checkAPIService(name string) error { +// checkAPIService syncs the current APIService against a list of desired APIService objects +// +// | A. desired: not found | B. desired: sync on start | C. desired: sync always +// ------------------------------------------------|-----------------------|---------------------------|------------------------ +// 1. current: lookup error | error | error | error +// 2. current: not found | - | create once | create +// 3. current: no sync | - | - | - +// 4. current: sync on start, not present at start | - | - | - +// 5. current: sync on start, present at start | delete once | update once | update once +// 6. current: sync always | delete | update once | update +func (c *autoRegisterController) checkAPIService(name string) (err error) { desired := c.GetAPIServiceToSync(name) curr, err := c.apiServiceLister.Get(name) + // if we've never synced this service successfully, record a successful sync. + hasSynced := c.hasSyncedSuccessfully(name) + if !hasSynced { + defer func() { + if err == nil { + c.setSyncedSuccessfully(name) + } + }() + } + switch { - // we had a real error, just return it + // we had a real error, just return it (1A,1B,1C) case err != nil && !apierrors.IsNotFound(err): return err - // we don't have an entry and we don't want one + // we don't have an entry and we don't want one (2A) case apierrors.IsNotFound(err) && desired == nil: return nil - // we don't have an entry and we do want one + // the local object only wants to sync on start and has already synced (2B,5B,6B "once" enforcement) + case isAutomanagedOnStart(desired) && hasSynced: + return nil + + // we don't have an entry and we do want one (2B,2C) case apierrors.IsNotFound(err) && desired != nil: _, err := c.apiServiceClient.APIServices().Create(desired) return err - // we aren't trying to manage this APIService. If the user removes the label, he's taken over management himself - case curr.Labels[AutoRegisterManagedLabel] != "true": + // we aren't trying to manage this APIService (3A,3B,3C) + case !isAutomanaged(curr): + return nil + + // the remote object only wants to sync on start, but was added after we started (4A,4B,4C) + case isAutomanagedOnStart(curr) && !c.apiServicesAtStart[name]: + return nil + + // the remote object only wants to sync on start and has already synced (5A,5B,5C "once" enforcement) + case isAutomanagedOnStart(curr) && hasSynced: return nil - // we have a spurious APIService that we're managing, delete it + // we have a spurious APIService that we're managing, delete it (5A,6A) case desired == nil: return c.apiServiceClient.APIServices().Delete(curr.Name, nil) @@ -205,7 +265,7 @@ func (c *autoRegisterController) checkAPIService(name string) error { return nil } - // we have an entry and we have a desired, now we deconflict. Only a few fields matter. + // we have an entry and we have a desired, now we deconflict. Only a few fields matter. (5B,5C,6B,6C) apiService := &apiregistration.APIService{} if err := apiregistration.DeepCopy_apiregistration_APIService(curr, apiService, cloner); err != nil { return err @@ -222,7 +282,15 @@ func (c *autoRegisterController) GetAPIServiceToSync(name string) *apiregistrati return c.apiServicesToSync[name] } +func (c *autoRegisterController) AddAPIServiceToSyncOnStart(in *apiregistration.APIService) { + c.addAPIServiceToSync(in, manageOnStart) +} + func (c *autoRegisterController) AddAPIServiceToSync(in *apiregistration.APIService) { + c.addAPIServiceToSync(in, manageContinuously) +} + +func (c *autoRegisterController) addAPIServiceToSync(in *apiregistration.APIService, syncType string) { c.apiServicesToSyncLock.Lock() defer c.apiServicesToSyncLock.Unlock() @@ -235,7 +303,7 @@ func (c *autoRegisterController) AddAPIServiceToSync(in *apiregistration.APIServ if apiService.Labels == nil { apiService.Labels = map[string]string{} } - apiService.Labels[AutoRegisterManagedLabel] = "true" + apiService.Labels[AutoRegisterManagedLabel] = syncType c.apiServicesToSync[apiService.Name] = apiService c.queue.Add(apiService.Name) @@ -248,3 +316,31 @@ func (c *autoRegisterController) RemoveAPIServiceToSync(name string) { delete(c.apiServicesToSync, name) c.queue.Add(name) } + +func (c *autoRegisterController) hasSyncedSuccessfully(name string) bool { + c.syncedSuccessfullyLock.RLock() + defer c.syncedSuccessfullyLock.RUnlock() + return c.syncedSuccessfully[name] +} + +func (c *autoRegisterController) setSyncedSuccessfully(name string) { + c.syncedSuccessfullyLock.Lock() + defer c.syncedSuccessfullyLock.Unlock() + c.syncedSuccessfully[name] = true +} + +func automanagedType(service *apiregistration.APIService) string { + if service == nil { + return "" + } + return service.Labels[AutoRegisterManagedLabel] +} + +func isAutomanagedOnStart(service *apiregistration.APIService) bool { + return automanagedType(service) == manageOnStart +} + +func isAutomanaged(service *apiregistration.APIService) bool { + managedType := automanagedType(service) + return managedType == manageOnStart || managedType == manageContinuously +} diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller_test.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller_test.go index 9a6181f836..0fd4698102 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller_test.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/autoregister/autoregister_controller_test.go @@ -18,6 +18,7 @@ package autoregister import ( "fmt" + "sync" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,6 +36,12 @@ func newAutoRegisterManagedAPIService(name string) *apiregistration.APIService { } } +func newAutoRegisterManagedOnStartAPIService(name string) *apiregistration.APIService { + return &apiregistration.APIService{ + ObjectMeta: metav1.ObjectMeta{Name: name, Labels: map[string]string{AutoRegisterManagedLabel: string("onstart")}}, + } +} + func newAutoRegisterManagedModifiedAPIService(name string) *apiregistration.APIService { return &apiregistration.APIService{ ObjectMeta: metav1.ObjectMeta{Name: name, Labels: map[string]string{AutoRegisterManagedLabel: string("true")}}, @@ -44,6 +51,15 @@ func newAutoRegisterManagedModifiedAPIService(name string) *apiregistration.APIS } } +func newAutoRegisterManagedOnStartModifiedAPIService(name string) *apiregistration.APIService { + return &apiregistration.APIService{ + ObjectMeta: metav1.ObjectMeta{Name: name, Labels: map[string]string{AutoRegisterManagedLabel: string("onstart")}}, + Spec: apiregistration.APIServiceSpec{ + Group: "something", + }, + } +} + func newAPIService(name string) *apiregistration.APIService { return &apiregistration.APIService{ ObjectMeta: metav1.ObjectMeta{Name: name}, @@ -80,6 +96,28 @@ func checkForCreate(name string, client *fake.Clientset) error { return nil } +func checkForCreateOnStart(name string, client *fake.Clientset) error { + if len(client.Actions()) == 0 { + return nil + } + if len(client.Actions()) > 1 { + return fmt.Errorf("unexpected action: %v", client.Actions()) + } + + action := client.Actions()[0] + + createAction, ok := action.(clienttesting.CreateAction) + if !ok { + return fmt.Errorf("unexpected action: %v", client.Actions()) + } + apiService := createAction.GetObject().(*apiregistration.APIService) + if apiService.Name != name || apiService.Labels[AutoRegisterManagedLabel] != "onstart" { + return fmt.Errorf("bad name or label %v", createAction) + } + + return nil +} + func checkForUpdate(name string, client *fake.Clientset) error { if len(client.Actions()) == 0 { return nil @@ -121,13 +159,16 @@ func checkForDelete(name string, client *fake.Clientset) error { func TestSync(t *testing.T) { tests := []struct { - name string - apiServiceName string - addAPIServices []*apiregistration.APIService - updateAPIServices []*apiregistration.APIService - addSyncAPIServices []*apiregistration.APIService - delSyncAPIServices []string - expectedResults func(name string, client *fake.Clientset) error + name string + apiServiceName string + addAPIServices []*apiregistration.APIService + updateAPIServices []*apiregistration.APIService + addSyncAPIServices []*apiregistration.APIService + addSyncOnStartAPIServices []*apiregistration.APIService + delSyncAPIServices []string + alreadySynced map[string]bool + presentAtStart map[string]bool + expectedResults func(name string, client *fake.Clientset) error }{ { name: "adding an API service which isn't auto-managed does nothing", @@ -166,7 +207,7 @@ func TestSync(t *testing.T) { expectedResults: checkForDelete, }, { - name: "removing auto-manged then RemoveAPIService should not touch APIService", + name: "removing auto-managed then RemoveAPIService should not touch APIService", apiServiceName: "foo", addAPIServices: []*apiregistration.APIService{}, updateAPIServices: []*apiregistration.APIService{newAPIService("foo")}, @@ -192,17 +233,104 @@ func TestSync(t *testing.T) { delSyncAPIServices: []string{}, expectedResults: checkForUpdate, }, + + { + name: "adding one to auto-register on start should create", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{}, + updateAPIServices: []*apiregistration.APIService{}, + addSyncOnStartAPIServices: []*apiregistration.APIService{newAPIService("foo")}, + delSyncAPIServices: []string{}, + expectedResults: checkForCreateOnStart, + }, + { + name: "adding one to auto-register on start already synced should do nothing", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{}, + updateAPIServices: []*apiregistration.APIService{}, + addSyncOnStartAPIServices: []*apiregistration.APIService{newAPIService("foo")}, + delSyncAPIServices: []string{}, + alreadySynced: map[string]bool{"foo": true}, + expectedResults: checkForNothing, + }, + { + name: "managed onstart apiservice present at start without a matching request should delete", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{newAPIService("foo")}, + updateAPIServices: []*apiregistration.APIService{newAutoRegisterManagedOnStartAPIService("foo")}, + addSyncAPIServices: []*apiregistration.APIService{}, + delSyncAPIServices: []string{}, + presentAtStart: map[string]bool{"foo": true}, + alreadySynced: map[string]bool{}, + expectedResults: checkForDelete, + }, + { + name: "managed onstart apiservice present at start without a matching request already synced once should no-op", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{newAPIService("foo")}, + updateAPIServices: []*apiregistration.APIService{newAutoRegisterManagedOnStartAPIService("foo")}, + addSyncAPIServices: []*apiregistration.APIService{}, + delSyncAPIServices: []string{}, + presentAtStart: map[string]bool{"foo": true}, + alreadySynced: map[string]bool{"foo": true}, + expectedResults: checkForNothing, + }, + { + name: "managed onstart apiservice not present at start without a matching request should no-op", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{newAPIService("foo")}, + updateAPIServices: []*apiregistration.APIService{newAutoRegisterManagedOnStartAPIService("foo")}, + addSyncAPIServices: []*apiregistration.APIService{}, + delSyncAPIServices: []string{}, + presentAtStart: map[string]bool{}, + alreadySynced: map[string]bool{}, + expectedResults: checkForNothing, + }, + { + name: "modifying onstart it should result in stomping", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{}, + updateAPIServices: []*apiregistration.APIService{newAutoRegisterManagedModifiedAPIService("foo")}, + addSyncOnStartAPIServices: []*apiregistration.APIService{newAutoRegisterManagedOnStartAPIService("foo")}, + delSyncAPIServices: []string{}, + expectedResults: checkForUpdate, + }, + { + name: "modifying onstart already synced should no-op", + apiServiceName: "foo", + addAPIServices: []*apiregistration.APIService{}, + updateAPIServices: []*apiregistration.APIService{newAutoRegisterManagedModifiedAPIService("foo")}, + addSyncOnStartAPIServices: []*apiregistration.APIService{newAutoRegisterManagedOnStartAPIService("foo")}, + delSyncAPIServices: []string{}, + alreadySynced: map[string]bool{"foo": true}, + expectedResults: checkForNothing, + }, } for _, test := range tests { fakeClient := fake.NewSimpleClientset() apiServiceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c := autoRegisterController{ + alreadySynced := map[string]bool{} + for k, v := range test.alreadySynced { + alreadySynced[k] = v + } + + presentAtStart := map[string]bool{} + for k, v := range test.presentAtStart { + presentAtStart[k] = v + } + + c := &autoRegisterController{ apiServiceClient: fakeClient.Apiregistration(), apiServiceLister: listers.NewAPIServiceLister(apiServiceIndexer), apiServicesToSync: map[string]*apiregistration.APIService{}, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "autoregister"), + + syncedSuccessfullyLock: &sync.RWMutex{}, + syncedSuccessfully: alreadySynced, + + apiServicesAtStart: presentAtStart, } for _, obj := range test.addAPIServices { @@ -217,6 +345,10 @@ func TestSync(t *testing.T) { c.AddAPIServiceToSync(obj) } + for _, obj := range test.addSyncOnStartAPIServices { + c.AddAPIServiceToSyncOnStart(obj) + } + for _, objName := range test.delSyncAPIServices { c.RemoveAPIServiceToSync(objName) } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go index ec57144e87..05d053864a 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go @@ -126,10 +126,7 @@ func (c *AvailableConditionController) sync(key string) error { // local API services are always considered available if apiService.Spec.Service == nil { - availableCondition.Status = apiregistration.ConditionTrue - availableCondition.Reason = "Local" - availableCondition.Message = "Local APIServices are always available" - apiregistration.SetAPIServiceCondition(apiService, availableCondition) + apiregistration.SetAPIServiceCondition(apiService, apiregistration.NewLocalAvailableAPIServiceCondition()) _, err := c.apiServiceClient.APIServices().UpdateStatus(apiService) return err } diff --git a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/registry/apiservice/strategy.go b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/registry/apiservice/strategy.go index fdcb6637f7..51887d7193 100644 --- a/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/registry/apiservice/strategy.go +++ b/vendor/k8s.io/kubernetes/staging/src/k8s.io/kube-aggregator/pkg/registry/apiservice/strategy.go @@ -48,6 +48,11 @@ func (apiServerStrategy) NamespaceScoped() bool { func (apiServerStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { apiservice := obj.(*apiregistration.APIService) apiservice.Status = apiregistration.APIServiceStatus{} + + // mark local API services as immediately available on create + if apiservice.Spec.Service == nil { + apiregistration.SetAPIServiceCondition(apiservice, apiregistration.NewLocalAvailableAPIServiceCondition()) + } } func (apiServerStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { diff --git a/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/BUILD b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/BUILD index 0cc0797172..d2d7bddce8 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/BUILD +++ b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/BUILD @@ -13,6 +13,7 @@ go_library( "es.go", "es_utils.go", "sd.go", + "sd_events.go", "sd_load.go", "sd_utils.go", "utils.go", diff --git a/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_events.go b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_events.go new file mode 100644 index 0000000000..913ab18e12 --- /dev/null +++ b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_events.go @@ -0,0 +1,93 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "time" + + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/test/e2e/framework" + + . "github.com/onsi/ginkgo" +) + +const ( + // eventsIngestionTimeout is the amount of time to wait until some + // events are ingested. + eventsIngestionTimeout = 10 * time.Minute + + // eventPollingInterval is the delay between attempts to read events + // from the logs provider. + eventPollingInterval = 1 * time.Second + + // eventCreationInterval is the minimal delay between two events + // created for testing purposes. + eventCreationInterval = 10 * time.Second +) + +var _ = framework.KubeDescribe("Cluster level logging using GCL", func() { + f := framework.NewDefaultFramework("gcl-logging-events") + + BeforeEach(func() { + framework.SkipUnlessProviderIs("gce", "gke") + }) + + It("should ingest events", func() { + gclLogsProvider, err := newGclLogsProvider(f) + framework.ExpectNoError(err, "Failed to create GCL logs provider") + + err = gclLogsProvider.Init() + defer gclLogsProvider.Cleanup() + framework.ExpectNoError(err, "Failed to init GCL logs provider") + + stopCh := make(chan struct{}) + successCh := make(chan struct{}) + go func() { + wait.Poll(eventPollingInterval, eventsIngestionTimeout, func() (bool, error) { + events := gclLogsProvider.ReadEvents() + if len(events) > 0 { + framework.Logf("Some events are ingested, sample event: %v", events[0]) + close(successCh) + return true, nil + } + return false, nil + }) + close(stopCh) + }() + + By("Running pods to generate events while waiting for some of them to be ingested") + wait.PollUntil(eventCreationInterval, func() (bool, error) { + podName := "synthlogger" + createLoggingPod(f, podName, "", 1, 1*time.Second) + defer f.PodClient().Delete(podName, &meta_v1.DeleteOptions{}) + err = framework.WaitForPodSuccessInNamespace(f.ClientSet, podName, f.Namespace.Name) + if err != nil { + framework.Logf("Failed to wait pod %s to successfully complete due to %v", podName, err) + } + + return false, nil + }, stopCh) + + select { + case <-successCh: + break + default: + framework.Failf("No events are present in Stackdriver after %v", eventsIngestionTimeout) + } + }) +}) diff --git a/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_utils.go b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_utils.go index e3c50ba8fb..d64d9a293c 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_utils.go +++ b/vendor/k8s.io/kubernetes/test/e2e/cluster-logging/sd_utils.go @@ -40,8 +40,8 @@ const ( // The limit on the number of messages to pull from PubSub maxPullLogMessages = 100 * 1000 - // The limit on the number of messages in the cache for a pod - maxCachedMessagesPerPod = 10 * 1000 + // The limit on the number of messages in the single cache + maxCacheSize = 10 * 1000 // PubSub topic with log entries polling interval gclLoggingPollInterval = 100 * time.Millisecond @@ -55,6 +55,7 @@ type gclLogsProvider struct { Subscription *pubsub.Subscription LogSink *gcl.LogSink LogEntryCache map[string]chan logEntry + EventCache chan map[string]interface{} CacheMutex *sync.Mutex PollingStopChannel chan struct{} } @@ -77,6 +78,7 @@ func newGclLogsProvider(f *framework.Framework) (*gclLogsProvider, error) { PubsubService: pubsubService, Framework: f, LogEntryCache: map[string]chan logEntry{}, + EventCache: make(chan map[string]interface{}, maxCacheSize), CacheMutex: &sync.Mutex{}, PollingStopChannel: make(chan struct{}, 1), } @@ -137,7 +139,9 @@ func (gclLogsProvider *gclLogsProvider) createPubSubSubscription(projectId, subs func (gclLogsProvider *gclLogsProvider) createGclLogSink(projectId, nsName, sinkName, topicName string) (*gcl.LogSink, error) { projectDst := fmt.Sprintf("projects/%s", projectId) - filter := fmt.Sprintf("resource.labels.namespace_id=%s AND resource.labels.container_name=%s", nsName, loggingContainerName) + filter := fmt.Sprintf("(resource.type=\"gke_cluster\" AND jsonPayload.kind=\"Event\" AND jsonPayload.metadata.namespace=\"%s\") OR "+ + "(resource.type=\"container\" AND resource.labels.namespace_id=\"%s\")", nsName, nsName) + framework.Logf("Using the following filter for entries: %s", filter) sink := &gcl.LogSink{ Name: sinkName, Destination: fmt.Sprintf("pubsub.googleapis.com/%s", topicName), @@ -196,9 +200,30 @@ func (gclLogsProvider *gclLogsProvider) pollLogs() { continue } - podName := gclLogEntry.Resource.Labels["pod_id"] - ch := gclLogsProvider.getCacheChannel(podName) - ch <- logEntry{Payload: gclLogEntry.TextPayload} + switch gclLogEntry.Resource.Type { + case "container": + podName := gclLogEntry.Resource.Labels["pod_id"] + ch := gclLogsProvider.getCacheChannel(podName) + ch <- logEntry{Payload: gclLogEntry.TextPayload} + break + case "gke_cluster": + jsonPayloadRaw, err := gclLogEntry.JsonPayload.MarshalJSON() + if err != nil { + framework.Logf("Failed to get jsonPayload from LogEntry %v", gclLogEntry) + break + } + var eventObject map[string]interface{} + err = json.Unmarshal(jsonPayloadRaw, &eventObject) + if err != nil { + framework.Logf("Failed to deserialize jsonPayload as json object %s", string(jsonPayloadRaw[:])) + break + } + gclLogsProvider.EventCache <- eventObject + break + default: + framework.Logf("Received LogEntry with unexpected resource type: %s", gclLogEntry.Resource.Type) + break + } } if len(ids) > 0 { @@ -258,6 +283,20 @@ func (logsProvider *gclLogsProvider) FluentdApplicationName() string { return "fluentd-gcp" } +func (gclLogsProvider *gclLogsProvider) ReadEvents() []map[string]interface{} { + var events []map[string]interface{} +polling_loop: + for { + select { + case event := <-gclLogsProvider.EventCache: + events = append(events, event) + default: + break polling_loop + } + } + return events +} + func (gclLogsProvider *gclLogsProvider) getCacheChannel(podName string) chan logEntry { gclLogsProvider.CacheMutex.Lock() defer gclLogsProvider.CacheMutex.Unlock() @@ -266,7 +305,7 @@ func (gclLogsProvider *gclLogsProvider) getCacheChannel(podName string) chan log return ch } - newCh := make(chan logEntry, maxCachedMessagesPerPod) + newCh := make(chan logEntry, maxCacheSize) gclLogsProvider.LogEntryCache[podName] = newCh return newCh } diff --git a/vendor/k8s.io/kubernetes/test/e2e/cronjob.go b/vendor/k8s.io/kubernetes/test/e2e/cronjob.go index 8afbcecb6d..3675ee3ae5 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/cronjob.go +++ b/vendor/k8s.io/kubernetes/test/e2e/cronjob.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/job" "k8s.io/kubernetes/pkg/kubectl" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/test/e2e/framework" ) @@ -47,6 +48,7 @@ const ( var ( CronJobGroupVersionResource = schema.GroupVersionResource{Group: batchv2alpha1.GroupName, Version: "v2alpha1", Resource: "cronjobs"} ScheduledJobGroupVersionResource = schema.GroupVersionResource{Group: batchv2alpha1.GroupName, Version: "v2alpha1", Resource: "scheduledjobs"} + removedScheduledJobsVersion = utilversion.MustParseSemantic("v1.8.0") ) var _ = framework.KubeDescribe("CronJob", func() { @@ -63,6 +65,7 @@ var _ = framework.KubeDescribe("CronJob", func() { // multiple jobs running at once It("should schedule multiple jobs concurrently", func() { + framework.SkipUnlessServerVersionLT(removedScheduledJobsVersion, f.ClientSet.Discovery()) By("Creating a cronjob") cronJob := newTestCronJob("concurrent", "*/1 * * * ?", batchv2alpha1.AllowConcurrent, sleepCommand, nil) diff --git a/vendor/k8s.io/kubernetes/test/e2e/e2e.go b/vendor/k8s.io/kubernetes/test/e2e/e2e.go index ee8d7fa76b..123d2c25f7 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/e2e.go +++ b/vendor/k8s.io/kubernetes/test/e2e/e2e.go @@ -122,6 +122,11 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { framework.Failf("Failed to setup provider config: %v", err) } + switch framework.TestContext.Provider { + case "gce", "gke": + framework.LogClusterImageSources() + } + c, err := framework.LoadClientset() if err != nil { glog.Fatal("Error loading client: ", err) diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/firewall_util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/firewall_util.go index 2de5860777..dfca1e4f91 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/firewall_util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/firewall_util.go @@ -154,7 +154,7 @@ func GetClusterName(instancePrefix string) string { // Warning: this MUST be consistent with the CLUSTER_IP_RANGE set in // gce/config-test.sh. func GetClusterIpRange() string { - return "10.100.0.0/14" + return "10.64.0.0/14" } // GetE2eFirewalls returns all firewall rules we create for an e2e cluster. diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/google_compute.go b/vendor/k8s.io/kubernetes/test/e2e/framework/google_compute.go index 726726b397..19f3cc5b71 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/google_compute.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/google_compute.go @@ -17,8 +17,11 @@ limitations under the License. package framework import ( + "encoding/json" "fmt" + "io/ioutil" "os/exec" + "path/filepath" "regexp" "strings" "time" @@ -96,3 +99,100 @@ func DeleteGCEStaticIP(name string) error { } return nil } + +// Returns master & node image string, or error +func lookupClusterImageSources() (string, string, error) { + // Given args for a gcloud compute command, run it with other args, and return the values, + // whether separated by newlines, commas or semicolons. + gcloudf := func(argv ...string) ([]string, error) { + args := []string{"compute"} + args = append(args, argv...) + args = append(args, "--project", TestContext.CloudConfig.ProjectID, + "--zone", TestContext.CloudConfig.Zone) + outputBytes, err := exec.Command("gcloud", args...).CombinedOutput() + str := strings.Replace(string(outputBytes), ",", "\n", -1) + str = strings.Replace(str, ";", "\n", -1) + lines := strings.Split(str, "\n") + if err != nil { + Logf("lookupDiskImageSources: gcloud error with [%#v]; err:%v", argv, err) + for _, l := range lines { + Logf(" > %s", l) + } + } + return lines, err + } + + // Given a GCE instance, look through its disks, finding one that has a sourceImage + host2image := func(instance string) (string, error) { + // gcloud compute instances describe {INSTANCE} --format="get(disks[].source)" + // gcloud compute disks describe {DISKURL} --format="get(sourceImage)" + disks, err := gcloudf("instances", "describe", instance, "--format=get(disks[].source)") + if err != nil { + return "", err + } else if len(disks) == 0 { + return "", fmt.Errorf("instance %q had no findable disks", instance) + } + // Loop over disks, looking for the boot disk + for _, disk := range disks { + lines, err := gcloudf("disks", "describe", disk, "--format=get(sourceImage)") + if err != nil { + return "", err + } else if len(lines) > 0 && lines[0] != "" { + return lines[0], nil // break, we're done + } + } + return "", fmt.Errorf("instance %q had no disk with a sourceImage", instance) + } + + // gcloud compute instance-groups list-instances {GROUPNAME} --format="get(instance)" + nodeName := "" + instGroupName := strings.Split(TestContext.CloudConfig.NodeInstanceGroup, ",")[0] + if lines, err := gcloudf("instance-groups", "list-instances", instGroupName, "--format=get(instance)"); err != nil { + return "", "", err + } else if len(lines) == 0 { + return "", "", fmt.Errorf("no instances inside instance-group %q", instGroupName) + } else { + nodeName = lines[0] + } + + nodeImg, err := host2image(nodeName) + if err != nil { + return "", "", err + } + frags := strings.Split(nodeImg, "/") + nodeImg = frags[len(frags)-1] + + // For GKE clusters, MasterName will not be defined; we just leave masterImg blank. + masterImg := "" + if masterName := TestContext.CloudConfig.MasterName; masterName != "" { + img, err := host2image(masterName) + if err != nil { + return "", "", err + } + frags = strings.Split(img, "/") + masterImg = frags[len(frags)-1] + } + + return masterImg, nodeImg, nil +} + +func LogClusterImageSources() { + masterImg, nodeImg, err := lookupClusterImageSources() + if err != nil { + Logf("Cluster image sources lookup failed: %v\n", err) + return + } + Logf("cluster-master-image: %s", masterImg) + Logf("cluster-node-image: %s", nodeImg) + + images := map[string]string{ + "master_os_image": masterImg, + "node_os_image": nodeImg, + } + + outputBytes, _ := json.MarshalIndent(images, "", " ") + filePath := filepath.Join(TestContext.ReportDir, "images.json") + if err := ioutil.WriteFile(filePath, outputBytes, 0644); err != nil { + Logf("cluster images sources, could not write to %q: %v", filePath, err) + } +} diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/ingress_utils.go b/vendor/k8s.io/kubernetes/test/e2e/framework/ingress_utils.go index 6d6969cd8d..f6e17ce2c8 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/ingress_utils.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/ingress_utils.go @@ -718,8 +718,7 @@ func (cont *GCEIngressController) Init() { func (cont *GCEIngressController) CreateStaticIP(name string) string { gceCloud := cont.Cloud.Provider.(*gcecloud.GCECloud) addr := &compute.Address{Name: name} - ip, err := gceCloud.ReserveGlobalAddress(addr) - if err != nil { + if err := gceCloud.ReserveGlobalAddress(addr); err != nil { if delErr := gceCloud.DeleteGlobalAddress(name); delErr != nil { if cont.isHTTPErrorCode(delErr, http.StatusNotFound) { Logf("Static ip with name %v was not allocated, nothing to delete", name) @@ -727,8 +726,14 @@ func (cont *GCEIngressController) CreateStaticIP(name string) string { Logf("Failed to delete static ip %v: %v", name, delErr) } } - Failf("Failed to allocated static ip %v: %v", name, err) + Failf("Failed to allocate static ip %v: %v", name, err) + } + + ip, err := gceCloud.GetGlobalAddress(name) + if err != nil { + Failf("Failed to get newly created static ip %v: %v", name, err) } + cont.staticIPName = ip.Name Logf("Reserved static ip %v: %v", cont.staticIPName, ip.Address) return ip.Address @@ -761,7 +766,7 @@ func gcloudComputeResourceList(resource, regex, project string, out interface{}) // so we only look at stdout. command := []string{ "compute", resource, "list", - fmt.Sprintf("--regexp=%q", regex), + fmt.Sprintf("--filter='name ~ \"%q\"'", regex), fmt.Sprintf("--project=%v", project), "-q", "--format=json", } @@ -883,9 +888,12 @@ func (j *IngressTestJig) GetRootCA(secretName string) (rootCA []byte) { return } -// DeleteIngress deletes the ingress resource -func (j *IngressTestJig) DeleteIngress() { - ExpectNoError(j.Client.Extensions().Ingresses(j.Ingress.Namespace).Delete(j.Ingress.Name, nil)) +// TryDeleteIngress attempts to delete the ingress resource and logs errors if they occur. +func (j *IngressTestJig) TryDeleteIngress() { + err := j.Client.Extensions().Ingresses(j.Ingress.Namespace).Delete(j.Ingress.Name, nil) + if err != nil { + Logf("Error while deleting the ingress %v/%v: %v", j.Ingress.Namespace, j.Ingress.Name, err) + } } // WaitForIngress waits till the ingress acquires an IP, then waits for its diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/pv_util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/pv_util.go index 950c36ea4d..5866875ebc 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/pv_util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/pv_util.go @@ -716,16 +716,21 @@ func createPD(zone string) (string, error) { } else if TestContext.Provider == "azure" { pdName := fmt.Sprintf("%s-%s", TestContext.Prefix, string(uuid.NewUUID())) azureCloud, err := GetAzureCloud() + if err != nil { return "", err } - _, diskUri, _, err := azureCloud.CreateVolume(pdName, "" /* account */, "" /* sku */, "" /* location */, 1 /* sizeGb */) + if azureCloud.BlobDiskController == nil { + return "", fmt.Errorf("BlobDiskController is nil, it's not expected.") + } + + diskUri, err := azureCloud.BlobDiskController.CreateBlobDisk(pdName, "standard_lrs", 1, false) if err != nil { return "", err } - return diskUri, nil + return diskUri, nil } else { return "", fmt.Errorf("provider does not support volume creation") } @@ -770,8 +775,11 @@ func deletePD(pdName string) error { if err != nil { return err } + if azureCloud.BlobDiskController == nil { + return fmt.Errorf("BlobDiskController is nil, it's not expected.") + } diskName := pdName[(strings.LastIndex(pdName, "/") + 1):] - err = azureCloud.DeleteVolume(diskName, pdName) + err = azureCloud.BlobDiskController.DeleteBlobDisk(diskName, false) if err != nil { Logf("failed to delete Azure volume %q: %v", pdName, err) return err diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/service_util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/service_util.go index d79672abf3..23d7c75c7d 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/service_util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/service_util.go @@ -38,6 +38,8 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/retry" + azurecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/azure" + gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" testutils "k8s.io/kubernetes/test/utils" . "github.com/onsi/ginkgo" @@ -1326,3 +1328,29 @@ func DescribeSvc(ns string) { "describe", "svc", fmt.Sprintf("--namespace=%v", ns)) Logf(desc) } + +// EnableAndDisableInternalLB returns two functions for enabling and disabling the internal load balancer +// setting for the supported cloud providers: GCE/GKE and Azure +func EnableAndDisableInternalLB() (enable func(svc *v1.Service), disable func(svc *v1.Service)) { + enable = func(svc *v1.Service) {} + disable = func(svc *v1.Service) {} + + switch TestContext.Provider { + case "gce", "gke": + enable = func(svc *v1.Service) { + svc.ObjectMeta.Annotations = map[string]string{gcecloud.ServiceAnnotationLoadBalancerType: string(gcecloud.LBTypeInternal)} + } + disable = func(svc *v1.Service) { + delete(svc.ObjectMeta.Annotations, gcecloud.ServiceAnnotationLoadBalancerType) + } + case "azure": + enable = func(svc *v1.Service) { + svc.ObjectMeta.Annotations = map[string]string{azurecloud.ServiceAnnotationLoadBalancerInternal: "true"} + } + disable = func(svc *v1.Service) { + svc.ObjectMeta.Annotations = map[string]string{azurecloud.ServiceAnnotationLoadBalancerInternal: "false"} + } + } + + return +} diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/statefulset_utils.go b/vendor/k8s.io/kubernetes/test/e2e/framework/statefulset_utils.go index fc54166d72..a32f1b380c 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/statefulset_utils.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/statefulset_utils.go @@ -19,6 +19,7 @@ package framework import ( "fmt" "path/filepath" + "reflect" "regexp" "sort" "strconv" @@ -32,6 +33,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" utilyaml "k8s.io/apimachinery/pkg/util/yaml" @@ -147,7 +149,7 @@ func (s *StatefulSetTester) CheckMount(ss *apps.StatefulSet, mountPath string) e func (s *StatefulSetTester) ExecInStatefulPods(ss *apps.StatefulSet, cmd string) error { podList := s.GetPodList(ss) for _, statefulPod := range podList.Items { - stdout, err := RunHostCmd(statefulPod.Namespace, statefulPod.Name, cmd) + stdout, err := RunHostCmdWithRetries(statefulPod.Namespace, statefulPod.Name, cmd, StatefulSetPoll, StatefulPodTimeout) Logf("stdout of %v on %v: %v", cmd, statefulPod.Name, stdout) if err != nil { return err @@ -161,7 +163,7 @@ func (s *StatefulSetTester) CheckHostname(ss *apps.StatefulSet) error { cmd := "printf $(hostname)" podList := s.GetPodList(ss) for _, statefulPod := range podList.Items { - hostname, err := RunHostCmd(statefulPod.Namespace, statefulPod.Name, cmd) + hostname, err := RunHostCmdWithRetries(statefulPod.Namespace, statefulPod.Name, cmd, StatefulSetPoll, StatefulPodTimeout) if err != nil { return err } @@ -176,10 +178,10 @@ func (s *StatefulSetTester) CheckHostname(ss *apps.StatefulSet) error { func (s *StatefulSetTester) Saturate(ss *apps.StatefulSet) { var i int32 for i = 0; i < *(ss.Spec.Replicas); i++ { - Logf("Waiting for stateful pod at index " + fmt.Sprintf("%v", i+1) + " to enter Running") - s.WaitForRunningAndReady(i+1, ss) - Logf("Marking stateful pod at index " + fmt.Sprintf("%v", i) + " healthy") - s.SetHealthy(ss) + Logf("Waiting for stateful pod at index %v to enter Running", i) + s.WaitForRunning(i+1, i, ss) + Logf("Resuming stateful pod at index %v", i) + s.ResumeNextPod(ss) } } @@ -210,10 +212,12 @@ func getStatefulSetPodNameAtIndex(index int, ss *apps.StatefulSet) string { } // Scale scales ss to count replicas. -func (s *StatefulSetTester) Scale(ss *apps.StatefulSet, count int32) error { +func (s *StatefulSetTester) Scale(ss *apps.StatefulSet, count int32) (*apps.StatefulSet, error) { name := ss.Name ns := ss.Namespace - s.update(ns, name, func(ss *apps.StatefulSet) { *(ss.Spec.Replicas) = count }) + + Logf("Scaling statefulset %s to %d", name, count) + ss = s.update(ns, name, func(ss *apps.StatefulSet) { *(ss.Spec.Replicas) = count }) var statefulPodList *v1.PodList pollErr := wait.PollImmediate(StatefulSetPoll, StatefulSetTimeout, func() (bool, error) { @@ -231,9 +235,9 @@ func (s *StatefulSetTester) Scale(ss *apps.StatefulSet, count int32) error { unhealthy = append(unhealthy, fmt.Sprintf("%v: deletion %v, phase %v, readiness %v", statefulPod.Name, delTs, phase, readiness)) } } - return fmt.Errorf("Failed to scale statefulset to %d in %v. Remaining pods:\n%v", count, StatefulSetTimeout, unhealthy) + return ss, fmt.Errorf("Failed to scale statefulset to %d in %v. Remaining pods:\n%v", count, StatefulSetTimeout, unhealthy) } - return nil + return ss, nil } // UpdateReplicas updates the replicas of ss to count. @@ -244,11 +248,16 @@ func (s *StatefulSetTester) UpdateReplicas(ss *apps.StatefulSet, count int32) { // Restart scales ss to 0 and then back to its previous number of replicas. func (s *StatefulSetTester) Restart(ss *apps.StatefulSet) { oldReplicas := *(ss.Spec.Replicas) - ExpectNoError(s.Scale(ss, 0)) + ss, err := s.Scale(ss, 0) + ExpectNoError(err) + // Wait for controller to report the desired number of Pods. + // This way we know the controller has observed all Pod deletions + // before we scale it back up. + s.WaitForStatusReplicas(ss, 0) s.update(ss.Namespace, ss.Name, func(ss *apps.StatefulSet) { *(ss.Spec.Replicas) = oldReplicas }) } -func (s *StatefulSetTester) update(ns, name string, update func(ss *apps.StatefulSet)) { +func (s *StatefulSetTester) update(ns, name string, update func(ss *apps.StatefulSet)) *apps.StatefulSet { for i := 0; i < 3; i++ { ss, err := s.c.Apps().StatefulSets(ns).Get(name, metav1.GetOptions{}) if err != nil { @@ -257,13 +266,14 @@ func (s *StatefulSetTester) update(ns, name string, update func(ss *apps.Statefu update(ss) ss, err = s.c.Apps().StatefulSets(ns).Update(ss) if err == nil { - return + return ss } if !apierrs.IsConflict(err) && !apierrs.IsServerTimeout(err) { Failf("failed to update statefulset %q: %v", name, err) } } Failf("too many retries draining statefulset %q", name) + return nil } // GetPodList gets the current Pods in ss. @@ -298,18 +308,22 @@ func (s *StatefulSetTester) ConfirmStatefulPodCount(count int, ss *apps.Stateful } } -func (s *StatefulSetTester) waitForRunning(numStatefulPods int32, ss *apps.StatefulSet, shouldBeReady bool) { +// WaitForRunning waits for numPodsRunning in ss to be Running and for the first +// numPodsReady ordinals to be Ready. +func (s *StatefulSetTester) WaitForRunning(numPodsRunning, numPodsReady int32, ss *apps.StatefulSet) { pollErr := wait.PollImmediate(StatefulSetPoll, StatefulSetTimeout, func() (bool, error) { podList := s.GetPodList(ss) - if int32(len(podList.Items)) < numStatefulPods { - Logf("Found %d stateful pods, waiting for %d", len(podList.Items), numStatefulPods) + s.SortStatefulPods(podList) + if int32(len(podList.Items)) < numPodsRunning { + Logf("Found %d stateful pods, waiting for %d", len(podList.Items), numPodsRunning) return false, nil } - if int32(len(podList.Items)) > numStatefulPods { - return false, fmt.Errorf("Too many pods scheduled, expected %d got %d", numStatefulPods, len(podList.Items)) + if int32(len(podList.Items)) > numPodsRunning { + return false, fmt.Errorf("Too many pods scheduled, expected %d got %d", numPodsRunning, len(podList.Items)) } for _, p := range podList.Items { + shouldBeReady := getStatefulPodOrdinal(&p) < int(numPodsReady) isReady := podutil.IsPodReady(&p) desiredReadiness := shouldBeReady == isReady Logf("Waiting for pod %v to enter %v - Ready=%v, currently %v - Ready=%v", p.Name, v1.PodRunning, shouldBeReady, p.Status.Phase, isReady) @@ -355,7 +369,7 @@ func (s *StatefulSetTester) WaitForStatus(set *apps.StatefulSet) *apps.StatefulS // WaitForRunningAndReady waits for numStatefulPods in ss to be Running and Ready. func (s *StatefulSetTester) WaitForRunningAndReady(numStatefulPods int32, ss *apps.StatefulSet) { - s.waitForRunning(numStatefulPods, ss, true) + s.WaitForRunning(numStatefulPods, numStatefulPods, ss) } // WaitForPodReady waits for the Pod named podName in set to exist and have a Ready condition. @@ -489,73 +503,120 @@ func (s *StatefulSetTester) WaitForPartitionedRollingUpdate(set *apps.StatefulSe // WaitForRunningAndReady waits for numStatefulPods in ss to be Running and not Ready. func (s *StatefulSetTester) WaitForRunningAndNotReady(numStatefulPods int32, ss *apps.StatefulSet) { - s.waitForRunning(numStatefulPods, ss, false) + s.WaitForRunning(numStatefulPods, 0, ss) +} + +var httpProbe = &v1.Probe{ + Handler: v1.Handler{ + HTTPGet: &v1.HTTPGetAction{ + Path: "/index.html", + Port: intstr.IntOrString{IntVal: 80}, + }, + }, + PeriodSeconds: 1, + SuccessThreshold: 1, + FailureThreshold: 1, +} + +// SetHttpProbe sets the pod template's ReadinessProbe for Nginx StatefulSet containers. +// This probe can then be controlled with BreakHttpProbe() and RestoreHttpProbe(). +// Note that this cannot be used together with PauseNewPods(). +func (s *StatefulSetTester) SetHttpProbe(ss *apps.StatefulSet) { + ss.Spec.Template.Spec.Containers[0].ReadinessProbe = httpProbe } -// BreakProbe breaks the readiness probe for Nginx StatefulSet containers in ss. -func (s *StatefulSetTester) BreakProbe(ss *apps.StatefulSet, probe *v1.Probe) error { - path := probe.HTTPGet.Path +// BreakHttpProbe breaks the readiness probe for Nginx StatefulSet containers in ss. +func (s *StatefulSetTester) BreakHttpProbe(ss *apps.StatefulSet) error { + path := httpProbe.HTTPGet.Path if path == "" { return fmt.Errorf("Path expected to be not empty: %v", path) } - cmd := fmt.Sprintf("mv -v /usr/share/nginx/html%v /tmp/", path) + // Ignore 'mv' errors to make this idempotent. + cmd := fmt.Sprintf("mv -v /usr/share/nginx/html%v /tmp/ || true", path) return s.ExecInStatefulPods(ss, cmd) } -// BreakProbe breaks the readiness probe for Nginx StatefulSet containers in pod. -func (s *StatefulSetTester) BreakPodProbe(ss *apps.StatefulSet, pod *v1.Pod, probe *v1.Probe) error { - path := probe.HTTPGet.Path +// BreakPodHttpProbe breaks the readiness probe for Nginx StatefulSet containers in one pod. +func (s *StatefulSetTester) BreakPodHttpProbe(ss *apps.StatefulSet, pod *v1.Pod) error { + path := httpProbe.HTTPGet.Path if path == "" { return fmt.Errorf("Path expected to be not empty: %v", path) } - cmd := fmt.Sprintf("mv -v /usr/share/nginx/html%v /tmp/", path) - stdout, err := RunHostCmd(pod.Namespace, pod.Name, cmd) + // Ignore 'mv' errors to make this idempotent. + cmd := fmt.Sprintf("mv -v /usr/share/nginx/html%v /tmp/ || true", path) + stdout, err := RunHostCmdWithRetries(pod.Namespace, pod.Name, cmd, StatefulSetPoll, StatefulPodTimeout) Logf("stdout of %v on %v: %v", cmd, pod.Name, stdout) return err } -// RestoreProbe restores the readiness probe for Nginx StatefulSet containers in ss. -func (s *StatefulSetTester) RestoreProbe(ss *apps.StatefulSet, probe *v1.Probe) error { - path := probe.HTTPGet.Path +// RestoreHttpProbe restores the readiness probe for Nginx StatefulSet containers in ss. +func (s *StatefulSetTester) RestoreHttpProbe(ss *apps.StatefulSet) error { + path := httpProbe.HTTPGet.Path if path == "" { return fmt.Errorf("Path expected to be not empty: %v", path) } - cmd := fmt.Sprintf("mv -v /tmp%v /usr/share/nginx/html/", path) + // Ignore 'mv' errors to make this idempotent. + cmd := fmt.Sprintf("mv -v /tmp%v /usr/share/nginx/html/ || true", path) return s.ExecInStatefulPods(ss, cmd) } -// RestoreProbe restores the readiness probe for Nginx StatefulSet containers in pod. -func (s *StatefulSetTester) RestorePodProbe(ss *apps.StatefulSet, pod *v1.Pod, probe *v1.Probe) error { - path := probe.HTTPGet.Path +// RestorePodHttpProbe restores the readiness probe for Nginx StatefulSet containers in pod. +func (s *StatefulSetTester) RestorePodHttpProbe(ss *apps.StatefulSet, pod *v1.Pod) error { + path := httpProbe.HTTPGet.Path if path == "" { return fmt.Errorf("Path expected to be not empty: %v", path) } - cmd := fmt.Sprintf("mv -v /tmp%v /usr/share/nginx/html/", path) - stdout, err := RunHostCmd(pod.Namespace, pod.Name, cmd) + // Ignore 'mv' errors to make this idempotent. + cmd := fmt.Sprintf("mv -v /tmp%v /usr/share/nginx/html/ || true", path) + stdout, err := RunHostCmdWithRetries(pod.Namespace, pod.Name, cmd, StatefulSetPoll, StatefulPodTimeout) Logf("stdout of %v on %v: %v", cmd, pod.Name, stdout) return err } -// SetHealthy updates the StatefulSet InitAnnotation to true in order to set a StatefulSet Pod to be Running and Ready. -func (s *StatefulSetTester) SetHealthy(ss *apps.StatefulSet) { +var pauseProbe = &v1.Probe{ + Handler: v1.Handler{ + Exec: &v1.ExecAction{Command: []string{"test", "-f", "/data/statefulset-continue"}}, + }, + PeriodSeconds: 1, + SuccessThreshold: 1, + FailureThreshold: 1, +} + +func hasPauseProbe(pod *v1.Pod) bool { + probe := pod.Spec.Containers[0].ReadinessProbe + return probe != nil && reflect.DeepEqual(probe.Exec.Command, pauseProbe.Exec.Command) +} + +// PauseNewPods adds an always-failing ReadinessProbe to the StatefulSet PodTemplate. +// This causes all newly-created Pods to stay Unready until they are manually resumed +// with ResumeNextPod(). +// Note that this cannot be used together with SetHttpProbe(). +func (s *StatefulSetTester) PauseNewPods(ss *apps.StatefulSet) { + ss.Spec.Template.Spec.Containers[0].ReadinessProbe = pauseProbe +} + +// ResumeNextPod allows the next Pod in the StatefulSet to continue by removing the ReadinessProbe +// added by PauseNewPods(), if it's still there. +// It fails the test if it finds any pods that are not in phase Running, +// or if it finds more than one paused Pod existing at the same time. +// This is a no-op if there are no paused pods. +func (s *StatefulSetTester) ResumeNextPod(ss *apps.StatefulSet) { podList := s.GetPodList(ss) - markedHealthyPod := "" + resumedPod := "" for _, pod := range podList.Items { if pod.Status.Phase != v1.PodRunning { - Failf("Found pod in %v cannot set health", pod.Status.Phase) + Failf("Found pod in phase %q, cannot resume", pod.Status.Phase) } - if IsStatefulSetPodInitialized(pod) { + if podutil.IsPodReady(&pod) || !hasPauseProbe(&pod) { continue } - if markedHealthyPod != "" { - Failf("Found multiple non-healthy stateful pods: %v and %v", pod.Name, markedHealthyPod) + if resumedPod != "" { + Failf("Found multiple paused stateful pods: %v and %v", pod.Name, resumedPod) } - p, err := UpdatePodWithRetries(s.c, pod.Namespace, pod.Name, func(update *v1.Pod) { - update.Annotations[apps.StatefulSetInitAnnotation] = "true" - }) + _, err := RunHostCmdWithRetries(pod.Namespace, pod.Name, "touch /data/statefulset-continue; sync", StatefulSetPoll, StatefulPodTimeout) ExpectNoError(err) - Logf("Set annotation %v to %v on pod %v", apps.StatefulSetInitAnnotation, p.Annotations[apps.StatefulSetInitAnnotation], pod.Name) - markedHealthyPod = pod.Name + Logf("Resumed pod %v", pod.Name) + resumedPod = pod.Name } } @@ -635,12 +696,13 @@ func DeleteAllStatefulSets(c clientset.Interface, ns string) { // Scale down each statefulset, then delete it completely. // Deleting a pvc without doing this will leak volumes, #25101. errList := []string{} - for _, ss := range ssList.Items { - Logf("Scaling statefulset %v to 0", ss.Name) - if err := sst.Scale(&ss, 0); err != nil { + for i := range ssList.Items { + ss := &ssList.Items[i] + var err error + if ss, err = sst.Scale(ss, 0); err != nil { errList = append(errList, fmt.Sprintf("%v", err)) } - sst.WaitForStatusReplicas(&ss, 0) + sst.WaitForStatusReplicas(ss, 0) Logf("Deleting statefulset %v", ss.Name) // Use OrphanDependents=false so it's deleted synchronously. // We already made sure the Pods are gone inside Scale(). @@ -698,19 +760,6 @@ func DeleteAllStatefulSets(c clientset.Interface, ns string) { } } -// IsStatefulSetPodInitialized returns true if pod's StatefulSetInitAnnotation exists and is set to true. -func IsStatefulSetPodInitialized(pod v1.Pod) bool { - initialized, ok := pod.Annotations[apps.StatefulSetInitAnnotation] - if !ok { - return false - } - inited, err := strconv.ParseBool(initialized) - if err != nil { - Failf("Couldn't parse statefulset init annotations %v", initialized) - } - return inited -} - // NewStatefulSetPVC returns a PersistentVolumeClaim named name, for testing StatefulSets. func NewStatefulSetPVC(name string) v1.PersistentVolumeClaim { return v1.PersistentVolumeClaim{ @@ -792,11 +841,6 @@ func NewStatefulSet(name, ns, governingSvcName string, replicas int32, statefulP } } -// SetStatefulSetInitializedAnnotation sets teh StatefulSetInitAnnotation to value. -func SetStatefulSetInitializedAnnotation(ss *apps.StatefulSet, value string) { - ss.Spec.Template.ObjectMeta.Annotations["pod.alpha.kubernetes.io/initialized"] = value -} - var statefulPodRegex = regexp.MustCompile("(.*)-([0-9]+)$") func getStatefulPodOrdinal(pod *v1.Pod) int { diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go b/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go index 07ed74b282..eb2cfdd3dd 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go @@ -130,6 +130,10 @@ type NodeTestContextType struct { PrepullImages bool // KubeletConfig is the kubelet configuration the test is running against. KubeletConfig componentconfig.KubeletConfiguration + // SystemSpecName is the name of the system spec (e.g., gke) that's used in + // the node e2e test. If empty, the default one (system.DefaultSpec) is + // used. The system specs are in test/e2e_node/system/specs/. + SystemSpecName string } type CloudConfig struct { @@ -240,6 +244,7 @@ func RegisterNodeFlags() { // It is hard and unnecessary to deal with the complexity inside the test suite. flag.BoolVar(&TestContext.NodeConformance, "conformance", false, "If true, the test suite will not start kubelet, and fetch system log (kernel, docker, kubelet log etc.) to the report directory.") flag.BoolVar(&TestContext.PrepullImages, "prepull-images", true, "If true, prepull images so image pull failures do not cause test failures.") + flag.StringVar(&TestContext.SystemSpecName, "system-spec-name", "", "The name of the system spec (e.g., gke) that's used in the node e2e test. The system specs are in test/e2e_node/system/specs/. This is used by the test framework to determine which tests to run for validating the system requirements.") } // ViperizeFlags sets up all flag and config processing. Future configuration info should be added to viper, not to flags. diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/util.go index c44f2fad79..1f1073f867 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/util.go @@ -353,6 +353,24 @@ func SkipIfContainerRuntimeIs(runtimes ...string) { } } +func RunIfContainerRuntimeIs(runtimes ...string) { + for _, runtime := range runtimes { + if runtime == TestContext.ContainerRuntime { + return + } + } + Skipf("Skipped because container runtime %q is not in %s", TestContext.ContainerRuntime, runtimes) +} + +func RunIfSystemSpecNameIs(names ...string) { + for _, name := range names { + if name == TestContext.SystemSpecName { + return + } + } + Skipf("Skipped because system spec name %q is not in %v", TestContext.SystemSpecName, names) +} + func ProviderIs(providers ...string) bool { for _, provider := range providers { if strings.ToLower(provider) == strings.ToLower(TestContext.Provider) { @@ -410,6 +428,16 @@ func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersio } } +func SkipUnlessServerVersionLT(v *utilversion.Version, c discovery.ServerVersionInterface) { + gte, err := ServerVersionGTE(v, c) + if err != nil { + Failf("Failed to get server version: %v", err) + } + if gte { + Skipf("Not supported for server versions starting from %q", v) + } +} + func SkipIfMissingResource(clientPool dynamic.ClientPool, gvr schema.GroupVersionResource, namespace string) { dynamicClient, err := clientPool.ClientForGroupVersionResource(gvr) if err != nil { @@ -3736,6 +3764,24 @@ func RunHostCmdOrDie(ns, name, cmd string) string { return stdout } +// RunHostCmdWithRetries calls RunHostCmd and retries errors it thinks may be transient +// until it succeeds or the specified timeout expires. +// This can be used with idempotent commands to deflake transient Node issues. +func RunHostCmdWithRetries(ns, name, cmd string, interval, timeout time.Duration) (string, error) { + start := time.Now() + for { + out, err := RunHostCmd(ns, name, cmd) + if err == nil { + return out, nil + } + if elapsed := time.Since(start); elapsed > timeout { + return out, fmt.Errorf("RunHostCmd still failed after %v: %v", elapsed, err) + } + Logf("Waiting %v to retry failed RunHostCmd: %v", interval, err) + time.Sleep(interval) + } +} + // LaunchHostExecPod launches a hostexec pod in the given namespace and waits // until it's Running func LaunchHostExecPod(client clientset.Interface, ns, name string) *v1.Pod { @@ -4886,17 +4932,17 @@ func CheckConnectivityToHost(f *Framework, nodeName, podName, host string, timeo } // CoreDump SSHs to the master and all nodes and dumps their logs into dir. -// It shells out to cluster/log-dump.sh to accomplish this. +// It shells out to cluster/log-dump/log-dump.sh to accomplish this. func CoreDump(dir string) { if TestContext.DisableLogDump { Logf("Skipping dumping logs from cluster") return } - cmd := exec.Command(path.Join(TestContext.RepoRoot, "cluster", "log-dump.sh"), dir) + cmd := exec.Command(path.Join(TestContext.RepoRoot, "cluster", "log-dump", "log-dump.sh"), dir) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - Logf("Error running cluster/log-dump.sh: %v", err) + Logf("Error running cluster/log-dump/log-dump.sh: %v", err) } } diff --git a/vendor/k8s.io/kubernetes/test/e2e/ingress.go b/vendor/k8s.io/kubernetes/test/e2e/ingress.go index 2b3914a60b..a28bf38282 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/ingress.go +++ b/vendor/k8s.io/kubernetes/test/e2e/ingress.go @@ -87,7 +87,7 @@ var _ = framework.KubeDescribe("Loadbalancing: L7", func() { return } By("Deleting ingress") - jig.DeleteIngress() + jig.TryDeleteIngress() By("Cleaning up cloud resources") framework.CleanupGCEIngressController(gceController) @@ -177,7 +177,7 @@ var _ = framework.KubeDescribe("Loadbalancing: L7", func() { return } By("Deleting ingress") - jig.DeleteIngress() + jig.TryDeleteIngress() }) It("should conform to Ingress spec", func() { diff --git a/vendor/k8s.io/kubernetes/test/e2e/kubectl.go b/vendor/k8s.io/kubernetes/test/e2e/kubectl.go index 9e0f6f6a4c..731606adaa 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/kubectl.go +++ b/vendor/k8s.io/kubernetes/test/e2e/kubectl.go @@ -191,44 +191,6 @@ var _ = framework.KubeDescribe("Kubectl alpha client", func() { // Customized Wait / ForEach wrapper for this test. These demonstrate the - framework.KubeDescribe("Kubectl run ScheduledJob", func() { - var nsFlag string - var sjName string - - BeforeEach(func() { - nsFlag = fmt.Sprintf("--namespace=%v", ns) - sjName = "e2e-test-echo-scheduledjob" - }) - - AfterEach(func() { - framework.RunKubectlOrDie("delete", "cronjobs", sjName, nsFlag) - }) - - It("should create a ScheduledJob", func() { - framework.SkipIfMissingResource(f.ClientPool, ScheduledJobGroupVersionResource, f.Namespace.Name) - - schedule := "*/5 * * * ?" - framework.RunKubectlOrDie("run", sjName, "--restart=OnFailure", "--generator=scheduledjob/v2alpha1", - "--schedule="+schedule, "--image="+busyboxImage, nsFlag) - By("verifying the ScheduledJob " + sjName + " was created") - sj, err := c.BatchV2alpha1().CronJobs(ns).Get(sjName, metav1.GetOptions{}) - if err != nil { - framework.Failf("Failed getting ScheduledJob %s: %v", sjName, err) - } - if sj.Spec.Schedule != schedule { - framework.Failf("Failed creating a ScheduledJob with correct schedule %s, but got %s", schedule, sj.Spec.Schedule) - } - containers := sj.Spec.JobTemplate.Spec.Template.Spec.Containers - if containers == nil || len(containers) != 1 || containers[0].Image != busyboxImage { - framework.Failf("Failed creating ScheduledJob %s for 1 pod with expected image %s: %#v", sjName, busyboxImage, containers) - } - restartPolicy := sj.Spec.JobTemplate.Spec.Template.Spec.RestartPolicy - if sj.Spec.JobTemplate.Spec.Template.Spec.RestartPolicy != v1.RestartPolicyOnFailure { - framework.Failf("Failed creating a ScheduledJob with correct restart policy %s, but got %s", v1.RestartPolicyOnFailure, restartPolicy) - } - }) - }) - framework.KubeDescribe("Kubectl run CronJob", func() { var nsFlag string var cjName string diff --git a/vendor/k8s.io/kubernetes/test/e2e/service.go b/vendor/k8s.io/kubernetes/test/e2e/service.go index f9284a4786..4ca3b69bac 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/service.go +++ b/vendor/k8s.io/kubernetes/test/e2e/service.go @@ -1242,29 +1242,31 @@ var _ = framework.KubeDescribe("Services", func() { framework.CheckReachabilityFromPod(true, normalReachabilityTimeout, namespace, dropPodName, svcIP) }) - It("should be able to create an internal type load balancer on Azure [Slow]", func() { - framework.SkipUnlessProviderIs("azure") + It("should be able to create an internal type load balancer [Slow]", func() { + framework.SkipUnlessProviderIs("azure", "gke", "gce") createTimeout := framework.LoadBalancerCreateTimeoutDefault pollInterval := framework.Poll * 10 - serviceAnnotationLoadBalancerInternal := "service.beta.kubernetes.io/azure-load-balancer-internal" namespace := f.Namespace.Name serviceName := "lb-internal" jig := framework.NewServiceTestJig(cs, serviceName) + By("creating pod to be part of service " + serviceName) + jig.RunOrFail(namespace, nil) + + enableILB, disableILB := framework.EnableAndDisableInternalLB() + isInternalEndpoint := func(lbIngress *v1.LoadBalancerIngress) bool { ingressEndpoint := framework.GetIngressPoint(lbIngress) // Needs update for providers using hostname as endpoint. return strings.HasPrefix(ingressEndpoint, "10.") } - By("creating a service with type LoadBalancer and LoadBalancerInternal annotation set to true") + By("creating a service with type LoadBalancer and cloud specific Internal-LB annotation enabled") svc := jig.CreateTCPServiceOrFail(namespace, func(svc *v1.Service) { svc.Spec.Type = v1.ServiceTypeLoadBalancer - svc.ObjectMeta.Annotations = map[string]string{ - serviceAnnotationLoadBalancerInternal: "true", - } + enableILB(svc) }) svc = jig.WaitForLoadBalancerOrFail(namespace, serviceName, createTimeout) jig.SanityCheckService(svc, v1.ServiceTypeLoadBalancer) @@ -1272,9 +1274,9 @@ var _ = framework.KubeDescribe("Services", func() { // should have an internal IP. Expect(isInternalEndpoint(lbIngress)).To(BeTrue()) - By("switiching to external type LoadBalancer") + By("switching to external type LoadBalancer") svc = jig.UpdateServiceOrFail(namespace, serviceName, func(svc *v1.Service) { - svc.ObjectMeta.Annotations[serviceAnnotationLoadBalancerInternal] = "false" + disableILB(svc) }) framework.Logf("Waiting up to %v for service %q to have an external LoadBalancer", createTimeout, serviceName) if pollErr := wait.PollImmediate(pollInterval, createTimeout, func() (bool, error) { @@ -1291,26 +1293,33 @@ var _ = framework.KubeDescribe("Services", func() { jig.SanityCheckService(svc, v1.ServiceTypeLoadBalancer) Expect(isInternalEndpoint(lbIngress)).To(BeFalse()) - By("switiching back to interal type LoadBalancer, with static IP specified.") - internalStaticIP := "10.240.11.11" - svc = jig.UpdateServiceOrFail(namespace, serviceName, func(svc *v1.Service) { - svc.Spec.LoadBalancerIP = internalStaticIP - svc.ObjectMeta.Annotations[serviceAnnotationLoadBalancerInternal] = "true" - }) - framework.Logf("Waiting up to %v for service %q to have an internal LoadBalancer", createTimeout, serviceName) - if pollErr := wait.PollImmediate(pollInterval, createTimeout, func() (bool, error) { - svc, err := jig.Client.Core().Services(namespace).Get(serviceName, metav1.GetOptions{}) - if err != nil { - return false, err + // GCE cannot test a specific IP because the test may not own it. This cloud specific condition + // will be removed when GCP supports similar functionality. + if framework.ProviderIs("azure") { + By("switching back to interal type LoadBalancer, with static IP specified.") + internalStaticIP := "10.240.11.11" + svc = jig.UpdateServiceOrFail(namespace, serviceName, func(svc *v1.Service) { + svc.Spec.LoadBalancerIP = internalStaticIP + enableILB(svc) + }) + framework.Logf("Waiting up to %v for service %q to have an internal LoadBalancer", createTimeout, serviceName) + if pollErr := wait.PollImmediate(pollInterval, createTimeout, func() (bool, error) { + svc, err := jig.Client.Core().Services(namespace).Get(serviceName, metav1.GetOptions{}) + if err != nil { + return false, err + } + lbIngress = &svc.Status.LoadBalancer.Ingress[0] + return isInternalEndpoint(lbIngress), nil + }); pollErr != nil { + framework.Failf("Loadbalancer IP not changed to internal.") } - lbIngress = &svc.Status.LoadBalancer.Ingress[0] - return isInternalEndpoint(lbIngress), nil - }); pollErr != nil { - framework.Failf("Loadbalancer IP not changed to internal.") + // should have the given static internal IP. + jig.SanityCheckService(svc, v1.ServiceTypeLoadBalancer) + Expect(framework.GetIngressPoint(lbIngress)).To(Equal(internalStaticIP)) } - // should have the given static internal IP. - jig.SanityCheckService(svc, v1.ServiceTypeLoadBalancer) - Expect(framework.GetIngressPoint(lbIngress)).To(Equal(internalStaticIP)) + + By("switching to ClusterIP type to destroy loadbalancer") + jig.ChangeServiceType(svc.Namespace, svc.Name, v1.ServiceTypeClusterIP, createTimeout) }) }) diff --git a/vendor/k8s.io/kubernetes/test/e2e/statefulset.go b/vendor/k8s.io/kubernetes/test/e2e/statefulset.go index 36c370cdec..0763dd8e92 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/statefulset.go +++ b/vendor/k8s.io/kubernetes/test/e2e/statefulset.go @@ -27,7 +27,6 @@ import ( "k8s.io/apimachinery/pkg/labels" klabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" "k8s.io/kubernetes/pkg/api/v1" @@ -93,13 +92,12 @@ var _ = framework.KubeDescribe("StatefulSet", func() { It("should provide basic identity", func() { By("Creating statefulset " + ssName + " in namespace " + ns) *(ss.Spec.Replicas) = 3 - framework.SetStatefulSetInitializedAnnotation(ss, "false") + sst := framework.NewStatefulSetTester(c) + sst.PauseNewPods(ss) _, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) - sst := framework.NewStatefulSetTester(c) - By("Saturating stateful set " + ss.Name) sst.Saturate(ss) @@ -118,7 +116,7 @@ var _ = framework.KubeDescribe("StatefulSet", func() { By("Restarting statefulset " + ss.Name) sst.Restart(ss) - sst.Saturate(ss) + sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) By("Verifying statefulset mounted data directory is usable") framework.ExpectNoError(sst.CheckMount(ss, "/data")) @@ -131,7 +129,8 @@ var _ = framework.KubeDescribe("StatefulSet", func() { It("should adopt matching orphans and release non-matching pods", func() { By("Creating statefulset " + ssName + " in namespace " + ns) *(ss.Spec.Replicas) = 1 - framework.SetStatefulSetInitializedAnnotation(ss, "false") + sst := framework.NewStatefulSetTester(c) + sst.PauseNewPods(ss) // Replace ss with the one returned from Create() so it has the UID. // Save Kind since it won't be populated in the returned ss. @@ -140,8 +139,6 @@ var _ = framework.KubeDescribe("StatefulSet", func() { Expect(err).NotTo(HaveOccurred()) ss.Kind = kind - sst := framework.NewStatefulSetTester(c) - By("Saturating stateful set " + ss.Name) sst.Saturate(ss) pods := sst.GetPodList(ss) @@ -215,20 +212,19 @@ var _ = framework.KubeDescribe("StatefulSet", func() { It("should not deadlock when a pod's predecessor fails", func() { By("Creating statefulset " + ssName + " in namespace " + ns) *(ss.Spec.Replicas) = 2 - framework.SetStatefulSetInitializedAnnotation(ss, "false") + sst := framework.NewStatefulSetTester(c) + sst.PauseNewPods(ss) _, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) - sst := framework.NewStatefulSetTester(c) - - sst.WaitForRunningAndReady(1, ss) + sst.WaitForRunning(1, 0, ss) - By("Marking stateful pod at index 0 as healthy.") - sst.SetHealthy(ss) + By("Resuming stateful pod at index 0.") + sst.ResumeNextPod(ss) By("Waiting for stateful pod at index 1 to enter running.") - sst.WaitForRunningAndReady(2, ss) + sst.WaitForRunning(2, 1, ss) // Now we have 1 healthy and 1 unhealthy stateful pod. Deleting the healthy stateful pod should *not* // create a new stateful pod till the remaining stateful pod becomes healthy, which won't happen till @@ -238,25 +234,22 @@ var _ = framework.KubeDescribe("StatefulSet", func() { sst.DeleteStatefulPodAtIndex(0, ss) By("Confirming stateful pod at index 0 is recreated.") - sst.WaitForRunningAndReady(2, ss) + sst.WaitForRunning(2, 1, ss) - By("Deleting unhealthy stateful pod at index 1.") - sst.DeleteStatefulPodAtIndex(1, ss) + By("Resuming stateful pod at index 1.") + sst.ResumeNextPod(ss) By("Confirming all stateful pods in statefulset are created.") - sst.Saturate(ss) + sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) }) It("should perform rolling updates and roll backs of template modifications", func() { By("Creating a new StatefulSet") - testProbe := &v1.Probe{Handler: v1.Handler{HTTPGet: &v1.HTTPGetAction{ - Path: "/index.html", - Port: intstr.IntOrString{IntVal: 80}}}} ss := framework.NewStatefulSet("ss2", ns, headlessSvcName, 3, nil, nil, labels) - ss.Spec.Template.Spec.Containers[0].ReadinessProbe = testProbe + sst := framework.NewStatefulSetTester(c) + sst.SetHttpProbe(ss) ss, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) - sst := framework.NewStatefulSetTester(c) sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) ss = sst.WaitForStatus(ss) currentRevision, updateRevision := ss.Status.CurrentRevision, ss.Status.UpdateRevision @@ -273,7 +266,7 @@ var _ = framework.KubeDescribe("StatefulSet", func() { currentRevision)) } sst.SortStatefulPods(pods) - sst.BreakPodProbe(ss, &pods.Items[1], testProbe) + sst.BreakPodHttpProbe(ss, &pods.Items[1]) Expect(err).NotTo(HaveOccurred()) ss, pods = sst.WaitForPodNotReady(ss, pods.Items[1].Name) newImage := newNginxImage @@ -295,7 +288,7 @@ var _ = framework.KubeDescribe("StatefulSet", func() { By("Updating Pods in reverse ordinal order") pods = sst.GetPodList(ss) sst.SortStatefulPods(pods) - sst.RestorePodProbe(ss, &pods.Items[1], testProbe) + sst.RestorePodHttpProbe(ss, &pods.Items[1]) ss, pods = sst.WaitForPodReady(ss, pods.Items[1].Name) ss, pods = sst.WaitForRollingUpdate(ss) Expect(ss.Status.CurrentRevision).To(Equal(updateRevision), @@ -320,7 +313,7 @@ var _ = framework.KubeDescribe("StatefulSet", func() { } By("Rolling back to a previous revision") - sst.BreakPodProbe(ss, &pods.Items[1], testProbe) + sst.BreakPodHttpProbe(ss, &pods.Items[1]) Expect(err).NotTo(HaveOccurred()) ss, pods = sst.WaitForPodNotReady(ss, pods.Items[1].Name) priorRevision := currentRevision @@ -339,7 +332,7 @@ var _ = framework.KubeDescribe("StatefulSet", func() { By("Rolling back update in reverse ordinal order") pods = sst.GetPodList(ss) sst.SortStatefulPods(pods) - sst.RestorePodProbe(ss, &pods.Items[1], testProbe) + sst.RestorePodHttpProbe(ss, &pods.Items[1]) ss, pods = sst.WaitForPodReady(ss, pods.Items[1].Name) ss, pods = sst.WaitForRollingUpdate(ss) Expect(ss.Status.CurrentRevision).To(Equal(priorRevision), @@ -367,11 +360,9 @@ var _ = framework.KubeDescribe("StatefulSet", func() { It("should perform canary updates and phased rolling updates of template modifications", func() { By("Creating a new StaefulSet") - testProbe := &v1.Probe{Handler: v1.Handler{HTTPGet: &v1.HTTPGetAction{ - Path: "/index.html", - Port: intstr.IntOrString{IntVal: 80}}}} ss := framework.NewStatefulSet("ss2", ns, headlessSvcName, 3, nil, nil, labels) - ss.Spec.Template.Spec.Containers[0].ReadinessProbe = testProbe + sst := framework.NewStatefulSetTester(c) + sst.SetHttpProbe(ss) ss.Spec.UpdateStrategy = apps.StatefulSetUpdateStrategy{ Type: apps.RollingUpdateStatefulSetStrategyType, RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { @@ -384,7 +375,6 @@ var _ = framework.KubeDescribe("StatefulSet", func() { } ss, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) - sst := framework.NewStatefulSetTester(c) sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) ss = sst.WaitForStatus(ss) currentRevision, updateRevision := ss.Status.CurrentRevision, ss.Status.UpdateRevision @@ -579,17 +569,14 @@ var _ = framework.KubeDescribe("StatefulSet", func() { It("should implement legacy replacement when the update strategy is OnDelete", func() { By("Creating a new StatefulSet") - testProbe := &v1.Probe{Handler: v1.Handler{HTTPGet: &v1.HTTPGetAction{ - Path: "/index.html", - Port: intstr.IntOrString{IntVal: 80}}}} ss := framework.NewStatefulSet("ss2", ns, headlessSvcName, 3, nil, nil, labels) - ss.Spec.Template.Spec.Containers[0].ReadinessProbe = testProbe + sst := framework.NewStatefulSetTester(c) + sst.SetHttpProbe(ss) ss.Spec.UpdateStrategy = apps.StatefulSetUpdateStrategy{ Type: apps.OnDeleteStatefulSetStrategyType, } ss, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) - sst := framework.NewStatefulSetTester(c) sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) ss = sst.WaitForStatus(ss) currentRevision, updateRevision := ss.Status.CurrentRevision, ss.Status.UpdateRevision @@ -669,27 +656,24 @@ var _ = framework.KubeDescribe("StatefulSet", func() { Expect(err).NotTo(HaveOccurred()) By("Creating stateful set " + ssName + " in namespace " + ns) - testProbe := &v1.Probe{Handler: v1.Handler{HTTPGet: &v1.HTTPGetAction{ - Path: "/index.html", - Port: intstr.IntOrString{IntVal: 80}}}} ss := framework.NewStatefulSet(ssName, ns, headlessSvcName, 1, nil, nil, psLabels) - ss.Spec.Template.Spec.Containers[0].ReadinessProbe = testProbe + sst := framework.NewStatefulSetTester(c) + sst.SetHttpProbe(ss) ss, err = c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) By("Waiting until all stateful set " + ssName + " replicas will be running in namespace " + ns) - sst := framework.NewStatefulSetTester(c) sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) By("Confirming that stateful set scale up will halt with unhealthy stateful pod") - sst.BreakProbe(ss, testProbe) + sst.BreakHttpProbe(ss) sst.WaitForRunningAndNotReady(*ss.Spec.Replicas, ss) sst.WaitForStatusReadyReplicas(ss, 0) sst.UpdateReplicas(ss, 3) sst.ConfirmStatefulPodCount(1, ss, 10*time.Second, true) By("Scaling up stateful set " + ssName + " to 3 replicas and waiting until all of them will be running in namespace " + ns) - sst.RestoreProbe(ss, testProbe) + sst.RestoreHttpProbe(ss) sst.WaitForRunningAndReady(3, ss) By("Verifying that stateful set " + ssName + " was scaled up in order") @@ -713,14 +697,14 @@ var _ = framework.KubeDescribe("StatefulSet", func() { }) Expect(err).NotTo(HaveOccurred()) - sst.BreakProbe(ss, testProbe) + sst.BreakHttpProbe(ss) sst.WaitForStatusReadyReplicas(ss, 0) sst.WaitForRunningAndNotReady(3, ss) sst.UpdateReplicas(ss, 0) sst.ConfirmStatefulPodCount(3, ss, 10*time.Second, true) By("Scaling down stateful set " + ssName + " to 0 replicas and waiting until none of pods will run in namespace" + ns) - sst.RestoreProbe(ss, testProbe) + sst.RestoreHttpProbe(ss) sst.Scale(ss, 0) By("Verifying that stateful set " + ssName + " was scaled down in reverse order") @@ -743,41 +727,38 @@ var _ = framework.KubeDescribe("StatefulSet", func() { psLabels := klabels.Set(labels) By("Creating stateful set " + ssName + " in namespace " + ns) - testProbe := &v1.Probe{Handler: v1.Handler{HTTPGet: &v1.HTTPGetAction{ - Path: "/index.html", - Port: intstr.IntOrString{IntVal: 80}}}} ss := framework.NewStatefulSet(ssName, ns, headlessSvcName, 1, nil, nil, psLabels) ss.Spec.PodManagementPolicy = apps.ParallelPodManagement - ss.Spec.Template.Spec.Containers[0].ReadinessProbe = testProbe + sst := framework.NewStatefulSetTester(c) + sst.SetHttpProbe(ss) ss, err := c.Apps().StatefulSets(ns).Create(ss) Expect(err).NotTo(HaveOccurred()) By("Waiting until all stateful set " + ssName + " replicas will be running in namespace " + ns) - sst := framework.NewStatefulSetTester(c) sst.WaitForRunningAndReady(*ss.Spec.Replicas, ss) By("Confirming that stateful set scale up will not halt with unhealthy stateful pod") - sst.BreakProbe(ss, testProbe) + sst.BreakHttpProbe(ss) sst.WaitForRunningAndNotReady(*ss.Spec.Replicas, ss) sst.WaitForStatusReadyReplicas(ss, 0) sst.UpdateReplicas(ss, 3) sst.ConfirmStatefulPodCount(3, ss, 10*time.Second, false) By("Scaling up stateful set " + ssName + " to 3 replicas and waiting until all of them will be running in namespace " + ns) - sst.RestoreProbe(ss, testProbe) + sst.RestoreHttpProbe(ss) sst.WaitForRunningAndReady(3, ss) By("Scale down will not halt with unhealthy stateful pod") - sst.BreakProbe(ss, testProbe) + sst.BreakHttpProbe(ss) sst.WaitForStatusReadyReplicas(ss, 0) sst.WaitForRunningAndNotReady(3, ss) sst.UpdateReplicas(ss, 0) sst.ConfirmStatefulPodCount(0, ss, 10*time.Second, false) By("Scaling down stateful set " + ssName + " to 0 replicas and waiting until none of pods will run in namespace" + ns) - sst.RestoreProbe(ss, testProbe) + sst.RestoreHttpProbe(ss) sst.Scale(ss, 0) - sst.WaitForStatusReadyReplicas(ss, 0) + sst.WaitForStatusReplicas(ss, 0) }) It("Should recreate evicted statefulset", func() { diff --git a/vendor/k8s.io/kubernetes/test/e2e/upgrades/ingress.go b/vendor/k8s.io/kubernetes/test/e2e/upgrades/ingress.go index 1a6ace7e0d..7ca9e3b7d1 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/upgrades/ingress.go +++ b/vendor/k8s.io/kubernetes/test/e2e/upgrades/ingress.go @@ -101,7 +101,7 @@ func (t *IngressUpgradeTest) Teardown(f *framework.Framework) { } if t.jig.Ingress != nil { By("Deleting ingress") - t.jig.DeleteIngress() + t.jig.TryDeleteIngress() } else { By("No ingress created, no cleanup necessary") } diff --git a/vendor/k8s.io/kubernetes/test/e2e/upgrades/statefulset.go b/vendor/k8s.io/kubernetes/test/e2e/upgrades/statefulset.go index 7fad63d575..2fc9f335e3 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/upgrades/statefulset.go +++ b/vendor/k8s.io/kubernetes/test/e2e/upgrades/statefulset.go @@ -61,12 +61,12 @@ func (t *StatefulSetUpgradeTest) Setup(f *framework.Framework) { t.set = framework.NewStatefulSet(ssName, ns, headlessSvcName, 2, statefulPodMounts, podMounts, labels) t.service = framework.CreateStatefulSetService(ssName, labels) *(t.set.Spec.Replicas) = 3 - framework.SetStatefulSetInitializedAnnotation(t.set, "false") + t.tester = framework.NewStatefulSetTester(f.ClientSet) + t.tester.PauseNewPods(t.set) By("Creating service " + headlessSvcName + " in namespace " + ns) _, err := f.ClientSet.Core().Services(ns).Create(t.service) Expect(err).NotTo(HaveOccurred()) - t.tester = framework.NewStatefulSetTester(f.ClientSet) By("Creating statefulset " + ssName + " in namespace " + ns) *(t.set.Spec.Replicas) = 3 @@ -109,5 +109,5 @@ func (t *StatefulSetUpgradeTest) verify() { func (t *StatefulSetUpgradeTest) restart() { By("Restarting statefulset " + t.set.Name) t.tester.Restart(t.set) - t.tester.Saturate(t.set) + t.tester.WaitForRunningAndReady(*t.set.Spec.Replicas, t.set) } diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/BUILD b/vendor/k8s.io/kubernetes/test/e2e_node/BUILD index 74d508b811..e856837c88 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/BUILD +++ b/vendor/k8s.io/kubernetes/test/e2e_node/BUILD @@ -73,6 +73,7 @@ go_test( "dynamic_kubelet_configuration_test.go", "e2e_node_suite_test.go", "garbage_collector_test.go", + "gke_environment_test.go", "image_id_test.go", "inode_eviction_test.go", "kubelet_test.go", @@ -138,6 +139,7 @@ go_test( "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library", diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Dockerfile b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Dockerfile index 7424cc9e72..5783726a08 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Dockerfile +++ b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Dockerfile @@ -17,6 +17,9 @@ FROM BASEIMAGE COPY ginkgo /usr/local/bin/ COPY e2e_node.test /usr/local/bin +# This is a placeholder that will be substituted in the Makefile. +COPY_SYSTEM_SPEC_FILE + # The following environment variables can be override when starting the container. # FOCUS is regex matching test to run. By default run all conformance test. # SKIP is regex matching test to skip. By default skip flaky and serial test. @@ -39,4 +42,8 @@ ENTRYPOINT ginkgo --focus="$FOCUS" \ -- --conformance=true \ --prepull-images=false \ --report-dir="$REPORT_PATH" \ + # This is a placeholder that will be substituted in the Makefile. + --system-spec-name=SYSTEM_SPEC_NAME \ + # This is a placeholder that will be substituted in the Makefile. + --system-spec-file=SYSTEM_SPEC_FILE_PATH \ $TEST_ARGS diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Makefile b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Makefile index f726c5f363..23e8b461c5 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Makefile +++ b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/build/Makefile @@ -17,6 +17,11 @@ # Usage: # [ARCH=amd64] [REGISTRY="gcr.io/google_containers"] [BIN_DIR="../../../../_output/bin"] make (build|push) VERSION={some_version_number e.g. 0.1} +# SYSTEM_SPEC_NAME is the name of the system spec used for the node conformance +# test. The specs are expected to be in SYSTEM_SPEC_DIR. +SYSTEM_SPEC_NAME?= +SYSTEM_SPEC_DIR?=../../system/specs + # TODO(random-liu): Add this into release progress. REGISTRY?=gcr.io/google_containers ARCH?=amd64 @@ -32,6 +37,15 @@ BASEIMAGE_ppc64le=ppc64le/debian:jessie BASEIMAGE?=${BASEIMAGE_${ARCH}} +IMAGE_NAME:=${REGISTRY}/node-test +COPY_SYSTEM_SPEC_FILE= +SYSTEM_SPEC_FILE_PATH= +ifneq ($(strip $(SYSTEM_SPEC_NAME)),) + IMAGE_NAME:=${IMAGE_NAME}-${SYSTEM_SPEC_NAME} + COPY_SYSTEM_SPEC_FILE="'COPY system-spec.yaml /usr/local/etc/'" + SYSTEM_SPEC_FILE_PATH="'/usr/local/etc/system-spec.yaml'" +endif + all: build build: @@ -43,8 +57,15 @@ endif cp ${BIN_DIR}/ginkgo ${TEMP_DIR} cp ${BIN_DIR}/e2e_node.test ${TEMP_DIR} +ifneq ($(strip $(SYSTEM_SPEC_NAME)),) + cp ${SYSTEM_SPEC_DIR}/${SYSTEM_SPEC_NAME}.yaml ${TEMP_DIR}/system-spec.yaml +endif - cd ${TEMP_DIR} && sed -i.back "s|BASEIMAGE|${BASEIMAGE}|g" Dockerfile + cd ${TEMP_DIR} && sed -i.back \ + "s|BASEIMAGE|${BASEIMAGE}|g;\ + s|COPY_SYSTEM_SPEC_FILE|${COPY_SYSTEM_SPEC_FILE}|g;\ + s|SYSTEM_SPEC_NAME|${SYSTEM_SPEC_NAME}|g;\ + s|SYSTEM_SPEC_FILE_PATH|${SYSTEM_SPEC_FILE_PATH}|g" Dockerfile # Make scripts executable before they are copied into the Docker image. If we make them executable later, in another layer # they'll take up twice the space because the new executable binary differs from the old one, but everything is cached in layers. @@ -52,13 +73,13 @@ endif e2e_node.test \ ginkgo - docker build --pull -t ${REGISTRY}/node-test-${ARCH}:${VERSION} ${TEMP_DIR} + docker build --pull -t ${IMAGE_NAME}-${ARCH}:${VERSION} ${TEMP_DIR} push: build - gcloud docker -- push ${REGISTRY}/node-test-${ARCH}:${VERSION} + gcloud docker -- push ${IMAGE_NAME}-${ARCH}:${VERSION} ifeq ($(ARCH),amd64) - docker tag ${REGISTRY}/node-test-${ARCH}:${VERSION} ${REGISTRY}/node-test:${VERSION} - gcloud docker -- push ${REGISTRY}/node-test:${VERSION} + docker tag ${IMAGE_NAME}-${ARCH}:${VERSION} ${IMAGE_NAME}:${VERSION} + gcloud docker -- push ${IMAGE_NAME}:${VERSION} endif .PHONY: all diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/run_test.sh b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/run_test.sh index 3bc57d5fd5..95a1df2a35 100755 --- a/vendor/k8s.io/kubernetes/test/e2e_node/conformance/run_test.sh +++ b/vendor/k8s.io/kubernetes/test/e2e_node/conformance/run_test.sh @@ -153,7 +153,7 @@ allow_privileged=true serialize_image_pulls=false config_dir=`mktemp -d` file_check_frequency=10s -pod_cidr=10.100.0.0/24 +pod_cidr=10.64.0.0/24 log_level=4 start_kubelet --api-servers $apiserver \ --volume-stats-agg-period $volume_stats_agg_period \ diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/e2e_node_suite_test.go b/vendor/k8s.io/kubernetes/test/e2e_node/e2e_node_suite_test.go index eb7076ba02..2cc8138abe 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/e2e_node_suite_test.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/e2e_node_suite_test.go @@ -20,6 +20,7 @@ package e2e_node import ( "bytes" + "encoding/json" "flag" "fmt" "io/ioutil" @@ -32,6 +33,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilyaml "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/kubernetes/pkg/api/v1" nodeutil "k8s.io/kubernetes/pkg/api/v1/node" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" @@ -55,6 +57,7 @@ var e2es *services.E2EServices var runServicesMode = flag.Bool("run-services-mode", false, "If true, only run services (etcd, apiserver) in current process, and not run test.") var runKubeletMode = flag.Bool("run-kubelet-mode", false, "If true, only start kubelet, and not run test.") var systemValidateMode = flag.Bool("system-validate-mode", false, "If true, only run system validation in current process, and not run test.") +var systemSpecFile = flag.String("system-spec-file", "", "The name of the system spec file that will be used for node conformance test. If it's unspecified or empty, the default system spec (system.DefaultSysSpec) will be used.") func init() { framework.RegisterCommonFlags() @@ -91,6 +94,14 @@ func TestE2eNode(t *testing.T) { } if *systemValidateMode { // If system-validate-mode is specified, only run system validation in current process. + spec := &system.DefaultSysSpec + if *systemSpecFile != "" { + var err error + spec, err = loadSystemSpecFromFile(*systemSpecFile) + if err != nil { + glog.Exitf("Failed to load system spec: %v", err) + } + } if framework.TestContext.NodeConformance { // Chroot to /rootfs to make system validation can check system // as in the root filesystem. @@ -100,7 +111,7 @@ func TestE2eNode(t *testing.T) { glog.Exitf("chroot %q failed: %v", rootfs, err) } } - if _, err := system.ValidateDefault(framework.TestContext.ContainerRuntime); err != nil { + if _, err := system.ValidateSpec(*spec, framework.TestContext.ContainerRuntime); err != nil { glog.Exitf("system validation failed: %v", err) } return @@ -278,3 +289,21 @@ func getAPIServerClient() (*clientset.Clientset, error) { } return client, nil } + +// loadSystemSpecFromFile returns the system spec from the file with the +// filename. +func loadSystemSpecFromFile(filename string) (*system.SysSpec, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + data, err := utilyaml.ToJSON(b) + if err != nil { + return nil, err + } + spec := new(system.SysSpec) + if err := json.Unmarshal(data, spec); err != nil { + return nil, err + } + return spec, nil +} diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/gke_environment_test.go b/vendor/k8s.io/kubernetes/test/e2e_node/gke_environment_test.go new file mode 100644 index 0000000000..133f7647c1 --- /dev/null +++ b/vendor/k8s.io/kubernetes/test/e2e_node/gke_environment_test.go @@ -0,0 +1,412 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e_node + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "k8s.io/kubernetes/test/e2e/framework" + + . "github.com/onsi/ginkgo" +) + +// checkProcess checks whether there's a process whose command line contains +// the specified pattern and whose parent process id is ppid using the +// pre-built information in cmdToProcessMap. +func checkProcess(pattern string, ppid int, cmdToProcessMap map[string][]process) error { + for cmd, processes := range cmdToProcessMap { + if !strings.Contains(cmd, pattern) { + continue + } + for _, p := range processes { + if p.ppid == ppid { + return nil + } + } + } + return fmt.Errorf("failed to find the process whose cmdline contains %q with ppid = %d", pattern, ppid) +} + +// checkIPTables checks whether the functionality required by kube-proxy works +// in iptables. +func checkIPTables() (err error) { + cmds := [][]string{ + {"iptables", "-N", "KUBE-PORTALS-HOST", "-t", "nat"}, + {"iptables", "-I", "OUTPUT", "-t", "nat", "-m", "comment", "--comment", "ClusterIPs", "-j", "KUBE-PORTALS-HOST"}, + {"iptables", "-A", "KUBE-PORTALS-HOST", "-t", "nat", "-m", "comment", "--comment", "test-1:", "-p", "tcp", "-m", "tcp", "--dport", "443", "-d", "10.0.0.1/32", "-j", "DNAT", "--to-destination", "10.240.0.1:11111"}, + {"iptables", "-C", "KUBE-PORTALS-HOST", "-t", "nat", "-m", "comment", "--comment", "test-1:", "-p", "tcp", "-m", "tcp", "--dport", "443", "-d", "10.0.0.1/32", "-j", "DNAT", "--to-destination", "10.240.0.1:11111"}, + {"iptables", "-A", "KUBE-PORTALS-HOST", "-t", "nat", "-m", "comment", "--comment", "test-2:", "-p", "tcp", "-m", "tcp", "--dport", "80", "-d", "10.0.0.1/32", "-j", "REDIRECT", "--to-ports", "22222"}, + {"iptables", "-C", "KUBE-PORTALS-HOST", "-t", "nat", "-m", "comment", "--comment", "test-2:", "-p", "tcp", "-m", "tcp", "--dport", "80", "-d", "10.0.0.1/32", "-j", "REDIRECT", "--to-ports", "22222"}, + } + cleanupCmds := [][]string{ + {"iptables", "-F", "KUBE-PORTALS-HOST", "-t", "nat"}, + {"iptables", "-D", "OUTPUT", "-t", "nat", "-m", "comment", "--comment", "ClusterIPs", "-j", "KUBE-PORTALS-HOST"}, + {"iptables", "-X", "KUBE-PORTALS-HOST", "-t", "nat"}, + } + defer func() { + for _, cmd := range cleanupCmds { + if _, cleanupErr := runCommand(cmd...); cleanupErr != nil && err == nil { + err = cleanupErr + return + } + } + }() + for _, cmd := range cmds { + if _, err := runCommand(cmd...); err != nil { + return err + } + } + return +} + +// checkPublicGCR checks the access to the public Google Container Registry by +// pulling the busybox image. +func checkPublicGCR() error { + const image = "gcr.io/google-containers/busybox" + output, err := runCommand("docker", "images", "-q", image) + if len(output) != 0 { + if _, err := runCommand("docker", "rmi", "-f", image); err != nil { + return err + } + } + output, err = runCommand("docker", "pull", image) + if len(output) == 0 { + return fmt.Errorf("failed to pull %s", image) + } + if _, err = runCommand("docker", "rmi", "-f", image); err != nil { + return err + } + return nil +} + +// checkDockerConfig runs docker's check-config.sh script and ensures that all +// expected kernel configs are enabled. +func checkDockerConfig() error { + var ( + re = regexp.MustCompile("\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]") + bins = []string{ + "/usr/share/docker.io/contrib/check-config.sh", + "/usr/share/docker/contrib/check-config.sh", + } + whitelist = map[string]bool{ + "CONFIG_MEMCG_SWAP_ENABLED": true, + "CONFIG_RT_GROUP_SCHED": true, + "CONFIG_EXT3_FS": true, + "CONFIG_EXT3_FS_XATTR": true, + "CONFIG_EXT3_FS_POSIX_ACL": true, + "CONFIG_EXT3_FS_SECURITY": true, + "/dev/zfs": true, + "zfs command": true, + "zpool command": true, + } + missing = map[string]bool{} + ) + for _, bin := range bins { + if _, err := os.Stat(bin); os.IsNotExist(err) { + continue + } + output, err := runCommand(bin) + if err != nil { + return err + } + for _, line := range strings.Split(output, "\n") { + if !strings.Contains(line, "missing") { + continue + } + line = re.ReplaceAllString(line, "") + fields := strings.Split(line, ":") + if len(fields) != 2 { + continue + } + key := strings.TrimFunc(fields[0], func(c rune) bool { + return c == ' ' || c == '-' + }) + if _, found := whitelist[key]; !found { + missing[key] = true + } + } + if len(missing) != 0 { + return fmt.Errorf("missing docker config: %v", missing) + } + break + } + return nil +} + +// checkDockerNetworkClient checks client networking by pinging an external IP +// address from a container. +func checkDockerNetworkClient() error { + const imageName = "gcr.io/google-containers/busybox" + output, err := runCommand("docker", "run", "--rm", imageName, "sh", "-c", "ping -w 5 -q google.com") + if err != nil { + return err + } + if !strings.Contains(output, `0% packet loss`) { + return fmt.Errorf("failed to ping from container: %s", output) + } + return nil +} + +// checkDockerNetworkServer checks server networking by running an echo server +// within a container and accessing it from outside. +func checkDockerNetworkServer() error { + const ( + imageName = "gcr.io/google-containers/nginx:1.7.9" + hostAddr = "127.0.0.1" + hostPort = "8088" + containerPort = "80" + containerID = "nginx" + message = "Welcome to nginx!" + ) + var ( + portMapping = fmt.Sprintf("%s:%s", hostPort, containerPort) + host = fmt.Sprintf("http://%s:%s", hostAddr, hostPort) + ) + runCommand("docker", "rm", "-f", containerID) + if _, err := runCommand("docker", "run", "-d", "--name", containerID, "-p", portMapping, imageName); err != nil { + return err + } + output, err := runCommand("curl", host) + if err != nil { + return err + } + if !strings.Contains(output, message) { + return fmt.Errorf("failed to connect to container") + } + // Clean up + if _, err = runCommand("docker", "rm", "-f", containerID); err != nil { + return err + } + if _, err = runCommand("docker", "rmi", imageName); err != nil { + return err + } + return nil +} + +// checkDockerAppArmor checks whether AppArmor is enabled and has the +// "docker-default" profile. +func checkDockerAppArmor() error { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + if err != nil { + return err + } + if string(buf) != "Y\n" { + return fmt.Errorf("apparmor module is not loaded") + } + + // Checks that the "docker-default" profile is loaded and enforced. + buf, err = ioutil.ReadFile("/sys/kernel/security/apparmor/profiles") + if err != nil { + return err + } + if !strings.Contains(string(buf), "docker-default (enforce)") { + return fmt.Errorf("'docker-default' profile is not loaded and enforced") + } + + // Checks that the `apparmor_parser` binary is present. + _, err = exec.LookPath("apparmor_parser") + if err != nil { + return fmt.Errorf("'apparmor_parser' is not in directories named by the PATH env") + } + return nil +} + +// checkDockerSeccomp checks whether the Docker supports seccomp. +func checkDockerSeccomp() error { + const ( + seccompProfileFileName = "/tmp/no_mkdir.json" + seccompProfile = `{ + "defaultAction": "SCMP_ACT_ALLOW", + "syscalls": [ + { + "name": "mkdir", + "action": "SCMP_ACT_ERRNO" + } + ]}` + image = "gcr.io/google-appengine/debian8:2017-06-07-171918" + ) + if err := ioutil.WriteFile(seccompProfileFileName, []byte(seccompProfile), 0644); err != nil { + return err + } + // Starts a container with no seccomp profile and ensures that unshare + // succeeds. + _, err := runCommand("docker", "run", "--rm", "-i", "--security-opt", "seccomp=unconfined", image, "unshare", "-r", "whoami") + if err != nil { + return err + } + // Starts a container with the default seccomp profile and ensures that + // unshare (a blacklisted system call in the default profile) fails. + cmd := []string{"docker", "run", "--rm", "-i", image, "unshare", "-r", "whoami"} + _, err = runCommand(cmd...) + if err == nil { + return fmt.Errorf("%q did not fail as expected", strings.Join(cmd, " ")) + } + // Starts a container with a custom seccomp profile that blacklists mkdir + // and ensures that unshare succeeds. + _, err = runCommand("docker", "run", "--rm", "-i", "--security-opt", fmt.Sprintf("seccomp=%s", seccompProfileFileName), image, "unshare", "-r", "whoami") + if err != nil { + return err + } + // Starts a container with a custom seccomp profile that blacklists mkdir + // and ensures that mkdir fails. + cmd = []string{"docker", "run", "--rm", "-i", "--security-opt", fmt.Sprintf("seccomp=%s", seccompProfileFileName), image, "mkdir", "-p", "/tmp/foo"} + _, err = runCommand(cmd...) + if err == nil { + return fmt.Errorf("%q did not fail as expected", strings.Join(cmd, " ")) + } + return nil +} + +// checkDockerStorageDriver checks whether the current storage driver used by +// Docker is overlay. +func checkDockerStorageDriver() error { + output, err := runCommand("docker", "info") + if err != nil { + return err + } + for _, line := range strings.Split(string(output), "\n") { + if !strings.Contains(line, "Storage Driver:") { + continue + } + if !strings.Contains(line, "overlay") { + return fmt.Errorf("storage driver is not 'overlay': %s", line) + } + return nil + } + return fmt.Errorf("failed to find storage driver") +} + +var _ = framework.KubeDescribe("GKE system requirements [Conformance] [Feature:GKEEnv]", func() { + BeforeEach(func() { + framework.RunIfSystemSpecNameIs("gke") + }) + + It("The required processes should be running", func() { + cmdToProcessMap, err := getCmdToProcessMap() + framework.ExpectNoError(err) + for _, p := range []struct { + cmd string + ppid int + }{ + {"google_accounts_daemon", 1}, + {"google_clock_skew_daemon", 1}, + {"google_ip_forwarding_daemon", 1}, + } { + framework.ExpectNoError(checkProcess(p.cmd, p.ppid, cmdToProcessMap)) + } + }) + It("The iptable rules should work (required by kube-proxy)", func() { + framework.ExpectNoError(checkIPTables()) + }) + It("The GCR is accessible", func() { + framework.ExpectNoError(checkPublicGCR()) + }) + It("The docker configuration validation should pass", func() { + framework.RunIfContainerRuntimeIs("docker") + framework.ExpectNoError(checkDockerConfig()) + }) + It("The docker container network should work", func() { + framework.RunIfContainerRuntimeIs("docker") + framework.ExpectNoError(checkDockerNetworkServer()) + framework.ExpectNoError(checkDockerNetworkClient()) + }) + It("The docker daemon should support AppArmor and seccomp", func() { + framework.RunIfContainerRuntimeIs("docker") + framework.ExpectNoError(checkDockerAppArmor()) + framework.ExpectNoError(checkDockerSeccomp()) + }) + It("The docker storage driver should work", func() { + framework.Skipf("GKE does not currently require overlay") + framework.ExpectNoError(checkDockerStorageDriver()) + }) +}) + +// runCommand runs the cmd and returns the combined stdout and stderr, or an +// error if the command failed. +func runCommand(cmd ...string) (string, error) { + output, err := exec.Command(cmd[0], cmd[1:]...).CombinedOutput() + if err != nil { + return "", fmt.Errorf("failed to run %q: %s (%s)", strings.Join(cmd, " "), err, output) + } + return string(output), nil +} + +// getPPID returns the PPID for the pid. +func getPPID(pid int) (int, error) { + statusFile := "/proc/" + strconv.Itoa(pid) + "/status" + content, err := ioutil.ReadFile(statusFile) + if err != nil { + return 0, err + } + for _, line := range strings.Split(string(content), "\n") { + if !strings.HasPrefix(line, "PPid:") { + continue + } + s := strings.TrimSpace(strings.TrimPrefix(line, "PPid:")) + ppid, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return ppid, nil + } + return 0, fmt.Errorf("no PPid in %s", statusFile) +} + +// process contains a process ID and its parent's process ID. +type process struct { + pid int + ppid int +} + +// getCmdToProcessMap returns a mapping from the process command line to its +// process ids. +func getCmdToProcessMap() (map[string][]process, error) { + root, err := os.Open("/proc") + if err != nil { + return nil, err + } + defer root.Close() + dirs, err := root.Readdirnames(0) + if err != nil { + return nil, err + } + result := make(map[string][]process) + for _, dir := range dirs { + pid, err := strconv.Atoi(dir) + if err != nil { + continue + } + ppid, err := getPPID(pid) + if err != nil { + continue + } + content, err := ioutil.ReadFile("/proc/" + dir + "/cmdline") + if err != nil || len(content) == 0 { + continue + } + cmd := string(bytes.Replace(content, []byte("\x00"), []byte(" "), -1)) + result[cmd] = append(result[cmd], process{pid, ppid}) + } + return result, nil +} diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/conformance/conformance-jenkins.sh b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/conformance/conformance-jenkins.sh index bcf66d79cb..b4dce50776 100755 --- a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/conformance/conformance-jenkins.sh +++ b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/conformance/conformance-jenkins.sh @@ -39,4 +39,5 @@ go run test/e2e_node/runner/remote/run_remote.go conformance \ --image-config-file="$GCE_IMAGE_CONFIG_PATH" --cleanup="$CLEANUP" \ --results-dir="$ARTIFACTS" --test-timeout="$TIMEOUT" \ --test_args="--kubelet-flags=\"$KUBELET_ARGS\"" \ - --instance-metadata="$GCE_INSTANCE_METADATA" + --instance-metadata="$GCE_INSTANCE_METADATA" \ + --system-spec-name="$SYSTEM_SPEC_NAME" diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/e2e-node-jenkins.sh b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/e2e-node-jenkins.sh index fd2dbef2ff..c0f83e59e7 100755 --- a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/e2e-node-jenkins.sh +++ b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/e2e-node-jenkins.sh @@ -47,4 +47,4 @@ go run test/e2e_node/runner/remote/run_remote.go --logtostderr --vmodule=*=4 \ --image-config-file="$GCE_IMAGE_CONFIG_PATH" --cleanup="$CLEANUP" \ --results-dir="$ARTIFACTS" --ginkgo-flags="--nodes=$PARALLELISM $GINKGO_FLAGS" \ --test-timeout="$TIMEOUT" --test_args="$TEST_ARGS --kubelet-flags=\"$KUBELET_ARGS\"" \ - --instance-metadata="$GCE_INSTANCE_METADATA" + --instance-metadata="$GCE_INSTANCE_METADATA" --system-spec-name="$SYSTEM_SPEC_NAME" diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-ci-ubuntu.properties b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-ci-ubuntu.properties index be5864611b..1e0c76fa14 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-ci-ubuntu.properties +++ b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-ci-ubuntu.properties @@ -8,3 +8,5 @@ CLEANUP=true GINKGO_FLAGS='--skip="\[Flaky\]|\[Serial\]"' KUBELET_ARGS='--cgroups-per-qos=true --cgroup-root=/' TIMEOUT=1h +# Use the system spec defined in test/e2e_node/system/specs/gke.yaml. +SYSTEM_SPEC_NAME=gke diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-serial-ubuntu.properties b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-serial-ubuntu.properties index e34bffce7f..5333bb8b03 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-serial-ubuntu.properties +++ b/vendor/k8s.io/kubernetes/test/e2e_node/jenkins/jenkins-serial-ubuntu.properties @@ -10,3 +10,5 @@ TEST_ARGS='--feature-gates=DynamicKubeletConfig=true' KUBELET_ARGS='--cgroups-per-qos=true --cgroup-root=/' PARALLELISM=1 TIMEOUT=3h +# Use the system spec defined at test/e2e_node/system/specs/gke.yaml. +SYSTEM_SPEC_NAME=gke diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_allocatable_eviction_test.go b/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_allocatable_eviction_test.go index 2ae146615f..60c797c202 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_allocatable_eviction_test.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_allocatable_eviction_test.go @@ -52,8 +52,7 @@ var _ = framework.KubeDescribe("LocalStorageAllocatableEviction [Slow] [Serial] diskReserve = uint64(0.8 * diskAvail / 1000000) // Reserve 0.8 * disk Capacity for kube-reserved scratch storage maxDisk := 10000000 // Set dd command to read and write up to 10MB at a time count := uint64(0.8 * diskAvail / float64(maxDisk)) - command := fmt.Sprintf("dd if=/dev/urandom of=dummy bs=%d count=%d; sleep 0.5; while true; do sleep 5; done", maxDisk, count) - + command := fmt.Sprintf("dd if=/dev/urandom of=dummy bs=%d count=%d; while true; do sleep 5; done", maxDisk, count) podTestSpecs = []podTestSpec{ { evictionPriority: 1, // This pod should be evicted before the innocent pod diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_isolation_eviction_test.go b/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_isolation_eviction_test.go index a42bbf7b7a..84e8b94348 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_isolation_eviction_test.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/local_storage_isolation_eviction_test.go @@ -75,7 +75,7 @@ var _ = framework.KubeDescribe("LocalStorageCapacityIsolationEviction [Slow] [Se Name: emptyDirVolumeName, VolumeSource: v1.VolumeSource{ EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(int64(1000), resource.BinarySI), + SizeLimit: resource.NewQuantity(int64(1000), resource.BinarySI), }, }, }, @@ -112,7 +112,7 @@ var _ = framework.KubeDescribe("LocalStorageCapacityIsolationEviction [Slow] [Se VolumeSource: v1.VolumeSource{ EmptyDir: &v1.EmptyDirVolumeSource{ Medium: "Memory", - SizeLimit: *resource.NewQuantity(int64(10000), resource.BinarySI), + SizeLimit: resource.NewQuantity(int64(10000), resource.BinarySI), }, }, }, @@ -148,7 +148,7 @@ var _ = framework.KubeDescribe("LocalStorageCapacityIsolationEviction [Slow] [Se Name: emptyDirVolumeName, VolumeSource: v1.VolumeSource{ EmptyDir: &v1.EmptyDirVolumeSource{ - SizeLimit: *resource.NewQuantity(int64(100000), resource.BinarySI), + SizeLimit: resource.NewQuantity(int64(100000), resource.BinarySI), }, }, }, diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_conformance.go b/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_conformance.go index 750f8447a9..d51bc28999 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_conformance.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_conformance.go @@ -63,13 +63,17 @@ const ( // timestamp is used as an unique id of current test. var timestamp = getTimestamp() -// getConformanceImageRepo returns conformance image full repo name. -func getConformanceImageRepo() string { - return fmt.Sprintf("%s/node-test-%s:%s", conformanceRegistry, conformanceArch, timestamp) +// getConformanceTestImageName returns name of the conformance test image given the system spec name. +func getConformanceTestImageName(systemSpecName string) string { + if systemSpecName == "" { + return fmt.Sprintf("%s/node-test-%s:%s", conformanceRegistry, conformanceArch, timestamp) + } else { + return fmt.Sprintf("%s/node-test-%s-%s:%s", conformanceRegistry, systemSpecName, conformanceArch, timestamp) + } } // buildConformanceTest builds node conformance test image tarball into binDir. -func buildConformanceTest(binDir string) error { +func buildConformanceTest(binDir, systemSpecName string) error { // Get node conformance directory. conformancePath, err := getConformanceDirectory() if err != nil { @@ -79,13 +83,14 @@ func buildConformanceTest(binDir string) error { cmd := exec.Command("make", "-C", conformancePath, "BIN_DIR="+binDir, "REGISTRY="+conformanceRegistry, "ARCH="+conformanceArch, - "VERSION="+timestamp) + "VERSION="+timestamp, + "SYSTEM_SPEC_NAME="+systemSpecName) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to build node conformance docker image: command - %q, error - %v, output - %q", commandToString(cmd), err, output) } // Save docker image into tar file. - cmd = exec.Command("docker", "save", "-o", filepath.Join(binDir, conformanceTarfile), getConformanceImageRepo()) + cmd = exec.Command("docker", "save", "-o", filepath.Join(binDir, conformanceTarfile), getConformanceTestImageName(systemSpecName)) if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("failed to save node conformance docker image into tar file: command - %q, error - %v, output - %q", commandToString(cmd), err, output) @@ -94,7 +99,7 @@ func buildConformanceTest(binDir string) error { } // SetupTestPackage sets up the test package with binaries k8s required for node conformance test -func (c *ConformanceRemote) SetupTestPackage(tardir string) error { +func (c *ConformanceRemote) SetupTestPackage(tardir, systemSpecName string) error { // Build the executables if err := builder.BuildGo(); err != nil { return fmt.Errorf("failed to build the depedencies: %v", err) @@ -107,8 +112,8 @@ func (c *ConformanceRemote) SetupTestPackage(tardir string) error { } // Build node conformance tarball. - if err := buildConformanceTest(buildOutputDir); err != nil { - return fmt.Errorf("failed to build node conformance test %v", err) + if err := buildConformanceTest(buildOutputDir, systemSpecName); err != nil { + return fmt.Errorf("failed to build node conformance test: %v", err) } // Copy files @@ -253,7 +258,7 @@ func stopKubelet(host, workspace string) error { } // RunTest runs test on the node. -func (c *ConformanceRemote) RunTest(host, workspace, results, junitFilePrefix, testArgs, _ string, timeout time.Duration) (string, error) { +func (c *ConformanceRemote) RunTest(host, workspace, results, junitFilePrefix, testArgs, _, systemSpecName string, timeout time.Duration) (string, error) { // Install the cni plugins and add a basic CNI configuration. if err := setupCNI(host, workspace); err != nil { return "", err @@ -288,7 +293,7 @@ func (c *ConformanceRemote) RunTest(host, workspace, results, junitFilePrefix, t glog.V(2).Infof("Starting tests on %q", host) podManifestPath := getPodManifestPath(workspace) cmd := fmt.Sprintf("'timeout -k 30s %fs docker run --rm --privileged=true --net=host -v /:/rootfs -v %s:%s -v %s:/var/result -e TEST_ARGS=--report-prefix=%s %s'", - timeout.Seconds(), podManifestPath, podManifestPath, results, junitFilePrefix, getConformanceImageRepo()) + timeout.Seconds(), podManifestPath, podManifestPath, results, junitFilePrefix, getConformanceTestImageName(systemSpecName)) testOutput, err := SSH(host, "sh", "-c", cmd) if err != nil { return testOutput, err diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_e2e.go b/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_e2e.go index 3068cd5e32..7485137d4d 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_e2e.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/remote/node_e2e.go @@ -29,7 +29,10 @@ import ( "k8s.io/kubernetes/test/e2e_node/builder" ) -const localCOSMounterPath = "cluster/gce/gci/mounter/mounter" +const ( + localCOSMounterPath = "cluster/gce/gci/mounter/mounter" + systemSpecPath = "test/e2e_node/system/specs" +) // NodeE2ERemote contains the specific functions in the node e2e test suite. type NodeE2ERemote struct{} @@ -40,7 +43,7 @@ func InitNodeE2ERemote() TestSuite { } // SetupTestPackage sets up the test package with binaries k8s required for node e2e tests -func (n *NodeE2ERemote) SetupTestPackage(tardir string) error { +func (n *NodeE2ERemote) SetupTestPackage(tardir, systemSpecName string) error { // Build the executables if err := builder.BuildGo(); err != nil { return fmt.Errorf("failed to build the depedencies: %v", err) @@ -49,7 +52,12 @@ func (n *NodeE2ERemote) SetupTestPackage(tardir string) error { // Make sure we can find the newly built binaries buildOutputDir, err := builder.GetK8sBuildOutputDir() if err != nil { - return fmt.Errorf("failed to locate kubernetes build output directory %v", err) + return fmt.Errorf("failed to locate kubernetes build output directory: %v", err) + } + + rootDir, err := builder.GetK8sRootDir() + if err != nil { + return fmt.Errorf("failed to locate kubernetes root directory: %v", err) } // Copy binaries @@ -65,6 +73,18 @@ func (n *NodeE2ERemote) SetupTestPackage(tardir string) error { } } + if systemSpecName != "" { + // Copy system spec file + source := filepath.Join(rootDir, systemSpecPath, systemSpecName+".yaml") + if _, err := os.Stat(source); err != nil { + return fmt.Errorf("failed to locate system spec %q: %v", source, err) + } + out, err := exec.Command("cp", source, tardir).CombinedOutput() + if err != nil { + return fmt.Errorf("failed to copy system spec %q: %v, output: %q", source, err, out) + } + } + // Include the GCI/COS mounter artifacts in the deployed tarball err = tarAddCOSMounter(tardir) if err != nil { @@ -163,7 +183,7 @@ func updateOSSpecificKubeletFlags(args, host, workspace string) (string, error) } // RunTest runs test on the node. -func (n *NodeE2ERemote) RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoArgs string, timeout time.Duration) (string, error) { +func (n *NodeE2ERemote) RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoArgs, systemSpecName string, timeout time.Duration) (string, error) { // Install the cni plugins and add a basic CNI configuration. if err := setupCNI(host, workspace); err != nil { return "", err @@ -182,12 +202,17 @@ func (n *NodeE2ERemote) RunTest(host, workspace, results, junitFilePrefix, testA return "", err } + systemSpecFile := "" + if systemSpecName != "" { + systemSpecFile = systemSpecName + ".yaml" + } + // Run the tests glog.V(2).Infof("Starting tests on %q", host) cmd := getSSHCommand(" && ", fmt.Sprintf("cd %s", workspace), - fmt.Sprintf("timeout -k 30s %fs ./ginkgo %s ./e2e_node.test -- --logtostderr --v 4 --node-name=%s --report-dir=%s --report-prefix=%s %s", - timeout.Seconds(), ginkgoArgs, host, results, junitFilePrefix, testArgs), + fmt.Sprintf("timeout -k 30s %fs ./ginkgo %s ./e2e_node.test -- --system-spec-name=%s --system-spec-file=%s --logtostderr --v 4 --node-name=%s --report-dir=%s --report-prefix=%s %s", + timeout.Seconds(), ginkgoArgs, systemSpecName, systemSpecFile, host, results, junitFilePrefix, testArgs), ) return SSH(host, "sh", "-c", cmd) } diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/remote/remote.go b/vendor/k8s.io/kubernetes/test/e2e_node/remote/remote.go index 9b6d0b9b7b..a5406cc779 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/remote/remote.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/remote/remote.go @@ -34,7 +34,7 @@ var resultsDir = flag.String("results-dir", "/tmp/", "Directory to scp test resu const archiveName = "e2e_node_test.tar.gz" -func CreateTestArchive(suite TestSuite) (string, error) { +func CreateTestArchive(suite TestSuite, systemSpecName string) (string, error) { glog.V(2).Infof("Building archive...") tardir, err := ioutil.TempDir("", "node-e2e-archive") if err != nil { @@ -43,7 +43,7 @@ func CreateTestArchive(suite TestSuite) (string, error) { defer os.RemoveAll(tardir) // Call the suite function to setup the test package. - err = suite.SetupTestPackage(tardir) + err = suite.SetupTestPackage(tardir, systemSpecName) if err != nil { return "", fmt.Errorf("failed to setup test package %q: %v", tardir, err) } @@ -63,7 +63,7 @@ func CreateTestArchive(suite TestSuite) (string, error) { // Returns the command output, whether the exit was ok, and any errors // TODO(random-liu): junitFilePrefix is not prefix actually, the file name is junit-junitFilePrefix.xml. Change the variable name. -func RunRemote(suite TestSuite, archive string, host string, cleanup bool, junitFilePrefix string, testArgs string, ginkgoArgs string) (string, bool, error) { +func RunRemote(suite TestSuite, archive string, host string, cleanup bool, junitFilePrefix string, testArgs string, ginkgoArgs string, systemSpecName string) (string, bool, error) { // Create the temp staging directory glog.V(2).Infof("Staging test binaries on %q", host) workspace := fmt.Sprintf("/tmp/node-e2e-%s", getTimestamp()) @@ -108,7 +108,7 @@ func RunRemote(suite TestSuite, archive string, host string, cleanup bool, junit } glog.V(2).Infof("Running test on %q", host) - output, err := suite.RunTest(host, workspace, resultDir, junitFilePrefix, testArgs, ginkgoArgs, *testTimeoutSeconds) + output, err := suite.RunTest(host, workspace, resultDir, junitFilePrefix, testArgs, ginkgoArgs, systemSpecName, *testTimeoutSeconds) aggErrs := []error{} // Do not log the output here, let the caller deal with the test output. diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/remote/types.go b/vendor/k8s.io/kubernetes/test/e2e_node/remote/types.go index 52b80a5422..984d3797c5 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/remote/types.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/remote/types.go @@ -29,7 +29,7 @@ type TestSuite interface { // * create a tarball with the directory. // * deploy the tarball to the testing host. // * untar the tarball to the testing workspace on the testing host. - SetupTestPackage(path string) error + SetupTestPackage(path, systemSpecName string) error // RunTest runs test on the node in the given workspace and returns test output // and test error if there is any. // * host is the target node to run the test. @@ -40,6 +40,8 @@ type TestSuite interface { // * junitFilePrefix is the prefix of output junit file. // * testArgs is the arguments passed to test. // * ginkgoArgs is the arguments passed to ginkgo. + // * systemSpecName is the name of the system spec used for validating the + // image on which the test runs. // * timeout is the test timeout. - RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoArgs string, timeout time.Duration) (string, error) + RunTest(host, workspace, results, junitFilePrefix, testArgs, ginkgoArgs, systemSpecName string, timeout time.Duration) (string, error) } diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/runner/local/run_local.go b/vendor/k8s.io/kubernetes/test/e2e_node/runner/local/run_local.go index 3371f53351..0d89f83aaa 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/runner/local/run_local.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/runner/local/run_local.go @@ -18,6 +18,7 @@ package main import ( "flag" + "fmt" "os" "os/exec" "path/filepath" @@ -31,6 +32,11 @@ import ( var buildDependencies = flag.Bool("build-dependencies", true, "If true, build all dependencies.") var ginkgoFlags = flag.String("ginkgo-flags", "", "Space-separated list of arguments to pass to Ginkgo test runner.") var testFlags = flag.String("test-flags", "", "Space-separated list of arguments to pass to node e2e test.") +var systemSpecName = flag.String("system-spec-name", "", "The name of the system spec used for validating the image in the node conformance test. The specs are at test/e2e_node/system/specs/. If unspecified, the default built-in spec (system.DefaultSpec) will be used.") + +const ( + systemSpecPath = "test/e2e_node/system/specs" +) func main() { flag.Parse() @@ -50,7 +56,17 @@ func main() { glog.Infof("Got build output dir: %v", outputDir) ginkgo := filepath.Join(outputDir, "ginkgo") test := filepath.Join(outputDir, "e2e_node.test") - runCommand(ginkgo, *ginkgoFlags, test, "--", *testFlags) + + if *systemSpecName == "" { + runCommand(ginkgo, *ginkgoFlags, test, "--", *testFlags) + return + } + rootDir, err := builder.GetK8sRootDir() + if err != nil { + glog.Fatalf("Failed to get k8s root directory: %v", err) + } + systemSpecFile := filepath.Join(rootDir, systemSpecPath, *systemSpecName+".yaml") + runCommand(ginkgo, *ginkgoFlags, test, "--", fmt.Sprintf("--system-spec-name=%s --system-spec-file=%s", *systemSpecName, systemSpecFile), *testFlags) return } diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/runner/remote/run_remote.go b/vendor/k8s.io/kubernetes/test/e2e_node/runner/remote/run_remote.go index ddc4a26140..f869994cf8 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/runner/remote/run_remote.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/runner/remote/run_remote.go @@ -58,6 +58,7 @@ var buildOnly = flag.Bool("build-only", false, "If true, build e2e_node_test.tar var instanceMetadata = flag.String("instance-metadata", "", "key/value metadata for instances separated by '=' or '<', 'k=v' means the key is 'k' and the value is 'v'; 'k=2.10.1' +- name: apparmor-profiles + versionRange: '>=2.10.1' +- name: audit + versionRange: '>=2.5.0' +- name: autofs + versionRange: '>=5.0.7' +- name: bash + versionRange: '>=4.3' +- name: bridge-utils + versionRange: '>=1.5' +- name: cloud-init + versionRange: '>=0.7.6' +- name: coreutils + versionRange: '>=8.24' +- name: dbus + versionRange: '>=1.6.8' +- name: e2fsprogs + versionRange: '>=1.4.3' +- name: ebtables + versionRange: '>=2.0.10' +- name: ethtool + versionRange: '>=3.18' +- name: iproute2 + versionRange: '>=4.2.0' +- name: less + versionRange: '>=481' +- name: linux-headers-${KERNEL_RELEASE} +- name: netcat-openbsd + versionRange: '>=1.10' +- name: python + versionRange: '>=2.7.10' +- name: pv + versionRange: '>=1.3.4' +- name: sudo + versionRange: '>=1.8.12' +- name: systemd + versionRange: '>=225' +- name: tar + versionRange: '>=1.28' +- name: util-linux + versionRange: '>=2.27.1' +- name: vim + versionRange: '>=7.4.712' +- name: wget + versionRange: '>=1.18' +- name: gce-compute-image-packages + versionRange: '>=20170227' +# TODO(yguo0905): Figure out whether watchdog is required. + +# packageSpecOverrides contains the OS distro specific package requirements. +packageSpecOverrides: +# The following overrides apply to all Ubuntu images. +- osDistro: ubuntu + subtractions: + - name: apparmor-profiles + description: 'On Ubuntu the apparmor profiles are shipped with individual + application package, so the "apparmor-profiles" package is not required.' + - name: audit + description: 'On Ubuntu the equivalent package is called "auditd", so the + "audit" package is not required and "auditd" exists in the additions.' + - name: wget + description: 'The Ubuntu 1604-xenial image includes wget 1.17.1, which does + not satisfy the spec (>=1.18), but meets the functionality requirements. + Therefore, it is removed from the base spec. See wget in the additions.' + additions: + - name: auditd + versionRange: '>=2.4.5' + description: 'auditd 2.4.5 currently satisfies the requirements because the + GKE features that require auditd 2.5 are not yet available.' + - name: grub-common + versionRange: '>=2.2' + description: 'grub is the bootloader on Ubuntu.' + - name: wget + versionRange: '>=1.17.1' + description: 'wget 1.17.1 satisfies the functionality requirements but does + not meet the spec, which is fine' diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/system/types.go b/vendor/k8s.io/kubernetes/test/e2e_node/system/types.go index f119e92ff7..07c15f0451 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/system/types.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/system/types.go @@ -20,16 +20,19 @@ package system type KernelConfig struct { // Name is the general name of the kernel configuration. It is used to // match kernel configuration. - Name string + Name string `json:"name,omitempty"` + // TODO(yguo0905): Support the "or" operation, which will be the same + // as the "aliases". + // // Aliases are aliases of the kernel configuration. Some configuration // has different names in different kernel version. Names of different // versions will be treated as aliases. - Aliases []string + Aliases []string `json:"aliases,omitempty"` // Description is the description of the kernel configuration, for example: // * What is it used for? // * Why is it needed? // * Who needs it? - Description string + Description string `json:"description,omitempty"` } // KernelSpec defines the specification for the kernel. Currently, it contains @@ -38,31 +41,31 @@ type KernelConfig struct { // * Kernel Configuration type KernelSpec struct { // Versions define supported kernel version. It is a group of regexps. - Versions []string + Versions []string `json:"versions,omitempty"` // Required contains all kernel configurations required to be enabled // (built in or as module). - Required []KernelConfig + Required []KernelConfig `json:"required,omitempty"` // Optional contains all kernel configurations are required for optional // features. - Optional []KernelConfig + Optional []KernelConfig `json:"optional,omitempty"` // Forbidden contains all kernel configurations which areforbidden (disabled // or not set) - Forbidden []KernelConfig + Forbidden []KernelConfig `json:"forbidden,omitempty"` } // DockerSpec defines the requirement configuration for docker. Currently, it only // contains spec for graph driver. type DockerSpec struct { // Version is a group of regex matching supported docker versions. - Version []string + Version []string `json:"version,omitempty"` // GraphDriver is the graph drivers supported by kubelet. - GraphDriver []string + GraphDriver []string `json:"graphDriver,omitempty"` } // RuntimeSpec is the abstract layer for different runtimes. Different runtimes // should put their spec inside the RuntimeSpec. type RuntimeSpec struct { - *DockerSpec + *DockerSpec `json:",inline"` } // PackageSpec defines the required packages and their versions. @@ -72,7 +75,7 @@ type RuntimeSpec struct { // either "foo (>=1.0)" or "bar (>=2.0)" is required. type PackageSpec struct { // Name is the name of the package to be checked. - Name string + Name string `json:"name,omitempty"` // VersionRange represents a range of versions that the package must // satisfy. Note that the version requirement will not be enforced if // the version range is empty. For example, @@ -81,9 +84,11 @@ type PackageSpec struct { // - ">1.0 <2.0" would match between both ranges, so "1.1.1" and "1.8.7" // but not "1.0.0" or "2.0.0". // - "<2.0.0 || >=3.0.0" would match "1.0.0" and "3.0.0" but not "2.0.0". - VersionRange string + VersionRange string `json:"versionRange,omitempty"` // Description explains the reason behind this package requirements. - Description string + // + // TODO(yguo0905): Print the description where necessary. + Description string `json:"description,omitempty"` } // PackageSpecOverride defines the overrides on the PackageSpec for an OS @@ -91,31 +96,31 @@ type PackageSpec struct { type PackageSpecOverride struct { // OSDistro identifies to which OS distro this override applies. // Must be "ubuntu", "cos" or "coreos". - OSDistro string + OSDistro string `json:"osDistro,omitempty"` // Subtractions is a list of package names that are excluded from the // package spec. - Subtractions []PackageSpec + Subtractions []PackageSpec `json:"subtractions,omitempty"` // Additions is a list of additional package requirements included the // package spec. - Additions []PackageSpec + Additions []PackageSpec `json:"additions,omitempty"` } // SysSpec defines the requirement of supported system. Currently, it only contains // spec for OS, Kernel and Cgroups. type SysSpec struct { // OS is the operating system of the SysSpec. - OS string + OS string `json:"os,omitempty"` // KernelConfig defines the spec for kernel. - KernelSpec KernelSpec + KernelSpec KernelSpec `json:"kernelSpec,omitempty"` // Cgroups is the required cgroups. - Cgroups []string + Cgroups []string `json:"cgroups,omitempty"` // RuntimeSpec defines the spec for runtime. - RuntimeSpec RuntimeSpec + RuntimeSpec RuntimeSpec `json:"runtimeSpec,omitempty"` // PackageSpec defines the required packages and their versions. - PackageSpecs []PackageSpec + PackageSpecs []PackageSpec `json:"packageSpecs,omitempty"` // PackageSpec defines the overrides of the required packages and their // versions for an OS distro. - PackageSpecOverrides []PackageSpecOverride + PackageSpecOverrides []PackageSpecOverride `json:"packageSpecOverrides,omitempty"` } // DefaultSysSpec is the default SysSpec. diff --git a/vendor/k8s.io/kubernetes/test/e2e_node/system/validators.go b/vendor/k8s.io/kubernetes/test/e2e_node/system/validators.go index 8f6d9c1c41..7819da7b4a 100644 --- a/vendor/k8s.io/kubernetes/test/e2e_node/system/validators.go +++ b/vendor/k8s.io/kubernetes/test/e2e_node/system/validators.go @@ -49,8 +49,8 @@ func Validate(spec SysSpec, validators []Validator) (error, error) { return errors.NewAggregate(warns), errors.NewAggregate(errs) } -// ValidateDefault uses all default validators to validate the system and writes to stdout. -func ValidateDefault(runtime string) (error, error) { +// ValidateSpec uses all default validators to validate the system and writes to stdout. +func ValidateSpec(spec SysSpec, runtime string) (error, error) { // OS-level validators. var osValidators = []Validator{ &OSValidator{Reporter: DefaultReporter}, @@ -68,5 +68,5 @@ func ValidateDefault(runtime string) (error, error) { case "docker": validators = append(validators, dockerValidators...) } - return Validate(DefaultSysSpec, validators) + return Validate(spec, validators) } diff --git a/vendor/k8s.io/kubernetes/test/integration/auth/BUILD b/vendor/k8s.io/kubernetes/test/integration/auth/BUILD index c7d2f81812..980d70d44e 100644 --- a/vendor/k8s.io/kubernetes/test/integration/auth/BUILD +++ b/vendor/k8s.io/kubernetes/test/integration/auth/BUILD @@ -26,6 +26,7 @@ go_test( "//pkg/apis/authorization:go_default_library", "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/extensions:go_default_library", + "//pkg/apis/policy:go_default_library", "//pkg/apis/rbac:go_default_library", "//pkg/auth/authorizer/abac:go_default_library", "//pkg/auth/nodeidentifier:go_default_library", diff --git a/vendor/k8s.io/kubernetes/test/integration/auth/node_test.go b/vendor/k8s.io/kubernetes/test/integration/auth/node_test.go index d8d9d895fa..4135062589 100644 --- a/vendor/k8s.io/kubernetes/test/integration/auth/node_test.go +++ b/vendor/k8s.io/kubernetes/test/integration/auth/node_test.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" restclient "k8s.io/client-go/rest" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/auth/nodeidentifier" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" @@ -205,6 +206,30 @@ func TestNodeAuthorizer(t *testing.T) { deleteNode2 := func(client clientset.Interface) error { return client.Core().Nodes().Delete("node2", nil) } + createNode2NormalPodEviction := func(client clientset.Interface) error { + return client.Policy().Evictions("ns").Evict(&policy.Eviction{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "policy/v1beta1", + Kind: "Eviction", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "node2normalpod", + Namespace: "ns", + }, + }) + } + createNode2MirrorPodEviction := func(client clientset.Interface) error { + return client.Policy().Evictions("ns").Evict(&policy.Eviction{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "policy/v1beta1", + Kind: "Eviction", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "node2mirrorpod", + Namespace: "ns", + }, + }) + } nodeanonClient := clientsetForUser("unknown/system:nodes", clientConfig) node1Client := clientsetForUser("system:node:node1/system:nodes", clientConfig) @@ -218,7 +243,9 @@ func TestNodeAuthorizer(t *testing.T) { expectForbidden(t, getPV(nodeanonClient)) expectForbidden(t, createNode2NormalPod(nodeanonClient)) expectForbidden(t, createNode2MirrorPod(nodeanonClient)) + expectForbidden(t, deleteNode2NormalPod(nodeanonClient)) expectForbidden(t, deleteNode2MirrorPod(nodeanonClient)) + expectForbidden(t, createNode2MirrorPodEviction(nodeanonClient)) expectForbidden(t, createNode2(nodeanonClient)) expectForbidden(t, updateNode2Status(nodeanonClient)) expectForbidden(t, deleteNode2(nodeanonClient)) @@ -230,7 +257,8 @@ func TestNodeAuthorizer(t *testing.T) { expectForbidden(t, getPV(node1Client)) expectForbidden(t, createNode2NormalPod(nodeanonClient)) expectForbidden(t, createNode2MirrorPod(node1Client)) - expectForbidden(t, deleteNode2MirrorPod(node1Client)) + expectNotFound(t, deleteNode2MirrorPod(node1Client)) + expectNotFound(t, createNode2MirrorPodEviction(node1Client)) expectForbidden(t, createNode2(node1Client)) expectForbidden(t, updateNode2Status(node1Client)) expectForbidden(t, deleteNode2(node1Client)) @@ -245,6 +273,8 @@ func TestNodeAuthorizer(t *testing.T) { // mirror pod and self node lifecycle is allowed expectAllowed(t, createNode2MirrorPod(node2Client)) expectAllowed(t, deleteNode2MirrorPod(node2Client)) + expectAllowed(t, createNode2MirrorPod(node2Client)) + expectAllowed(t, createNode2MirrorPodEviction(node2Client)) expectAllowed(t, createNode2(node2Client)) expectAllowed(t, updateNode2Status(node2Client)) expectAllowed(t, deleteNode2(node2Client)) @@ -261,8 +291,10 @@ func TestNodeAuthorizer(t *testing.T) { expectForbidden(t, createNode2NormalPod(nodeanonClient)) expectForbidden(t, updateNode2NormalPodStatus(nodeanonClient)) expectForbidden(t, deleteNode2NormalPod(nodeanonClient)) + expectForbidden(t, createNode2NormalPodEviction(nodeanonClient)) expectForbidden(t, createNode2MirrorPod(nodeanonClient)) expectForbidden(t, deleteNode2MirrorPod(nodeanonClient)) + expectForbidden(t, createNode2MirrorPodEviction(nodeanonClient)) expectForbidden(t, getSecret(node1Client)) expectForbidden(t, getPVSecret(node1Client)) @@ -272,8 +304,10 @@ func TestNodeAuthorizer(t *testing.T) { expectForbidden(t, createNode2NormalPod(node1Client)) expectForbidden(t, updateNode2NormalPodStatus(node1Client)) expectForbidden(t, deleteNode2NormalPod(node1Client)) + expectForbidden(t, createNode2NormalPodEviction(node1Client)) expectForbidden(t, createNode2MirrorPod(node1Client)) - expectForbidden(t, deleteNode2MirrorPod(node1Client)) + expectNotFound(t, deleteNode2MirrorPod(node1Client)) + expectNotFound(t, createNode2MirrorPodEviction(node1Client)) // node2 can get referenced objects now expectAllowed(t, getSecret(node2Client)) @@ -286,6 +320,11 @@ func TestNodeAuthorizer(t *testing.T) { expectAllowed(t, deleteNode2NormalPod(node2Client)) expectAllowed(t, createNode2MirrorPod(node2Client)) expectAllowed(t, deleteNode2MirrorPod(node2Client)) + // recreate as an admin to test eviction + expectAllowed(t, createNode2NormalPod(superuserClient)) + expectAllowed(t, createNode2MirrorPod(superuserClient)) + expectAllowed(t, createNode2NormalPodEviction(node2Client)) + expectAllowed(t, createNode2MirrorPodEviction(node2Client)) } func expectForbidden(t *testing.T, err error) { @@ -295,6 +334,13 @@ func expectForbidden(t *testing.T, err error) { } } +func expectNotFound(t *testing.T, err error) { + if !errors.IsNotFound(err) { + _, file, line, _ := runtime.Caller(1) + t.Errorf("%s:%d: Expected notfound error, got %v", filepath.Base(file), line, err) + } +} + func expectAllowed(t *testing.T, err error) { if err != nil { _, file, line, _ := runtime.Caller(1) diff --git a/vendor/k8s.io/kubernetes/test/kubemark/master-log-dump.sh b/vendor/k8s.io/kubernetes/test/kubemark/master-log-dump.sh index 7028d648cc..fc18541e44 100755 --- a/vendor/k8s.io/kubernetes/test/kubemark/master-log-dump.sh +++ b/vendor/k8s.io/kubernetes/test/kubemark/master-log-dump.sh @@ -25,4 +25,4 @@ source "${KUBE_ROOT}/cluster/kubemark/util.sh" detect-master echo "Dumping logs for kubemark master: ${MASTER_NAME}" -DUMP_ONLY_MASTER_LOGS=true ${KUBE_ROOT}/cluster/log-dump.sh "${REPORT_DIR}" +DUMP_ONLY_MASTER_LOGS=true ${KUBE_ROOT}/cluster/log-dump/log-dump.sh "${REPORT_DIR}"