diff --git a/glide.lock b/glide.lock index 760f0d76c1e..2fc3f38cfa7 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 721bab006d880b97996f61d8060113ed2d2de9eafcdf27d48cce8e181478d99c -updated: 2020-05-05T15:12:59.992247+02:00 +updated: 2020-06-17T15:14:10.6611016+05:30 imports: - name: cloud.google.com/go version: 8c41231e01b2085512d98153bcffb847ff9b4b9f @@ -74,7 +74,7 @@ imports: - pkg/term - pkg/term/windows - name: github.com/docker/go-connections - version: 7dc0a2d6ddce55257ea8851e23b4fb9ef44fd4a0 + version: 480d0b58242613178844e8ffabde7a5d55658f0d subpackages: - nat - sockets @@ -202,8 +202,6 @@ imports: version: 03217c3e97663914aec3faafde50d081f197a0a2 - name: github.com/kballard/go-shellquote version: 95032a82bc518f77982ea72343cc1ade730072f0 -- name: github.com/konsorten/go-windows-terminal-sequences - version: 5c8c8bd35d3832f5d134ae1e1e375b69a4d25242 - name: github.com/kr/pty version: 3a6a957789163cacdfe0e291617a1c8e80612c11 repo: https://github.com/creack/pty @@ -300,7 +298,7 @@ imports: - matchers/support/goraph/util - types - name: github.com/opencontainers/go-digest - version: 279bed98673dd5bef374d3b6e4b09e2af76183bf + version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb - name: github.com/opencontainers/image-spec version: 79b036d80240ae530a8de15e1d21c7ab9292c693 subpackages: @@ -355,14 +353,14 @@ imports: - user/clientset/versioned/scheme - user/clientset/versioned/typed/user/v1 - name: github.com/openshift/library-go - version: 2e79bd232e72b0a2c80fce375450cc1a999aeaf4 + version: e4959e210d3ae8807ea47c470d7afffebb546b8c subpackages: - pkg/apps/appsserialization - pkg/apps/appsutil - pkg/build/naming - pkg/oauth/oauthdiscovery - name: github.com/openshift/oc - version: 2576e482bf003e34e67ba3d69edcf5d411cfd6f3 + version: d038424d6d4f1cc39ad586ac0d36dac3a7a37ceb subpackages: - pkg/cli/login - pkg/helpers/errors @@ -374,7 +372,7 @@ imports: - pkg/helpers/term - pkg/helpers/tokencmd - name: github.com/operator-framework/operator-lifecycle-manager - version: a6acf50218ed5dff731b47ec6029cc353f9cbdfe + version: 33671ebb9929e837d1e9f8104476bf278f203080 subpackages: - pkg/api/apis/operators - pkg/api/apis/operators/v1 @@ -401,7 +399,6 @@ imports: subpackages: - prometheus - prometheus/internal - - prometheus/promhttp - name: github.com/prometheus/client_model version: fd36f4220a901265f90734c3183c5f0c91daa0b8 subpackages: @@ -427,7 +424,7 @@ imports: - name: github.com/satori/go.uuid version: 879c5887cd475cd7864858769793b2ceb0d44feb - name: github.com/sirupsen/logrus - version: 839c75faf7f98a33d445d181f3018b5c3409a45e + version: 89742aefa4b206dcf400792f3bd35b542998eb3b - name: github.com/spf13/afero version: 588a75ec4f32903aa5e39a2619ba6a4631e28424 subpackages: @@ -655,7 +652,7 @@ imports: - third_party/forked/golang/netutil - third_party/forked/golang/reflect - name: k8s.io/apiserver - version: 67a2f5bbc9d8f88bdaa7659cc0cb3307a7f9d61d + version: 79427f02047f9189a75b8cdaadccaf65a126853e subpackages: - pkg/authentication/authenticator - pkg/authentication/request/x509 @@ -819,8 +816,6 @@ imports: - name: k8s.io/component-base version: e22fc98bf46cf388fdc8cb047daf7a6b4f208954 subpackages: - - metrics - - metrics/legacyregistry - version - name: k8s.io/klog version: 2ca9ad30301bf30a8a6e0fa2110db6b8df699a91 diff --git a/pkg/lclient/containers_test.go b/pkg/lclient/containers_test.go index 54dab7f08ee..c9789c2f376 100644 --- a/pkg/lclient/containers_test.go +++ b/pkg/lclient/containers_test.go @@ -8,7 +8,6 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" - "github.com/docker/go-connections/nat" gomock "github.com/golang/mock/gomock" "github.com/openshift/odo/pkg/devfile/adapters/common" ) @@ -183,16 +182,6 @@ func TestGetContainersList(t *testing.T) { "component": "golang", "8080": "testurl2", }, - HostConfig: container.HostConfig{ - PortBindings: nat.PortMap{ - nat.Port("8080/tcp"): []nat.PortBinding{ - nat.PortBinding{ - HostIP: "127.0.0.1", - HostPort: "54321", - }, - }, - }, - }, }, { Names: []string{"/go-test-build"}, @@ -203,16 +192,6 @@ func TestGetContainersList(t *testing.T) { "alias": "alias1", "8080": "testurl3", }, - HostConfig: container.HostConfig{ - PortBindings: nat.PortMap{ - nat.Port("8080/tcp"): []nat.PortBinding{ - nat.PortBinding{ - HostIP: "127.0.0.1", - HostPort: "65432", - }, - }, - }, - }, Mounts: []types.MountPoint{ { Destination: OdoSourceVolumeMount, diff --git a/pkg/lclient/fakeclient.go b/pkg/lclient/fakeclient.go index 3c7646fec1b..efe3617c906 100644 --- a/pkg/lclient/fakeclient.go +++ b/pkg/lclient/fakeclient.go @@ -39,6 +39,82 @@ var mockImageSummary = []types.ImageSummary{ }, } +var mockContainerJSONList = []types.ContainerJSON{ + types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + Name: "/node", + Image: "node", + ID: "1", + }, + Mounts: []types.MountPoint{ + { + Destination: OdoSourceVolumeMount, + }, + }, + Config: &container.Config{ + Image: "node", + Labels: map[string]string{ + "component": "test", + "alias": "alias1", + }, + }, + }, + types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + Name: "/go-test", + Image: "golang", + ID: "2", + HostConfig: &container.HostConfig{ + PortBindings: nat.PortMap{ + nat.Port("8080/tcp"): []nat.PortBinding{ + nat.PortBinding{ + HostIP: "127.0.0.1", + HostPort: "54321", + }, + }, + }, + }, + }, + Config: &container.Config{ + Image: "golang", + Labels: map[string]string{ + "component": "golang", + "8080": "testurl2", + }, + }, + }, + types.ContainerJSON{ + ContainerJSONBase: &types.ContainerJSONBase{ + Name: "/go-test-build", + Image: "golang", + ID: "3", + HostConfig: &container.HostConfig{ + PortBindings: nat.PortMap{ + nat.Port("8080/tcp"): []nat.PortBinding{ + nat.PortBinding{ + HostIP: "127.0.0.1", + HostPort: "65432", + }, + }, + }, + }, + }, + Mounts: []types.MountPoint{ + { + Destination: OdoSourceVolumeMount, + }, + }, + Config: &container.Config{ + Image: "golang", + Labels: map[string]string{ + "component": "test", + "alias": "alias1", + "8080": "testurl3", + }, + }, + }, +} + var mockContainerList = []types.Container{ types.Container{ Names: []string{"/node"}, @@ -62,16 +138,6 @@ var mockContainerList = []types.Container{ "component": "golang", "8080": "testurl2", }, - HostConfig: container.HostConfig{ - PortBindings: nat.PortMap{ - nat.Port("8080/tcp"): []nat.PortBinding{ - nat.PortBinding{ - HostIP: "127.0.0.1", - HostPort: "54321", - }, - }, - }, - }, }, types.Container{ Names: []string{"/go-test-build"}, @@ -87,16 +153,6 @@ var mockContainerList = []types.Container{ Destination: OdoSourceVolumeMount, }, }, - HostConfig: container.HostConfig{ - PortBindings: nat.PortMap{ - nat.Port("8080/tcp"): []nat.PortBinding{ - nat.PortBinding{ - HostIP: "127.0.0.1", - HostPort: "65432", - }, - }, - }, - }, }, } @@ -143,18 +199,9 @@ func (m *mockDockerClient) ContainerRemove(ctx context.Context, containerID stri } func (m *mockDockerClient) ContainerInspect(ctx context.Context, containerID string) (types.ContainerJSON, error) { - for _, containerElement := range mockContainerList { + for _, containerElement := range mockContainerJSONList { if containerElement.ID == containerID { - containerConfig := container.Config{ - Image: containerElement.Image, - Labels: containerElement.Labels, - } - return types.ContainerJSON{ - ContainerJSONBase: &types.ContainerJSONBase{ - HostConfig: &containerElement.HostConfig, - }, - Config: &containerConfig, - }, nil + return containerElement, nil } } return types.ContainerJSON{}, nil diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go index d11ed239b6d..a39ffcb7be2 100644 --- a/vendor/github.com/docker/docker/api/types/types.go +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -56,19 +56,21 @@ type ImageMetadata struct { // Container contains response of Engine API: // GET "/containers/json" type Container struct { - ID string `json:"Id"` - Names []string - Image string - ImageID string - Command string - Created int64 - Ports []Port - SizeRw int64 `json:",omitempty"` - SizeRootFs int64 `json:",omitempty"` - Labels map[string]string - State string - Status string - HostConfig container.HostConfig + ID string `json:"Id"` + Names []string + Image string + ImageID string + Command string + Created int64 + Ports []Port + SizeRw int64 `json:",omitempty"` + SizeRootFs int64 `json:",omitempty"` + Labels map[string]string + State string + Status string + HostConfig struct { + NetworkMode string `json:",omitempty"` + } NetworkSettings *SummaryNetworkSettings Mounts []MountPoint } diff --git a/vendor/github.com/docker/go-connections/.gitignore b/vendor/github.com/docker/go-connections/.gitignore new file mode 100644 index 00000000000..3b42f25c517 --- /dev/null +++ b/vendor/github.com/docker/go-connections/.gitignore @@ -0,0 +1,7 @@ +# if you want to ignore files created by your editor/tools, consider using a +# global .gitignore or .git/info/exclude see https://help.github.com/articles/ignoring-files +.* +!.github +!.gitignore +# support running go modules in vendor mode for local development +vendor/ diff --git a/vendor/github.com/docker/go-connections/circle.yml b/vendor/github.com/docker/go-connections/circle.yml index f69a9579e1f..660f4bacfe3 100644 --- a/vendor/github.com/docker/go-connections/circle.yml +++ b/vendor/github.com/docker/go-connections/circle.yml @@ -1,8 +1,8 @@ version: 2 jobs: build: - machine: true - working_directory: ~/go/src/github.com/docker/go-connections + machine: + image: ubuntu-1604:202004-01 steps: - checkout - run: @@ -11,10 +11,7 @@ jobs: - run: name: Get dependencies command: | - go get -u golang.org/x/lint/golint && - go get -d github.com/pkg/errors && - go get -d github.com/stretchr/testify && - go get -d golang.org/x/net/proxy + go get -u golang.org/x/lint/golint - run: name: Run analysis before tests command: go vet ./... @@ -35,7 +32,6 @@ jobs: - run: name: Build for Windows command: | - go get -d github.com/Microsoft/go-winio && go build ./... environment: GOOS: windows diff --git a/vendor/github.com/docker/go-connections/go.mod b/vendor/github.com/docker/go-connections/go.mod new file mode 100644 index 00000000000..70ec3128f5a --- /dev/null +++ b/vendor/github.com/docker/go-connections/go.mod @@ -0,0 +1,8 @@ +module github.com/docker/go-connections + +go 1.13 + +require ( + github.com/Microsoft/go-winio v0.4.14 + github.com/pkg/errors v0.9.1 +) diff --git a/vendor/github.com/docker/go-connections/go.sum b/vendor/github.com/docker/go-connections/go.sum new file mode 100644 index 00000000000..2bcfb4ffb43 --- /dev/null +++ b/vendor/github.com/docker/go-connections/go.sum @@ -0,0 +1,16 @@ +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/docker/go-connections/nat/nat_test.go b/vendor/github.com/docker/go-connections/nat/nat_test.go index 575401b8e14..12e61ea123e 100644 --- a/vendor/github.com/docker/go-connections/nat/nat_test.go +++ b/vendor/github.com/docker/go-connections/nat/nat_test.go @@ -1,9 +1,8 @@ package nat import ( + "reflect" "testing" - - "github.com/stretchr/testify/assert" ) func TestParsePort(t *testing.T) { @@ -175,7 +174,9 @@ func TestSplitProtoPort(t *testing.T) { func TestParsePortSpecFull(t *testing.T) { portMappings, err := ParsePortSpec("0.0.0.0:1234-1235:3333-3334/tcp") - assert.Nil(t, err) + if err != nil { + t.Fatalf("expected nil error, got: %v", err) + } expected := []PortMapping{ { @@ -194,12 +195,16 @@ func TestParsePortSpecFull(t *testing.T) { }, } - assert.Equal(t, expected, portMappings) + if !reflect.DeepEqual(expected, portMappings) { + t.Fatalf("wrong port mappings: got=%v, want=%v", portMappings, expected) + } } func TestPartPortSpecIPV6(t *testing.T) { portMappings, err := ParsePortSpec("[2001:4860:0:2001::68]::333") - assert.Nil(t, err) + if err != nil { + t.Fatalf("expected nil error, got: %v", err) + } expected := []PortMapping{ { @@ -210,12 +215,16 @@ func TestPartPortSpecIPV6(t *testing.T) { }, }, } - assert.Equal(t, expected, portMappings) + if !reflect.DeepEqual(expected, portMappings) { + t.Fatalf("wrong port mappings: got=%v, want=%v", portMappings, expected) + } } func TestPartPortSpecIPV6WithHostPort(t *testing.T) { portMappings, err := ParsePortSpec("[::1]:80:80") - assert.Nil(t, err) + if err != nil { + t.Fatalf("expected nil error, got: %v", err) + } expected := []PortMapping{ { @@ -226,7 +235,9 @@ func TestPartPortSpecIPV6WithHostPort(t *testing.T) { }, }, } - assert.Equal(t, expected, portMappings) + if !reflect.DeepEqual(expected, portMappings) { + t.Fatalf("wrong port mappings: got=%v, want=%v", portMappings, expected) + } } func TestParsePortSpecs(t *testing.T) { diff --git a/vendor/github.com/docker/go-connections/sockets/sockets_windows.go b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go index 16f8cdbb1fc..7acafc5a2ad 100644 --- a/vendor/github.com/docker/go-connections/sockets/sockets_windows.go +++ b/vendor/github.com/docker/go-connections/sockets/sockets_windows.go @@ -17,12 +17,7 @@ func configureNpipeTransport(tr *http.Transport, proto, addr string) error { // No need for compression in local communications. tr.DisableCompression = true tr.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) { - // DialPipeContext() has been added to winio: - // https://github.com/Microsoft/go-winio/commit/5fdbdcc2ae1c7e1073157fa7cb34a15eab472e1d - // However, a new version of winio with this commit has not been released yet. - // Continue to use DialPipe() until DialPipeContext() becomes available. - //return winio.DialPipeContext(ctx, addr) - return DialPipe(addr, defaultTimeout) + return winio.DialPipeContext(ctx, addr) } return nil } diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE deleted file mode 100644 index 14127cd831e..00000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -(The MIT License) - -Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) - -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. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md deleted file mode 100644 index 949b77e304e..00000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Windows Terminal Sequences - -This library allow for enabling Windows terminal color support for Go. - -See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. - -## Usage - -```go -import ( - "syscall" - - sequences "github.com/konsorten/go-windows-terminal-sequences" -) - -func main() { - sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) -} - -``` - -## Authors - -The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). - -We thank all the authors who provided code to this library: - -* Felix Kollmann - -## License - -(The MIT License) - -Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) - -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. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod deleted file mode 100644 index 716c6131256..00000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go deleted file mode 100644 index ef18d8f9787..00000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go +++ /dev/null @@ -1,36 +0,0 @@ -// +build windows - -package sequences - -import ( - "syscall" - "unsafe" -) - -var ( - kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") - setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") -) - -func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { - const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 - - var mode uint32 - err := syscall.GetConsoleMode(syscall.Stdout, &mode) - if err != nil { - return err - } - - if enable { - mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING - } else { - mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING - } - - ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) - if ret == 0 { - return err - } - - return nil -} diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go deleted file mode 100644 index aad41c5cf60..00000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// +build windows - -package sequences - -import ( - "fmt" - "os" - "syscall" - "testing" -) - -func TestStdoutSequencesOn(t *testing.T) { - err := EnableVirtualTerminalProcessing(syscall.Stdout, true) - if err != nil { - t.Fatalf("Failed to enable VTP: %v", err) - } - defer EnableVirtualTerminalProcessing(syscall.Stdout, false) - - fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") -} - -func TestStdoutSequencesOff(t *testing.T) { - err := EnableVirtualTerminalProcessing(syscall.Stdout, false) - if err != nil { - t.Fatalf("Failed to enable VTP: %v", err) - } - - fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") -} - -func TestStderrSequencesOn(t *testing.T) { - err := EnableVirtualTerminalProcessing(syscall.Stderr, true) - if err != nil { - t.Fatalf("Failed to enable VTP: %v", err) - } - defer EnableVirtualTerminalProcessing(syscall.Stderr, false) - - fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") -} - -func TestStderrSequencesOff(t *testing.T) { - err := EnableVirtualTerminalProcessing(syscall.Stderr, false) - if err != nil { - t.Fatalf("Failed to enable VTP: %v", err) - } - - fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") -} diff --git a/vendor/github.com/opencontainers/go-digest/.mailmap b/vendor/github.com/opencontainers/go-digest/.mailmap deleted file mode 100644 index ba611cb21ca..00000000000 --- a/vendor/github.com/opencontainers/go-digest/.mailmap +++ /dev/null @@ -1 +0,0 @@ -Stephen J Day diff --git a/vendor/github.com/opencontainers/go-digest/MAINTAINERS b/vendor/github.com/opencontainers/go-digest/MAINTAINERS index 42a29795d7a..f5bd5a6ed75 100644 --- a/vendor/github.com/opencontainers/go-digest/MAINTAINERS +++ b/vendor/github.com/opencontainers/go-digest/MAINTAINERS @@ -1,7 +1,5 @@ -Aaron Lehmann (@aaronlehmann) Brandon Philips (@philips) Brendan Burns (@brendandburns) -Derek McGowan (@dmcgowan) Jason Bouzane (@jbouzane) John Starks (@jstarks) Jonathan Boulle (@jonboulle) diff --git a/vendor/github.com/opencontainers/go-digest/README.md b/vendor/github.com/opencontainers/go-digest/README.md index 0f5a04092c4..9d6174cfdcc 100644 --- a/vendor/github.com/opencontainers/go-digest/README.md +++ b/vendor/github.com/opencontainers/go-digest/README.md @@ -1,10 +1,10 @@ # go-digest -[![GoDoc](https://godoc.org/github.com/opencontainers/go-digest?status.svg)](https://godoc.org/github.com/opencontainers/go-digest) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/go-digest)](https://goreportcard.com/report/github.com/opencontainers/go-digest) [![Build Status](https://travis-ci.org/opencontainers/go-digest.svg?branch=master)](https://travis-ci.org/opencontainers/go-digest) +[![GoDoc](https://godoc.org/github.com/docker/go-digest?status.svg)](https://godoc.org/github.com/docker/go-digest) [![Go Report Card](https://goreportcard.com/badge/github.com/docker/go-digest)](https://goreportcard.com/report/github.com/docker/go-digest) [![Build Status](https://travis-ci.org/docker/go-digest.svg?branch=master)](https://travis-ci.org/docker/go-digest) Common digest package used across the container ecosystem. -Please see the [godoc](https://godoc.org/github.com/opencontainers/go-digest) for more information. +Please see the [godoc](https://godoc.org/github.com/docker/go-digest) for more information. # What is a digest? @@ -49,7 +49,7 @@ can power a rich, safe, content distribution system. # Usage -While the [godoc](https://godoc.org/github.com/opencontainers/go-digest) is +While the [godoc](https://godoc.org/github.com/docker/go-digest) is considered the best resource, a few important items need to be called out when using this package. @@ -76,7 +76,7 @@ out when using this package. The Go API, at this stage, is considered stable, unless otherwise noted. -As always, before using a package export, read the [godoc](https://godoc.org/github.com/opencontainers/go-digest). +As always, before using a package export, read the [godoc](https://godoc.org/github.com/docker/go-digest). # Contributing @@ -88,16 +88,16 @@ the alternatives you tried before submitting a PR. # Reporting security issues -Please DO NOT file a public issue, instead send your report privately to -security@opencontainers.org. +The maintainers take security seriously. If you discover a security +issue, please bring it to their attention right away! -The maintainers take security seriously. If you discover a security issue, -please bring it to their attention right away! +Please DO NOT file a public issue, instead send your report privately +to security@docker.com. -If you are reporting a security issue, do not create an issue or file a pull -request on GitHub. Instead, disclose the issue responsibly by sending an email -to security@opencontainers.org (which is inhabited only by the maintainers of -the various OCI projects). +Security reports are greatly appreciated and we will publicly thank you +for it. We also like to send gifts—if you're into Docker schwag, make +sure to let us know. We currently do not offer a paid security bounty +program, but are not ruling it out in the future. # Copyright and license diff --git a/vendor/github.com/opencontainers/go-digest/algorithm.go b/vendor/github.com/opencontainers/go-digest/algorithm.go index 8813bd26f1f..a3c44801d5e 100644 --- a/vendor/github.com/opencontainers/go-digest/algorithm.go +++ b/vendor/github.com/opencontainers/go-digest/algorithm.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( @@ -19,7 +5,6 @@ import ( "fmt" "hash" "io" - "regexp" ) // Algorithm identifies and implementation of a digester by an identifier. @@ -29,9 +14,9 @@ type Algorithm string // supported digest types const ( - SHA256 Algorithm = "sha256" // sha256 with hex encoding (lower case only) - SHA384 Algorithm = "sha384" // sha384 with hex encoding (lower case only) - SHA512 Algorithm = "sha512" // sha512 with hex encoding (lower case only) + SHA256 Algorithm = "sha256" // sha256 with hex encoding + SHA384 Algorithm = "sha384" // sha384 with hex encoding + SHA512 Algorithm = "sha512" // sha512 with hex encoding // Canonical is the primary digest algorithm used with the distribution // project. Other digests may be used but this one is the primary storage @@ -51,14 +36,6 @@ var ( SHA384: crypto.SHA384, SHA512: crypto.SHA512, } - - // anchoredEncodedRegexps contains anchored regular expressions for hex-encoded digests. - // Note that /A-F/ disallowed. - anchoredEncodedRegexps = map[Algorithm]*regexp.Regexp{ - SHA256: regexp.MustCompile(`^[a-f0-9]{64}$`), - SHA384: regexp.MustCompile(`^[a-f0-9]{96}$`), - SHA512: regexp.MustCompile(`^[a-f0-9]{128}$`), - } ) // Available returns true if the digest type is available for use. If this @@ -134,14 +111,6 @@ func (a Algorithm) Hash() hash.Hash { return algorithms[a].New() } -// Encode encodes the raw bytes of a digest, typically from a hash.Hash, into -// the encoded portion of the digest. -func (a Algorithm) Encode(d []byte) string { - // TODO(stevvooe): Currently, all algorithms use a hex encoding. When we - // add support for back registration, we can modify this accordingly. - return fmt.Sprintf("%x", d) -} - // FromReader returns the digest of the reader using the algorithm. func (a Algorithm) FromReader(rd io.Reader) (Digest, error) { digester := a.Digester() @@ -173,20 +142,3 @@ func (a Algorithm) FromBytes(p []byte) Digest { func (a Algorithm) FromString(s string) Digest { return a.FromBytes([]byte(s)) } - -// Validate validates the encoded portion string -func (a Algorithm) Validate(encoded string) error { - r, ok := anchoredEncodedRegexps[a] - if !ok { - return ErrDigestUnsupported - } - // Digests much always be hex-encoded, ensuring that their hex portion will - // always be size*2 - if a.Size()*2 != len(encoded) { - return ErrDigestInvalidLength - } - if r.MatchString(encoded) { - return nil - } - return ErrDigestInvalidFormat -} diff --git a/vendor/github.com/opencontainers/go-digest/algorithm_test.go b/vendor/github.com/opencontainers/go-digest/algorithm_test.go index d50e8494fa5..12db5d13cee 100644 --- a/vendor/github.com/opencontainers/go-digest/algorithm_test.go +++ b/vendor/github.com/opencontainers/go-digest/algorithm_test.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( diff --git a/vendor/github.com/opencontainers/go-digest/digest.go b/vendor/github.com/opencontainers/go-digest/digest.go index ad398cba2fb..7c66c30c017 100644 --- a/vendor/github.com/opencontainers/go-digest/digest.go +++ b/vendor/github.com/opencontainers/go-digest/digest.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( @@ -45,21 +31,16 @@ func NewDigest(alg Algorithm, h hash.Hash) Digest { // functions. This is also useful for rebuilding digests from binary // serializations. func NewDigestFromBytes(alg Algorithm, p []byte) Digest { - return NewDigestFromEncoded(alg, alg.Encode(p)) + return Digest(fmt.Sprintf("%s:%x", alg, p)) } -// NewDigestFromHex is deprecated. Please use NewDigestFromEncoded. +// NewDigestFromHex returns a Digest from alg and a the hex encoded digest. func NewDigestFromHex(alg, hex string) Digest { - return NewDigestFromEncoded(Algorithm(alg), hex) -} - -// NewDigestFromEncoded returns a Digest from alg and the encoded digest. -func NewDigestFromEncoded(alg Algorithm, encoded string) Digest { - return Digest(fmt.Sprintf("%s:%s", alg, encoded)) + return Digest(fmt.Sprintf("%s:%s", alg, hex)) } // DigestRegexp matches valid digest types. -var DigestRegexp = regexp.MustCompile(`[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+`) +var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`) // DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match. var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`) @@ -101,18 +82,26 @@ func FromString(s string) Digest { // error if not. func (d Digest) Validate() error { s := string(d) + i := strings.Index(s, ":") - if i <= 0 || i+1 == len(s) { + + // validate i then run through regexp + if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) { return ErrDigestInvalidFormat } - algorithm, encoded := Algorithm(s[:i]), s[i+1:] + + algorithm := Algorithm(s[:i]) if !algorithm.Available() { - if !DigestRegexpAnchored.MatchString(s) { - return ErrDigestInvalidFormat - } return ErrDigestUnsupported } - return algorithm.Validate(encoded) + + // Digests much always be hex-encoded, ensuring that their hex portion will + // always be size*2 + if algorithm.Size()*2 != len(s[i+1:]) { + return ErrDigestInvalidLength + } + + return nil } // Algorithm returns the algorithm portion of the digest. This will panic if @@ -130,15 +119,10 @@ func (d Digest) Verifier() Verifier { } } -// Encoded returns the encoded portion of the digest. This will panic if the +// Hex returns the hex digest portion of the digest. This will panic if the // underlying digest is not in a valid format. -func (d Digest) Encoded() string { - return string(d[d.sepIndex()+1:]) -} - -// Hex is deprecated. Please use Digest.Encoded. func (d Digest) Hex() string { - return d.Encoded() + return string(d[d.sepIndex()+1:]) } func (d Digest) String() string { diff --git a/vendor/github.com/opencontainers/go-digest/digest_test.go b/vendor/github.com/opencontainers/go-digest/digest_test.go index cc3b648a889..d85c476f36a 100644 --- a/vendor/github.com/opencontainers/go-digest/digest_test.go +++ b/vendor/github.com/opencontainers/go-digest/digest_test.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( @@ -23,17 +9,17 @@ func TestParseDigest(t *testing.T) { input string err error algorithm Algorithm - encoded string + hex string }{ { input: "sha256:e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b", algorithm: "sha256", - encoded: "e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b", + hex: "e58fcf7418d4390dec8e8fb69d88c06ec07039d651fedd3aa72af9972e7d046b", }, { input: "sha384:d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", algorithm: "sha384", - encoded: "d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", + hex: "d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", }, { // empty hex @@ -53,7 +39,7 @@ func TestParseDigest(t *testing.T) { { // not hex input: "sha256:d41d8cd98f00b204e9800m98ecf8427e", - err: ErrDigestInvalidLength, + err: ErrDigestInvalidFormat, }, { // too short @@ -69,34 +55,6 @@ func TestParseDigest(t *testing.T) { input: "foo:d41d8cd98f00b204e9800998ecf8427e", err: ErrDigestUnsupported, }, - { - // repeated separators - input: "sha384__foo+bar:d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", - err: ErrDigestInvalidFormat, - }, - { - // ensure that we parse, but we don't have support for the algorithm - input: "sha384.foo+bar:d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", - algorithm: "sha384.foo+bar", - encoded: "d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", - err: ErrDigestUnsupported, - }, - { - input: "sha384_foo+bar:d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", - algorithm: "sha384_foo+bar", - encoded: "d3fc7881460b7e22e3d172954463dddd7866d17597e7248453c48b3e9d26d9596bf9c4a9cf8072c9d5bad76e19af801d", - err: ErrDigestUnsupported, - }, - { - input: "sha256+b64:LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564", - algorithm: "sha256+b64", - encoded: "LCa0a2j_xo_5m0U8HTBBNBNCLXBkg7-g-YpeiGJm564", - err: ErrDigestUnsupported, - }, - { - input: "sha256:E58FCF7418D4390DEC8E8FB69D88C06EC07039D651FEDD3AA72AF9972E7D046B", - err: ErrDigestInvalidFormat, - }, } { digest, err := Parse(testcase.input) if err != testcase.err { @@ -111,8 +69,8 @@ func TestParseDigest(t *testing.T) { t.Fatalf("incorrect algorithm for parsed digest: %q != %q", digest.Algorithm(), testcase.algorithm) } - if digest.Encoded() != testcase.encoded { - t.Fatalf("incorrect hex for parsed digest: %q != %q", digest.Encoded(), testcase.encoded) + if digest.Hex() != testcase.hex { + t.Fatalf("incorrect hex for parsed digest: %q != %q", digest.Hex(), testcase.hex) } // Parse string return value and check equality @@ -126,7 +84,7 @@ func TestParseDigest(t *testing.T) { t.Fatalf("expected equal: %q != %q", newParsed, digest) } - newFromHex := NewDigestFromEncoded(newParsed.Algorithm(), newParsed.Encoded()) + newFromHex := NewDigestFromHex(newParsed.Algorithm().String(), newParsed.Hex()) if newFromHex != digest { t.Fatalf("%v != %v", newFromHex, digest) } diff --git a/vendor/github.com/opencontainers/go-digest/digester.go b/vendor/github.com/opencontainers/go-digest/digester.go index 36fa2728ef4..918a3f9191e 100644 --- a/vendor/github.com/opencontainers/go-digest/digester.go +++ b/vendor/github.com/opencontainers/go-digest/digester.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import "hash" diff --git a/vendor/github.com/opencontainers/go-digest/doc.go b/vendor/github.com/opencontainers/go-digest/doc.go index 491ea1ef1f8..f64b0db32b4 100644 --- a/vendor/github.com/opencontainers/go-digest/doc.go +++ b/vendor/github.com/opencontainers/go-digest/doc.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest provides a generalized type to opaquely represent message // digests and their operations within the registry. The Digest type is // designed to serve as a flexible identifier in a content-addressable system. diff --git a/vendor/github.com/opencontainers/go-digest/verifiers.go b/vendor/github.com/opencontainers/go-digest/verifiers.go index 32125e91878..f1db6cda842 100644 --- a/vendor/github.com/opencontainers/go-digest/verifiers.go +++ b/vendor/github.com/opencontainers/go-digest/verifiers.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( diff --git a/vendor/github.com/opencontainers/go-digest/verifiers_test.go b/vendor/github.com/opencontainers/go-digest/verifiers_test.go index d67bb1bc651..251d4fce54a 100644 --- a/vendor/github.com/opencontainers/go-digest/verifiers_test.go +++ b/vendor/github.com/opencontainers/go-digest/verifiers_test.go @@ -1,17 +1,3 @@ -// Copyright 2017 Docker, Inc. -// -// 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 -// -// https://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 digest import ( diff --git a/vendor/github.com/openshift/library-go/go.mod b/vendor/github.com/openshift/library-go/go.mod index de4f5215593..d8c4263bd03 100644 --- a/vendor/github.com/openshift/library-go/go.mod +++ b/vendor/github.com/openshift/library-go/go.mod @@ -41,6 +41,7 @@ require ( github.com/openshift/api v0.0.0-20200210091934-a0e53e94816b github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160 github.com/openshift/client-go v0.0.0-20200116152001-92a2713fa240 + github.com/pkg/errors v0.8.1 github.com/pkg/profile v1.3.0 github.com/prometheus/client_golang v1.1.0 github.com/sirupsen/logrus v1.4.2 diff --git a/vendor/github.com/openshift/library-go/pkg/manifest/manifest.go b/vendor/github.com/openshift/library-go/pkg/manifest/manifest.go new file mode 100644 index 00000000000..9007599ba8e --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/manifest/manifest.go @@ -0,0 +1,120 @@ +package manifest + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/kubernetes/scheme" +) + +// Manifest stores Kubernetes object in Raw from a file. +// It stores the GroupVersionKind for the manifest. +// Raw and Obj should always be kept in sync such that +// each provides the same data but in different formats. +// To ensure Raw and Obj are always in sync, they should not +// be set directly but rather only be set by calling +// either method ManifestsFromFiles or ParseManifests. +type Manifest struct { + // OriginalFilename is set to the filename this manifest was loaded from. + // It is not guaranteed to be set or be unique, but we will set it when + // loading from disk to provide better debuggability. + OriginalFilename string + + Raw []byte + GVK schema.GroupVersionKind + + Obj *unstructured.Unstructured +} + +// UnmarshalJSON implements the json.Unmarshaler interface for the Manifest +// type. It unmarshals bytes of a single kubernetes object to Manifest. +func (m *Manifest) UnmarshalJSON(in []byte) error { + if m == nil { + return errors.New("Manifest: UnmarshalJSON on nil pointer") + } + + // This happens when marshalling + // + // --- (this between two `---`) + // --- + // + if bytes.Equal(in, []byte("null")) { + m.Raw = nil + return nil + } + + m.Raw = append(m.Raw[0:0], in...) + udi, _, err := scheme.Codecs.UniversalDecoder().Decode(in, nil, &unstructured.Unstructured{}) + if err != nil { + return errors.Wrapf(err, "unable to decode manifest") + } + ud, ok := udi.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("expected manifest to decode into *unstructured.Unstructured, got %T", ud) + } + + m.GVK = ud.GroupVersionKind() + m.Obj = ud + return nil +} + +// ManifestsFromFiles reads files and returns Manifests in the same order. +// files should be list of absolute paths for the manifests on disk. +func ManifestsFromFiles(files []string) ([]Manifest, error) { + var manifests []Manifest + var errs []error + for _, file := range files { + file, err := os.Open(file) + if err != nil { + errs = append(errs, errors.Wrapf(err, "error opening %s", file.Name())) + continue + } + defer file.Close() + + ms, err := ParseManifests(file) + if err != nil { + errs = append(errs, errors.Wrapf(err, "error parsing %s", file.Name())) + continue + } + for _, m := range ms { + m.OriginalFilename = filepath.Base(file.Name()) + } + manifests = append(manifests, ms...) + } + + agg := utilerrors.NewAggregate(errs) + if agg != nil { + return nil, fmt.Errorf("error loading manifests: %v", agg.Error()) + } + + return manifests, nil +} + +// ParseManifests parses a YAML or JSON document that may contain one or more +// kubernetes resources. +func ParseManifests(r io.Reader) ([]Manifest, error) { + d := yaml.NewYAMLOrJSONDecoder(r, 1024) + var manifests []Manifest + for { + m := Manifest{} + if err := d.Decode(&m); err != nil { + if err == io.EOF { + return manifests, nil + } + return manifests, errors.Wrapf(err, "error parsing") + } + m.Raw = bytes.TrimSpace(m.Raw) + if len(m.Raw) == 0 || bytes.Equal(m.Raw, []byte("null")) { + continue + } + manifests = append(manifests, m) + } +} diff --git a/vendor/github.com/openshift/library-go/pkg/manifest/manifest_test.go b/vendor/github.com/openshift/library-go/pkg/manifest/manifest_test.go new file mode 100644 index 00000000000..5663ac8e27d --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/manifest/manifest_test.go @@ -0,0 +1,323 @@ +package manifest + +import ( + "flag" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/davecgh/go-spew/spew" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog" +) + +func init() { + klog.InitFlags(flag.CommandLine) +} + +func TestParseManifests(t *testing.T) { + tests := []struct { + name string + raw string + want []Manifest + }{{ + name: "ingress", + raw: ` +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + namespace: test-namespace +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +`, + want: []Manifest{{ + Raw: []byte(`{"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"name":"test-ingress","namespace":"test-namespace"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"test","servicePort":80},"path":"/testpath"}]}}]}}`), + GVK: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}, + }}, + }, { + name: "configmap", + raw: ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +`, + want: []Manifest{{ + Raw: []byte(`{"apiVersion":"v1","data":{"color":"red","multi-line":"hello world\nhow are you?\n"},"kind":"ConfigMap","metadata":{"name":"a-config","namespace":"default"}}`), + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }}, + }, { + name: "two-resources", + raw: ` +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + namespace: test-namespace +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +`, + want: []Manifest{{ + Raw: []byte(`{"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"name":"test-ingress","namespace":"test-namespace"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"test","servicePort":80},"path":"/testpath"}]}}]}}`), + GVK: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}, + }, { + Raw: []byte(`{"apiVersion":"v1","data":{"color":"red","multi-line":"hello world\nhow are you?\n"},"kind":"ConfigMap","metadata":{"name":"a-config","namespace":"default"}}`), + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }}, + }, { + name: "two-resources-with-empty", + raw: ` +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + namespace: test-namespace +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +--- +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +--- +`, + want: []Manifest{{ + Raw: []byte(`{"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"name":"test-ingress","namespace":"test-namespace"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"test","servicePort":80},"path":"/testpath"}]}}]}}`), + GVK: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}, + }, { + Raw: []byte(`{"apiVersion":"v1","data":{"color":"red","multi-line":"hello world\nhow are you?\n"},"kind":"ConfigMap","metadata":{"name":"a-config","namespace":"default"}}`), + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }}, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := ParseManifests(strings.NewReader(test.raw)) + if err != nil { + t.Fatalf("failed to parse manifest: %v", err) + } + + for i := range got { + got[i].Obj = nil + } + + if !reflect.DeepEqual(got, test.want) { + t.Fatalf("mismatch found") + } + }) + } + +} + +func TestManifestsFromFiles(t *testing.T) { + tests := []struct { + name string + fs dir + want []Manifest + }{{ + name: "no-files", + fs: dir{ + name: "a", + }, + want: nil, + }, { + name: "all-files", + fs: dir{ + name: "a", + files: []file{{ + name: "f0", + contents: ` +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + namespace: test-namespace +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +`, + }, { + name: "f1", + contents: ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +`, + }}, + }, + want: []Manifest{{ + GVK: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}, + }, { + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }}, + }, { + name: "files-with-multiple-manifests", + fs: dir{ + name: "a", + files: []file{{ + name: "f0", + contents: ` +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: test-ingress + namespace: test-namespace +spec: + rules: + - http: + paths: + - path: /testpath + backend: + serviceName: test + servicePort: 80 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +`, + }, { + name: "f1", + contents: ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: a-config + namespace: default +data: + color: "red" + multi-line: | + hello world + how are you? +`, + }}, + }, + want: []Manifest{{ + GVK: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}, + }, { + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }, { + GVK: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}, + }}, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tmpdir, cleanup := setupTestFS(t, test.fs) + defer func() { + if err := cleanup(); err != nil { + t.Logf("error cleaning %q", tmpdir) + } + }() + + files := []string{} + for _, f := range test.fs.files { + files = append(files, filepath.Join(tmpdir, test.fs.name, f.name)) + } + got, err := ManifestsFromFiles(files) + if err != nil { + t.Fatal(err) + } + for i := range got { + got[i].Raw = nil + got[i].Obj = nil + } + if !reflect.DeepEqual(got, test.want) { + t.Fatalf("mismatch \ngot: %s \nwant: %s", spew.Sdump(got), spew.Sdump(test.want)) + } + }) + } +} + +type file struct { + name string + contents string +} + +type dir struct { + name string + files []file +} + +// setupTestFS returns path of the tmp d created and cleanup function. +func setupTestFS(t *testing.T, d dir) (string, func() error) { + root, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatal(err) + } + dpath := filepath.Join(root, d.name) + if err := os.MkdirAll(dpath, 0755); err != nil { + t.Fatal(err) + } + for _, file := range d.files { + path := filepath.Join(dpath, file.name) + ioutil.WriteFile(path, []byte(file.contents), 0755) + } + cleanup := func() error { + return os.RemoveAll(root) + } + return root, cleanup +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go index f0e5c252f36..095095e5db6 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go @@ -154,6 +154,7 @@ func getPlatformName(platformType configv1.PlatformType, recorder events.Recorde case configv1.OpenStackPlatformType: cloudProvider = "openstack" case configv1.NonePlatformType: + case configv1.OvirtPlatformType: default: // the new doc on the infrastructure fields requires that we treat an unrecognized thing the same bare metal. // TODO find a way to indicate to the user that we didn't honor their choice diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/apps.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/apps.go index 91630dba51d..234e069055a 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/apps.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/apps.go @@ -1,6 +1,10 @@ package resourceapply import ( + "crypto/sha256" + "encoding/json" + "fmt" + "k8s.io/klog" appsv1 "k8s.io/api/apps/v1" @@ -13,13 +17,103 @@ import ( "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" ) -// ApplyDeployment merges objectmeta and requires matching generation. It returns the final Object, whether any change as made, and an error -func ApplyDeployment(client appsclientv1.DeploymentsGetter, recorder events.Recorder, required *appsv1.Deployment, expectedGeneration int64, +// The Apply methods in this file ensure that a resource is created or updated to match +// the form provided by the caller. +// +// If the resource does not yet exist, it will be created. +// +// If the resource exists, the metadata of the required resource will be merged with the +// existing resource and an update will be performed if the spec and metadata differ between +// the required and existing resources. To be reliable, the input of the required spec from +// the operator should be stable. It does not need to set all fields, since some fields are +// defaulted server-side. Detection of spec drift from intent by other actors is determined +// by generation, not by spec comparison. +// +// To ensure an update in response to state external to the resource spec, the caller should +// set an annotation representing that external state e.g. +// +// `myoperator.openshift.io/config-resource-version: ` +// +// An update will be performed if: +// +// - The required resource metadata differs from that of the existing resource. +// - The difference will be detected by comparing the name, namespace, labels and +// annotations of the 2 resources. +// +// - The generation expected by the operator differs from generation of the existing +// resource. +// - This is the likely result of an actor other than the operator updating a resource +// managed by the operator. +// +// - The spec of the required resource differs from the spec of the existing resource. +// - The difference will be detected via metadata comparison since the hash of the +// resource's spec will be set as an annotation prior to comparison. + +const specHashAnnotation = "operator.openshift.io/spec-hash" + +// SetSpecHashAnnotation computes the hash of the provided spec and sets an annotation of the +// hash on the provided ObjectMeta. This method is used internally by Apply methods, and +// is exposed to support testing with fake clients that need to know the mutated form of the +// resource resulting from an Apply call. +func SetSpecHashAnnotation(objMeta *metav1.ObjectMeta, spec interface{}) error { + jsonBytes, err := json.Marshal(spec) + if err != nil { + return err + } + specHash := fmt.Sprintf("%x", sha256.Sum256(jsonBytes)) + if objMeta.Annotations == nil { + objMeta.Annotations = map[string]string{} + } + objMeta.Annotations[specHashAnnotation] = specHash + return nil +} + +// ApplyDeployment ensures the form of the specified deployment is present in the API. If it +// does not exist, it will be created. If it does exist, the metadata of the required +// deployment will be merged with the existing deployment and an update performed if the +// deployment spec and metadata differ from the previously required spec and metadata. For +// further detail, check the top-level comment. +// +// NOTE: The previous implementation of this method was renamed to +// ApplyDeploymentWithForce. If are reading this in response to a compile error due to the +// change in signature, you have the following options: +// +// - Update the calling code to rely on the spec comparison provided by the new +// implementation. If the code in question was specifying the force parameter to ensure +// rollout in response to changes in resources external to the deployment, it will need to be +// revised to set that external state as an annotation e.g. +// +// myoperator.openshift.io/my-resource: +// +// - Update the call to use ApplyDeploymentWithForce. This is available as a temporary measure +// but the method is deprecated and will be removed in 4.6. +func ApplyDeployment(client appsclientv1.DeploymentsGetter, recorder events.Recorder, + requiredOriginal *appsv1.Deployment, expectedGeneration int64) (*appsv1.Deployment, bool, error) { + + required := requiredOriginal.DeepCopy() + err := SetSpecHashAnnotation(&required.ObjectMeta, required.Spec) + if err != nil { + return nil, false, err + } + + return ApplyDeploymentWithForce(client, recorder, required, expectedGeneration, false) +} + +// ApplyDeploymentWithForce merges objectmeta and requires matching generation. It returns the final Object, whether any change as made, and an error. +// +// DEPRECATED - This method will be removed in 4.6 and callers will need to migrate to ApplyDeployment before then. +func ApplyDeploymentWithForce(client appsclientv1.DeploymentsGetter, recorder events.Recorder, requiredOriginal *appsv1.Deployment, expectedGeneration int64, forceRollout bool) (*appsv1.Deployment, bool, error) { + + required := requiredOriginal.DeepCopy() if required.Annotations == nil { required.Annotations = map[string]string{} } - required.Annotations["operator.openshift.io/pull-spec"] = required.Spec.Template.Spec.Containers[0].Image + if _, ok := required.Annotations[specHashAnnotation]; !ok { + // If the spec hash annotation is not present, the caller expects the + // pull-spec annotation to be applied. + required.Annotations["operator.openshift.io/pull-spec"] = required.Spec.Template.Spec.Containers[0].Image + } existing, err := client.Deployments(required.Namespace).Get(required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { actual, err := client.Deployments(required.Namespace).Create(required) @@ -64,12 +158,49 @@ func ApplyDeployment(client appsclientv1.DeploymentsGetter, recorder events.Reco return actual, true, err } -// ApplyDaemonSet merges objectmeta and requires matching generation. It returns the final Object, whether any change as made, and an error -func ApplyDaemonSet(client appsclientv1.DaemonSetsGetter, recorder events.Recorder, required *appsv1.DaemonSet, expectedGeneration int64, forceRollout bool) (*appsv1.DaemonSet, bool, error) { +// ApplyDaemonSet ensures the form of the specified daemonset is present in the API. If it +// does not exist, it will be created. If it does exist, the metadata of the required +// daemonset will be merged with the existing daemonset and an update performed if the +// daemonset spec and metadata differ from the previously required spec and metadata. For +// further detail, check the top-level comment. +// +// NOTE: The previous implementation of this method was renamed to ApplyDaemonSetWithForce. If +// are reading this in response to a compile error due to the change in signature, you have +// the following options: +// +// - Update the calling code to rely on the spec comparison provided by the new +// implementation. If the code in question was specifying the force parameter to ensure +// rollout in response to changes in resources external to the daemonset, it will need to be +// revised to set that external state as an annotation e.g. +// +// myoperator.openshift.io/my-resource: +// +// - Update the call to use ApplyDaemonSetWithForce. This is available as a temporary measure +// but the method is deprecated and will be removed in 4.6. +func ApplyDaemonSet(client appsclientv1.DaemonSetsGetter, recorder events.Recorder, + requiredOriginal *appsv1.DaemonSet, expectedGeneration int64) (*appsv1.DaemonSet, bool, error) { + + required := requiredOriginal.DeepCopy() + err := SetSpecHashAnnotation(&required.ObjectMeta, required.Spec) + if err != nil { + return nil, false, err + } + + return ApplyDaemonSetWithForce(client, recorder, required, expectedGeneration, false) +} + +// ApplyDaemonSetWithForce merges objectmeta and requires matching generation. It returns the final Object, whether any change as made, and an error +// DEPRECATED - This method will be removed in 4.6 and callers will need to migrate to ApplyDaemonSet before then. +func ApplyDaemonSetWithForce(client appsclientv1.DaemonSetsGetter, recorder events.Recorder, requiredOriginal *appsv1.DaemonSet, expectedGeneration int64, forceRollout bool) (*appsv1.DaemonSet, bool, error) { + required := requiredOriginal.DeepCopy() if required.Annotations == nil { required.Annotations = map[string]string{} } - required.Annotations["operator.openshift.io/pull-spec"] = required.Spec.Template.Spec.Containers[0].Image + if _, ok := required.Annotations[specHashAnnotation]; !ok { + // If the spec hash annotation is not present, the caller expects the + // pull-spec annotation to be applied. + required.Annotations["operator.openshift.io/pull-spec"] = required.Spec.Template.Spec.Containers[0].Image + } existing, err := client.DaemonSets(required.Namespace).Get(required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { actual, err := client.DaemonSets(required.Namespace).Create(required) diff --git a/vendor/github.com/openshift/oc/Makefile b/vendor/github.com/openshift/oc/Makefile index 987ad94e3f1..e30cdafd815 100644 --- a/vendor/github.com/openshift/oc/Makefile +++ b/vendor/github.com/openshift/oc/Makefile @@ -58,6 +58,10 @@ image-ocp-deployer: image-ocp-cli $(call build-image,ocp-recycler,$(IMAGE_REGISTRY)/ocp/4.2:recycler,./images/recycler/Dockerfile.rhel,.) image-ocp-recycler: image-ocp-cli +oc: GO_BUILD_PACKAGES :=./cmd/oc +oc: build +.PHONY: oc + update: update-generated-completions .PHONY: update diff --git a/vendor/github.com/openshift/oc/contrib/completions/bash/oc b/vendor/github.com/openshift/oc/contrib/completions/bash/oc index e8d044a6e06..501537bb8a3 100644 --- a/vendor/github.com/openshift/oc/contrib/completions/bash/oc +++ b/vendor/github.com/openshift/oc/contrib/completions/bash/oc @@ -5429,6 +5429,8 @@ _oc_adm_release_mirror() flags_with_completion=() flags_completion=() + flags+=("--apply-release-image-signature") + local_nonpersistent_flags+=("--apply-release-image-signature") flags+=("--dry-run") local_nonpersistent_flags+=("--dry-run") flags+=("--from=") @@ -5442,10 +5444,15 @@ _oc_adm_release_mirror() flags+=("--max-per-registry=") two_word_flags+=("--max-per-registry") local_nonpersistent_flags+=("--max-per-registry=") + flags+=("--overwrite") + local_nonpersistent_flags+=("--overwrite") flags+=("--registry-config=") two_word_flags+=("--registry-config") two_word_flags+=("-a") local_nonpersistent_flags+=("--registry-config=") + flags+=("--release-image-signature-to-dir=") + two_word_flags+=("--release-image-signature-to-dir") + local_nonpersistent_flags+=("--release-image-signature-to-dir=") flags+=("--skip-release-image") local_nonpersistent_flags+=("--skip-release-image") flags+=("--skip-verification") diff --git a/vendor/github.com/openshift/oc/contrib/completions/zsh/oc b/vendor/github.com/openshift/oc/contrib/completions/zsh/oc index d0ff47c1501..d911efe5832 100644 --- a/vendor/github.com/openshift/oc/contrib/completions/zsh/oc +++ b/vendor/github.com/openshift/oc/contrib/completions/zsh/oc @@ -5571,6 +5571,8 @@ _oc_adm_release_mirror() flags_with_completion=() flags_completion=() + flags+=("--apply-release-image-signature") + local_nonpersistent_flags+=("--apply-release-image-signature") flags+=("--dry-run") local_nonpersistent_flags+=("--dry-run") flags+=("--from=") @@ -5584,10 +5586,15 @@ _oc_adm_release_mirror() flags+=("--max-per-registry=") two_word_flags+=("--max-per-registry") local_nonpersistent_flags+=("--max-per-registry=") + flags+=("--overwrite") + local_nonpersistent_flags+=("--overwrite") flags+=("--registry-config=") two_word_flags+=("--registry-config") two_word_flags+=("-a") local_nonpersistent_flags+=("--registry-config=") + flags+=("--release-image-signature-to-dir=") + two_word_flags+=("--release-image-signature-to-dir") + local_nonpersistent_flags+=("--release-image-signature-to-dir=") flags+=("--skip-release-image") local_nonpersistent_flags+=("--skip-release-image") flags+=("--skip-verification") diff --git a/vendor/github.com/openshift/oc/go.mod b/vendor/github.com/openshift/oc/go.mod index 2b01f7b3f8e..ee9e52fbdcb 100644 --- a/vendor/github.com/openshift/oc/go.mod +++ b/vendor/github.com/openshift/oc/go.mod @@ -33,10 +33,10 @@ require ( github.com/moby/buildkit v0.0.0-20181107081847-c3a857e3fca0 github.com/mtrmac/gpgme v0.1.2 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 - github.com/openshift/api v0.0.0-20200205133042-34f0ec8dab87 + github.com/openshift/api v0.0.0-20200210091934-a0e53e94816b github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160 github.com/openshift/client-go v0.0.0-20200116152001-92a2713fa240 - github.com/openshift/library-go v0.0.0-20200206134157-b4c763d94dcf + github.com/openshift/library-go v0.0.0-20200521120150-e4959e210d3a github.com/operator-framework/operator-registry v1.5.11 github.com/pkg/errors v0.8.1 github.com/prometheus/client_golang v1.1.0 @@ -47,12 +47,12 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.1.0 // indirect golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 - golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 + golang.org/x/net v0.0.0-20200202094626-16171245cfb2 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 gopkg.in/ldap.v2 v2.5.1 - k8s.io/api v0.17.1 - k8s.io/apimachinery v0.17.1 + k8s.io/api v0.17.2 + k8s.io/apimachinery v0.17.2 k8s.io/apiserver v0.17.1 k8s.io/cli-runtime v0.17.0 k8s.io/client-go v8.0.0+incompatible @@ -84,7 +84,7 @@ replace ( k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.17.1 k8s.io/kube-proxy => k8s.io/kube-proxy v0.17.1 k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.17.1 - k8s.io/kubectl => github.com/openshift/kubernetes-kubectl v0.0.0-20200211153013-50adac736181 + k8s.io/kubectl => github.com/openshift/kubernetes-kubectl v0.0.0-20200514121803-1a063728c98c k8s.io/kubelet => k8s.io/kubelet v0.17.1 k8s.io/kubernetes => github.com/openshift/kubernetes v1.17.0-alpha.0.0.20191216151305-079984b0a154 k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.17.1 diff --git a/vendor/github.com/openshift/oc/go.sum b/vendor/github.com/openshift/oc/go.sum index d7453158bee..0d9ce55f65f 100644 --- a/vendor/github.com/openshift/oc/go.sum +++ b/vendor/github.com/openshift/oc/go.sum @@ -323,6 +323,8 @@ github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang-migrate/migrate/v4 v4.6.2 h1:LDDOHo/q1W5UDj6PbkxdCv7lv9yunyZHXvxuwDkGo3k= github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -401,6 +403,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -609,9 +613,8 @@ github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/openshift/api v0.0.0-20200116145750-0e2ff1e215dd/go.mod h1:fT6U/JfG8uZzemTRwZA2kBDJP5nWz7v05UHnty/D+pk= -github.com/openshift/api v0.0.0-20200205133042-34f0ec8dab87 h1:L/fZlWB7DdYCd09r9LvBa44xRH42Dx80ybxfN1h5C8Y= -github.com/openshift/api v0.0.0-20200205133042-34f0ec8dab87/go.mod h1:fT6U/JfG8uZzemTRwZA2kBDJP5nWz7v05UHnty/D+pk= -github.com/openshift/build-machinery-go v0.0.0-20200205161356-ef115f5adc73/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= +github.com/openshift/api v0.0.0-20200210091934-a0e53e94816b h1:BERD6sZj7w9Tt0RBpuw87AC0+SppyxEUgUG/Of5rI+E= +github.com/openshift/api v0.0.0-20200210091934-a0e53e94816b/go.mod h1:fT6U/JfG8uZzemTRwZA2kBDJP5nWz7v05UHnty/D+pk= github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160 h1:V4E6yt4XWiBEPKnJbs/E8pgUq9AjZqzQfsL3eeT84Qs= github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160/go.mod h1:1CkcsT3aVebzRBzVTSbiKSkJMsC/CASqxesfqEMfJEc= github.com/openshift/client-go v0.0.0-20200116152001-92a2713fa240 h1:XYfJWv2Ch+qInGLDEedHRtDsJwnxyU1L8U7SY56NcA8= @@ -628,10 +631,10 @@ github.com/openshift/kubernetes-cli-runtime v0.0.0-20200114162348-c8810ef308ee h github.com/openshift/kubernetes-cli-runtime v0.0.0-20200114162348-c8810ef308ee/go.mod h1:1E5iQpMODZq2lMWLUJELwRu2MLWIzwvMgDBpn3Y81Qo= github.com/openshift/kubernetes-client-go v0.0.0-20191211181558-5dcabadb2b45 h1:jHJuv5QzUaLdx50lkvTYcZqM59xNhV6insW6K0EAduQ= github.com/openshift/kubernetes-client-go v0.0.0-20191211181558-5dcabadb2b45/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -github.com/openshift/kubernetes-kubectl v0.0.0-20200211153013-50adac736181 h1:4WxKYoPDfiSAGA85zyjYUo1re4onK9MUcmfMc0U0CLs= -github.com/openshift/kubernetes-kubectl v0.0.0-20200211153013-50adac736181/go.mod h1:jIPrUAW656Vzn9wZCCe0PC+oTcu56u2HgFD21Xbfk1s= -github.com/openshift/library-go v0.0.0-20200206134157-b4c763d94dcf h1:KXxMZGtbwefe89jh+XdZRcj2UMO71jdIZhKM3CQefMQ= -github.com/openshift/library-go v0.0.0-20200206134157-b4c763d94dcf/go.mod h1:mLRZGYfPe9Kaum4pyhn6hTO3FTPjOZKFB0RxQSIxiuQ= +github.com/openshift/kubernetes-kubectl v0.0.0-20200514121803-1a063728c98c h1:OXoXztgMiZAJoLwOK+jqof44Uzf05ZE7R+NRnsIcz6g= +github.com/openshift/kubernetes-kubectl v0.0.0-20200514121803-1a063728c98c/go.mod h1:jIPrUAW656Vzn9wZCCe0PC+oTcu56u2HgFD21Xbfk1s= +github.com/openshift/library-go v0.0.0-20200521120150-e4959e210d3a h1:gQ//Tpad7iV061CKTsouAE65aMgNArhuGqOeVgGqE+Q= +github.com/openshift/library-go v0.0.0-20200521120150-e4959e210d3a/go.mod h1:HM1nXsKTup/9rYnmXdYbbN+8Ux8Xp39odoqZ4qvSyBo= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/operator-framework/api v0.1.0/go.mod h1:/Jcpy9Ls8W1LK1hhEw30nCRBSBzbT8e/fE09TfRG0To= github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= @@ -877,6 +880,8 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= diff --git a/vendor/github.com/openshift/oc/pkg/cli/admin/release/extract.go b/vendor/github.com/openshift/oc/pkg/cli/admin/release/extract.go index a04d6a83da5..e6182e4a34d 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/admin/release/extract.go +++ b/vendor/github.com/openshift/oc/pkg/cli/admin/release/extract.go @@ -2,34 +2,46 @@ package release import ( "archive/tar" + "bytes" "fmt" "io" + "io/ioutil" "os" + "path" + "path/filepath" + "strings" "time" digest "github.com/opencontainers/go-digest" "github.com/spf13/cobra" "k8s.io/klog" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/cli-runtime/pkg/genericclioptions" kcmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/templates" "github.com/openshift/library-go/pkg/image/dockerv1client" + "github.com/openshift/library-go/pkg/manifest" "github.com/openshift/oc/pkg/cli/image/extract" "github.com/openshift/oc/pkg/cli/image/imagesource" imagemanifest "github.com/openshift/oc/pkg/cli/image/manifest" + "github.com/pkg/errors" ) -func NewExtractOptions(streams genericclioptions.IOStreams) *ExtractOptions { +// NewExtractOptions is also used internally as part of image mirroring. For image mirroring +// internal use, extractManifests is set to true so image manifest files are searched for +// signature information to be returned for use by mirroring. +func NewExtractOptions(streams genericclioptions.IOStreams, extractManifests bool) *ExtractOptions { return &ExtractOptions{ - IOStreams: streams, - Directory: ".", + IOStreams: streams, + Directory: ".", + ExtractManifests: extractManifests, } } func NewExtract(f kcmdutil.Factory, parentName string, streams genericclioptions.IOStreams) *cobra.Command { - o := NewExtractOptions(streams) + o := NewExtractOptions(streams, false) cmd := &cobra.Command{ Use: "extract", Short: "Extract the contents of an update payload to disk", @@ -88,7 +100,8 @@ type ExtractOptions struct { SecurityOptions imagemanifest.SecurityOptions ParallelOptions imagemanifest.ParallelOptions - From string + FromDir string + From string Tools bool Command string @@ -102,6 +115,9 @@ type ExtractOptions struct { File string FileDir string + ExtractManifests bool + Manifests []manifest.Manifest + ImageMetadataCallback func(m *extract.Mapping, dgst, contentDigest digest.Digest, config *dockerv1client.DockerImageConfig) } @@ -167,6 +183,7 @@ func (o *ExtractOptions) Run() error { return err } opts := extract.NewOptions(genericclioptions.IOStreams{Out: o.Out, ErrOut: o.ErrOut}) + opts.ParallelOptions = o.ParallelOptions opts.SecurityOptions = o.SecurityOptions opts.FileDir = o.FileDir @@ -184,16 +201,64 @@ func (o *ExtractOptions) Run() error { To: dir, }, } + var manifestErrs []error found := false opts.TarEntryCallback = func(hdr *tar.Header, _ extract.LayerInfo, r io.Reader) (bool, error) { - if hdr.Name != o.File { + if !o.ExtractManifests { + if hdr.Name != o.File { + return true, nil + } + if _, err := io.Copy(o.Out, r); err != nil { + return false, err + } + found = true + return false, nil + } else { + switch hdr.Name { + case o.File: + if _, err := io.Copy(o.Out, r); err != nil { + return false, err + } + found = true + case "image-references": + return true, nil + case "release-metadata": + return true, nil + default: + if ext := path.Ext(hdr.Name); len(ext) > 0 && (ext == ".yaml" || ext == ".yml" || ext == ".json") { + klog.V(4).Infof("Found manifest %s", hdr.Name) + raw, err := ioutil.ReadAll(r) + if err != nil { + manifestErrs = append(manifestErrs, errors.Wrapf(err, "error reading file %s", hdr.Name)) + return true, nil + } + ms, err := manifest.ParseManifests(bytes.NewReader(raw)) + if err != nil { + manifestErrs = append(manifestErrs, errors.Wrapf(err, "error parsing %s", hdr.Name)) + return true, nil + } + for i := range ms { + ms[i].OriginalFilename = filepath.Base(hdr.Name) + src := fmt.Sprintf("the config map %s/%s", ms[i].Obj.GetNamespace(), ms[i].Obj.GetName()) + data, _, err := unstructured.NestedStringMap(ms[i].Obj.Object, "data") + if err != nil { + manifestErrs = append(manifestErrs, errors.Wrapf(err, "%s is not valid", src)) + continue + } + for k, v := range data { + switch { + case strings.HasPrefix(k, "verifier-public-key-"): + klog.V(2).Infof("Found in %s:\n%s %s", hdr.Name, k, v) + case strings.HasPrefix(k, "store-"): + klog.V(2).Infof("Found in %s:\n%s\n%s", hdr.Name, k, v) + } + } + } + o.Manifests = append(o.Manifests, ms...) + } + } return true, nil } - if _, err := io.Copy(o.Out, r); err != nil { - return false, err - } - found = true - return false, nil } if err := opts.Run(); err != nil { return err @@ -201,6 +266,21 @@ func (o *ExtractOptions) Run() error { if !found { return fmt.Errorf("image did not contain %s", o.File) } + + // Only output manifest errors if manifests were being extracted and we didn't find the expected signature + // manifests. We don't care about errors in other manifests and they will only confuse/alarm the user. + // Do not return an error so current operation, e.g. mirroring, continues. + if len(manifestErrs) > 0 { + if o.ExtractManifests && len(o.Manifests) == 0 { + fmt.Fprintf(o.ErrOut, "Errors: %s\n", errorList(manifestErrs)) + } + } + + // Output an error if manifests were being extracted and we didn't find the expected signature + // manifests. Do not return an error so current operation, e.g. mirroring, continues. + if o.ExtractManifests && len(o.Manifests) == 0 { + fmt.Fprintf(o.ErrOut, "No manifests found\n") + } return nil default: diff --git a/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go b/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go index bbb990005b0..7ddb2d40ac6 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go +++ b/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go @@ -4,9 +4,13 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" + "io/ioutil" + "net/http" "os" + "path/filepath" "sort" "strings" "sync" @@ -15,11 +19,14 @@ import ( digest "github.com/opencontainers/go-digest" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/transport" "k8s.io/client-go/util/retry" "k8s.io/klog" kcmdutil "k8s.io/kubectl/pkg/cmd/util" @@ -31,12 +38,26 @@ import ( imageclient "github.com/openshift/client-go/image/clientset/versioned" "github.com/openshift/library-go/pkg/image/dockerv1client" imagereference "github.com/openshift/library-go/pkg/image/reference" + "github.com/openshift/library-go/pkg/manifest" "github.com/openshift/oc/pkg/cli/image/extract" "github.com/openshift/oc/pkg/cli/image/imagesource" imagemanifest "github.com/openshift/oc/pkg/cli/image/manifest" "github.com/openshift/oc/pkg/cli/image/mirror" + "github.com/openshift/oc/pkg/helpers/release" ) +// configFilesBaseDir is created under '--to-dir', when specified, to contain release image +// signature files. It is not used when '--release-image-signature-to-dir` is specified +// which takes precedence over '--to-dir'. +const configFilesBaseDir = "config" + +// maxDigestHashLen is used to truncate digest hash portion before using as part of +// signature file name. +const maxDigestHashLen = 16 + +// signatureFileNameFmt defines format of the release image signature file name +const signatureFileNameFmt = "signature-%s-%s.yaml" + // NewMirrorOptions creates the options for mirroring a release. func NewMirrorOptions(streams genericclioptions.IOStreams) *MirrorOptions { return &MirrorOptions{ @@ -59,39 +80,61 @@ func NewMirror(f kcmdutil.Factory, parentName string, streams genericclioptions. Use: "mirror", Short: "Mirror a release to a different image registry location", Long: templates.LongDesc(` - Mirror an OpenShift release image to another registry + Mirror an OpenShift release image to another registry and produce a configuration + manifest containing the release image signature. Copies the images and update payload for a given release from one registry to another. By default this command will not alter the payload and will print out the configuration that must be applied to a cluster to use the mirror, but you may opt to rewrite the update to point to the new location and lose the cryptographic integrity of the update. + Creates a release image signature ConfigMap that can be saved to a directory, applied + directly to a connected cluster, or both. + The common use for this command is to mirror a specific OpenShift release version to - a private registry for use in a disconnected or offline context. The command copies all - images that are part of a release into the target repository and then prints the - correct information to give to OpenShift to use that content offline. An alternate mode - is to specify --to-image-stream, which imports the images directly into an OpenShift - image stream. + a private registry and create a signature ConfigMap for use in a disconnected or + offline context. The command copies all images that are part of a release into the + target repository and then prints the correct information to give to OpenShift to use + that content offline. An alternate mode is to specify --to-image-stream, which imports + the images directly into an OpenShift image stream. You may use --to-dir to specify a directory to download release content into, and add the file:// prefix to the --to flag. The command will print the 'oc image mirror' command that can be used to upload the release to another registry. + + You may use --apply-release-image-signature, --release-image-signature-to-dir, or both + to control the handling of the signature ConfigMap. Option + --apply-release-image-signature will apply the ConfigMap directly to a connected + cluster while --release-image-signature-to-dir specifies an export target directory. If + --release-image-signature-to-dir is not specified but --to-dir is, + --release-image-signature-to-dir defaults to a 'config' subdirectory of --to-dir. + The --overwrite option only applies when --apply-release-image-signature is specified + and indicates to update an exisiting ConfigMap if one is found. A ConfigMap written to a + directory will always replace onethat already exists. `), - Example: templates.Examples(` + Example: templates.Examples(fmt.Sprintf(` # Perform a dry run showing what would be mirrored, including the mirror objects - %[1]s 4.2.2 --to myregistry.local/openshift/release --dry-run + %[1]s mirror 4.3.0 --to myregistry.local/openshift/release \ + --release-image-signature-to-dir /tmp/releases --dry-run # Mirror a release into the current directory - %[1]s 4.2.2 --to file://openshift/release + %[1]s mirror 4.3.0 --to file://openshift/release \ + --release-image-signature-to-dir /tmp/releases # Mirror a release to another directory in the default location - %[1]s 4.2.2 --to-dir /tmp/releases + %[1]s mirror 4.3.0 --to-dir /tmp/releases # Upload a release from the current directory to another server - %[1]s --from file://openshift/release --to myregistry.com/openshift/release - `), + %[1]s mirror --from file://openshift/release --to myregistry.com/openshift/release \ + --release-image-signature-to-dir /tmp/releases + + # Mirror the 4.3.0 release to repository registry.example.com and apply signatures to connected cluster + %[1]s mirror --from=quay.io/openshift-release-dev/ocp-release:4.3.0-x86_64 \ + --to=registry.example.com/your/repository --apply-release-image-signature + `, parentName)), Run: func(cmd *cobra.Command, args []string) { kcmdutil.CheckErr(o.Complete(cmd, f, args)) + kcmdutil.CheckErr(o.Validate()) kcmdutil.CheckErr(o.Run()) }, } @@ -102,13 +145,16 @@ func NewMirror(f kcmdutil.Factory, parentName string, streams genericclioptions. flags.StringVar(&o.From, "from", o.From, "Image containing the release payload.") flags.StringVar(&o.To, "to", o.To, "An image repository to push to.") flags.StringVar(&o.ToImageStream, "to-image-stream", o.ToImageStream, "An image stream to tag images into.") - flags.StringVar(&o.FromDir, "from-dir", o.ToDir, "A directory to import images from.") + flags.StringVar(&o.FromDir, "from-dir", o.FromDir, "A directory to import images from.") flags.StringVar(&o.ToDir, "to-dir", o.ToDir, "A directory to export images to.") flags.BoolVar(&o.ToMirror, "to-mirror", o.ToMirror, "Output the mirror mappings instead of mirroring.") flags.BoolVar(&o.DryRun, "dry-run", o.DryRun, "Display information about the mirror without actually executing it.") + flags.BoolVar(&o.ApplyReleaseImageSignature, "apply-release-image-signature", o.ApplyReleaseImageSignature, "Apply release image signature to connected cluster.") + flags.StringVar(&o.ReleaseImageSignatureToDir, "release-image-signature-to-dir", o.ReleaseImageSignatureToDir, "A directory to export release image signature to.") flags.BoolVar(&o.SkipRelease, "skip-release-image", o.SkipRelease, "Do not push the release image.") - flags.StringVar(&o.ToRelease, "to-release-image", o.ToRelease, "Specify an alternate locations for the release image instead as tag 'release' in --to") + flags.StringVar(&o.ToRelease, "to-release-image", o.ToRelease, "Specify an alternate locations for the release image instead as tag 'release' in --to.") + flags.BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Used with --apply-release-image-signature to update exisitng signature configmap.") return cmd } @@ -131,10 +177,15 @@ type MirrorOptions struct { ToMirror bool ToDir string + ApplyReleaseImageSignature bool + ReleaseImageSignatureToDir string + Overwrite bool + DryRun bool PrintImageContentInstructions bool - ClientFn func() (imageclient.Interface, string, error) + ImageClientFn func() (imageclient.Interface, string, error) + CoreV1ClientFn func() (corev1client.ConfigMapInterface, error) ImageStream *imagev1.ImageStream TargetFn func(component string) imagereference.DockerImageReference @@ -161,7 +212,7 @@ func (o *MirrorOptions) Complete(cmd *cobra.Command, f kcmdutil.Factory, args [] } o.From = args[0] - o.ClientFn = func() (imageclient.Interface, string, error) { + o.ImageClientFn = func() (imageclient.Interface, string, error) { cfg, err := f.ToRESTConfig() if err != nil { return nil, "", err @@ -176,14 +227,23 @@ func (o *MirrorOptions) Complete(cmd *cobra.Command, f kcmdutil.Factory, args [] } return client, ns, nil } + o.CoreV1ClientFn = func() (corev1client.ConfigMapInterface, error) { + cfg, err := f.ToRESTConfig() + if err != nil { + return nil, err + } + coreClient, err := corev1client.NewForConfig(cfg) + if err != nil { + return nil, err + } + client := coreClient.ConfigMaps(release.NamespaceLabelConfigMap) + return client, nil + } o.PrintImageContentInstructions = true return nil } -const replaceComponentMarker = "X-X-X-X-X-X-X" -const replaceVersionMarker = "V-V-V-V-V-V-V" - -func (o *MirrorOptions) Run() error { +func (o *MirrorOptions) Validate() error { if len(o.From) == 0 && o.ImageStream == nil { return fmt.Errorf("must specify a release image with --from") } @@ -213,6 +273,111 @@ func (o *MirrorOptions) Run() error { return fmt.Errorf("--skip-release-image and --to-release-image may not both be specified") } + if len(o.ReleaseImageSignatureToDir) == 0 && len(o.ToDir) > 0 { + o.ReleaseImageSignatureToDir = filepath.Join(o.ToDir, configFilesBaseDir) + } + + if o.Overwrite && !o.ApplyReleaseImageSignature { + return fmt.Errorf("--overwite is only valid when --apply-release-image-signature is specified") + } + return nil +} + +const replaceComponentMarker = "X-X-X-X-X-X-X" +const replaceVersionMarker = "V-V-V-V-V-V-V" + +// verifyClientBuilder is a wrapper around the operator's HTTPClient method. +// It is used by the image verifier to get an up-to-date http client. +type verifyClientBuilder struct { + builder func() (*http.Client, error) +} + +func (vcb *verifyClientBuilder) HTTPClient() (*http.Client, error) { + return vcb.builder() +} + +func createSignatureFileName(digest string) (string, error) { + parts := strings.SplitN(digest, ":", 3) + if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { + return "", fmt.Errorf("the provided digest, %s, must be of the form ALGO:HASH", digest) + } + algo, hash := parts[0], parts[1] + + if len(hash) > maxDigestHashLen { + hash = hash[:maxDigestHashLen] + } + return fmt.Sprintf(signatureFileNameFmt, algo, hash), nil +} + +// handleSignatures implements the image release signature configmap specific logic. +// Signature configmaps may be written to a directory or applied to a cluster. +func (o *MirrorOptions) handleSignatures(context context.Context, signaturesByDigest map[string][][]byte) error { + var client corev1client.ConfigMapInterface + if !o.DryRun && o.ApplyReleaseImageSignature { + var err error + client, err = o.CoreV1ClientFn() + if err != nil { + return fmt.Errorf("creating a Kubernetes API client: %v", err) + } + } + for digest, signatures := range signaturesByDigest { + cmData, err := release.GetSignaturesAsConfigmap(digest, signatures) + if err != nil { + return fmt.Errorf("converting signatures to a configmap: %v", err) + } + if o.ApplyReleaseImageSignature { + if o.DryRun { + fmt.Fprintf(o.Out, "info: Create or configure configmap %s\n", cmData.Name) + } else { + var create bool = true + if o.Overwrite { + // An error is returned if the configmap does not exist in which case we will + // attempt to create the manifest. + if _, err := client.Get(cmData.Name, metav1.GetOptions{}); err == nil { + create = false + if _, err := client.Update(cmData); err != nil { + return fmt.Errorf("updating configmap %s: %v", cmData.Name, err) + } else { + fmt.Fprintf(o.Out, "configmap/%s configured\n", cmData.Name) + } + } + } + if create { + if _, err := client.Create(cmData); err != nil { + return fmt.Errorf("creating configmap %s: %v", cmData.Name, err) + } else { + fmt.Fprintf(o.Out, "configmap/%s created\n", cmData.Name) + } + } + } + } + if len(o.ReleaseImageSignatureToDir) > 0 { + fileName, err := createSignatureFileName(digest) + if err != nil { + return fmt.Errorf("creating filename: %v", err) + } + fullName := filepath.Join(o.ReleaseImageSignatureToDir, fileName) + if o.DryRun { + fmt.Fprintf(o.Out, "info: Write configmap signature file %s\n", fullName) + } else { + cmDataBytes, err := yaml.Marshal(cmData) + if err != nil { + return fmt.Errorf("marshaling configmap YAML: %v", err) + } + if err := os.MkdirAll(filepath.Dir(fullName), 0750); err != nil { + return err + } + if err := ioutil.WriteFile(fullName, cmDataBytes, 0640); err != nil { + return err + } + fmt.Fprintf(o.Out, "Configmap signature file %s created\n", fullName) + } + } + } + return nil +} + +func (o *MirrorOptions) Run() error { var recreateRequired bool var hasPrefix bool var targetFn func(name string) imagesource.TypedImageReference @@ -289,6 +454,8 @@ func (o *MirrorOptions) Run() error { return fmt.Errorf("when mirroring to multiple repositories, use the new release command with --from-release and --mirror") } + var releaseDigest string + var manifests []manifest.Manifest verifier := imagemanifest.NewVerifier() is := o.ImageStream if is == nil { @@ -296,11 +463,14 @@ func (o *MirrorOptions) Run() error { is = o.ImageStream // load image references buf := &bytes.Buffer{} - extractOpts := NewExtractOptions(genericclioptions.IOStreams{Out: buf, ErrOut: o.ErrOut}) + extractOpts := NewExtractOptions(genericclioptions.IOStreams{Out: buf, ErrOut: o.ErrOut}, true) + extractOpts.ParallelOptions = o.ParallelOptions extractOpts.SecurityOptions = o.SecurityOptions extractOpts.ImageMetadataCallback = func(m *extract.Mapping, dgst, contentDigest digest.Digest, config *dockerv1client.DockerImageConfig) { + releaseDigest = contentDigest.String() verifier.Verify(dgst, contentDigest) } + extractOpts.FileDir = o.FromDir extractOpts.From = o.From extractOpts.File = "image-references" if err := extractOpts.Run(); err != nil { @@ -319,6 +489,7 @@ func (o *MirrorOptions) Run() error { } fmt.Fprintf(o.ErrOut, "warning: %v\n", err) } + manifests = extractOpts.Manifests } version = is.Name @@ -326,6 +497,26 @@ func (o *MirrorOptions) Run() error { sourceFn := func(ref imagesource.TypedImageReference) imagesource.TypedImageReference { return ref } + // Wraps operator's HTTPClient method to allow image verifier to create http client with up-to-date config + clientBuilder := &verifyClientBuilder{builder: o.HTTPClient} + + // Attempt to load a verifier as defined by the release being mirrored + imageVerifier, err := release.LoadConfigMapVerifierDataFromUpdate(manifests, clientBuilder, nil) + if err != nil { + return fmt.Errorf("Unable to load configmap verifier: %v", err) + } + if imageVerifier != nil { + klog.V(4).Infof("Verifying release authenticity: %v", imageVerifier) + } else { + fmt.Fprintf(o.ErrOut, "warning: No release authenticity verification is configured, all releases are considered unverified\n") + imageVerifier = release.Reject + } + // verify the provided payload + ctx, cancelFn := context.WithCancel(context.Background()) + defer cancelFn() + if err := imageVerifier.Verify(ctx, releaseDigest); err != nil { + fmt.Fprintf(o.ErrOut, "warning: An image was retrieved that failed verification: %v\n", err) + } var mappings []mirror.Mapping if len(o.From) > 0 { src := o.From @@ -440,7 +631,7 @@ func (o *MirrorOptions) Run() error { for _, mapping := range mappings { remaining[mapping.Name] = mapping } - client, ns, err := o.ClientFn() + client, ns, err := o.ImageClientFn() if err != nil { return err } @@ -505,7 +696,7 @@ func (o *MirrorOptions) Run() error { delete(hasErrors, name) } else { delete(remaining, name) - err := errors.FromObject(&image.Status) + err := apierrors.FromObject(&image.Status) hasErrors[name] = err klog.V(2).Infof("Failed to import %s as tag %s: %v", remaining[name].Source, name, err) } @@ -539,6 +730,7 @@ func (o *MirrorOptions) Run() error { opts.SecurityOptions = o.SecurityOptions opts.ParallelOptions = o.ParallelOptions opts.Mappings = mappings + opts.FromFileDir = o.FromDir opts.FileDir = o.ToDir opts.DryRun = o.DryRun opts.ManifestUpdateCallback = func(registry string, manifests map[digest.Digest]digest.Digest) error { @@ -574,6 +766,7 @@ func (o *MirrorOptions) Run() error { if len(to) == 0 { to = targetFn("").Ref.Exact() } + fmt.Fprintf(o.Out, "\nSuccess\nUpdate image: %s\n", to) if len(o.To) > 0 { if hasPrefix { @@ -590,17 +783,36 @@ func (o *MirrorOptions) Run() error { } } else if len(o.To) > 0 { if o.PrintImageContentInstructions { - if err := printImageContentInstructions(o.Out, o.From, o.To, repositories); err != nil { + if err := printImageContentInstructions(o.Out, o.From, o.To, o.ReleaseImageSignatureToDir, repositories); err != nil { return fmt.Errorf("Error creating mirror usage instructions: %v", err) } } } + if o.ApplyReleaseImageSignature || len(o.ReleaseImageSignatureToDir) > 0 { + signatures := imageVerifier.Signatures() + if signatures == nil || len(signatures) == 0 { + return errors.New("failed to retrieve cached signatures") + } + if _, ok := signatures[releaseDigest]; ok { + err := o.handleSignatures(ctx, signatures) + if err != nil { + return fmt.Errorf("handling release image signatures: %v", err) + } + } else { + digests := make([]string, 0, len(signatures)) + for digest := range signatures { + digests = append(digests, digest) + } + sort.Strings(digests) + return fmt.Errorf("no cached signatures for digest %s, just:\n%s", releaseDigest, strings.Join(digests, "\n")) + } + } return nil } // printImageContentInstructions provides examples to the user for using the new repository mirror // https://github.com/openshift/installer/blob/master/docs/dev/alternative_release_image_sources.md -func printImageContentInstructions(out io.Writer, from, to string, repositories map[string]struct{}) error { +func printImageContentInstructions(out io.Writer, from, to string, signatureToDir string, repositories map[string]struct{}) error { type installConfigSubsection struct { ImageContentSources []operatorv1alpha1.RepositoryDigestMirrors `json:"imageContentSources"` } @@ -680,5 +892,26 @@ func printImageContentInstructions(out io.Writer, from, to string, repositories fmt.Fprintf(out, "\n\nTo use the new mirrored repository for upgrades, use the following to create an ImageContentSourcePolicy:\n\n") fmt.Fprintf(out, string(icspExample)) + if len(signatureToDir) != 0 { + fmt.Fprintf(out, "\n\nTo apply signature configmaps use 'oc apply' on files found in %s\n\n", signatureToDir) + } + return nil } + +// HTTPClient provides a method for generating an HTTP client +// with the proxy and trust settings, if set in the cluster. +func (o *MirrorOptions) HTTPClient() (*http.Client, error) { + transport, err := transport.HTTPWrappersForConfig( + &transport.Config{ + UserAgent: rest.DefaultKubernetesUserAgent() + "(release-mirror)", + }, + http.DefaultTransport, + ) + if err != nil { + return nil, err + } + return &http.Client{ + Transport: transport, + }, nil +} diff --git a/vendor/github.com/openshift/oc/pkg/cli/admin/release/new.go b/vendor/github.com/openshift/oc/pkg/cli/admin/release/new.go index 01eb80f1e4d..d74ac1ccaa3 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/admin/release/new.go +++ b/vendor/github.com/openshift/oc/pkg/cli/admin/release/new.go @@ -390,6 +390,7 @@ func (o *NewOptions) Run() error { buf := &bytes.Buffer{} extractOpts := extract.NewOptions(genericclioptions.IOStreams{Out: buf, ErrOut: o.ErrOut}) + extractOpts.ParallelOptions = o.ParallelOptions extractOpts.SecurityOptions = o.SecurityOptions extractOpts.OnlyFiles = true extractOpts.Mappings = []extract.Mapping{ @@ -925,9 +926,9 @@ func (o *NewOptions) extractManifests(is *imageapi.ImageStream, name string, met verifier := imagemanifest.NewVerifier() var lock sync.Mutex opts := extract.NewOptions(genericclioptions.IOStreams{Out: o.Out, ErrOut: o.ErrOut}) + opts.ParallelOptions = o.ParallelOptions opts.SecurityOptions = o.SecurityOptions opts.OnlyFiles = true - opts.ParallelOptions = o.ParallelOptions opts.ImageMetadataCallback = func(m *extract.Mapping, dgst, contentDigest digest.Digest, config *dockerv1client.DockerImageConfig) { verifier.Verify(dgst, contentDigest) @@ -1052,6 +1053,7 @@ func (o *NewOptions) mirrorImages(is *imageapi.ImageStream) error { opts.ImageStream = copied opts.To = o.Mirror opts.SkipRelease = true + opts.ParallelOptions = o.ParallelOptions opts.SecurityOptions = o.SecurityOptions if err := opts.Run(); err != nil { @@ -1182,6 +1184,7 @@ func (o *NewOptions) write(r io.Reader, is *imageapi.ImageStream, now time.Time) verifier := imagemanifest.NewVerifier() options := imageappend.NewAppendImageOptions(genericclioptions.IOStreams{Out: ioutil.Discard, ErrOut: o.ErrOut}) + options.ParallelOptions = o.ParallelOptions options.SecurityOptions = o.SecurityOptions options.DryRun = o.DryRun options.From = toImageBase diff --git a/vendor/github.com/openshift/oc/pkg/cli/project/project.go b/vendor/github.com/openshift/oc/pkg/cli/project/project.go index 9dbc8878079..dc4c0bbc004 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/project/project.go +++ b/vendor/github.com/openshift/oc/pkg/cli/project/project.go @@ -165,10 +165,8 @@ func (o ProjectOptions) Run() error { } switch err := ConfirmProjectAccess(currentProject, client, kubeclient); { - case kapierrors.IsForbidden(err): - return fmt.Errorf("you do not have rights to view project %q.", currentProject) - case kapierrors.IsNotFound(err): - return fmt.Errorf("the project %q specified in your config does not exist.", currentProject) + case kapierrors.IsForbidden(err), kapierrors.IsNotFound(err): + return fmt.Errorf("you do not have rights to view project %q specified in your config or the project doesn't exist", currentProject) case err != nil: return err } diff --git a/vendor/github.com/openshift/oc/pkg/cli/status/status.go b/vendor/github.com/openshift/oc/pkg/cli/status/status.go index e4b371ea932..fa745e883a7 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/status/status.go +++ b/vendor/github.com/openshift/oc/pkg/cli/status/status.go @@ -7,6 +7,7 @@ import ( "github.com/gonum/graph/encoding/dot" "github.com/spf13/cobra" + kapierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" @@ -155,6 +156,13 @@ func (o *StatusOptions) Complete(f kcmdutil.Factory, cmd *cobra.Command, baseCLI if err != nil { return err } + _, err = projectClient.Projects().Get(namespace, metav1.GetOptions{}) + switch { + case kapierrors.IsForbidden(err), kapierrors.IsNotFound(err): + return fmt.Errorf("you do not have rights to view project %q specified in your config or the project doesn't exist", namespace) + case err != nil: + return err + } o.namespace = namespace } diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/configmap.go b/vendor/github.com/openshift/oc/pkg/helpers/release/configmap.go new file mode 100644 index 00000000000..472a7db1ad5 --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/configmap.go @@ -0,0 +1,140 @@ +package release + +import ( + "bytes" + "fmt" + "net/url" + "strings" + + "golang.org/x/crypto/openpgp" + + "github.com/pkg/errors" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog" +) + +// ReleaseAnnotationConfigMapVerifier is an annotation set on a config map in the +// release payload to indicate that this config map controls signing for the payload. +// Only the first config map within the payload should be used, regardless of whether +// it has data. See NewFromConfigMapData for more. +const ReleaseAnnotationConfigMapVerifier = "release.openshift.io/verification-config-map" + +// NamespaceLabelConfigMap is the Namespace label applied to a configmap +// containing signatures. +const NamespaceLabelConfigMap = "openshift-config-managed" + +// ReleaseLabelConfigMap is a label applied to a configmap inside the +// NamespaceLabelConfigMap namespace that indicates it contains signatures +// for release image digests. Any binaryData key that starts with the digest +// is added to the list of signatures checked. +const ReleaseLabelConfigMap = "release.openshift.io/verification-signatures" + +// digestToKeyPrefix changes digest to use '-' in place of ':', +// {algo}-{hash} instead of {algo}:{hash}, because colons are not +// allowed in ConfigMap keys. +func digestToKeyPrefix(digest string) (string, error) { + parts := strings.SplitN(digest, ":", 3) + if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { + return "", fmt.Errorf("the provided digest must be of the form ALGO:HASH") + } + algo, hash := parts[0], parts[1] + return fmt.Sprintf("%s-%s", algo, hash), nil +} + +// GetSignaturesAsConfigmap returns the given signatures in a configmap. Uses +// digestToKeyPrefix to replace colon with dash when saving digest to configmap. +func GetSignaturesAsConfigmap(digest string, signatures [][]byte) (*corev1.ConfigMap, error) { + cm := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: NamespaceLabelConfigMap, + Labels: map[string]string{ + ReleaseLabelConfigMap: "", + }, + }, + BinaryData: make(map[string][]byte), + } + prefix, err := digestToKeyPrefix(digest) + if err != nil { + return nil, err + } + cm.Name = prefix + for i := 0; i < len(signatures); i++ { + cm.BinaryData[fmt.Sprintf("%s-%d", prefix, i+1)] = signatures[i] + } + return cm, nil +} + +// NewFromConfigMapData expects to receive the data field of the first config map in the release +// image payload with the annotation "release.openshift.io/verification-config-map". Only the +// first payload item in lexographic order will be considered - all others are ignored. The +// verifier returned by this method +// +// The presence of one or more config maps instructs the CVO to verify updates before they are +// downloaded. +// +// The keys within the config map in the data field define how verification is performed: +// +// verifier-public-key-*: One or more GPG public keys in ASCII form that must have signed the +// release image by digest. +// +// store-*: A URL (scheme file://, http://, or https://) location that contains signatures. These +// signatures are in the atomic container signature format. The URL will have the digest +// of the image appended to it as "/=/signature-" as described +// in the container image signing format. The docker-image-manifest section of the +// signature must match the release image digest. Signatures are searched starting at +// NUMBER 1 and incrementing if the signature exists but is not valid. The signature is a +// GPG signed and encrypted JSON message. The file store is provided for testing only at +// the current time, although future versions of the CVO might allow host mounting of +// signatures. +// +// See https://github.com/containers/image/blob/ab49b0a48428c623a8f03b41b9083d48966b34a9/docs/signature-protocols.md +// for a description of the signature store +// +// The returned verifier will require that any new release image will only be considered verified +// if each provided public key has signed the release image digest. The signature may be in any +// store and the lookup order is internally defined. +func NewFromConfigMapData(src string, data map[string]string, clientBuilder ClientBuilder) (*ReleaseVerifier, error) { + verifiers := make(map[string]openpgp.EntityList) + var stores []*url.URL + for k, v := range data { + switch { + case strings.HasPrefix(k, "verifier-public-key-"): + keyring, err := loadArmoredOrUnarmoredGPGKeyRing([]byte(v)) + if err != nil { + return nil, errors.Wrapf(err, "%s has an invalid key %q that must be a GPG public key: %v", src, k, err) + } + verifiers[k] = keyring + case strings.HasPrefix(k, "store-"): + v = strings.TrimSpace(v) + u, err := url.Parse(v) + if err != nil || (u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "file") { + return nil, fmt.Errorf("%s has an invalid key %q: must be a valid URL with scheme file://, http://, or https://", src, k) + } + stores = append(stores, u) + default: + klog.Warningf("An unexpected key was found in %s and will be ignored (expected store-* or verifier-public-key-*): %s", src, k) + } + } + if len(stores) == 0 { + return nil, fmt.Errorf("%s did not provide any signature stores to read from and cannot be used", src) + } + if len(verifiers) == 0 { + return nil, fmt.Errorf("%s did not provide any GPG public keys to verify signatures from and cannot be used", src) + } + + return NewReleaseVerifier(verifiers, stores, clientBuilder), nil +} + +func loadArmoredOrUnarmoredGPGKeyRing(data []byte) (openpgp.EntityList, error) { + keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(data)) + if err == nil { + return keyring, nil + } + return openpgp.ReadKeyRing(bytes.NewReader(data)) +} diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/configmap_test.go b/vendor/github.com/openshift/oc/pkg/helpers/release/configmap_test.go new file mode 100644 index 00000000000..3fe99d871b5 --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/configmap_test.go @@ -0,0 +1,78 @@ +package release + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "golang.org/x/crypto/openpgp" +) + +type VerifierAccessor interface { + Verifiers() map[string]openpgp.EntityList +} + +func Test_loadReleaseVerifierFromConfigMap(t *testing.T) { + redhatData, err := ioutil.ReadFile(filepath.Join("testdata", "keyrings", "redhat.txt")) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + data map[string]string + want bool + wantErr bool + wantVerifiers int + }{ + { + name: "requires data", + data: nil, + wantErr: true, + }, + { + name: "requires stores", + data: map[string]string{ + "verifier-public-key-redhat": string(redhatData), + }, + wantErr: true, + }, + { + name: "requires verifiers", + data: map[string]string{ + "store-local": "file://../testdata/signatures", + }, + wantErr: true, + }, + { + name: "loads valid configuration", + data: map[string]string{ + "verifier-public-key-redhat": string(redhatData), + "store-local": "file://../testdata/signatures", + }, + want: true, + wantVerifiers: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewFromConfigMapData("from_test", tt.data, DefaultClient) + if (err != nil) != tt.wantErr { + t.Fatalf("loadReleaseVerifierFromPayload() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil != tt.want { + t.Fatal(got) + } + if err != nil { + return + } + if got == nil { + return + } + if len(got.Verifiers()) != tt.wantVerifiers { + t.Fatalf("unexpected release verifier: %#v", got) + } + }) + } +} diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/combined.txt b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/combined.txt new file mode 100644 index 00000000000..cfe4a4734e0 --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/combined.txt @@ -0,0 +1,56 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) +Comment: Use "gpg --dearmor" for unpacking + +mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF +0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF +0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c +u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh +XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H +5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW +9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj +/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1 +PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY +HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF +buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB +tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0 +LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK +CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC +2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf +C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5 +un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E +0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE +IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh +8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL +Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki +JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25 +OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq +dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKY5kB +DQRcvUOrAQgA9TL3MF/X9VbvzP3YfkiWG7gD+Lq7WWe2KGTpc6OpcP8Qxfc9BHn/ +AVwLTu2DErX28Z+Uam95D5wNtAkV62luD6gOZgd+7mwxk4cW/HGrQk3lqXf+aJq2 +4yzKygqYNDg304DWWI/YEQ8g0yj45VtsY1/Qpo/5Zphj2AxuKnazaXonJjI6WF8m +A1cRU0RTHYn8U4x0EU+UfT3avFgxS63d2WVqOHzeUW/gclofDLrB4/hch8QOCXw/ +xulR8p9fU+8U/4OdyXz6Gyi3WqFynUmqKwmClrshmhsi0rQJ9TF4HIbMHAWXFPdh +HoHKGWPCt3GIUW8O60FFJMd6dMr4ktQ6zwARAQABtAxvcGVuc2hpZnQtY2mJAVQE +EwEIAD4WIQTQR2GxFiA7DAhZthYot24FuSOIjgUCXL1DqwIbAwUJA8JnAAULCQgH +AgYVCgkICwIEFgIDAQIeAQIXgAAKCRAot24FuSOIjqsFB/sE0V12ZAej3ZLENrRf +8d7092AKdRb5vmgbdC9/p1MiOFuMFpgr0PZmKpFzA0sfK4EsDLcMCXu8SQZANXyv +AqD3gqh3P6JqC1EuvwY3G7F8kv57OneWb9HylR7pmdt1dqlScD6ZjXaZHXwYcBxS +ptByz2gsijN/Hzj4a1MBFvDnHlXR3wZ5JAMmFwPfvahhd4BwtzFzC5Gh+qQ2GDX8 +dj+PqmJzJ0zEjjryrCVmO7fE579UKLWoP7lvMlpSAUp74NQUO7tWSbNRCksIcEGy +K2I/nkvnvHXTe6khyU6DMx7LU40mEE4QNYglVOkvih2ixXsp39Xej6pMnh/xg25P +hPobuQENBFy9Q6sBCADYVORXM8KrhAHI4QPpH/p4tFJfUNmqvqwC99XYPrBjGWsH +A7uWqHMKJV3gSJFZdt+RhXyUnWEcyG5OZUqlSvlreWI+MjiDvkBAJOSOdXczguYt +wD06jjNFD0NevLm3KE+S2P2liyap1QI4GP0p9r1wMLGL5LiWTKXjj6DYKHAFsMBs +V5DxMv/zgN68MsujxEdlO8S1i+Ujh/KMY57JxwPfJxeIrjkKm8D08H8lje8a+xwG +OiomsB5g9E98sLMEdWxGdQmJ/CsaTTLh3+7W2jDzjb2sFRKjNcXPfuLQdyJnTFAf +XiIsCLKauvJnRON3slHjPX9n6DUeuyo+he4bwcA7ABEBAAGJATYEGAEIACAWIQTQ +R2GxFiA7DAhZthYot24FuSOIjgUCXL1DqwIbDAAKCRAot24FuSOIjiwgCADTXQcB +RSaU2hGYTrwxLHzphwxRPsRtnwavkjudwODP+MXyegVZ6UbwID7xLvxA/CzCAW7m +jFKV4wMFCyDpzRAbGHpvptyCnK2QCIX1wIyPBKs6a43IlIlRMdPl0eniG7BZtoJu +tbx3274ikskIN4aShvP4NrBYEPQjYuQxYISGHrKfuzcAgvlDlRgbvdDuEiKviDLN +p9zk0dhiBM9C4BLwv90e6ZATYyzU3HBMQTajkoSct158J7b2H5cVcBAVbMhGyi7y +1NsbZSBPyHRrLCkEfFBRbIBZhol97dU3GoRZy5a+hLfrweCdNl6/rr2fNb/2atTh +8+4iI63dvDLJWLtu +=8lmj +-----END PGP PUBLIC KEY BLOCK----- diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/redhat.txt b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/redhat.txt new file mode 100644 index 00000000000..0009a3e88b2 --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/redhat.txt @@ -0,0 +1,34 @@ +pub 4096R/FD431D51 2009-10-22 + Key fingerprint = 567E 347A D004 4ADE 55BA 8A5F 199E 2F91 FD43 1D51 +uid Red Hat, Inc. (release key 2) + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.5 (GNU/Linux) + +mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF +0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF +0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c +u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh +XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H +5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW +9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj +/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1 +PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY +HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF +buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB +tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0 +LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK +CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC +2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf +C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5 +un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E +0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE +IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh +8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL +Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki +JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25 +OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq +dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKYw== +=zbHE +-----END PGP PUBLIC KEY BLOCK----- + diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/simple.txt b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/simple.txt new file mode 100644 index 00000000000..72775a7b57f --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/keyrings/simple.txt @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFy9Q6sBCAD1MvcwX9f1Vu/M/dh+SJYbuAP4urtZZ7YoZOlzo6lw/xDF9z0E +ef8BXAtO7YMStfbxn5Rqb3kPnA20CRXraW4PqA5mB37ubDGThxb8catCTeWpd/5o +mrbjLMrKCpg0ODfTgNZYj9gRDyDTKPjlW2xjX9Cmj/lmmGPYDG4qdrNpeicmMjpY +XyYDVxFTRFMdifxTjHQRT5R9Pdq8WDFLrd3ZZWo4fN5Rb+ByWh8MusHj+FyHxA4J +fD/G6VHyn19T7xT/g53JfPobKLdaoXKdSaorCYKWuyGaGyLStAn1MXgchswcBZcU +92EegcoZY8K3cYhRbw7rQUUkx3p0yviS1DrPABEBAAG0DG9wZW5zaGlmdC1jaYkB +VAQTAQgAPhYhBNBHYbEWIDsMCFm2Fii3bgW5I4iOBQJcvUOrAhsDBQkDwmcABQsJ +CAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJECi3bgW5I4iOqwUH+wTRXXZkB6PdksQ2 +tF/x3vT3YAp1Fvm+aBt0L3+nUyI4W4wWmCvQ9mYqkXMDSx8rgSwMtwwJe7xJBkA1 +fK8CoPeCqHc/omoLUS6/BjcbsXyS/ns6d5Zv0fKVHumZ23V2qVJwPpmNdpkdfBhw +HFKm0HLPaCyKM38fOPhrUwEW8OceVdHfBnkkAyYXA9+9qGF3gHC3MXMLkaH6pDYY +Nfx2P4+qYnMnTMSOOvKsJWY7t8Tnv1Qotag/uW8yWlIBSnvg1BQ7u1ZJs1EKSwhw +QbIrYj+eS+e8ddN7qSHJToMzHstTjSYQThA1iCVU6S+KHaLFeynf1d6PqkyeH/GD +bk+E+hu5AQ0EXL1DqwEIANhU5FczwquEAcjhA+kf+ni0Ul9Q2aq+rAL31dg+sGMZ +awcDu5aocwolXeBIkVl235GFfJSdYRzIbk5lSqVK+Wt5Yj4yOIO+QEAk5I51dzOC +5i3APTqOM0UPQ168ubcoT5LY/aWLJqnVAjgY/Sn2vXAwsYvkuJZMpeOPoNgocAWw +wGxXkPEy//OA3rwyy6PER2U7xLWL5SOH8oxjnsnHA98nF4iuOQqbwPTwfyWN7xr7 +HAY6KiawHmD0T3ywswR1bEZ1CYn8KxpNMuHf7tbaMPONvawVEqM1xc9+4tB3ImdM +UB9eIiwIspq68mdE43eyUeM9f2foNR67Kj6F7hvBwDsAEQEAAYkBNgQYAQgAIBYh +BNBHYbEWIDsMCFm2Fii3bgW5I4iOBQJcvUOrAhsMAAoJECi3bgW5I4iOLCAIANNd +BwFFJpTaEZhOvDEsfOmHDFE+xG2fBq+SO53A4M/4xfJ6BVnpRvAgPvEu/ED8LMIB +buaMUpXjAwULIOnNEBsYem+m3IKcrZAIhfXAjI8EqzprjciUiVEx0+XR6eIbsFm2 +gm61vHfbviKSyQg3hpKG8/g2sFgQ9CNi5DFghIYesp+7NwCC+UOVGBu90O4SIq+I +Ms2n3OTR2GIEz0LgEvC/3R7pkBNjLNTccExBNqOShJy3XnwntvYflxVwEBVsyEbK +LvLU2xtlIE/IdGssKQR8UFFsgFmGiX3t1TcahFnLlr6Et+vB4J02Xr+uvZ81v/Zq +1OHz7iIjrd28MslYu24= +=xMCa +-----END PGP PUBLIC KEY BLOCK----- diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures-2/.gitkeep b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures-2/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7/signature-1 b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7/signature-1 new file mode 100644 index 00000000000..b13c5c4a921 Binary files /dev/null and b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7/signature-1 differ diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=edd9824f0404f1a139688017e7001370e2f3fbc088b94da84506653b473fe140/signature-1 b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=edd9824f0404f1a139688017e7001370e2f3fbc088b94da84506653b473fe140/signature-1 new file mode 100644 index 00000000000..c6dcbfc34e9 Binary files /dev/null and b/vendor/github.com/openshift/oc/pkg/helpers/release/testdata/signatures/sha256=edd9824f0404f1a139688017e7001370e2f3fbc088b94da84506653b473fe140/signature-1 differ diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/verify.go b/vendor/github.com/openshift/oc/pkg/helpers/release/verify.go new file mode 100644 index 00000000000..7393a3f8698 --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/verify.go @@ -0,0 +1,592 @@ +package release + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/pkg/errors" + "golang.org/x/crypto/openpgp" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + coreclientsetv1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/klog" + + "github.com/openshift/library-go/pkg/manifest" +) + +// Interface performs verification of the provided content. The default implementation +// in this package uses the container signature format defined at https://github.com/containers/image +// to authenticate that a given release image digest has been signed by a trusted party. +type Interface interface { + // Verify should return nil if the provided release digest has suffient signatures to be considered + // valid. It should return an error in all other cases. + Verify(ctx context.Context, releaseDigest string) error + + Signatures() map[string][][]byte +} + +// SignatureStore retrieves signatures for a digest or returns an error. It requires String() +// for describing the store. +type SignatureStore interface { + // DigestSignatures returns zero or more signatures for the provided digest, or returns an + // error if no signatures could be retrieved. + DigestSignatures(ctx context.Context, digest string) ([][]byte, error) + // String should return a description of where this store finds signatures in a short + // clause intended for display in a description of the verifier. + String() string +} + +type rejectVerifier struct{} + +func (rejectVerifier) Verify(ctx context.Context, releaseDigest string) error { + return fmt.Errorf("verification is not possible") +} + +func (rejectVerifier) Signatures() map[string][][]byte { + return nil +} + +// Reject fails always fails verification. +var Reject Interface = rejectVerifier{} + +// ClientBuilder provides a method for generating an HTTP Client configured +// with cluster proxy settings, if they exist. +type ClientBuilder interface { + // HTTPClient returns a client suitable for retrieving signatures. It is not + // required to be unique per call, but may be called concurrently. + HTTPClient() (*http.Client, error) +} + +// DefaultClient uses the default http.Client for accessing signatures. +var DefaultClient = simpleClientBuilder{} + +// simpleClientBuilder implements the ClientBuilder interface and may be used for testing. +type simpleClientBuilder struct{} + +// HTTPClient from simpleClientBuilder creates an http.Client with no configuration. +func (s simpleClientBuilder) HTTPClient() (*http.Client, error) { + return &http.Client{}, nil +} + +// maxSignatureSearch prevents unbounded recursion on malicious signature stores (if +// an attacker was able to take ownership of the store to perform DoS on clusters). +const maxSignatureSearch = 10 + +// validReleaseDigest is a verification rule to filter clearly invalid digests. +var validReleaseDigest = regexp.MustCompile(`^[a-zA-Z0-9:]+$`) + +// ReleaseVerifier implements a signature intersection operation on a provided release +// digest - all verifiers must have at least one valid signature attesting the release +// digest. If any failure occurs the caller should assume the content is unverified. +type ReleaseVerifier struct { + verifiers map[string]openpgp.EntityList + + locations []*url.URL + clientBuilder ClientBuilder + stores []SignatureStore + + lock sync.Mutex + signatureCache map[string][][]byte +} + +// NewReleaseVerifier creates a release verifier for the provided inputs. +func NewReleaseVerifier(verifiers map[string]openpgp.EntityList, locations []*url.URL, clientBuilder ClientBuilder) *ReleaseVerifier { + return &ReleaseVerifier{ + verifiers: verifiers, + locations: locations, + clientBuilder: clientBuilder, + + signatureCache: make(map[string][][]byte), + } +} + +// WithStores copies the provided verifier and adds any provided stores to the list. +func (v *ReleaseVerifier) WithStores(stores ...SignatureStore) *ReleaseVerifier { + return &ReleaseVerifier{ + verifiers: v.verifiers, + locations: v.locations, + clientBuilder: v.clientBuilder, + + stores: append(append(make([]SignatureStore, 0, len(v.stores)+len(stores)), v.stores...), stores...), + signatureCache: v.Signatures(), + } +} + +// Verifiers returns a copy of the verifiers in this payload. +func (v *ReleaseVerifier) Verifiers() map[string]openpgp.EntityList { + out := make(map[string]openpgp.EntityList, len(v.verifiers)) + for k, v := range v.verifiers { + out[k] = v + } + return out +} + +// String summarizes the verifier for human consumption +func (v *ReleaseVerifier) String() string { + var keys []string + for name := range v.verifiers { + keys = append(keys, name) + } + sort.Strings(keys) + + var builder strings.Builder + builder.Grow(256) + fmt.Fprintf(&builder, "All release image digests must have GPG signatures from") + if len(keys) == 0 { + fmt.Fprint(&builder, " ") + } + for _, name := range keys { + verifier := v.verifiers[name] + fmt.Fprintf(&builder, " %s (", name) + for i, entity := range verifier { + if i != 0 { + fmt.Fprint(&builder, ", ") + } + if entity.PrimaryKey != nil { + fmt.Fprintf(&builder, strings.ToUpper(fmt.Sprintf("%x", entity.PrimaryKey.Fingerprint))) + fmt.Fprint(&builder, ": ") + } + count := 0 + for identityName := range entity.Identities { + if count != 0 { + fmt.Fprint(&builder, ", ") + } + fmt.Fprintf(&builder, "%s", identityName) + count++ + } + } + fmt.Fprint(&builder, ")") + } + + hasLocations := len(v.locations) > 0 + hasStores := len(v.stores) > 0 + if hasLocations || hasStores { + fmt.Fprintf(&builder, " - will check for signatures in containers/image format") + if hasLocations { + fmt.Fprintf(&builder, " at") + for i, location := range v.locations { + if i != 0 { + fmt.Fprint(&builder, ",") + } + fmt.Fprintf(&builder, " %s", location.String()) + } + } + if hasStores { + if hasLocations { + fmt.Fprintf(&builder, " and from") + } else { + fmt.Fprintf(&builder, " from") + } + for i, store := range v.stores { + if i != 0 { + fmt.Fprint(&builder, ",") + } + fmt.Fprintf(&builder, " %s", store.String()) + } + } + } else { + fmt.Fprintf(&builder, " - ") + } + return builder.String() +} + +// Verify ensures that at least one valid signature exists for an image with digest +// matching release digest in any of the provided locations for all verifiers, or returns +// an error. +func (v *ReleaseVerifier) Verify(ctx context.Context, releaseDigest string) error { + if len(v.verifiers) == 0 || (len(v.locations) == 0 && len(v.stores) == 0) { + return fmt.Errorf("the release verifier is incorrectly configured, unable to verify digests") + } + if len(releaseDigest) == 0 { + return fmt.Errorf("release images that are not accessed via digest cannot be verified") + } + if !validReleaseDigest.MatchString(releaseDigest) { + return fmt.Errorf("the provided release image digest contains prohibited characters") + } + + if v.hasVerified(releaseDigest) { + return nil + } + + parts := strings.SplitN(releaseDigest, ":", 3) + if len(parts) != 2 || len(parts[0]) == 0 || len(parts[1]) == 0 { + return fmt.Errorf("the provided release image digest must be of the form ALGO:HASH") + } + algo, hash := parts[0], parts[1] + name := fmt.Sprintf("%s=%s", algo, hash) + + remaining := make(map[string]openpgp.EntityList, len(v.verifiers)) + for k, v := range v.verifiers { + remaining[k] = v + } + + var signedWith [][]byte + verifier := func(path string, signature []byte) (bool, error) { + for k, keyring := range remaining { + content, _, err := verifySignatureWithKeyring(bytes.NewReader(signature), keyring) + if err != nil { + klog.Infof("keyring %q could not verify signature: %v", k, err) + klog.V(4).Infof("keyring %q could not verify signature: %v", k, err) + continue + } + if err := verifyAtomicContainerSignature(content, releaseDigest); err != nil { + klog.Infof("signature %q is not valid: %v", path, err) + klog.V(4).Infof("signature %q is not valid: %v", path, err) + continue + } + delete(remaining, k) + signedWith = append(signedWith, signature) + } + return len(remaining) > 0, nil + } + + // check the stores to see if they match any signatures + for i, store := range v.stores { + if len(remaining) == 0 { + break + } + signatures, err := store.DigestSignatures(ctx, releaseDigest) + if err != nil { + klog.Infof("store %s could not load signatures: %v", store, err) + klog.V(4).Infof("store %s could not load signatures: %v", store, err) + continue + } + for _, signature := range signatures { + hasUnsigned, err := verifier(fmt.Sprintf("store %d", i), signature) + if err != nil { + return err + } + if !hasUnsigned { + break + } + } + } + + var client *http.Client + for _, location := range v.locations { + if len(remaining) == 0 { + break + } + switch location.Scheme { + case "file": + dir := filepath.Join(location.Path, name) + if err := checkFileSignatures(ctx, dir, maxSignatureSearch, verifier); err != nil { + return err + } + case "http", "https": + if client == nil { + var err error + client, err = v.clientBuilder.HTTPClient() + if err != nil { + return err + } + } + + copied := *location + copied.Path = path.Join(location.Path, name) + if err := checkHTTPSignatures(ctx, client, copied, maxSignatureSearch, verifier); err != nil { + return err + } + default: + return fmt.Errorf("internal error: the store %s type is unrecognized, cannot verify signatures", location) + } + } + + if len(remaining) > 0 { + if klog.V(4) { + for k := range remaining { + klog.Infof("Unable to verify %s against keyring %s", releaseDigest, k) + } + } + return fmt.Errorf("unable to locate a valid signature for one or more sources") + } + + v.cacheVerification(releaseDigest, signedWith) + + return nil +} + +// Signatures returns a copy of any cached signatures that have been validated +// so far. It may return no signatures. +func (v *ReleaseVerifier) Signatures() map[string][][]byte { + copied := make(map[string][][]byte) + v.lock.Lock() + defer v.lock.Unlock() + for k, v := range v.signatureCache { + copied[k] = v + } + return copied +} + +// LoadConfigMapVerifierDataFromUpdate fetches the first config map in the payload with the correct annotation. +// It returns an error if the data is not valid, or no verifier if no config map is found. See the verify +// package for more details on the algorithm for verification. If the annotation is set, a verifier or error +// is always returned. +func LoadConfigMapVerifierDataFromUpdate(manifests []manifest.Manifest, clientBuilder ClientBuilder, configMapClient coreclientsetv1.ConfigMapsGetter) (Interface /**StorePersister,*/, error) { + configMapGVK := corev1.SchemeGroupVersion.WithKind("ConfigMap") + for _, manifest := range manifests { + if manifest.GVK != configMapGVK { + continue + } + if _, ok := manifest.Obj.GetAnnotations()[ReleaseAnnotationConfigMapVerifier]; !ok { + continue + } + src := fmt.Sprintf("the config map %s/%s", manifest.Obj.GetNamespace(), manifest.Obj.GetName()) + data, _, err := unstructured.NestedStringMap(manifest.Obj.Object, "data") + if err != nil { + return nil, errors.Wrapf(err, "%s is not valid: %v", src, err) + } + verifier, err := NewFromConfigMapData(src, data, clientBuilder) + if err != nil { + return nil, err + } + return verifier, nil + } + return nil, nil +} + +// hasVerified returns true if the digest has already been verified. +func (v *ReleaseVerifier) hasVerified(releaseDigest string) bool { + v.lock.Lock() + defer v.lock.Unlock() + _, ok := v.signatureCache[releaseDigest] + return ok +} + +const maxSignatureCacheSize = 64 + +// cacheVerification caches the result of signature check for a digest for later retrieval. +func (v *ReleaseVerifier) cacheVerification(releaseDigest string, signedWith [][]byte) { + v.lock.Lock() + defer v.lock.Unlock() + + if len(signedWith) == 0 || len(releaseDigest) == 0 || v.signatureCache == nil { + return + } + // remove the new entry + delete(v.signatureCache, releaseDigest) + // ensure the cache doesn't grow beyond our cap + for k := range v.signatureCache { + if len(v.signatureCache) < maxSignatureCacheSize { + break + } + delete(v.signatureCache, k) + } + v.signatureCache[releaseDigest] = signedWith +} + +// checkFileSignatures reads signatures as "signature-1", "signature-2", etc out of a directory until +// either the provided fn returns an error, false, or no such file exists. No more than maxSignaturesToCheck +// will be read. +func checkFileSignatures(ctx context.Context, dir string, maxSignaturesToCheck int, fn func(path string, signature []byte) (bool, error)) error { + base := filepath.Join(dir, "signature-") + for i := 1; i < maxSignatureSearch; i++ { + if err := ctx.Err(); err != nil { + return err + } + + path := base + strconv.Itoa(i) + data, err := ioutil.ReadFile(path) + if os.IsNotExist(err) { + break + } + if err != nil { + klog.V(4).Infof("unable to load signature: %v", err) + continue + } + ok, err := fn(path, data) + if err != nil { + return err + } + if !ok { + break + } + } + return nil +} + +var errNotFound = fmt.Errorf("no more signatures to check") + +// checkHTTPSignatures reads signatures as "signature-1", "signature-2", etc as children of the provided URL +// over HTTP or HTTPS until either the provided fn returns an error, false, or the server returns 404. No +// more than maxSignaturesToCheck will be read. If the provided context is cancelled search will be terminated. +func checkHTTPSignatures(ctx context.Context, client *http.Client, u url.URL, maxSignaturesToCheck int, fn func(path string, signature []byte) (bool, error)) error { + base := filepath.Join(u.Path, "signature-") + sigURL := u + for i := 1; i < maxSignatureSearch; i++ { + if err := ctx.Err(); err != nil { + return err + } + + sigURL.Path = base + strconv.Itoa(i) + + req, err := http.NewRequest("GET", sigURL.String(), nil) + if err != nil { + return fmt.Errorf("could not build request to check signature: %v", err) + } + req = req.WithContext(ctx) + // load the body, being careful not to allow unbounded reads + resp, err := client.Do(req) + if err != nil { + klog.V(4).Infof("unable to load signature: %v", err) + continue + } + data, err := func() ([]byte, error) { + body := resp.Body + r := io.LimitReader(body, 50*1024) + + defer func() { + // read the remaining body to avoid breaking the connection + io.Copy(ioutil.Discard, r) + body.Close() + }() + + if resp.StatusCode == 404 { + return nil, errNotFound + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + if i == 1 { + klog.V(4).Infof("Could not find signature at store location %v", sigURL) + } + return nil, fmt.Errorf("unable to retrieve signature from %v: %d", sigURL, resp.StatusCode) + } + + return ioutil.ReadAll(resp.Body) + }() + if err == errNotFound { + klog.Info("not found") + break + } + if err != nil { + klog.Info(err) + klog.V(4).Info(err) + continue + } + if len(data) == 0 { + continue + } + + ok, err := fn(sigURL.String(), data) + if err != nil { + return err + } + if !ok { + break + } + } + return nil +} + +// verifySignatureWithKeyring performs a containers/image verification of the provided signature +// message, checking for the integrity and authenticity of the provided message in r. It will return +// the identity of the signer if successful along with the message contents. +func verifySignatureWithKeyring(r io.Reader, keyring openpgp.EntityList) ([]byte, string, error) { + md, err := openpgp.ReadMessage(r, keyring, nil, nil) + if err != nil { + return nil, "", fmt.Errorf("could not read the message: %v", err) + } + if !md.IsSigned { + return nil, "", fmt.Errorf("not signed") + } + content, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + return nil, "", err + } + if md.SignatureError != nil { + return nil, "", fmt.Errorf("signature error: %v", md.SignatureError) + } + if md.SignedBy == nil { + return nil, "", fmt.Errorf("invalid signature") + } + if md.Signature != nil { + if md.Signature.SigLifetimeSecs != nil { + expiry := md.Signature.CreationTime.Add(time.Duration(*md.Signature.SigLifetimeSecs) * time.Second) + if time.Now().After(expiry) { + return nil, "", fmt.Errorf("signature expired on %s", expiry) + } + } + } else if md.SignatureV3 == nil { + return nil, "", fmt.Errorf("unexpected openpgp.MessageDetails: neither Signature nor SignatureV3 is set") + } + + // follow conventions in containers/image + return content, strings.ToUpper(fmt.Sprintf("%x", md.SignedBy.PublicKey.Fingerprint)), nil +} + +// An atomic container signature has the following schema: +// +// { +// "critical": { +// "type": "atomic container signature", +// "image": { +// "docker-manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e" +// }, +// "identity": { +// "docker-reference": "docker.io/library/busybox:latest" +// } +// }, +// "optional": { +// "creator": "some software package v1.0.1-35", +// "timestamp": 1483228800, +// } +// } +type signature struct { + Critical criticalSignature `json:"critical"` + Optional optionalSignature `json:"optional"` +} + +type criticalSignature struct { + Type string `json:"type"` + Image criticalImage `json:"image"` + Identity criticalIdentity `json:"identity"` +} + +type criticalImage struct { + DockerManifestDigest string `json:"docker-manifest-digest"` +} + +type criticalIdentity struct { + DockerReference string `json:"docker-reference"` +} + +type optionalSignature struct { + Creator string `json:"creator"` + Timestamp int64 `json:"timestamp"` +} + +// verifyAtomicContainerSignature verifiers that the provided data authenticates the +// specified release digest. If error is returned the provided data does NOT authenticate +// the release digest and the signature must be ignored. +func verifyAtomicContainerSignature(data []byte, releaseDigest string) error { + d := json.NewDecoder(bytes.NewReader(data)) + d.DisallowUnknownFields() + var sig signature + if err := d.Decode(&sig); err != nil { + return fmt.Errorf("the signature is not valid JSON: %v", err) + } + if sig.Critical.Type != "atomic container signature" { + return fmt.Errorf("signature is not the correct type") + } + if len(sig.Critical.Identity.DockerReference) == 0 { + return fmt.Errorf("signature must have an identity") + } + if sig.Critical.Image.DockerManifestDigest != releaseDigest { + return fmt.Errorf("signature digest does not match") + } + return nil +} diff --git a/vendor/github.com/openshift/oc/pkg/helpers/release/verify_test.go b/vendor/github.com/openshift/oc/pkg/helpers/release/verify_test.go new file mode 100644 index 00000000000..bd428dbac3b --- /dev/null +++ b/vendor/github.com/openshift/oc/pkg/helpers/release/verify_test.go @@ -0,0 +1,354 @@ +package release + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "path/filepath" + "reflect" + "testing" + + "golang.org/x/crypto/openpgp" +) + +type fakeSigStore struct { + digest string + signatures [][]byte + err error +} + +func (s *fakeSigStore) DigestSignatures(ctx context.Context, digest string) ([][]byte, error) { + if len(s.digest) > 0 && s.digest != digest { + panic("unexpected digest") + } + return s.signatures, s.err +} + +func (s *fakeSigStore) String() string { + return "test sig store" +} + +func Test_ReleaseVerifier_Verify(t *testing.T) { + data, err := ioutil.ReadFile(filepath.Join("testdata", "keyrings", "redhat.txt")) + if err != nil { + t.Fatal(err) + } + redhatPublic, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + data, err = ioutil.ReadFile(filepath.Join("testdata", "keyrings", "simple.txt")) + if err != nil { + t.Fatal(err) + } + simple, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + data, err = ioutil.ReadFile(filepath.Join("testdata", "keyrings", "combined.txt")) + if err != nil { + t.Fatal(err) + } + combined, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + + serveSignatures := http.FileServer(http.Dir(filepath.Join("testdata", "signatures"))) + sigServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + serveSignatures.ServeHTTP(w, req) + })) + defer sigServer.Close() + sigServerURL, _ := url.Parse(sigServer.URL) + + serveEmpty := http.FileServer(http.Dir(filepath.Join("testdata", "signatures-2"))) + emptyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + serveEmpty.ServeHTTP(w, req) + })) + defer emptyServer.Close() + emptyServerURL, _ := url.Parse(emptyServer.URL) + + validSignatureData, err := ioutil.ReadFile(filepath.Join("testdata", "signatures", "sha256=e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", "signature-1")) + + tests := []struct { + name string + verifiers map[string]openpgp.EntityList + locations []*url.URL + stores []SignatureStore + releaseDigest string + wantErr bool + }{ + {releaseDigest: "", wantErr: true}, + {releaseDigest: "!", wantErr: true}, + + { + name: "valid signature for sha over file", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + locations: []*url.URL{ + {Scheme: "file", Path: "testdata/signatures"}, + }, + stores: []SignatureStore{ + &fakeSigStore{err: fmt.Errorf("logged only")}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + }, + { + name: "valid signature for sha over http", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + locations: []*url.URL{ + sigServerURL, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + }, + { + name: "valid signature for sha from store", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + stores: []SignatureStore{ + &fakeSigStore{}, + &fakeSigStore{err: fmt.Errorf("logged only")}, + &fakeSigStore{digest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", signatures: [][]byte{validSignatureData}}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + }, + { + name: "valid signature for sha over http with custom gpg key", + releaseDigest: "sha256:edd9824f0404f1a139688017e7001370e2f3fbc088b94da84506653b473fe140", + locations: []*url.URL{ + sigServerURL, + }, + verifiers: map[string]openpgp.EntityList{"simple": simple}, + }, + { + name: "valid signature for sha over http with multi-key keyring", + releaseDigest: "sha256:edd9824f0404f1a139688017e7001370e2f3fbc088b94da84506653b473fe140", + locations: []*url.URL{ + sigServerURL, + }, + verifiers: map[string]openpgp.EntityList{"combined": combined}, + }, + + { + name: "store rejects if no store found", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + stores: []SignatureStore{ + &fakeSigStore{}, + &fakeSigStore{}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + { + name: "file location rejects if digest is not found", + releaseDigest: "sha256:0000000000000000000000000000000000000000000000000000000000000000", + locations: []*url.URL{ + {Scheme: "file", Path: "testdata/signatures"}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + { + name: "http location rejects if digest is not found", + releaseDigest: "sha256:0000000000000000000000000000000000000000000000000000000000000000", + locations: []*url.URL{ + sigServerURL, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + + { + name: "sha contains invalid characters", + releaseDigest: "!sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + locations: []*url.URL{ + {Scheme: "file", Path: "testdata/signatures"}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + { + name: "sha contains too many separators", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7:", + locations: []*url.URL{ + {Scheme: "file", Path: "testdata/signatures"}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + + { + name: "could not find signature in file location", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + locations: []*url.URL{ + {Scheme: "file", Path: "testdata/signatures-2"}, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + { + name: "could not find signature in http location", + releaseDigest: "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", + locations: []*url.URL{ + emptyServerURL, + }, + verifiers: map[string]openpgp.EntityList{"redhat": redhatPublic}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err != nil { + t.Fatal(err) + } + v := &ReleaseVerifier{ + verifiers: tt.verifiers, + stores: tt.stores, + locations: tt.locations, + clientBuilder: DefaultClient, + } + if err := v.Verify(context.Background(), tt.releaseDigest); (err != nil) != tt.wantErr { + t.Errorf("ReleaseVerifier.Verify() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_ReleaseVerifier_String(t *testing.T) { + data, err := ioutil.ReadFile(filepath.Join("testdata", "keyrings", "redhat.txt")) + if err != nil { + t.Fatal(err) + } + redhatPublic, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + verifiers map[string]openpgp.EntityList + locations []*url.URL + stores []SignatureStore + want string + }{ + { + want: `All release image digests must have GPG signatures from - `, + }, + { + locations: []*url.URL{ + {Scheme: "http", Host: "localhost", Path: "test"}, + {Scheme: "file", Path: "/absolute/url"}, + }, + want: `All release image digests must have GPG signatures from - will check for signatures in containers/image format at http://localhost/test, file:///absolute/url`, + }, + { + verifiers: map[string]openpgp.EntityList{ + "redhat": redhatPublic, + }, + locations: []*url.URL{{Scheme: "http", Host: "localhost", Path: "test"}}, + want: `All release image digests must have GPG signatures from redhat (567E347AD0044ADE55BA8A5F199E2F91FD431D51: Red Hat, Inc. (release key 2) ) - will check for signatures in containers/image format at http://localhost/test`, + }, + { + verifiers: map[string]openpgp.EntityList{ + "redhat": redhatPublic, + }, + stores: []SignatureStore{&fakeSigStore{}, &fakeSigStore{}}, + want: `All release image digests must have GPG signatures from redhat (567E347AD0044ADE55BA8A5F199E2F91FD431D51: Red Hat, Inc. (release key 2) ) - will check for signatures in containers/image format from test sig store, test sig store`, + }, + { + verifiers: map[string]openpgp.EntityList{ + "redhat": redhatPublic, + }, + locations: []*url.URL{ + {Scheme: "http", Host: "localhost", Path: "test"}, + {Scheme: "file", Path: "/absolute/url"}, + }, + stores: []SignatureStore{&fakeSigStore{}, &fakeSigStore{}}, + want: `All release image digests must have GPG signatures from redhat (567E347AD0044ADE55BA8A5F199E2F91FD431D51: Red Hat, Inc. (release key 2) ) - will check for signatures in containers/image format at http://localhost/test, file:///absolute/url and from test sig store, test sig store`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &ReleaseVerifier{ + verifiers: tt.verifiers, + locations: tt.locations, + stores: tt.stores, + } + if got := v.String(); got != tt.want { + t.Errorf("ReleaseVerifier.String() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_ReleaseVerifier_Signatures(t *testing.T) { + data, err := ioutil.ReadFile(filepath.Join("testdata", "keyrings", "redhat.txt")) + if err != nil { + t.Fatal(err) + } + redhatPublic, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + + const signedDigest = "sha256:e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7" + + // verify we don't cache a negative result + verifier := NewReleaseVerifier( + map[string]openpgp.EntityList{"redhat": redhatPublic}, + []*url.URL{{Scheme: "file", Path: "testdata/signatures-wrong"}}, + DefaultClient, + ) + if err := verifier.Verify(context.Background(), signedDigest); err == nil || err.Error() != "unable to locate a valid signature for one or more sources" { + t.Fatal(err) + } + if sigs := verifier.Signatures(); len(sigs) != 0 { + t.Fatalf("%#v", sigs) + } + + // verify we cache a valid request + verifier = NewReleaseVerifier( + map[string]openpgp.EntityList{"redhat": redhatPublic}, + []*url.URL{{Scheme: "file", Path: "testdata/signatures"}}, + DefaultClient, + ) + if err := verifier.Verify(context.Background(), signedDigest); err != nil { + t.Fatal(err) + } + if sigs := verifier.Signatures(); len(sigs) != 1 { + t.Fatalf("%#v", sigs) + } + + // verify we hit the cache instead of verifying, even after changing the locations directory + verifier.locations = []*url.URL{{Scheme: "file", Path: "testdata/signatures-wrong"}} + if err := verifier.Verify(context.Background(), signedDigest); err != nil { + t.Fatal(err) + } + if sigs := verifier.Signatures(); len(sigs) != 1 { + t.Fatalf("%#v", sigs) + } + + // verify we maintain a maximum number of cache entries a valid request + expectedSignature, err := ioutil.ReadFile(filepath.Join("testdata", "signatures", "sha256=e3f12513a4b22a2d7c0e7c9207f52128113758d9d68c7d06b11a0ac7672966f7", "signature-1")) + if err != nil { + t.Fatal(err) + } + + verifier = NewReleaseVerifier( + map[string]openpgp.EntityList{"redhat": redhatPublic}, + []*url.URL{{Scheme: "file", Path: "testdata/signatures"}}, + DefaultClient, + ) + for i := 0; i < maxSignatureCacheSize*2; i++ { + verifier.signatureCache[fmt.Sprintf("test-%d", i)] = [][]byte{[]byte("blah")} + } + + if err := verifier.Verify(context.Background(), signedDigest); err != nil { + t.Fatal(err) + } + if sigs := verifier.Signatures(); len(sigs) != maxSignatureCacheSize || !reflect.DeepEqual(sigs[signedDigest], [][]byte{expectedSignature}) { + t.Fatalf("%d %#v", len(sigs), sigs) + } +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go index f8feebab1b9..22970a5022c 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go @@ -661,8 +661,9 @@ func (a *Operator) syncObject(obj interface{}) (syncError error) { kubestate.ResourceUpdated, metaObj, ) - syncError = a.objGCQueueSet.RequeueEvent(ns, resourceEvent) - logger.Debugf("syncObject - requeued update event for %v, res=%v", resourceEvent, syncError) + if syncError = a.objGCQueueSet.RequeueEvent("", resourceEvent); syncError != nil { + logger.WithError(syncError).Warnf("failed to requeue gc event: %v", resourceEvent) + } return } } @@ -855,8 +856,9 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { logger.WithError(err).Warn("cannot list cluster role bindings") } for _, crb := range crbs { - syncError := a.objGCQueueSet.RequeueEvent("", kubestate.NewResourceEvent(kubestate.ResourceUpdated, crb)) - logger.Debugf("handleCSVdeletion - requeued update event for %v, res=%v", crb, syncError) + if err := a.objGCQueueSet.RequeueEvent("", kubestate.NewResourceEvent(kubestate.ResourceUpdated, crb)); err != nil { + logger.WithError(err).Warnf("failed to requeue gc event: %v", crb) + } } crs, err := a.lister.RbacV1().ClusterRoleLister().List(ownerSelector) @@ -864,8 +866,9 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { logger.WithError(err).Warn("cannot list cluster roles") } for _, cr := range crs { - syncError := a.objGCQueueSet.RequeueEvent("", kubestate.NewResourceEvent(kubestate.ResourceUpdated, cr)) - logger.Debugf("handleCSVdeletion - requeued update event for %v, res=%v", cr, syncError) + if err := a.objGCQueueSet.RequeueEvent("", kubestate.NewResourceEvent(kubestate.ResourceUpdated, cr)); err != nil { + logger.WithError(err).Warnf("failed to requeue gc event: %v", cr) + } } } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc/source.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc/source.go index 3a33dcbbbb4..c65e33d3c66 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc/source.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/grpc/source.go @@ -9,8 +9,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/connectivity" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver" - "github.com/operator-framework/operator-registry/pkg/client" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -190,8 +190,8 @@ func (s *SourceStore) Remove(key resolver.CatalogKey) error { return source.Conn.Close() } -func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[resolver.CatalogKey]client.Interface { - refs := map[resolver.CatalogKey]client.Interface{} +func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[resolver.CatalogKey]registry.ClientInterface { + refs := map[resolver.CatalogKey]registry.ClientInterface{} s.sourcesLock.RLock() defer s.sourcesLock.RUnlock() for key, source := range s.sources { @@ -201,7 +201,7 @@ func (s *SourceStore) AsClients(globalNamespace, localNamespace string) map[reso if source.LastConnect.IsZero() { continue } - refs[key] = client.NewClientFromConn(source.Conn) + refs[key] = registry.NewClientFromConn(source.Conn) } // TODO : remove unhealthy diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/registry_client.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/registry_client.go new file mode 100644 index 00000000000..9fe3ef9bc3b --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/registry_client.go @@ -0,0 +1,121 @@ +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o resolver/fakes/fake_registry_client_interface.go . ClientInterface +package registry + +import ( + "context" + "fmt" + "io" + + "google.golang.org/grpc" + + registryapi "github.com/operator-framework/operator-registry/pkg/api" + "github.com/operator-framework/operator-registry/pkg/client" + opregistry "github.com/operator-framework/operator-registry/pkg/registry" +) + +// ChannelEntryStream interface +type ChannelEntryStream interface { + Recv() (*registryapi.ChannelEntry, error) +} + +// ClientInterface that extends client.Interface +type ClientInterface interface { + client.Interface + FindBundleThatProvides(ctx context.Context, group, version, kind, excludedPkgName string) (*registryapi.Bundle, error) + GetLatestChannelEntriesThatProvide(ctx context.Context, group, version, kind string) (*ChannelEntryIterator, error) +} + +// ChannelEntryIterator struct +type ChannelEntryIterator struct { + stream ChannelEntryStream + error error +} + +// NewChannelEntryIterator returns a new ChannelEntryIterator +func NewChannelEntryIterator(stream ChannelEntryStream) *ChannelEntryIterator { + return &ChannelEntryIterator{stream: stream} +} + +// Next returns the next Channel Entry in the grpc stream +func (ceit *ChannelEntryIterator) Next() *registryapi.ChannelEntry { + if ceit.error != nil { + return nil + } + next, err := ceit.stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + ceit.error = err + } + return next +} + +func (ceit *ChannelEntryIterator) Error() error { + return ceit.error +} + +// Client struct with a registry client embedded +type Client struct { + *client.Client +} + +// NewClientFromConn returns the next Channel Entry in the grpc stream +func NewClientFromConn(conn *grpc.ClientConn) *Client { + return &Client{ + Client: client.NewClientFromConn(conn), + } +} + +var _ ClientInterface = &Client{} + +// GetLatestChannelEntriesThatProvide uses registry client to get a list of +// latest channel entries that provide the requested API (via an iterator) +func (rc *Client) GetLatestChannelEntriesThatProvide(ctx context.Context, group, version, kind string) (*ChannelEntryIterator, error) { + stream, err := rc.Client.Registry.GetLatestChannelEntriesThatProvide(ctx, ®istryapi.GetLatestProvidersRequest{Group: group, Version: version, Kind: kind}) + if err != nil { + return nil, err + } + return NewChannelEntryIterator(stream), nil +} + +// FindBundleThatProvides returns a bundle that provides the request API and +// doesn't belong to the provided package +func (rc *Client) FindBundleThatProvides(ctx context.Context, group, version, kind, excludedPkgName string) (*registryapi.Bundle, error) { + it, err := rc.GetLatestChannelEntriesThatProvide(ctx, group, version, kind) + if err != nil { + return nil, err + } + entry := rc.filterChannelEntries(it, excludedPkgName) + if entry == nil { + return nil, fmt.Errorf("Unable to find a channel entry which doesn't belong to package %s", excludedPkgName) + } + bundle, err := rc.Client.Registry.GetBundle(ctx, ®istryapi.GetBundleRequest{PkgName: entry.PackageName, ChannelName: entry.ChannelName, CsvName: entry.BundleName}) + if err != nil { + return nil, err + } + return bundle, nil +} + +// FilterChannelEntries filters out a channel entries that provide the requested +// API and come from the same package with original operator and returns the +// first entry on the list +func (rc *Client) filterChannelEntries(it *ChannelEntryIterator, excludedPkgName string) *opregistry.ChannelEntry { + var entries []*opregistry.ChannelEntry + for e := it.Next(); e != nil; e = it.Next() { + if e.PackageName != excludedPkgName { + entry := &opregistry.ChannelEntry{ + PackageName: e.PackageName, + ChannelName: e.ChannelName, + BundleName: e.BundleName, + Replaces: e.Replaces, + } + entries = append(entries, entry) + } + } + + if entries != nil { + return entries[0] + } + return nil +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver.go index 28b8e35aec6..32cbd2db856 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver.go @@ -51,8 +51,13 @@ func (e *NamespaceGenerationEvolver) Evolve(add map[OperatorSourceInfo]struct{}) } func (e *NamespaceGenerationEvolver) checkForUpdates() error { + // maps the old operator identifier to the new operator + updates := EmptyOperatorSet() + // take a snapshot of the current generation so that we don't update the same operator twice in one resolution - for _, op := range e.gen.Operators().Snapshot() { + snapshot := e.gen.Operators().Snapshot() + + for _, op := range snapshot { // only check for updates if we have sourceinfo if op.SourceInfo() == &ExistingOperator { continue @@ -68,11 +73,21 @@ func (e *NamespaceGenerationEvolver) checkForUpdates() error { return errors.Wrap(err, "error parsing bundle") } o.SetReplaces(op.Identifier()) - if err := e.gen.AddOperator(o); err != nil { + updates[op.Identifier()] = o + } + + // remove any operators we found updates for + for old := range updates { + e.gen.RemoveOperator(e.gen.Operators().Snapshot()[old]) + } + + // add the new operators we found + for _, new := range updates { + if err := e.gen.AddOperator(new); err != nil { return errors.Wrap(err, "error calculating generation changes due to new bundle") } - e.gen.RemoveOperator(op) } + return nil } @@ -119,7 +134,7 @@ func (e *NamespaceGenerationEvolver) queryForRequiredAPIs() error { } // attempt to find a bundle that provides that api - if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog); err == nil { + if bundle, key, err := e.querier.FindProvider(*api, initialSource.Catalog, initialSource.Package); err == nil { // add a bundle that provides the api to the generation o, err := NewOperatorFromBundle(bundle, "", *key) if err != nil { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver_test.go index ad810e3291d..be6316d7577 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/evolver_test.go @@ -411,6 +411,46 @@ func TestNamespaceGenerationEvolver(t *testing.T) { "original"), ), }, + { + name: "OwnershipTransfer", + fields: fields{ + querier: NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{ + CatalogKey{"catsrc", "catsrc-namespace"}: { + bundle("depender.v2", "depender", "channel", "depender.v1", + APISet{opregistry.APIKey{"g", "v", "k", "ks"}: {}}, EmptyAPISet(), EmptyAPISet(), EmptyAPISet()), + bundle("original.v2", "o", "c", "original", EmptyAPISet(), EmptyAPISet(), EmptyAPISet(), EmptyAPISet()), + }, + }), + gen: NewGenerationFromOperators( + NewFakeOperatorSurface("original", "o", "c", "", "catsrc", "", []opregistry.APIKey{{"g", "v", "k", "ks"}}, nil, nil, nil), + NewFakeOperatorSurface("depender.v1", "depender", "channel", "", "catsrc", "", nil, []opregistry.APIKey{{"g", "v", "k", "ks"}}, nil, nil), + ), + }, + args: args{}, + wantGen: NewGenerationFromOperators( + NewFakeOperatorSurface("original.v2", "o", "c", "original", "catsrc", "", nil, nil, nil, nil), + NewFakeOperatorSurface("depender.v2", "depender", "channel", "depender.v1", "catsrc", "", []opregistry.APIKey{{"g", "v", "k", "ks"}}, nil, nil, nil), + ), + }, + { + name: "PicksOlderProvider", + fields: fields{ + querier: NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{ + CatalogKey{"catsrc", "catsrc-namespace"}: { + bundle("original", "o", "c", "", APISet{opregistry.APIKey{"g", "v", "k", "ks"}: {}}, EmptyAPISet(), EmptyAPISet(), EmptyAPISet()), + bundle("original.v2", "o", "c", "original", EmptyAPISet(), EmptyAPISet(), EmptyAPISet(), EmptyAPISet()), + }, + }), + gen: NewGenerationFromOperators( + NewFakeOperatorSurface("depender.v1", "depender", "channel", "", "catsrc", "", nil, []opregistry.APIKey{{"g", "v", "k", "ks"}}, nil, nil), + ), + }, + args: args{}, + wantGen: NewGenerationFromOperators( + NewFakeOperatorSurface("original", "o", "c", "", "catsrc", "", []opregistry.APIKey{{"g", "v", "k", "ks"}},nil, nil, nil), + NewFakeOperatorSurface("depender.v1", "depender", "channel", "", "catsrc", "", nil,[]opregistry.APIKey{{"g", "v", "k", "ks"}}, nil, nil), + ), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client.go index d3eb6b55b87..61356922b0c 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client.go @@ -4,30 +4,18 @@ package fakes import ( "context" "sync" - "time" "github.com/operator-framework/operator-registry/pkg/api" - "github.com/operator-framework/operator-registry/pkg/client" + "google.golang.org/grpc" ) -type FakeInterface struct { - CloseStub func() error - closeMutex sync.RWMutex - closeArgsForCall []struct { - } - closeReturns struct { - result1 error - } - closeReturnsOnCall map[int]struct { - result1 error - } - GetBundleStub func(context.Context, string, string, string) (*api.Bundle, error) +type FakeRegistryClient struct { + GetBundleStub func(context.Context, *api.GetBundleRequest, ...grpc.CallOption) (*api.Bundle, error) getBundleMutex sync.RWMutex getBundleArgsForCall []struct { arg1 context.Context - arg2 string - arg3 string - arg4 string + arg2 *api.GetBundleRequest + arg3 []grpc.CallOption } getBundleReturns struct { result1 *api.Bundle @@ -37,136 +25,142 @@ type FakeInterface struct { result1 *api.Bundle result2 error } - GetBundleInPackageChannelStub func(context.Context, string, string) (*api.Bundle, error) - getBundleInPackageChannelMutex sync.RWMutex - getBundleInPackageChannelArgsForCall []struct { + GetBundleForChannelStub func(context.Context, *api.GetBundleInChannelRequest, ...grpc.CallOption) (*api.Bundle, error) + getBundleForChannelMutex sync.RWMutex + getBundleForChannelArgsForCall []struct { arg1 context.Context - arg2 string - arg3 string + arg2 *api.GetBundleInChannelRequest + arg3 []grpc.CallOption } - getBundleInPackageChannelReturns struct { + getBundleForChannelReturns struct { result1 *api.Bundle result2 error } - getBundleInPackageChannelReturnsOnCall map[int]struct { + getBundleForChannelReturnsOnCall map[int]struct { result1 *api.Bundle result2 error } - GetBundleThatProvidesStub func(context.Context, string, string, string) (*api.Bundle, error) - getBundleThatProvidesMutex sync.RWMutex - getBundleThatProvidesArgsForCall []struct { + GetBundleThatReplacesStub func(context.Context, *api.GetReplacementRequest, ...grpc.CallOption) (*api.Bundle, error) + getBundleThatReplacesMutex sync.RWMutex + getBundleThatReplacesArgsForCall []struct { arg1 context.Context - arg2 string - arg3 string - arg4 string + arg2 *api.GetReplacementRequest + arg3 []grpc.CallOption } - getBundleThatProvidesReturns struct { + getBundleThatReplacesReturns struct { result1 *api.Bundle result2 error } - getBundleThatProvidesReturnsOnCall map[int]struct { + getBundleThatReplacesReturnsOnCall map[int]struct { result1 *api.Bundle result2 error } - GetReplacementBundleInPackageChannelStub func(context.Context, string, string, string) (*api.Bundle, error) - getReplacementBundleInPackageChannelMutex sync.RWMutex - getReplacementBundleInPackageChannelArgsForCall []struct { + GetChannelEntriesThatProvideStub func(context.Context, *api.GetAllProvidersRequest, ...grpc.CallOption) (api.Registry_GetChannelEntriesThatProvideClient, error) + getChannelEntriesThatProvideMutex sync.RWMutex + getChannelEntriesThatProvideArgsForCall []struct { + arg1 context.Context + arg2 *api.GetAllProvidersRequest + arg3 []grpc.CallOption + } + getChannelEntriesThatProvideReturns struct { + result1 api.Registry_GetChannelEntriesThatProvideClient + result2 error + } + getChannelEntriesThatProvideReturnsOnCall map[int]struct { + result1 api.Registry_GetChannelEntriesThatProvideClient + result2 error + } + GetChannelEntriesThatReplaceStub func(context.Context, *api.GetAllReplacementsRequest, ...grpc.CallOption) (api.Registry_GetChannelEntriesThatReplaceClient, error) + getChannelEntriesThatReplaceMutex sync.RWMutex + getChannelEntriesThatReplaceArgsForCall []struct { + arg1 context.Context + arg2 *api.GetAllReplacementsRequest + arg3 []grpc.CallOption + } + getChannelEntriesThatReplaceReturns struct { + result1 api.Registry_GetChannelEntriesThatReplaceClient + result2 error + } + getChannelEntriesThatReplaceReturnsOnCall map[int]struct { + result1 api.Registry_GetChannelEntriesThatReplaceClient + result2 error + } + GetDefaultBundleThatProvidesStub func(context.Context, *api.GetDefaultProviderRequest, ...grpc.CallOption) (*api.Bundle, error) + getDefaultBundleThatProvidesMutex sync.RWMutex + getDefaultBundleThatProvidesArgsForCall []struct { arg1 context.Context - arg2 string - arg3 string - arg4 string + arg2 *api.GetDefaultProviderRequest + arg3 []grpc.CallOption } - getReplacementBundleInPackageChannelReturns struct { + getDefaultBundleThatProvidesReturns struct { result1 *api.Bundle result2 error } - getReplacementBundleInPackageChannelReturnsOnCall map[int]struct { + getDefaultBundleThatProvidesReturnsOnCall map[int]struct { result1 *api.Bundle result2 error } - HealthCheckStub func(context.Context, time.Duration) (bool, error) - healthCheckMutex sync.RWMutex - healthCheckArgsForCall []struct { + GetLatestChannelEntriesThatProvideStub func(context.Context, *api.GetLatestProvidersRequest, ...grpc.CallOption) (api.Registry_GetLatestChannelEntriesThatProvideClient, error) + getLatestChannelEntriesThatProvideMutex sync.RWMutex + getLatestChannelEntriesThatProvideArgsForCall []struct { arg1 context.Context - arg2 time.Duration + arg2 *api.GetLatestProvidersRequest + arg3 []grpc.CallOption } - healthCheckReturns struct { - result1 bool + getLatestChannelEntriesThatProvideReturns struct { + result1 api.Registry_GetLatestChannelEntriesThatProvideClient result2 error } - healthCheckReturnsOnCall map[int]struct { - result1 bool + getLatestChannelEntriesThatProvideReturnsOnCall map[int]struct { + result1 api.Registry_GetLatestChannelEntriesThatProvideClient result2 error } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *FakeInterface) Close() error { - fake.closeMutex.Lock() - ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)] - fake.closeArgsForCall = append(fake.closeArgsForCall, struct { - }{}) - fake.recordInvocation("Close", []interface{}{}) - fake.closeMutex.Unlock() - if fake.CloseStub != nil { - return fake.CloseStub() + GetPackageStub func(context.Context, *api.GetPackageRequest, ...grpc.CallOption) (*api.Package, error) + getPackageMutex sync.RWMutex + getPackageArgsForCall []struct { + arg1 context.Context + arg2 *api.GetPackageRequest + arg3 []grpc.CallOption } - if specificReturn { - return ret.result1 + getPackageReturns struct { + result1 *api.Package + result2 error } - fakeReturns := fake.closeReturns - return fakeReturns.result1 -} - -func (fake *FakeInterface) CloseCallCount() int { - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() - return len(fake.closeArgsForCall) -} - -func (fake *FakeInterface) CloseCalls(stub func() error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = stub -} - -func (fake *FakeInterface) CloseReturns(result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - fake.closeReturns = struct { - result1 error - }{result1} -} - -func (fake *FakeInterface) CloseReturnsOnCall(i int, result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - if fake.closeReturnsOnCall == nil { - fake.closeReturnsOnCall = make(map[int]struct { - result1 error - }) + getPackageReturnsOnCall map[int]struct { + result1 *api.Package + result2 error } - fake.closeReturnsOnCall[i] = struct { - result1 error - }{result1} + ListPackagesStub func(context.Context, *api.ListPackageRequest, ...grpc.CallOption) (api.Registry_ListPackagesClient, error) + listPackagesMutex sync.RWMutex + listPackagesArgsForCall []struct { + arg1 context.Context + arg2 *api.ListPackageRequest + arg3 []grpc.CallOption + } + listPackagesReturns struct { + result1 api.Registry_ListPackagesClient + result2 error + } + listPackagesReturnsOnCall map[int]struct { + result1 api.Registry_ListPackagesClient + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex } -func (fake *FakeInterface) GetBundle(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { +func (fake *FakeRegistryClient) GetBundle(arg1 context.Context, arg2 *api.GetBundleRequest, arg3 ...grpc.CallOption) (*api.Bundle, error) { fake.getBundleMutex.Lock() ret, specificReturn := fake.getBundleReturnsOnCall[len(fake.getBundleArgsForCall)] fake.getBundleArgsForCall = append(fake.getBundleArgsForCall, struct { arg1 context.Context - arg2 string - arg3 string - arg4 string - }{arg1, arg2, arg3, arg4}) - fake.recordInvocation("GetBundle", []interface{}{arg1, arg2, arg3, arg4}) + arg2 *api.GetBundleRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetBundle", []interface{}{arg1, arg2, arg3}) fake.getBundleMutex.Unlock() if fake.GetBundleStub != nil { - return fake.GetBundleStub(arg1, arg2, arg3, arg4) + return fake.GetBundleStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 @@ -175,26 +169,26 @@ func (fake *FakeInterface) GetBundle(arg1 context.Context, arg2 string, arg3 str return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeInterface) GetBundleCallCount() int { +func (fake *FakeRegistryClient) GetBundleCallCount() int { fake.getBundleMutex.RLock() defer fake.getBundleMutex.RUnlock() return len(fake.getBundleArgsForCall) } -func (fake *FakeInterface) GetBundleCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { +func (fake *FakeRegistryClient) GetBundleCalls(stub func(context.Context, *api.GetBundleRequest, ...grpc.CallOption) (*api.Bundle, error)) { fake.getBundleMutex.Lock() defer fake.getBundleMutex.Unlock() fake.GetBundleStub = stub } -func (fake *FakeInterface) GetBundleArgsForCall(i int) (context.Context, string, string, string) { +func (fake *FakeRegistryClient) GetBundleArgsForCall(i int) (context.Context, *api.GetBundleRequest, []grpc.CallOption) { fake.getBundleMutex.RLock() defer fake.getBundleMutex.RUnlock() argsForCall := fake.getBundleArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) GetBundleReturns(result1 *api.Bundle, result2 error) { +func (fake *FakeRegistryClient) GetBundleReturns(result1 *api.Bundle, result2 error) { fake.getBundleMutex.Lock() defer fake.getBundleMutex.Unlock() fake.GetBundleStub = nil @@ -204,7 +198,7 @@ func (fake *FakeInterface) GetBundleReturns(result1 *api.Bundle, result2 error) }{result1, result2} } -func (fake *FakeInterface) GetBundleReturnsOnCall(i int, result1 *api.Bundle, result2 error) { +func (fake *FakeRegistryClient) GetBundleReturnsOnCall(i int, result1 *api.Bundle, result2 error) { fake.getBundleMutex.Lock() defer fake.getBundleMutex.Unlock() fake.GetBundleStub = nil @@ -220,282 +214,547 @@ func (fake *FakeInterface) GetBundleReturnsOnCall(i int, result1 *api.Bundle, re }{result1, result2} } -func (fake *FakeInterface) GetBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string) (*api.Bundle, error) { - fake.getBundleInPackageChannelMutex.Lock() - ret, specificReturn := fake.getBundleInPackageChannelReturnsOnCall[len(fake.getBundleInPackageChannelArgsForCall)] - fake.getBundleInPackageChannelArgsForCall = append(fake.getBundleInPackageChannelArgsForCall, struct { +func (fake *FakeRegistryClient) GetBundleForChannel(arg1 context.Context, arg2 *api.GetBundleInChannelRequest, arg3 ...grpc.CallOption) (*api.Bundle, error) { + fake.getBundleForChannelMutex.Lock() + ret, specificReturn := fake.getBundleForChannelReturnsOnCall[len(fake.getBundleForChannelArgsForCall)] + fake.getBundleForChannelArgsForCall = append(fake.getBundleForChannelArgsForCall, struct { arg1 context.Context - arg2 string - arg3 string + arg2 *api.GetBundleInChannelRequest + arg3 []grpc.CallOption }{arg1, arg2, arg3}) - fake.recordInvocation("GetBundleInPackageChannel", []interface{}{arg1, arg2, arg3}) - fake.getBundleInPackageChannelMutex.Unlock() - if fake.GetBundleInPackageChannelStub != nil { - return fake.GetBundleInPackageChannelStub(arg1, arg2, arg3) + fake.recordInvocation("GetBundleForChannel", []interface{}{arg1, arg2, arg3}) + fake.getBundleForChannelMutex.Unlock() + if fake.GetBundleForChannelStub != nil { + return fake.GetBundleForChannelStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.getBundleInPackageChannelReturns + fakeReturns := fake.getBundleForChannelReturns return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeInterface) GetBundleInPackageChannelCallCount() int { - fake.getBundleInPackageChannelMutex.RLock() - defer fake.getBundleInPackageChannelMutex.RUnlock() - return len(fake.getBundleInPackageChannelArgsForCall) +func (fake *FakeRegistryClient) GetBundleForChannelCallCount() int { + fake.getBundleForChannelMutex.RLock() + defer fake.getBundleForChannelMutex.RUnlock() + return len(fake.getBundleForChannelArgsForCall) } -func (fake *FakeInterface) GetBundleInPackageChannelCalls(stub func(context.Context, string, string) (*api.Bundle, error)) { - fake.getBundleInPackageChannelMutex.Lock() - defer fake.getBundleInPackageChannelMutex.Unlock() - fake.GetBundleInPackageChannelStub = stub +func (fake *FakeRegistryClient) GetBundleForChannelCalls(stub func(context.Context, *api.GetBundleInChannelRequest, ...grpc.CallOption) (*api.Bundle, error)) { + fake.getBundleForChannelMutex.Lock() + defer fake.getBundleForChannelMutex.Unlock() + fake.GetBundleForChannelStub = stub } -func (fake *FakeInterface) GetBundleInPackageChannelArgsForCall(i int) (context.Context, string, string) { - fake.getBundleInPackageChannelMutex.RLock() - defer fake.getBundleInPackageChannelMutex.RUnlock() - argsForCall := fake.getBundleInPackageChannelArgsForCall[i] +func (fake *FakeRegistryClient) GetBundleForChannelArgsForCall(i int) (context.Context, *api.GetBundleInChannelRequest, []grpc.CallOption) { + fake.getBundleForChannelMutex.RLock() + defer fake.getBundleForChannelMutex.RUnlock() + argsForCall := fake.getBundleForChannelArgsForCall[i] return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) GetBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { - fake.getBundleInPackageChannelMutex.Lock() - defer fake.getBundleInPackageChannelMutex.Unlock() - fake.GetBundleInPackageChannelStub = nil - fake.getBundleInPackageChannelReturns = struct { +func (fake *FakeRegistryClient) GetBundleForChannelReturns(result1 *api.Bundle, result2 error) { + fake.getBundleForChannelMutex.Lock() + defer fake.getBundleForChannelMutex.Unlock() + fake.GetBundleForChannelStub = nil + fake.getBundleForChannelReturns = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) GetBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { - fake.getBundleInPackageChannelMutex.Lock() - defer fake.getBundleInPackageChannelMutex.Unlock() - fake.GetBundleInPackageChannelStub = nil - if fake.getBundleInPackageChannelReturnsOnCall == nil { - fake.getBundleInPackageChannelReturnsOnCall = make(map[int]struct { +func (fake *FakeRegistryClient) GetBundleForChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleForChannelMutex.Lock() + defer fake.getBundleForChannelMutex.Unlock() + fake.GetBundleForChannelStub = nil + if fake.getBundleForChannelReturnsOnCall == nil { + fake.getBundleForChannelReturnsOnCall = make(map[int]struct { result1 *api.Bundle result2 error }) } - fake.getBundleInPackageChannelReturnsOnCall[i] = struct { + fake.getBundleForChannelReturnsOnCall[i] = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) GetBundleThatProvides(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { - fake.getBundleThatProvidesMutex.Lock() - ret, specificReturn := fake.getBundleThatProvidesReturnsOnCall[len(fake.getBundleThatProvidesArgsForCall)] - fake.getBundleThatProvidesArgsForCall = append(fake.getBundleThatProvidesArgsForCall, struct { +func (fake *FakeRegistryClient) GetBundleThatReplaces(arg1 context.Context, arg2 *api.GetReplacementRequest, arg3 ...grpc.CallOption) (*api.Bundle, error) { + fake.getBundleThatReplacesMutex.Lock() + ret, specificReturn := fake.getBundleThatReplacesReturnsOnCall[len(fake.getBundleThatReplacesArgsForCall)] + fake.getBundleThatReplacesArgsForCall = append(fake.getBundleThatReplacesArgsForCall, struct { arg1 context.Context - arg2 string - arg3 string - arg4 string - }{arg1, arg2, arg3, arg4}) - fake.recordInvocation("GetBundleThatProvides", []interface{}{arg1, arg2, arg3, arg4}) - fake.getBundleThatProvidesMutex.Unlock() - if fake.GetBundleThatProvidesStub != nil { - return fake.GetBundleThatProvidesStub(arg1, arg2, arg3, arg4) + arg2 *api.GetReplacementRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetBundleThatReplaces", []interface{}{arg1, arg2, arg3}) + fake.getBundleThatReplacesMutex.Unlock() + if fake.GetBundleThatReplacesStub != nil { + return fake.GetBundleThatReplacesStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.getBundleThatProvidesReturns + fakeReturns := fake.getBundleThatReplacesReturns return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeInterface) GetBundleThatProvidesCallCount() int { - fake.getBundleThatProvidesMutex.RLock() - defer fake.getBundleThatProvidesMutex.RUnlock() - return len(fake.getBundleThatProvidesArgsForCall) +func (fake *FakeRegistryClient) GetBundleThatReplacesCallCount() int { + fake.getBundleThatReplacesMutex.RLock() + defer fake.getBundleThatReplacesMutex.RUnlock() + return len(fake.getBundleThatReplacesArgsForCall) } -func (fake *FakeInterface) GetBundleThatProvidesCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { - fake.getBundleThatProvidesMutex.Lock() - defer fake.getBundleThatProvidesMutex.Unlock() - fake.GetBundleThatProvidesStub = stub +func (fake *FakeRegistryClient) GetBundleThatReplacesCalls(stub func(context.Context, *api.GetReplacementRequest, ...grpc.CallOption) (*api.Bundle, error)) { + fake.getBundleThatReplacesMutex.Lock() + defer fake.getBundleThatReplacesMutex.Unlock() + fake.GetBundleThatReplacesStub = stub } -func (fake *FakeInterface) GetBundleThatProvidesArgsForCall(i int) (context.Context, string, string, string) { - fake.getBundleThatProvidesMutex.RLock() - defer fake.getBundleThatProvidesMutex.RUnlock() - argsForCall := fake.getBundleThatProvidesArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +func (fake *FakeRegistryClient) GetBundleThatReplacesArgsForCall(i int) (context.Context, *api.GetReplacementRequest, []grpc.CallOption) { + fake.getBundleThatReplacesMutex.RLock() + defer fake.getBundleThatReplacesMutex.RUnlock() + argsForCall := fake.getBundleThatReplacesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) GetBundleThatProvidesReturns(result1 *api.Bundle, result2 error) { - fake.getBundleThatProvidesMutex.Lock() - defer fake.getBundleThatProvidesMutex.Unlock() - fake.GetBundleThatProvidesStub = nil - fake.getBundleThatProvidesReturns = struct { +func (fake *FakeRegistryClient) GetBundleThatReplacesReturns(result1 *api.Bundle, result2 error) { + fake.getBundleThatReplacesMutex.Lock() + defer fake.getBundleThatReplacesMutex.Unlock() + fake.GetBundleThatReplacesStub = nil + fake.getBundleThatReplacesReturns = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) GetBundleThatProvidesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { - fake.getBundleThatProvidesMutex.Lock() - defer fake.getBundleThatProvidesMutex.Unlock() - fake.GetBundleThatProvidesStub = nil - if fake.getBundleThatProvidesReturnsOnCall == nil { - fake.getBundleThatProvidesReturnsOnCall = make(map[int]struct { +func (fake *FakeRegistryClient) GetBundleThatReplacesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleThatReplacesMutex.Lock() + defer fake.getBundleThatReplacesMutex.Unlock() + fake.GetBundleThatReplacesStub = nil + if fake.getBundleThatReplacesReturnsOnCall == nil { + fake.getBundleThatReplacesReturnsOnCall = make(map[int]struct { result1 *api.Bundle result2 error }) } - fake.getBundleThatProvidesReturnsOnCall[i] = struct { + fake.getBundleThatReplacesReturnsOnCall[i] = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) GetReplacementBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { - fake.getReplacementBundleInPackageChannelMutex.Lock() - ret, specificReturn := fake.getReplacementBundleInPackageChannelReturnsOnCall[len(fake.getReplacementBundleInPackageChannelArgsForCall)] - fake.getReplacementBundleInPackageChannelArgsForCall = append(fake.getReplacementBundleInPackageChannelArgsForCall, struct { +func (fake *FakeRegistryClient) GetChannelEntriesThatProvide(arg1 context.Context, arg2 *api.GetAllProvidersRequest, arg3 ...grpc.CallOption) (api.Registry_GetChannelEntriesThatProvideClient, error) { + fake.getChannelEntriesThatProvideMutex.Lock() + ret, specificReturn := fake.getChannelEntriesThatProvideReturnsOnCall[len(fake.getChannelEntriesThatProvideArgsForCall)] + fake.getChannelEntriesThatProvideArgsForCall = append(fake.getChannelEntriesThatProvideArgsForCall, struct { + arg1 context.Context + arg2 *api.GetAllProvidersRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetChannelEntriesThatProvide", []interface{}{arg1, arg2, arg3}) + fake.getChannelEntriesThatProvideMutex.Unlock() + if fake.GetChannelEntriesThatProvideStub != nil { + return fake.GetChannelEntriesThatProvideStub(arg1, arg2, arg3...) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getChannelEntriesThatProvideReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatProvideCallCount() int { + fake.getChannelEntriesThatProvideMutex.RLock() + defer fake.getChannelEntriesThatProvideMutex.RUnlock() + return len(fake.getChannelEntriesThatProvideArgsForCall) +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatProvideCalls(stub func(context.Context, *api.GetAllProvidersRequest, ...grpc.CallOption) (api.Registry_GetChannelEntriesThatProvideClient, error)) { + fake.getChannelEntriesThatProvideMutex.Lock() + defer fake.getChannelEntriesThatProvideMutex.Unlock() + fake.GetChannelEntriesThatProvideStub = stub +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatProvideArgsForCall(i int) (context.Context, *api.GetAllProvidersRequest, []grpc.CallOption) { + fake.getChannelEntriesThatProvideMutex.RLock() + defer fake.getChannelEntriesThatProvideMutex.RUnlock() + argsForCall := fake.getChannelEntriesThatProvideArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatProvideReturns(result1 api.Registry_GetChannelEntriesThatProvideClient, result2 error) { + fake.getChannelEntriesThatProvideMutex.Lock() + defer fake.getChannelEntriesThatProvideMutex.Unlock() + fake.GetChannelEntriesThatProvideStub = nil + fake.getChannelEntriesThatProvideReturns = struct { + result1 api.Registry_GetChannelEntriesThatProvideClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatProvideReturnsOnCall(i int, result1 api.Registry_GetChannelEntriesThatProvideClient, result2 error) { + fake.getChannelEntriesThatProvideMutex.Lock() + defer fake.getChannelEntriesThatProvideMutex.Unlock() + fake.GetChannelEntriesThatProvideStub = nil + if fake.getChannelEntriesThatProvideReturnsOnCall == nil { + fake.getChannelEntriesThatProvideReturnsOnCall = make(map[int]struct { + result1 api.Registry_GetChannelEntriesThatProvideClient + result2 error + }) + } + fake.getChannelEntriesThatProvideReturnsOnCall[i] = struct { + result1 api.Registry_GetChannelEntriesThatProvideClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplace(arg1 context.Context, arg2 *api.GetAllReplacementsRequest, arg3 ...grpc.CallOption) (api.Registry_GetChannelEntriesThatReplaceClient, error) { + fake.getChannelEntriesThatReplaceMutex.Lock() + ret, specificReturn := fake.getChannelEntriesThatReplaceReturnsOnCall[len(fake.getChannelEntriesThatReplaceArgsForCall)] + fake.getChannelEntriesThatReplaceArgsForCall = append(fake.getChannelEntriesThatReplaceArgsForCall, struct { + arg1 context.Context + arg2 *api.GetAllReplacementsRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetChannelEntriesThatReplace", []interface{}{arg1, arg2, arg3}) + fake.getChannelEntriesThatReplaceMutex.Unlock() + if fake.GetChannelEntriesThatReplaceStub != nil { + return fake.GetChannelEntriesThatReplaceStub(arg1, arg2, arg3...) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getChannelEntriesThatReplaceReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplaceCallCount() int { + fake.getChannelEntriesThatReplaceMutex.RLock() + defer fake.getChannelEntriesThatReplaceMutex.RUnlock() + return len(fake.getChannelEntriesThatReplaceArgsForCall) +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplaceCalls(stub func(context.Context, *api.GetAllReplacementsRequest, ...grpc.CallOption) (api.Registry_GetChannelEntriesThatReplaceClient, error)) { + fake.getChannelEntriesThatReplaceMutex.Lock() + defer fake.getChannelEntriesThatReplaceMutex.Unlock() + fake.GetChannelEntriesThatReplaceStub = stub +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplaceArgsForCall(i int) (context.Context, *api.GetAllReplacementsRequest, []grpc.CallOption) { + fake.getChannelEntriesThatReplaceMutex.RLock() + defer fake.getChannelEntriesThatReplaceMutex.RUnlock() + argsForCall := fake.getChannelEntriesThatReplaceArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplaceReturns(result1 api.Registry_GetChannelEntriesThatReplaceClient, result2 error) { + fake.getChannelEntriesThatReplaceMutex.Lock() + defer fake.getChannelEntriesThatReplaceMutex.Unlock() + fake.GetChannelEntriesThatReplaceStub = nil + fake.getChannelEntriesThatReplaceReturns = struct { + result1 api.Registry_GetChannelEntriesThatReplaceClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetChannelEntriesThatReplaceReturnsOnCall(i int, result1 api.Registry_GetChannelEntriesThatReplaceClient, result2 error) { + fake.getChannelEntriesThatReplaceMutex.Lock() + defer fake.getChannelEntriesThatReplaceMutex.Unlock() + fake.GetChannelEntriesThatReplaceStub = nil + if fake.getChannelEntriesThatReplaceReturnsOnCall == nil { + fake.getChannelEntriesThatReplaceReturnsOnCall = make(map[int]struct { + result1 api.Registry_GetChannelEntriesThatReplaceClient + result2 error + }) + } + fake.getChannelEntriesThatReplaceReturnsOnCall[i] = struct { + result1 api.Registry_GetChannelEntriesThatReplaceClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetDefaultBundleThatProvides(arg1 context.Context, arg2 *api.GetDefaultProviderRequest, arg3 ...grpc.CallOption) (*api.Bundle, error) { + fake.getDefaultBundleThatProvidesMutex.Lock() + ret, specificReturn := fake.getDefaultBundleThatProvidesReturnsOnCall[len(fake.getDefaultBundleThatProvidesArgsForCall)] + fake.getDefaultBundleThatProvidesArgsForCall = append(fake.getDefaultBundleThatProvidesArgsForCall, struct { arg1 context.Context - arg2 string - arg3 string - arg4 string - }{arg1, arg2, arg3, arg4}) - fake.recordInvocation("GetReplacementBundleInPackageChannel", []interface{}{arg1, arg2, arg3, arg4}) - fake.getReplacementBundleInPackageChannelMutex.Unlock() - if fake.GetReplacementBundleInPackageChannelStub != nil { - return fake.GetReplacementBundleInPackageChannelStub(arg1, arg2, arg3, arg4) + arg2 *api.GetDefaultProviderRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetDefaultBundleThatProvides", []interface{}{arg1, arg2, arg3}) + fake.getDefaultBundleThatProvidesMutex.Unlock() + if fake.GetDefaultBundleThatProvidesStub != nil { + return fake.GetDefaultBundleThatProvidesStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.getReplacementBundleInPackageChannelReturns + fakeReturns := fake.getDefaultBundleThatProvidesReturns return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeInterface) GetReplacementBundleInPackageChannelCallCount() int { - fake.getReplacementBundleInPackageChannelMutex.RLock() - defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() - return len(fake.getReplacementBundleInPackageChannelArgsForCall) +func (fake *FakeRegistryClient) GetDefaultBundleThatProvidesCallCount() int { + fake.getDefaultBundleThatProvidesMutex.RLock() + defer fake.getDefaultBundleThatProvidesMutex.RUnlock() + return len(fake.getDefaultBundleThatProvidesArgsForCall) } -func (fake *FakeInterface) GetReplacementBundleInPackageChannelCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { - fake.getReplacementBundleInPackageChannelMutex.Lock() - defer fake.getReplacementBundleInPackageChannelMutex.Unlock() - fake.GetReplacementBundleInPackageChannelStub = stub +func (fake *FakeRegistryClient) GetDefaultBundleThatProvidesCalls(stub func(context.Context, *api.GetDefaultProviderRequest, ...grpc.CallOption) (*api.Bundle, error)) { + fake.getDefaultBundleThatProvidesMutex.Lock() + defer fake.getDefaultBundleThatProvidesMutex.Unlock() + fake.GetDefaultBundleThatProvidesStub = stub } -func (fake *FakeInterface) GetReplacementBundleInPackageChannelArgsForCall(i int) (context.Context, string, string, string) { - fake.getReplacementBundleInPackageChannelMutex.RLock() - defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() - argsForCall := fake.getReplacementBundleInPackageChannelArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +func (fake *FakeRegistryClient) GetDefaultBundleThatProvidesArgsForCall(i int) (context.Context, *api.GetDefaultProviderRequest, []grpc.CallOption) { + fake.getDefaultBundleThatProvidesMutex.RLock() + defer fake.getDefaultBundleThatProvidesMutex.RUnlock() + argsForCall := fake.getDefaultBundleThatProvidesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) GetReplacementBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { - fake.getReplacementBundleInPackageChannelMutex.Lock() - defer fake.getReplacementBundleInPackageChannelMutex.Unlock() - fake.GetReplacementBundleInPackageChannelStub = nil - fake.getReplacementBundleInPackageChannelReturns = struct { +func (fake *FakeRegistryClient) GetDefaultBundleThatProvidesReturns(result1 *api.Bundle, result2 error) { + fake.getDefaultBundleThatProvidesMutex.Lock() + defer fake.getDefaultBundleThatProvidesMutex.Unlock() + fake.GetDefaultBundleThatProvidesStub = nil + fake.getDefaultBundleThatProvidesReturns = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) GetReplacementBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { - fake.getReplacementBundleInPackageChannelMutex.Lock() - defer fake.getReplacementBundleInPackageChannelMutex.Unlock() - fake.GetReplacementBundleInPackageChannelStub = nil - if fake.getReplacementBundleInPackageChannelReturnsOnCall == nil { - fake.getReplacementBundleInPackageChannelReturnsOnCall = make(map[int]struct { +func (fake *FakeRegistryClient) GetDefaultBundleThatProvidesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getDefaultBundleThatProvidesMutex.Lock() + defer fake.getDefaultBundleThatProvidesMutex.Unlock() + fake.GetDefaultBundleThatProvidesStub = nil + if fake.getDefaultBundleThatProvidesReturnsOnCall == nil { + fake.getDefaultBundleThatProvidesReturnsOnCall = make(map[int]struct { result1 *api.Bundle result2 error }) } - fake.getReplacementBundleInPackageChannelReturnsOnCall[i] = struct { + fake.getDefaultBundleThatProvidesReturnsOnCall[i] = struct { result1 *api.Bundle result2 error }{result1, result2} } -func (fake *FakeInterface) HealthCheck(arg1 context.Context, arg2 time.Duration) (bool, error) { - fake.healthCheckMutex.Lock() - ret, specificReturn := fake.healthCheckReturnsOnCall[len(fake.healthCheckArgsForCall)] - fake.healthCheckArgsForCall = append(fake.healthCheckArgsForCall, struct { +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvide(arg1 context.Context, arg2 *api.GetLatestProvidersRequest, arg3 ...grpc.CallOption) (api.Registry_GetLatestChannelEntriesThatProvideClient, error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + ret, specificReturn := fake.getLatestChannelEntriesThatProvideReturnsOnCall[len(fake.getLatestChannelEntriesThatProvideArgsForCall)] + fake.getLatestChannelEntriesThatProvideArgsForCall = append(fake.getLatestChannelEntriesThatProvideArgsForCall, struct { + arg1 context.Context + arg2 *api.GetLatestProvidersRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetLatestChannelEntriesThatProvide", []interface{}{arg1, arg2, arg3}) + fake.getLatestChannelEntriesThatProvideMutex.Unlock() + if fake.GetLatestChannelEntriesThatProvideStub != nil { + return fake.GetLatestChannelEntriesThatProvideStub(arg1, arg2, arg3...) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getLatestChannelEntriesThatProvideReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvideCallCount() int { + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + return len(fake.getLatestChannelEntriesThatProvideArgsForCall) +} + +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvideCalls(stub func(context.Context, *api.GetLatestProvidersRequest, ...grpc.CallOption) (api.Registry_GetLatestChannelEntriesThatProvideClient, error)) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = stub +} + +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvideArgsForCall(i int) (context.Context, *api.GetLatestProvidersRequest, []grpc.CallOption) { + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + argsForCall := fake.getLatestChannelEntriesThatProvideArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvideReturns(result1 api.Registry_GetLatestChannelEntriesThatProvideClient, result2 error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = nil + fake.getLatestChannelEntriesThatProvideReturns = struct { + result1 api.Registry_GetLatestChannelEntriesThatProvideClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetLatestChannelEntriesThatProvideReturnsOnCall(i int, result1 api.Registry_GetLatestChannelEntriesThatProvideClient, result2 error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = nil + if fake.getLatestChannelEntriesThatProvideReturnsOnCall == nil { + fake.getLatestChannelEntriesThatProvideReturnsOnCall = make(map[int]struct { + result1 api.Registry_GetLatestChannelEntriesThatProvideClient + result2 error + }) + } + fake.getLatestChannelEntriesThatProvideReturnsOnCall[i] = struct { + result1 api.Registry_GetLatestChannelEntriesThatProvideClient + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) GetPackage(arg1 context.Context, arg2 *api.GetPackageRequest, arg3 ...grpc.CallOption) (*api.Package, error) { + fake.getPackageMutex.Lock() + ret, specificReturn := fake.getPackageReturnsOnCall[len(fake.getPackageArgsForCall)] + fake.getPackageArgsForCall = append(fake.getPackageArgsForCall, struct { arg1 context.Context - arg2 time.Duration - }{arg1, arg2}) - fake.recordInvocation("HealthCheck", []interface{}{arg1, arg2}) - fake.healthCheckMutex.Unlock() - if fake.HealthCheckStub != nil { - return fake.HealthCheckStub(arg1, arg2) + arg2 *api.GetPackageRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("GetPackage", []interface{}{arg1, arg2, arg3}) + fake.getPackageMutex.Unlock() + if fake.GetPackageStub != nil { + return fake.GetPackageStub(arg1, arg2, arg3...) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.healthCheckReturns + fakeReturns := fake.getPackageReturns return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeInterface) HealthCheckCallCount() int { - fake.healthCheckMutex.RLock() - defer fake.healthCheckMutex.RUnlock() - return len(fake.healthCheckArgsForCall) +func (fake *FakeRegistryClient) GetPackageCallCount() int { + fake.getPackageMutex.RLock() + defer fake.getPackageMutex.RUnlock() + return len(fake.getPackageArgsForCall) +} + +func (fake *FakeRegistryClient) GetPackageCalls(stub func(context.Context, *api.GetPackageRequest, ...grpc.CallOption) (*api.Package, error)) { + fake.getPackageMutex.Lock() + defer fake.getPackageMutex.Unlock() + fake.GetPackageStub = stub +} + +func (fake *FakeRegistryClient) GetPackageArgsForCall(i int) (context.Context, *api.GetPackageRequest, []grpc.CallOption) { + fake.getPackageMutex.RLock() + defer fake.getPackageMutex.RUnlock() + argsForCall := fake.getPackageArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) HealthCheckCalls(stub func(context.Context, time.Duration) (bool, error)) { - fake.healthCheckMutex.Lock() - defer fake.healthCheckMutex.Unlock() - fake.HealthCheckStub = stub +func (fake *FakeRegistryClient) GetPackageReturns(result1 *api.Package, result2 error) { + fake.getPackageMutex.Lock() + defer fake.getPackageMutex.Unlock() + fake.GetPackageStub = nil + fake.getPackageReturns = struct { + result1 *api.Package + result2 error + }{result1, result2} } -func (fake *FakeInterface) HealthCheckArgsForCall(i int) (context.Context, time.Duration) { - fake.healthCheckMutex.RLock() - defer fake.healthCheckMutex.RUnlock() - argsForCall := fake.healthCheckArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 +func (fake *FakeRegistryClient) GetPackageReturnsOnCall(i int, result1 *api.Package, result2 error) { + fake.getPackageMutex.Lock() + defer fake.getPackageMutex.Unlock() + fake.GetPackageStub = nil + if fake.getPackageReturnsOnCall == nil { + fake.getPackageReturnsOnCall = make(map[int]struct { + result1 *api.Package + result2 error + }) + } + fake.getPackageReturnsOnCall[i] = struct { + result1 *api.Package + result2 error + }{result1, result2} +} + +func (fake *FakeRegistryClient) ListPackages(arg1 context.Context, arg2 *api.ListPackageRequest, arg3 ...grpc.CallOption) (api.Registry_ListPackagesClient, error) { + fake.listPackagesMutex.Lock() + ret, specificReturn := fake.listPackagesReturnsOnCall[len(fake.listPackagesArgsForCall)] + fake.listPackagesArgsForCall = append(fake.listPackagesArgsForCall, struct { + arg1 context.Context + arg2 *api.ListPackageRequest + arg3 []grpc.CallOption + }{arg1, arg2, arg3}) + fake.recordInvocation("ListPackages", []interface{}{arg1, arg2, arg3}) + fake.listPackagesMutex.Unlock() + if fake.ListPackagesStub != nil { + return fake.ListPackagesStub(arg1, arg2, arg3...) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.listPackagesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeRegistryClient) ListPackagesCallCount() int { + fake.listPackagesMutex.RLock() + defer fake.listPackagesMutex.RUnlock() + return len(fake.listPackagesArgsForCall) +} + +func (fake *FakeRegistryClient) ListPackagesCalls(stub func(context.Context, *api.ListPackageRequest, ...grpc.CallOption) (api.Registry_ListPackagesClient, error)) { + fake.listPackagesMutex.Lock() + defer fake.listPackagesMutex.Unlock() + fake.ListPackagesStub = stub +} + +func (fake *FakeRegistryClient) ListPackagesArgsForCall(i int) (context.Context, *api.ListPackageRequest, []grpc.CallOption) { + fake.listPackagesMutex.RLock() + defer fake.listPackagesMutex.RUnlock() + argsForCall := fake.listPackagesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeInterface) HealthCheckReturns(result1 bool, result2 error) { - fake.healthCheckMutex.Lock() - defer fake.healthCheckMutex.Unlock() - fake.HealthCheckStub = nil - fake.healthCheckReturns = struct { - result1 bool +func (fake *FakeRegistryClient) ListPackagesReturns(result1 api.Registry_ListPackagesClient, result2 error) { + fake.listPackagesMutex.Lock() + defer fake.listPackagesMutex.Unlock() + fake.ListPackagesStub = nil + fake.listPackagesReturns = struct { + result1 api.Registry_ListPackagesClient result2 error }{result1, result2} } -func (fake *FakeInterface) HealthCheckReturnsOnCall(i int, result1 bool, result2 error) { - fake.healthCheckMutex.Lock() - defer fake.healthCheckMutex.Unlock() - fake.HealthCheckStub = nil - if fake.healthCheckReturnsOnCall == nil { - fake.healthCheckReturnsOnCall = make(map[int]struct { - result1 bool +func (fake *FakeRegistryClient) ListPackagesReturnsOnCall(i int, result1 api.Registry_ListPackagesClient, result2 error) { + fake.listPackagesMutex.Lock() + defer fake.listPackagesMutex.Unlock() + fake.ListPackagesStub = nil + if fake.listPackagesReturnsOnCall == nil { + fake.listPackagesReturnsOnCall = make(map[int]struct { + result1 api.Registry_ListPackagesClient result2 error }) } - fake.healthCheckReturnsOnCall[i] = struct { - result1 bool + fake.listPackagesReturnsOnCall[i] = struct { + result1 api.Registry_ListPackagesClient result2 error }{result1, result2} } -func (fake *FakeInterface) Invocations() map[string][][]interface{} { +func (fake *FakeRegistryClient) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() fake.getBundleMutex.RLock() defer fake.getBundleMutex.RUnlock() - fake.getBundleInPackageChannelMutex.RLock() - defer fake.getBundleInPackageChannelMutex.RUnlock() - fake.getBundleThatProvidesMutex.RLock() - defer fake.getBundleThatProvidesMutex.RUnlock() - fake.getReplacementBundleInPackageChannelMutex.RLock() - defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() - fake.healthCheckMutex.RLock() - defer fake.healthCheckMutex.RUnlock() + fake.getBundleForChannelMutex.RLock() + defer fake.getBundleForChannelMutex.RUnlock() + fake.getBundleThatReplacesMutex.RLock() + defer fake.getBundleThatReplacesMutex.RUnlock() + fake.getChannelEntriesThatProvideMutex.RLock() + defer fake.getChannelEntriesThatProvideMutex.RUnlock() + fake.getChannelEntriesThatReplaceMutex.RLock() + defer fake.getChannelEntriesThatReplaceMutex.RUnlock() + fake.getDefaultBundleThatProvidesMutex.RLock() + defer fake.getDefaultBundleThatProvidesMutex.RUnlock() + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + fake.getPackageMutex.RLock() + defer fake.getPackageMutex.RUnlock() + fake.listPackagesMutex.RLock() + defer fake.listPackagesMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} for key, value := range fake.invocations { copiedInvocations[key] = value @@ -503,7 +762,7 @@ func (fake *FakeInterface) Invocations() map[string][][]interface{} { return copiedInvocations } -func (fake *FakeInterface) recordInvocation(key string, args []interface{}) { +func (fake *FakeRegistryClient) recordInvocation(key string, args []interface{}) { fake.invocationsMutex.Lock() defer fake.invocationsMutex.Unlock() if fake.invocations == nil { @@ -515,4 +774,4 @@ func (fake *FakeInterface) recordInvocation(key string, args []interface{}) { fake.invocations[key] = append(fake.invocations[key], args) } -var _ client.Interface = new(FakeInterface) +var _ api.RegistryClient = new(FakeRegistryClient) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client_interface.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client_interface.go new file mode 100644 index 00000000000..88dccac5ae2 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_client_interface.go @@ -0,0 +1,688 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + "context" + "sync" + "time" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" + "github.com/operator-framework/operator-registry/pkg/api" +) + +type FakeClientInterface struct { + CloseStub func() error + closeMutex sync.RWMutex + closeArgsForCall []struct { + } + closeReturns struct { + result1 error + } + closeReturnsOnCall map[int]struct { + result1 error + } + FindBundleThatProvidesStub func(context.Context, string, string, string, string) (*api.Bundle, error) + findBundleThatProvidesMutex sync.RWMutex + findBundleThatProvidesArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + arg5 string + } + findBundleThatProvidesReturns struct { + result1 *api.Bundle + result2 error + } + findBundleThatProvidesReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetBundleStub func(context.Context, string, string, string) (*api.Bundle, error) + getBundleMutex sync.RWMutex + getBundleArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getBundleReturns struct { + result1 *api.Bundle + result2 error + } + getBundleReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetBundleInPackageChannelStub func(context.Context, string, string) (*api.Bundle, error) + getBundleInPackageChannelMutex sync.RWMutex + getBundleInPackageChannelArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + } + getBundleInPackageChannelReturns struct { + result1 *api.Bundle + result2 error + } + getBundleInPackageChannelReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetBundleThatProvidesStub func(context.Context, string, string, string) (*api.Bundle, error) + getBundleThatProvidesMutex sync.RWMutex + getBundleThatProvidesArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getBundleThatProvidesReturns struct { + result1 *api.Bundle + result2 error + } + getBundleThatProvidesReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetLatestChannelEntriesThatProvideStub func(context.Context, string, string, string) (*registry.ChannelEntryIterator, error) + getLatestChannelEntriesThatProvideMutex sync.RWMutex + getLatestChannelEntriesThatProvideArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getLatestChannelEntriesThatProvideReturns struct { + result1 *registry.ChannelEntryIterator + result2 error + } + getLatestChannelEntriesThatProvideReturnsOnCall map[int]struct { + result1 *registry.ChannelEntryIterator + result2 error + } + GetReplacementBundleInPackageChannelStub func(context.Context, string, string, string) (*api.Bundle, error) + getReplacementBundleInPackageChannelMutex sync.RWMutex + getReplacementBundleInPackageChannelArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getReplacementBundleInPackageChannelReturns struct { + result1 *api.Bundle + result2 error + } + getReplacementBundleInPackageChannelReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + HealthCheckStub func(context.Context, time.Duration) (bool, error) + healthCheckMutex sync.RWMutex + healthCheckArgsForCall []struct { + arg1 context.Context + arg2 time.Duration + } + healthCheckReturns struct { + result1 bool + result2 error + } + healthCheckReturnsOnCall map[int]struct { + result1 bool + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeClientInterface) Close() error { + fake.closeMutex.Lock() + ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)] + fake.closeArgsForCall = append(fake.closeArgsForCall, struct { + }{}) + fake.recordInvocation("Close", []interface{}{}) + fake.closeMutex.Unlock() + if fake.CloseStub != nil { + return fake.CloseStub() + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.closeReturns + return fakeReturns.result1 +} + +func (fake *FakeClientInterface) CloseCallCount() int { + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + return len(fake.closeArgsForCall) +} + +func (fake *FakeClientInterface) CloseCalls(stub func() error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = stub +} + +func (fake *FakeClientInterface) CloseReturns(result1 error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = nil + fake.closeReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeClientInterface) CloseReturnsOnCall(i int, result1 error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = nil + if fake.closeReturnsOnCall == nil { + fake.closeReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.closeReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeClientInterface) FindBundleThatProvides(arg1 context.Context, arg2 string, arg3 string, arg4 string, arg5 string) (*api.Bundle, error) { + fake.findBundleThatProvidesMutex.Lock() + ret, specificReturn := fake.findBundleThatProvidesReturnsOnCall[len(fake.findBundleThatProvidesArgsForCall)] + fake.findBundleThatProvidesArgsForCall = append(fake.findBundleThatProvidesArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + arg5 string + }{arg1, arg2, arg3, arg4, arg5}) + fake.recordInvocation("FindBundleThatProvides", []interface{}{arg1, arg2, arg3, arg4, arg5}) + fake.findBundleThatProvidesMutex.Unlock() + if fake.FindBundleThatProvidesStub != nil { + return fake.FindBundleThatProvidesStub(arg1, arg2, arg3, arg4, arg5) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.findBundleThatProvidesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) FindBundleThatProvidesCallCount() int { + fake.findBundleThatProvidesMutex.RLock() + defer fake.findBundleThatProvidesMutex.RUnlock() + return len(fake.findBundleThatProvidesArgsForCall) +} + +func (fake *FakeClientInterface) FindBundleThatProvidesCalls(stub func(context.Context, string, string, string, string) (*api.Bundle, error)) { + fake.findBundleThatProvidesMutex.Lock() + defer fake.findBundleThatProvidesMutex.Unlock() + fake.FindBundleThatProvidesStub = stub +} + +func (fake *FakeClientInterface) FindBundleThatProvidesArgsForCall(i int) (context.Context, string, string, string, string) { + fake.findBundleThatProvidesMutex.RLock() + defer fake.findBundleThatProvidesMutex.RUnlock() + argsForCall := fake.findBundleThatProvidesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 +} + +func (fake *FakeClientInterface) FindBundleThatProvidesReturns(result1 *api.Bundle, result2 error) { + fake.findBundleThatProvidesMutex.Lock() + defer fake.findBundleThatProvidesMutex.Unlock() + fake.FindBundleThatProvidesStub = nil + fake.findBundleThatProvidesReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) FindBundleThatProvidesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.findBundleThatProvidesMutex.Lock() + defer fake.findBundleThatProvidesMutex.Unlock() + fake.FindBundleThatProvidesStub = nil + if fake.findBundleThatProvidesReturnsOnCall == nil { + fake.findBundleThatProvidesReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.findBundleThatProvidesReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundle(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getBundleMutex.Lock() + ret, specificReturn := fake.getBundleReturnsOnCall[len(fake.getBundleArgsForCall)] + fake.getBundleArgsForCall = append(fake.getBundleArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetBundle", []interface{}{arg1, arg2, arg3, arg4}) + fake.getBundleMutex.Unlock() + if fake.GetBundleStub != nil { + return fake.GetBundleStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) GetBundleCallCount() int { + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + return len(fake.getBundleArgsForCall) +} + +func (fake *FakeClientInterface) GetBundleCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = stub +} + +func (fake *FakeClientInterface) GetBundleArgsForCall(i int) (context.Context, string, string, string) { + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + argsForCall := fake.getBundleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeClientInterface) GetBundleReturns(result1 *api.Bundle, result2 error) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = nil + fake.getBundleReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundleReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = nil + if fake.getBundleReturnsOnCall == nil { + fake.getBundleReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string) (*api.Bundle, error) { + fake.getBundleInPackageChannelMutex.Lock() + ret, specificReturn := fake.getBundleInPackageChannelReturnsOnCall[len(fake.getBundleInPackageChannelArgsForCall)] + fake.getBundleInPackageChannelArgsForCall = append(fake.getBundleInPackageChannelArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + }{arg1, arg2, arg3}) + fake.recordInvocation("GetBundleInPackageChannel", []interface{}{arg1, arg2, arg3}) + fake.getBundleInPackageChannelMutex.Unlock() + if fake.GetBundleInPackageChannelStub != nil { + return fake.GetBundleInPackageChannelStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleInPackageChannelReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) GetBundleInPackageChannelCallCount() int { + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + return len(fake.getBundleInPackageChannelArgsForCall) +} + +func (fake *FakeClientInterface) GetBundleInPackageChannelCalls(stub func(context.Context, string, string) (*api.Bundle, error)) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = stub +} + +func (fake *FakeClientInterface) GetBundleInPackageChannelArgsForCall(i int) (context.Context, string, string) { + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + argsForCall := fake.getBundleInPackageChannelArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeClientInterface) GetBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = nil + fake.getBundleInPackageChannelReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = nil + if fake.getBundleInPackageChannelReturnsOnCall == nil { + fake.getBundleInPackageChannelReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleInPackageChannelReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundleThatProvides(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getBundleThatProvidesMutex.Lock() + ret, specificReturn := fake.getBundleThatProvidesReturnsOnCall[len(fake.getBundleThatProvidesArgsForCall)] + fake.getBundleThatProvidesArgsForCall = append(fake.getBundleThatProvidesArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetBundleThatProvides", []interface{}{arg1, arg2, arg3, arg4}) + fake.getBundleThatProvidesMutex.Unlock() + if fake.GetBundleThatProvidesStub != nil { + return fake.GetBundleThatProvidesStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleThatProvidesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) GetBundleThatProvidesCallCount() int { + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + return len(fake.getBundleThatProvidesArgsForCall) +} + +func (fake *FakeClientInterface) GetBundleThatProvidesCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = stub +} + +func (fake *FakeClientInterface) GetBundleThatProvidesArgsForCall(i int) (context.Context, string, string, string) { + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + argsForCall := fake.getBundleThatProvidesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeClientInterface) GetBundleThatProvidesReturns(result1 *api.Bundle, result2 error) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = nil + fake.getBundleThatProvidesReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetBundleThatProvidesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = nil + if fake.getBundleThatProvidesReturnsOnCall == nil { + fake.getBundleThatProvidesReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleThatProvidesReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvide(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*registry.ChannelEntryIterator, error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + ret, specificReturn := fake.getLatestChannelEntriesThatProvideReturnsOnCall[len(fake.getLatestChannelEntriesThatProvideArgsForCall)] + fake.getLatestChannelEntriesThatProvideArgsForCall = append(fake.getLatestChannelEntriesThatProvideArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetLatestChannelEntriesThatProvide", []interface{}{arg1, arg2, arg3, arg4}) + fake.getLatestChannelEntriesThatProvideMutex.Unlock() + if fake.GetLatestChannelEntriesThatProvideStub != nil { + return fake.GetLatestChannelEntriesThatProvideStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getLatestChannelEntriesThatProvideReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvideCallCount() int { + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + return len(fake.getLatestChannelEntriesThatProvideArgsForCall) +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvideCalls(stub func(context.Context, string, string, string) (*registry.ChannelEntryIterator, error)) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = stub +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvideArgsForCall(i int) (context.Context, string, string, string) { + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + argsForCall := fake.getLatestChannelEntriesThatProvideArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvideReturns(result1 *registry.ChannelEntryIterator, result2 error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = nil + fake.getLatestChannelEntriesThatProvideReturns = struct { + result1 *registry.ChannelEntryIterator + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetLatestChannelEntriesThatProvideReturnsOnCall(i int, result1 *registry.ChannelEntryIterator, result2 error) { + fake.getLatestChannelEntriesThatProvideMutex.Lock() + defer fake.getLatestChannelEntriesThatProvideMutex.Unlock() + fake.GetLatestChannelEntriesThatProvideStub = nil + if fake.getLatestChannelEntriesThatProvideReturnsOnCall == nil { + fake.getLatestChannelEntriesThatProvideReturnsOnCall = make(map[int]struct { + result1 *registry.ChannelEntryIterator + result2 error + }) + } + fake.getLatestChannelEntriesThatProvideReturnsOnCall[i] = struct { + result1 *registry.ChannelEntryIterator + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + ret, specificReturn := fake.getReplacementBundleInPackageChannelReturnsOnCall[len(fake.getReplacementBundleInPackageChannelArgsForCall)] + fake.getReplacementBundleInPackageChannelArgsForCall = append(fake.getReplacementBundleInPackageChannelArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetReplacementBundleInPackageChannel", []interface{}{arg1, arg2, arg3, arg4}) + fake.getReplacementBundleInPackageChannelMutex.Unlock() + if fake.GetReplacementBundleInPackageChannelStub != nil { + return fake.GetReplacementBundleInPackageChannelStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getReplacementBundleInPackageChannelReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannelCallCount() int { + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + return len(fake.getReplacementBundleInPackageChannelArgsForCall) +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannelCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = stub +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannelArgsForCall(i int) (context.Context, string, string, string) { + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + argsForCall := fake.getReplacementBundleInPackageChannelArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = nil + fake.getReplacementBundleInPackageChannelReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) GetReplacementBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = nil + if fake.getReplacementBundleInPackageChannelReturnsOnCall == nil { + fake.getReplacementBundleInPackageChannelReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getReplacementBundleInPackageChannelReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) HealthCheck(arg1 context.Context, arg2 time.Duration) (bool, error) { + fake.healthCheckMutex.Lock() + ret, specificReturn := fake.healthCheckReturnsOnCall[len(fake.healthCheckArgsForCall)] + fake.healthCheckArgsForCall = append(fake.healthCheckArgsForCall, struct { + arg1 context.Context + arg2 time.Duration + }{arg1, arg2}) + fake.recordInvocation("HealthCheck", []interface{}{arg1, arg2}) + fake.healthCheckMutex.Unlock() + if fake.HealthCheckStub != nil { + return fake.HealthCheckStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.healthCheckReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeClientInterface) HealthCheckCallCount() int { + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + return len(fake.healthCheckArgsForCall) +} + +func (fake *FakeClientInterface) HealthCheckCalls(stub func(context.Context, time.Duration) (bool, error)) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = stub +} + +func (fake *FakeClientInterface) HealthCheckArgsForCall(i int) (context.Context, time.Duration) { + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + argsForCall := fake.healthCheckArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeClientInterface) HealthCheckReturns(result1 bool, result2 error) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = nil + fake.healthCheckReturns = struct { + result1 bool + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) HealthCheckReturnsOnCall(i int, result1 bool, result2 error) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = nil + if fake.healthCheckReturnsOnCall == nil { + fake.healthCheckReturnsOnCall = make(map[int]struct { + result1 bool + result2 error + }) + } + fake.healthCheckReturnsOnCall[i] = struct { + result1 bool + result2 error + }{result1, result2} +} + +func (fake *FakeClientInterface) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + fake.findBundleThatProvidesMutex.RLock() + defer fake.findBundleThatProvidesMutex.RUnlock() + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + fake.getLatestChannelEntriesThatProvideMutex.RLock() + defer fake.getLatestChannelEntriesThatProvideMutex.RUnlock() + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeClientInterface) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ registry.ClientInterface = new(FakeClientInterface) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_interface.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_interface.go new file mode 100644 index 00000000000..d3eb6b55b87 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes/fake_registry_interface.go @@ -0,0 +1,518 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package fakes + +import ( + "context" + "sync" + "time" + + "github.com/operator-framework/operator-registry/pkg/api" + "github.com/operator-framework/operator-registry/pkg/client" +) + +type FakeInterface struct { + CloseStub func() error + closeMutex sync.RWMutex + closeArgsForCall []struct { + } + closeReturns struct { + result1 error + } + closeReturnsOnCall map[int]struct { + result1 error + } + GetBundleStub func(context.Context, string, string, string) (*api.Bundle, error) + getBundleMutex sync.RWMutex + getBundleArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getBundleReturns struct { + result1 *api.Bundle + result2 error + } + getBundleReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetBundleInPackageChannelStub func(context.Context, string, string) (*api.Bundle, error) + getBundleInPackageChannelMutex sync.RWMutex + getBundleInPackageChannelArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + } + getBundleInPackageChannelReturns struct { + result1 *api.Bundle + result2 error + } + getBundleInPackageChannelReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetBundleThatProvidesStub func(context.Context, string, string, string) (*api.Bundle, error) + getBundleThatProvidesMutex sync.RWMutex + getBundleThatProvidesArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getBundleThatProvidesReturns struct { + result1 *api.Bundle + result2 error + } + getBundleThatProvidesReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + GetReplacementBundleInPackageChannelStub func(context.Context, string, string, string) (*api.Bundle, error) + getReplacementBundleInPackageChannelMutex sync.RWMutex + getReplacementBundleInPackageChannelArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getReplacementBundleInPackageChannelReturns struct { + result1 *api.Bundle + result2 error + } + getReplacementBundleInPackageChannelReturnsOnCall map[int]struct { + result1 *api.Bundle + result2 error + } + HealthCheckStub func(context.Context, time.Duration) (bool, error) + healthCheckMutex sync.RWMutex + healthCheckArgsForCall []struct { + arg1 context.Context + arg2 time.Duration + } + healthCheckReturns struct { + result1 bool + result2 error + } + healthCheckReturnsOnCall map[int]struct { + result1 bool + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeInterface) Close() error { + fake.closeMutex.Lock() + ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)] + fake.closeArgsForCall = append(fake.closeArgsForCall, struct { + }{}) + fake.recordInvocation("Close", []interface{}{}) + fake.closeMutex.Unlock() + if fake.CloseStub != nil { + return fake.CloseStub() + } + if specificReturn { + return ret.result1 + } + fakeReturns := fake.closeReturns + return fakeReturns.result1 +} + +func (fake *FakeInterface) CloseCallCount() int { + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + return len(fake.closeArgsForCall) +} + +func (fake *FakeInterface) CloseCalls(stub func() error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = stub +} + +func (fake *FakeInterface) CloseReturns(result1 error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = nil + fake.closeReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeInterface) CloseReturnsOnCall(i int, result1 error) { + fake.closeMutex.Lock() + defer fake.closeMutex.Unlock() + fake.CloseStub = nil + if fake.closeReturnsOnCall == nil { + fake.closeReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.closeReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeInterface) GetBundle(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getBundleMutex.Lock() + ret, specificReturn := fake.getBundleReturnsOnCall[len(fake.getBundleArgsForCall)] + fake.getBundleArgsForCall = append(fake.getBundleArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetBundle", []interface{}{arg1, arg2, arg3, arg4}) + fake.getBundleMutex.Unlock() + if fake.GetBundleStub != nil { + return fake.GetBundleStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeInterface) GetBundleCallCount() int { + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + return len(fake.getBundleArgsForCall) +} + +func (fake *FakeInterface) GetBundleCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = stub +} + +func (fake *FakeInterface) GetBundleArgsForCall(i int) (context.Context, string, string, string) { + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + argsForCall := fake.getBundleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeInterface) GetBundleReturns(result1 *api.Bundle, result2 error) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = nil + fake.getBundleReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetBundleReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleMutex.Lock() + defer fake.getBundleMutex.Unlock() + fake.GetBundleStub = nil + if fake.getBundleReturnsOnCall == nil { + fake.getBundleReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string) (*api.Bundle, error) { + fake.getBundleInPackageChannelMutex.Lock() + ret, specificReturn := fake.getBundleInPackageChannelReturnsOnCall[len(fake.getBundleInPackageChannelArgsForCall)] + fake.getBundleInPackageChannelArgsForCall = append(fake.getBundleInPackageChannelArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + }{arg1, arg2, arg3}) + fake.recordInvocation("GetBundleInPackageChannel", []interface{}{arg1, arg2, arg3}) + fake.getBundleInPackageChannelMutex.Unlock() + if fake.GetBundleInPackageChannelStub != nil { + return fake.GetBundleInPackageChannelStub(arg1, arg2, arg3) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleInPackageChannelReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeInterface) GetBundleInPackageChannelCallCount() int { + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + return len(fake.getBundleInPackageChannelArgsForCall) +} + +func (fake *FakeInterface) GetBundleInPackageChannelCalls(stub func(context.Context, string, string) (*api.Bundle, error)) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = stub +} + +func (fake *FakeInterface) GetBundleInPackageChannelArgsForCall(i int) (context.Context, string, string) { + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + argsForCall := fake.getBundleInPackageChannelArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +} + +func (fake *FakeInterface) GetBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = nil + fake.getBundleInPackageChannelReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleInPackageChannelMutex.Lock() + defer fake.getBundleInPackageChannelMutex.Unlock() + fake.GetBundleInPackageChannelStub = nil + if fake.getBundleInPackageChannelReturnsOnCall == nil { + fake.getBundleInPackageChannelReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleInPackageChannelReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetBundleThatProvides(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getBundleThatProvidesMutex.Lock() + ret, specificReturn := fake.getBundleThatProvidesReturnsOnCall[len(fake.getBundleThatProvidesArgsForCall)] + fake.getBundleThatProvidesArgsForCall = append(fake.getBundleThatProvidesArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetBundleThatProvides", []interface{}{arg1, arg2, arg3, arg4}) + fake.getBundleThatProvidesMutex.Unlock() + if fake.GetBundleThatProvidesStub != nil { + return fake.GetBundleThatProvidesStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getBundleThatProvidesReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeInterface) GetBundleThatProvidesCallCount() int { + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + return len(fake.getBundleThatProvidesArgsForCall) +} + +func (fake *FakeInterface) GetBundleThatProvidesCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = stub +} + +func (fake *FakeInterface) GetBundleThatProvidesArgsForCall(i int) (context.Context, string, string, string) { + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + argsForCall := fake.getBundleThatProvidesArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeInterface) GetBundleThatProvidesReturns(result1 *api.Bundle, result2 error) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = nil + fake.getBundleThatProvidesReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetBundleThatProvidesReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getBundleThatProvidesMutex.Lock() + defer fake.getBundleThatProvidesMutex.Unlock() + fake.GetBundleThatProvidesStub = nil + if fake.getBundleThatProvidesReturnsOnCall == nil { + fake.getBundleThatProvidesReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getBundleThatProvidesReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannel(arg1 context.Context, arg2 string, arg3 string, arg4 string) (*api.Bundle, error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + ret, specificReturn := fake.getReplacementBundleInPackageChannelReturnsOnCall[len(fake.getReplacementBundleInPackageChannelArgsForCall)] + fake.getReplacementBundleInPackageChannelArgsForCall = append(fake.getReplacementBundleInPackageChannelArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + fake.recordInvocation("GetReplacementBundleInPackageChannel", []interface{}{arg1, arg2, arg3, arg4}) + fake.getReplacementBundleInPackageChannelMutex.Unlock() + if fake.GetReplacementBundleInPackageChannelStub != nil { + return fake.GetReplacementBundleInPackageChannelStub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.getReplacementBundleInPackageChannelReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannelCallCount() int { + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + return len(fake.getReplacementBundleInPackageChannelArgsForCall) +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannelCalls(stub func(context.Context, string, string, string) (*api.Bundle, error)) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = stub +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannelArgsForCall(i int) (context.Context, string, string, string) { + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + argsForCall := fake.getReplacementBundleInPackageChannelArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannelReturns(result1 *api.Bundle, result2 error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = nil + fake.getReplacementBundleInPackageChannelReturns = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) GetReplacementBundleInPackageChannelReturnsOnCall(i int, result1 *api.Bundle, result2 error) { + fake.getReplacementBundleInPackageChannelMutex.Lock() + defer fake.getReplacementBundleInPackageChannelMutex.Unlock() + fake.GetReplacementBundleInPackageChannelStub = nil + if fake.getReplacementBundleInPackageChannelReturnsOnCall == nil { + fake.getReplacementBundleInPackageChannelReturnsOnCall = make(map[int]struct { + result1 *api.Bundle + result2 error + }) + } + fake.getReplacementBundleInPackageChannelReturnsOnCall[i] = struct { + result1 *api.Bundle + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) HealthCheck(arg1 context.Context, arg2 time.Duration) (bool, error) { + fake.healthCheckMutex.Lock() + ret, specificReturn := fake.healthCheckReturnsOnCall[len(fake.healthCheckArgsForCall)] + fake.healthCheckArgsForCall = append(fake.healthCheckArgsForCall, struct { + arg1 context.Context + arg2 time.Duration + }{arg1, arg2}) + fake.recordInvocation("HealthCheck", []interface{}{arg1, arg2}) + fake.healthCheckMutex.Unlock() + if fake.HealthCheckStub != nil { + return fake.HealthCheckStub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + fakeReturns := fake.healthCheckReturns + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeInterface) HealthCheckCallCount() int { + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + return len(fake.healthCheckArgsForCall) +} + +func (fake *FakeInterface) HealthCheckCalls(stub func(context.Context, time.Duration) (bool, error)) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = stub +} + +func (fake *FakeInterface) HealthCheckArgsForCall(i int) (context.Context, time.Duration) { + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + argsForCall := fake.healthCheckArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeInterface) HealthCheckReturns(result1 bool, result2 error) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = nil + fake.healthCheckReturns = struct { + result1 bool + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) HealthCheckReturnsOnCall(i int, result1 bool, result2 error) { + fake.healthCheckMutex.Lock() + defer fake.healthCheckMutex.Unlock() + fake.HealthCheckStub = nil + if fake.healthCheckReturnsOnCall == nil { + fake.healthCheckReturnsOnCall = make(map[int]struct { + result1 bool + result2 error + }) + } + fake.healthCheckReturnsOnCall[i] = struct { + result1 bool + result2 error + }{result1, result2} +} + +func (fake *FakeInterface) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.closeMutex.RLock() + defer fake.closeMutex.RUnlock() + fake.getBundleMutex.RLock() + defer fake.getBundleMutex.RUnlock() + fake.getBundleInPackageChannelMutex.RLock() + defer fake.getBundleInPackageChannelMutex.RUnlock() + fake.getBundleThatProvidesMutex.RLock() + defer fake.getBundleThatProvidesMutex.RUnlock() + fake.getReplacementBundleInPackageChannelMutex.RLock() + defer fake.getReplacementBundleInPackageChannelMutex.RUnlock() + fake.healthCheckMutex.RLock() + defer fake.healthCheckMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeInterface) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ client.Interface = new(FakeInterface) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier.go index b85d29a4e37..89ba9308f40 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier.go @@ -1,4 +1,5 @@ -//go:generate counterfeiter -o fakes/fake_registry_client.go ../../../../vendor/github.com/operator-framework/operator-registry/pkg/client/client.go Interface +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o fakes/fake_registry_client.go ../../../../vendor/github.com/operator-framework/operator-registry/pkg/api.RegistryClient +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o fakes/fake_registry_interface.go ../../../../vendor/github.com/operator-framework/operator-registry/pkg/client/client.go Interface package resolver import ( @@ -10,8 +11,11 @@ import ( "k8s.io/apimachinery/pkg/util/errors" "github.com/operator-framework/operator-registry/pkg/api" + registryapi "github.com/operator-framework/operator-registry/pkg/api" "github.com/operator-framework/operator-registry/pkg/client" opregistry "github.com/operator-framework/operator-registry/pkg/registry" + + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" ) const SkipPackageAnnotationKey = "olm.skipRange" @@ -24,7 +28,7 @@ type SourceRef struct { } type SourceQuerier interface { - FindProvider(api opregistry.APIKey, initialSource CatalogKey) (*api.Bundle, *CatalogKey, error) + FindProvider(api opregistry.APIKey, initialSource CatalogKey, excludedPkgName string) (*api.Bundle, *CatalogKey, error) FindBundle(pkgName, channelName, bundleName string, initialSource CatalogKey) (*api.Bundle, *CatalogKey, error) FindLatestBundle(pkgName, channelName string, initialSource CatalogKey) (*api.Bundle, *CatalogKey, error) FindReplacement(currentVersion *semver.Version, bundleName, pkgName, channelName string, initialSource CatalogKey) (*api.Bundle, *CatalogKey, error) @@ -32,12 +36,12 @@ type SourceQuerier interface { } type NamespaceSourceQuerier struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } var _ SourceQuerier = &NamespaceSourceQuerier{} -func NewNamespaceSourceQuerier(sources map[CatalogKey]client.Interface) *NamespaceSourceQuerier { +func NewNamespaceSourceQuerier(sources map[CatalogKey]registry.ClientInterface) *NamespaceSourceQuerier { return &NamespaceSourceQuerier{ sources: sources, } @@ -50,23 +54,23 @@ func (q *NamespaceSourceQuerier) Queryable() error { return nil } -func (q *NamespaceSourceQuerier) FindProvider(api opregistry.APIKey, initialSource CatalogKey) (*api.Bundle, *CatalogKey, error) { +func (q *NamespaceSourceQuerier) FindProvider(api opregistry.APIKey, initialSource CatalogKey, excludedPkgName string) (*registryapi.Bundle, *CatalogKey, error) { if initialSource.Name != "" && initialSource.Namespace != "" { source, ok := q.sources[initialSource] if ok { - if bundle, err := source.GetBundleThatProvides(context.TODO(), api.Group, api.Version, api.Kind); err == nil { + if bundle, err := source.FindBundleThatProvides(context.TODO(), api.Group, api.Version, api.Kind, excludedPkgName); err == nil { return bundle, &initialSource, nil } - if bundle, err := source.GetBundleThatProvides(context.TODO(), api.Plural+"."+api.Group, api.Version, api.Kind); err == nil { + if bundle, err := source.FindBundleThatProvides(context.TODO(), api.Plural+"."+api.Group, api.Version, api.Kind, excludedPkgName); err == nil { return bundle, &initialSource, nil } } } for key, source := range q.sources { - if bundle, err := source.GetBundleThatProvides(context.TODO(), api.Group, api.Version, api.Kind); err == nil { + if bundle, err := source.FindBundleThatProvides(context.TODO(), api.Group, api.Version, api.Kind, excludedPkgName); err == nil { return bundle, &key, nil } - if bundle, err := source.GetBundleThatProvides(context.TODO(), api.Plural+"."+api.Group, api.Version, api.Kind); err == nil { + if bundle, err := source.FindBundleThatProvides(context.TODO(), api.Plural+"."+api.Group, api.Version, api.Kind, excludedPkgName); err == nil { return bundle, &key, nil } } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier_test.go index 53afae5f487..5358060fe09 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/querier_test.go @@ -14,17 +14,23 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/version" ) func TestNewNamespaceSourceQuerier(t *testing.T) { - emptySources := map[CatalogKey]client.Interface{} - nonEmptySources := map[CatalogKey]client.Interface{ - CatalogKey{"test", "ns"}: &fakes.FakeInterface{}, + emptySources := map[CatalogKey]registry.ClientInterface{} + nonEmptySources := map[CatalogKey]registry.ClientInterface{ + CatalogKey{"test", "ns"}: ®istry.Client{ + Client: &client.Client{ + Registry: &fakes.FakeRegistryClient{}, + }, + }, } + type args struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } tests := []struct { name string @@ -62,7 +68,7 @@ func TestNewNamespaceSourceQuerier(t *testing.T) { func TestNamespaceSourceQuerier_Queryable(t *testing.T) { type fields struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } tests := []struct { name string @@ -79,15 +85,19 @@ func TestNamespaceSourceQuerier_Queryable(t *testing.T) { { name: "empty", fields: fields{ - sources: map[CatalogKey]client.Interface{}, + sources: map[CatalogKey]registry.ClientInterface{}, }, error: fmt.Errorf("no catalog sources available"), }, { name: "nonEmpty", fields: fields{ - sources: map[CatalogKey]client.Interface{ - CatalogKey{"test", "ns"}: &fakes.FakeInterface{}, + sources: map[CatalogKey]registry.ClientInterface{ + CatalogKey{"test", "ns"}: ®istry.Client{ + Client: &client.Client{ + Registry: &fakes.FakeRegistryClient{}, + }, + }, }, }, error: nil, @@ -105,13 +115,12 @@ func TestNamespaceSourceQuerier_Queryable(t *testing.T) { } func TestNamespaceSourceQuerier_FindProvider(t *testing.T) { - fakeSource := fakes.FakeInterface{} - fakeSource2 := fakes.FakeInterface{} - sources := map[CatalogKey]client.Interface{ + fakeSource := fakes.FakeClientInterface{} + fakeSource2 := fakes.FakeClientInterface{} + sources := map[CatalogKey]registry.ClientInterface{ CatalogKey{"test", "ns"}: &fakeSource, CatalogKey{"test2", "ns"}: &fakeSource2, } - bundle := &api.Bundle{CsvName: "test", PackageName: "testPkg", ChannelName: "testChannel"} bundle2 := &api.Bundle{CsvName: "test2", PackageName: "testPkg2", ChannelName: "testChannel2"} fakeSource.GetBundleThatProvidesStub = func(ctx context.Context, group, version, kind string) (*api.Bundle, error) { @@ -126,9 +135,21 @@ func TestNamespaceSourceQuerier_FindProvider(t *testing.T) { } return bundle2, nil } + fakeSource.FindBundleThatProvidesStub = func(ctx context.Context, group, version, kind, pkgName string) (*api.Bundle, error) { + if group != "group" || version != "version" || kind != "kind" { + return nil, fmt.Errorf("Not Found") + } + return bundle, nil + } + fakeSource2.FindBundleThatProvidesStub = func(ctx context.Context, group, version, kind, pkgName string) (*api.Bundle, error) { + if group != "group2" || version != "version2" || kind != "kind2" { + return nil, fmt.Errorf("Not Found") + } + return bundle2, nil + } type fields struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } type args struct { api opregistry.APIKey @@ -207,7 +228,7 @@ func TestNamespaceSourceQuerier_FindProvider(t *testing.T) { q := &NamespaceSourceQuerier{ sources: tt.fields.sources, } - bundle, key, err := q.FindProvider(tt.args.api, tt.args.catalogKey) + bundle, key, err := q.FindProvider(tt.args.api, tt.args.catalogKey, "") require.Equal(t, tt.out.err, err) require.Equal(t, tt.out.bundle, bundle) require.Equal(t, tt.out.key, key) @@ -216,8 +237,8 @@ func TestNamespaceSourceQuerier_FindProvider(t *testing.T) { } func TestNamespaceSourceQuerier_FindPackage(t *testing.T) { - initialSource := fakes.FakeInterface{} - otherSource := fakes.FakeInterface{} + initialSource := fakes.FakeClientInterface{} + otherSource := fakes.FakeClientInterface{} initalBundle := &api.Bundle{CsvName: "test", PackageName: "testPkg", ChannelName: "testChannel"} startingBundle := &api.Bundle{CsvName: "starting-test", PackageName: "testPkg", ChannelName: "testChannel"} otherBundle := &api.Bundle{CsvName: "other", PackageName: "otherPkg", ChannelName: "otherChannel"} @@ -241,13 +262,13 @@ func TestNamespaceSourceQuerier_FindPackage(t *testing.T) { } initialKey := CatalogKey{"initial", "ns"} otherKey := CatalogKey{"other", "other"} - sources := map[CatalogKey]client.Interface{ + sources := map[CatalogKey]registry.ClientInterface{ initialKey: &initialSource, otherKey: &otherSource, } type fields struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } type args struct { pkgName string @@ -325,11 +346,11 @@ func TestNamespaceSourceQuerier_FindPackage(t *testing.T) { func TestNamespaceSourceQuerier_FindReplacement(t *testing.T) { // TODO: clean up this test setup - initialSource := fakes.FakeInterface{} - otherSource := fakes.FakeInterface{} - replacementSource := fakes.FakeInterface{} - replacementAndLatestSource := fakes.FakeInterface{} - replacementAndNoAnnotationLatestSource := fakes.FakeInterface{} + initialSource := fakes.FakeClientInterface{} + otherSource := fakes.FakeClientInterface{} + replacementSource := fakes.FakeClientInterface{} + replacementAndLatestSource := fakes.FakeClientInterface{} + replacementAndNoAnnotationLatestSource := fakes.FakeClientInterface{} latestVersion := semver.MustParse("1.0.0-1556661308") csv := v1alpha1.ClusterServiceVersion{ @@ -404,7 +425,7 @@ func TestNamespaceSourceQuerier_FindReplacement(t *testing.T) { replacementAndLatestKey := CatalogKey{"replat", "ns"} replacementAndNoAnnotationLatestKey := CatalogKey{"replatbad", "ns"} - sources := map[CatalogKey]client.Interface{ + sources := map[CatalogKey]registry.ClientInterface{ initialKey: &initialSource, otherKey: &otherSource, replacementKey: &replacementSource, @@ -416,7 +437,7 @@ func TestNamespaceSourceQuerier_FindReplacement(t *testing.T) { notInRange := semver.MustParse("1.0.0-1556661347") type fields struct { - sources map[CatalogKey]client.Interface + sources map[CatalogKey]registry.ClientInterface } type args struct { currentVersion *semver.Version diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go index eb6dbb88afb..c7d1d31a691 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver.go @@ -1,5 +1,5 @@ -//go:generate counterfeiter -o fakes/fake_registry_client.go ../../../../vendor/github.com/operator-framework/operator-registry/pkg/client/client.go Interface -//go:generate counterfeiter -o ../../../fakes/fake_resolver.go . Resolver +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o fakes/fake_registry_interface.go ../../../../vendor/github.com/operator-framework/operator-registry/pkg/client/client.go Interface +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -o ../../../fakes/fake_resolver.go . Resolver package resolver import ( diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go index 66e2d302693..c6b3559627d 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/resolver_test.go @@ -120,7 +120,7 @@ func TestNamespaceResolver(t *testing.T) { }, lookups: []v1alpha1.BundleLookup{ { - Path: "quay.io/test/bundle@sha256:abcd", + Path: "quay.io/test/bundle@sha256:abcd", Identifier: "b.v1", CatalogSourceRef: &corev1.ObjectReference{ Namespace: catalog.Namespace, @@ -234,9 +234,9 @@ func TestNamespaceResolver(t *testing.T) { steps: [][]*v1alpha1.Step{}, lookups: []v1alpha1.BundleLookup{ { - Path: "quay.io/test/bundle@sha256:abcd", + Path: "quay.io/test/bundle@sha256:abcd", Identifier: "a.v2", - Replaces: "a.v1", + Replaces: "a.v1", CatalogSourceRef: &corev1.ObjectReference{ Namespace: catalog.Namespace, Name: catalog.Name, @@ -409,6 +409,55 @@ func TestNamespaceResolver(t *testing.T) { }, }, }, + { + // This test verifies that ownership of an api can be migrated between two operators + name: "OwnedAPITransfer", + clusterState: []runtime.Object{ + existingSub(namespace, "a.v1", "a", "alpha", catalog), + existingOperator(namespace, "a.v1", "a", "alpha", "", Provides1, nil, nil, nil), + existingSub(namespace, "b.v1", "b", "alpha", catalog), + existingOperator(namespace, "b.v1", "b", "alpha", "", nil, Requires1, nil, nil), + }, + querier: NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{ + catalog: { + bundle("a.v2", "a", "alpha", "a.v1", nil, nil, nil, nil), + bundle("b.v2", "b", "alpha", "b.v1", Provides1, nil, nil, nil), + }, + }), + out: out{ + steps: [][]*v1alpha1.Step{ + bundleSteps(bundle("a.v2", "a", "alpha", "a.v1", nil, nil, nil, nil), namespace, "", catalog), + bundleSteps(bundle("b.v2", "b", "alpha", "b.v1", Provides1, nil, nil, nil), namespace, "", catalog), + }, + subs: []*v1alpha1.Subscription{ + updatedSub(namespace, "a.v2", "a", "alpha", catalog), + updatedSub(namespace, "b.v2", "b", "alpha", catalog), + }, + }, + }, + { + name: "PicksOlderProvider", + clusterState: []runtime.Object{ + newSub(namespace, "b", "alpha", catalog), + }, + querier: NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{ + catalog: { + bundle("a.v1", "a", "alpha", "", Provides1, nil, nil, nil), + bundle("a.v2", "a", "alpha", "a.v1", nil, nil, nil, nil), + bundle("b.v1", "b", "alpha", "", nil, Requires1, nil, nil), + }, + }), + out: out{ + steps: [][]*v1alpha1.Step{ + bundleSteps(bundle("a.v1", "a", "alpha", "", Provides1, nil, nil, nil), namespace, "", catalog), + bundleSteps(bundle("b.v1", "b", "alpha", "", nil, Requires1, nil, nil), namespace, "", catalog), + subSteps(namespace, "a.v1", "a", "alpha", catalog), + }, + subs: []*v1alpha1.Subscription{ + updatedSub(namespace, "b.v1", "b", "alpha", catalog), + }, + }, + }, { name: "InstalledSub/UpdateInHead/SkipRange", clusterState: []runtime.Object{ @@ -425,6 +474,43 @@ func TestNamespaceResolver(t *testing.T) { }, }, }, + { + // This test uses logic that implements the FakeSourceQuerier to ensure + // that the required API is provided by the new Operator. + // + // Background: + // OLM used to add the new operator to the generation before removing + // the old operator from the generation. The logic that removes an operator + // from the current generation removes the APIs it provides from the list of + // "available" APIs. This caused OLM to search for an operator that provides the API. + // If the operator that provides the API uses a skipRange rather than the Spec.Replaces + // field, the Replaces field is set to an empty string, causing OLM to fail to upgrade. + name: "InstalledSubs/ExistingOperators/OldCSVsReplaced", + clusterState: []runtime.Object{ + existingSub(namespace, "a.v1", "a", "alpha", catalog), + existingSub(namespace, "b.v1", "b", "beta", catalog), + existingOperator(namespace, "a.v1", "a", "alpha", "", nil, Requires1, nil, nil), + existingOperator(namespace, "b.v1", "b", "beta", "", Provides1, nil, nil, nil), + }, + querier: NewFakeSourceQuerier(map[CatalogKey][]*api.Bundle{ + catalog: { + bundle("a.v1", "a", "alpha", "", nil, nil, nil, nil), + bundle("a.v2", "a", "alpha", "a.v1", nil, Requires1, nil, nil), + bundle("b.v1", "b", "beta", "", Provides1, nil, nil, nil), + bundle("b.v2", "b", "beta", "b.v1", Provides1, nil, nil, nil), + }, + }), + out: out{ + steps: [][]*v1alpha1.Step{ + bundleSteps(bundle("a.v2", "a", "alpha", "a.v1", nil, Requires1, nil, nil), namespace, "", catalog), + bundleSteps(bundle("b.v2", "b", "beta", "b.v1", Provides1, nil, nil, nil), namespace, "", catalog), + }, + subs: []*v1alpha1.Subscription{ + updatedSub(namespace, "a.v2", "a", "alpha", catalog), + updatedSub(namespace, "b.v2", "b", "beta", catalog), + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/util_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/util_test.go index 8bf681bc5d0..829ae1cf568 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/util_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/util_test.go @@ -9,7 +9,6 @@ import ( "github.com/blang/semver" "github.com/operator-framework/operator-registry/pkg/api" - "github.com/operator-framework/operator-registry/pkg/client" opregistry "github.com/operator-framework/operator-registry/pkg/registry" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" @@ -20,6 +19,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/fakes" ) @@ -312,9 +312,9 @@ func withReplaces(operator *Operator, replaces string) *Operator { // NewFakeSourceQuerier builds a querier that talks to fake registry stubs for testing func NewFakeSourceQuerier(bundlesByCatalog map[CatalogKey][]*api.Bundle) *NamespaceSourceQuerier { - sources := map[CatalogKey]client.Interface{} + sources := map[CatalogKey]registry.ClientInterface{} for catKey, bundles := range bundlesByCatalog { - source := &fakes.FakeInterface{} + source := &fakes.FakeClientInterface{} source.GetBundleThatProvidesStub = func(ctx context.Context, groupOrName, version, kind string) (*api.Bundle, error) { for _, b := range bundles { apis := b.GetProvidedApis() @@ -356,17 +356,98 @@ func NewFakeSourceQuerier(bundlesByCatalog map[CatalogKey][]*api.Bundle) *Namesp return b, nil } } + return nil, fmt.Errorf("no bundle found") } + + source.FindBundleThatProvidesStub = func(ctx context.Context, groupOrName, version, kind, pkgName string) (*api.Bundle, error) { + bundles, ok := bundlesByCatalog[catKey] + if !ok { + return nil, fmt.Errorf("API (%s/%s/%s) not provided by a package in %s CatalogSource", groupOrName, version, kind, catKey) + } + sortedBundles := SortBundleInPackageChannel(bundles) + for k, v := range sortedBundles { + pkgname := getPkgName(k) + if pkgname == pkgName { + continue + } + + for i := len(v) - 1; i >= 0; i-- { + b := v[i] + apis := b.GetProvidedApis() + for _, api := range apis { + if api.Version == version && api.Kind == kind && strings.Contains(groupOrName, api.Group) && strings.Contains(groupOrName, api.Plural) { + return b, nil + } + } + } + } + return nil, fmt.Errorf("no bundle found") + } + sources[catKey] = source } return NewNamespaceSourceQuerier(sources) } +// SortBundleInPackageChannel will sort into map of package-channel key and list +// sorted (oldest to latest version) of bundles as value +func SortBundleInPackageChannel(bundles []*api.Bundle) map[string][]*api.Bundle { + sorted := map[string][]*api.Bundle{} + var initialReplaces string + for _, v := range bundles { + pkgChanKey := v.PackageName + "/" + v.ChannelName + sorted[pkgChanKey] = append(sorted[pkgChanKey], v) + } + + for k, v := range sorted { + resorted := []*api.Bundle{} + bundleMap := map[string]*api.Bundle{} + // Find the first (oldest) bundle in upgrade graph + for _, bundle := range v { + csv, err := V1alpha1CSVFromBundle(bundle) + if err != nil { + initialReplaces = bundle.CsvName + resorted = append(resorted, bundle) + continue + } + + if replaces := csv.Spec.Replaces; replaces == "" { + initialReplaces = bundle.CsvName + resorted = append(resorted, bundle) + } else { + bundleMap[replaces] = bundle + } + } + resorted = sortBundleInChannel(initialReplaces, bundleMap, resorted) + sorted[k] = resorted + } + return sorted +} + +// sortBundleInChannel recursively sorts a list of bundles to form a update graph +// of a specific channel. The first item in the returned list is the start +// (oldest version) of the upgrade graph and the last item is the head +// (latest version) of a channel +func sortBundleInChannel(replaces string, replacedBundle map[string]*api.Bundle, updated []*api.Bundle) []*api.Bundle { + bundle, ok := replacedBundle[replaces] + if ok { + updated = append(updated, bundle) + return sortBundleInChannel(bundle.CsvName, replacedBundle, updated) + } + return updated +} + +// getPkgName splits the package/channel string and return package name +func getPkgName(pkgChan string) string { + s := strings.Split(pkgChan, "/") + return s[0] +} + // NewFakeSourceQuerier builds a querier that talks to fake registry stubs for testing func NewFakeSourceQuerierCustomReplacement(catKey CatalogKey, bundle *api.Bundle) *NamespaceSourceQuerier { - sources := map[CatalogKey]client.Interface{} - source := &fakes.FakeInterface{} + sources := map[CatalogKey]registry.ClientInterface{} + source := &fakes.FakeClientInterface{} source.GetBundleThatProvidesStub = func(ctx context.Context, groupOrName, version, kind string) (*api.Bundle, error) { return nil, fmt.Errorf("no bundle found") } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/resourcequeue.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/resourcequeue.go index d52c9e66e7a..0e4da56cde2 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/resourcequeue.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer/resourcequeue.go @@ -39,6 +39,11 @@ func (r *ResourceQueueSet) RequeueEvent(namespace string, resourceEvent kubestat r.mutex.RLock() defer r.mutex.RUnlock() + if queue, ok := r.queueSet[metav1.NamespaceAll]; len(r.queueSet) == 1 && ok { + queue.AddRateLimited(resourceEvent) + return nil + } + if queue, ok := r.queueSet[namespace]; ok { queue.AddRateLimited(resourceEvent) return nil diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/provider/registry.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/provider/registry.go index ff0b1075a65..94f4c67a6fc 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/provider/registry.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/provider/registry.go @@ -9,7 +9,6 @@ import ( "sync" "time" - "github.com/operator-framework/operator-registry/pkg/api" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -29,6 +28,7 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer" "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators" pkglisters "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/client/listers/operators/internalversion" + "github.com/operator-framework/operator-registry/pkg/api" ) const ( @@ -189,9 +189,17 @@ func (p *RegistryProvider) syncCatalogSource(obj interface{}) (syncError error) Namespace: source.GetNamespace(), Name: source.GetName(), } + if sourceMeta := p.sources.GetMeta(key); sourceMeta != nil && sourceMeta.Address == address { - // If the address hasn't changed, don't bother creating a new source - logger.Debug("catalog address unchanged, skipping source creation") + logger.Infof("updating PackageManifest based on CatalogSource changes: %v", key) + timeout, cancel := context.WithTimeout(context.Background(), cacheTimeout) + defer cancel() + var client *registryClient + client, syncError = p.registryClient(key) + if syncError != nil { + return + } + syncError = p.refreshCache(timeout, client) return } diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go index 8de7491bb7f..0391157efbb 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "reflect" + "strings" "testing" "time" @@ -941,6 +942,116 @@ func TestCatalogImageUpdate(t *testing.T) { } } +func TestDependencySkipRange(t *testing.T) { + // Create a CatalogSource that contains the busybox v1 and busybox-dependency v1 images + // Create a Subscription for busybox v1, which has a dependency on busybox-dependency v1. + // Wait for the busybox and busybox2 Subscriptions to succeed + // Wait for the CSVs to succeed + // Update the catalog to point to an image that contains the busybox v2 and busybox-dependency v2 images. + // Wait for the new Subscriptions to succeed and check if they include the new CSVs + // Wait for the CSVs to succeed and confirm that the have the correct Spec.Replaces fields. + defer cleaner.NotifyTestComplete(t, true) + + sourceName := genName("catalog-") + packageName := "busybox" + channelName := "alpha" + + catSrcImage := "quay.io/olmtest/busybox-dependencies-index" + + // Create gRPC CatalogSource + source := &v1alpha1.CatalogSource{ + TypeMeta: metav1.TypeMeta{ + Kind: v1alpha1.CatalogSourceKind, + APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: sourceName, + Namespace: testNamespace, + }, + Spec: v1alpha1.CatalogSourceSpec{ + SourceType: v1alpha1.SourceTypeGrpc, + Image: catSrcImage + ":1.0.0", + }, + } + + crc := newCRClient(t) + source, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(source) + require.NoError(t, err) + defer func() { + require.NoError(t, crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Delete(source.GetName(), &metav1.DeleteOptions{})) + }() + + // Create a Subscription for busybox + subscriptionName := genName("sub-") + cleanupSubscription := createSubscriptionForCatalog(t, crc, source.GetNamespace(), subscriptionName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) + defer cleanupSubscription() + + // Wait for the Subscription to succeed + subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionStateAtLatestChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + require.Equal(t, subscription.Status.InstalledCSV, "busybox.v1.0.0") + + // Confirm that a subscription was created for busybox-dependency + subscriptionList, err := crc.OperatorsV1alpha1().Subscriptions(source.GetNamespace()).List(metav1.ListOptions{}) + require.NoError(t, err) + dependencySubscriptionName := "" + for _, sub := range subscriptionList.Items { + if strings.HasPrefix(sub.GetName(), "busybox-dependency") { + dependencySubscriptionName = sub.GetName() + } + } + + require.NotEmpty(t, dependencySubscriptionName) + // Wait for the Subscription to succeed + subscription, err = fetchSubscription(t, crc, testNamespace, dependencySubscriptionName, subscriptionStateAtLatestChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + require.Equal(t, subscription.Status.InstalledCSV, "busybox-dependency.v1.0.0") + + // Update the catalog image + err = wait.PollImmediate(pollInterval, pollDuration, func() (bool, error) { + existingSource, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Get(sourceName, metav1.GetOptions{}) + if err != nil { + return false, err + } + existingSource.Spec.Image = catSrcImage + ":2.0.0" + + source, err = crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Update(existingSource) + if err == nil { + return true, nil + } + return false, nil + }) + require.NoError(t, err) + + // Wait for the busybox v2 Subscription to succeed + subChecker := func(sub *v1alpha1.Subscription) bool { + return sub.Status.InstalledCSV == "busybox.v2.0.0" + } + subscription, err = fetchSubscription(t, crc, testNamespace, subscriptionName, subChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + + // Wait for busybox v2 csv to succeed and check the replaces field + csv, err := fetchCSV(t, crc, subscription.Status.CurrentCSV, subscription.GetNamespace(), csvSucceededChecker) + require.NoError(t, err) + require.Equal(t, "busybox.v1.0.0", csv.Spec.Replaces) + + // Wait for the busybox-dependency v2 Subscription to succeed + subChecker = func(sub *v1alpha1.Subscription) bool { + return sub.Status.InstalledCSV == "busybox-dependency.v2.0.0" + } + subscription, err = fetchSubscription(t, crc, testNamespace, dependencySubscriptionName, subChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + + // Wait for busybox-dependency v2 csv to succeed and check the replaces field + csv, err = fetchCSV(t, crc, subscription.Status.CurrentCSV, subscription.GetNamespace(), csvSucceededChecker) + require.NoError(t, err) + require.Equal(t, "busybox-dependency.v1.0.0", csv.Spec.Replaces) +} + func getOperatorDeployment(c operatorclient.ClientInterface, namespace string, operatorLabels labels.Set) (*appsv1.Deployment, error) { deployments, err := c.ListDeploymentsWithLabels(namespace, operatorLabels) if err != nil || deployments == nil || len(deployments.Items) != 1 { diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index 9aedd8ac583..4011d5eb520 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -575,7 +575,6 @@ func TestCreateInstallPlanWithPreExistingCRDOwners(t *testing.T) { mainPackageStable := fmt.Sprintf("%s-stable", mainPackageName) mainPackageBeta := fmt.Sprintf("%s-beta", mainPackageName) dependentPackageStable := fmt.Sprintf("%s-stable", dependentPackageName) - dependentPackageBeta := fmt.Sprintf("%s-beta", dependentPackageName) stableChannel := "stable" betaChannel := "beta" @@ -594,7 +593,6 @@ func TestCreateInstallPlanWithPreExistingCRDOwners(t *testing.T) { PackageName: dependentPackageName, Channels: []registry.PackageChannel{ {Name: stableChannel, CurrentCSVName: dependentPackageStable}, - {Name: betaChannel, CurrentCSVName: dependentPackageBeta}, }, DefaultChannelName: stableChannel, }, @@ -615,7 +613,6 @@ func TestCreateInstallPlanWithPreExistingCRDOwners(t *testing.T) { mainStableCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, mainNamedStrategy) mainBetaCSV := newCSV(mainPackageBeta, testNamespace, mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, mainNamedStrategy) dependentStableCSV := newCSV(dependentPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, dependentNamedStrategy) - dependentBetaCSV := newCSV(dependentPackageBeta, testNamespace, dependentPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, dependentNamedStrategy) c := newKubeClient(t) crc := newCRClient(t) @@ -625,7 +622,7 @@ func TestCreateInstallPlanWithPreExistingCRDOwners(t *testing.T) { // Create the catalog source mainCatalogSourceName := genName("mock-ocs-main-" + strings.ToLower(t.Name()) + "-") - _, cleanupCatalogSource := createInternalCatalogSource(t, c, crc, mainCatalogSourceName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{dependentCRD, mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentBetaCSV, dependentStableCSV, mainStableCSV, mainBetaCSV}) + _, cleanupCatalogSource := createInternalCatalogSource(t, c, crc, mainCatalogSourceName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{dependentCRD, mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentStableCSV, mainStableCSV, mainBetaCSV}) defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) _, err := fetchCatalogSource(t, crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go index ffbfb519272..c5f42397ce7 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/packagemanifest_e2e_test.go @@ -118,3 +118,61 @@ func TestPackageManifestLoading(t *testing.T) { require.NotNil(t, pmList.ListMeta, "package manifest list metadata empty") require.NotNil(t, pmList.Items) } + +func TestPkgManifestsFromCatsrc(t *testing.T) { + defer cleaner.NotifyTestComplete(t, true) + + sourceName := genName("catalog-") + packageName := "etcd-test" + displayName := "etcd test catalog" + image := "quay.io/olmtest/catsrc-update-test:related" + crc := newCRClient(t) + pmc := newPMClient(t) + + catalogSource := &v1alpha1.CatalogSource{ + TypeMeta: metav1.TypeMeta{ + Kind: v1alpha1.CatalogSourceKind, + APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: sourceName, + Namespace: testNamespace, + Labels: map[string]string{"olm.catalogSource": sourceName}, + }, + Spec: v1alpha1.CatalogSourceSpec{ + SourceType: v1alpha1.SourceTypeGrpc, + Image: image, + DisplayName: displayName, + }, + } + + catalogSource, err := crc.OperatorsV1alpha1().CatalogSources(catalogSource.GetNamespace()).Create(catalogSource) + require.NoError(t, err, "error creating Catalog Sources") + require.NotNil(t, catalogSource) + + pm, err := fetchPackageManifest(t, pmc, testNamespace, packageName, packageManifestHasStatus) + require.NoError(t, err, "error getting package manifest") + require.NotNil(t, pm) + require.Equal(t, packageName, pm.GetName()) + require.Equal(t, displayName, pm.Status.CatalogSourceDisplayName) + + catalogSource, err = crc.OperatorsV1alpha1().CatalogSources(testNamespace).Get(catalogSource.GetName(), metav1.GetOptions{}) + require.NoError(t, err, "error getting catalogSource") + + displayName = "updated Name" + catalogSource.Spec.DisplayName = displayName + catalogSource, err = crc.OperatorsV1alpha1().CatalogSources(testNamespace).Update(catalogSource) + require.NoError(t, err, "error updating catalogSource") + require.Equal(t, displayName, catalogSource.Spec.DisplayName) + + // waiting for the update to complete + err = wait.Poll(pollInterval, 1*time.Minute, func() (bool, error) { + t.Logf("Polling package-server...") + pm, err := fetchPackageManifest(t, pmc, testNamespace, packageName, packageManifestHasStatus) + if err != nil { + return false, err + } + return pm.Status.CatalogSourceDisplayName == displayName, nil + }) + require.NoError(t, err, "error package manifest Status.CatalogSourceDisplayName is not updated to catsrc Spec.DisplayName") +} diff --git a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go index c874daec1fb..f5caa2f6880 100644 --- a/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go +++ b/vendor/github.com/operator-framework/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go @@ -1404,7 +1404,183 @@ func TestCreateNewSubscriptionWithDependencies(t *testing.T) { installPlan, err := fetchInstallPlan(t, crClient, subscription.Status.InstallPlanRef.Name, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) require.NoError(t, err) require.Len(t, installPlan.Status.CatalogSources, 1) +} + +// Test creation with dependencies required and provided in different versions of an +// operator in the same package +// CatSrc: +// +// Package A (apackage) +// Default Channel: Stable +// Channel Stable: +// Operator A (Requires: CRD 1, CRD 2 ) +// Channel Alpha: +// Operator ABC (Provides: CRD 1, CRD 2 ) +// Package B (apackage) +// Default Channel: Stable +// Channel Stable: +// Operator B (Provides: CRD) +// CatSrc2: +// +// Package B (bpackage) +// Default Channel: Stable +// Channel Stable: +// Operator C (Provides: CRD 2) +// Then create a subscription: +// +// CatalogSource: CatSrc +// Package: Package A, +// Channel: Stable, +// StartingCSV: CSV A +// +// Check installed: +// +// CSV A, CSV B, CSV C +// +// CSV A required B and C but didn't get them from Package A +func TestCreateNewSubscriptionWithDependenciesSamePackage(t *testing.T) { + defer cleaner.NotifyTestComplete(t, true) + + kubeClient := newKubeClient(t) + crClient := newCRClient(t) + permissions := deploymentPermissions(t) + + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + crdPlural2 := genName("ins") + crdName2 := crdPlural2 + ".cluster.com" + + crd := apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Version: "v1alpha1", + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: "Namespaced", + }, + } + + crd2 := apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName2, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Version: "v1alpha1", + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural2, + Singular: crdPlural2, + Kind: crdPlural2, + ListKind: "list" + crdPlural2, + }, + Scope: "Namespaced", + }, + } + + // Create CSV + packageName1 := genName("apackage") + packageName2 := genName("bpackage") + + namedStrategy := newNginxInstallStrategy((genName("dep")), permissions, nil) + depNamedStrategy := newNginxInstallStrategy((genName("dep")), permissions, nil) + depNamedStrategy2 := newNginxInstallStrategy((genName("dep")), permissions, nil) + // csvA requires CRD1 and CRD2 + csvA := newCSV("nginx-a", testNamespace, "", semver.MustParse("0.1.0"), nil, []apiextensions.CustomResourceDefinition{crd, crd2}, namedStrategy) + // csvABC provides CRD1 and CRD2 in the same catalogsource with csvA (apackage) + // also in the same package with csvA but different channel + csvABC := newCSV("nginx-a-bc", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd, crd2}, nil, namedStrategy) + // csvB provides CRD1 in the same catalogsource with csvA (apackage) + csvB := newCSV("nginx-b-dep", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, depNamedStrategy) + // csvC provides CRD2 in the different catalogsource with csvA (apackage) + csvC := newCSV("nginx-c-dep", testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd2}, nil, depNamedStrategy2) + + // Create PackageManifests 1 + // Contain csvA, ABC and B + manifests := []registry.PackageManifest{ + { + PackageName: packageName1, + Channels: []registry.PackageChannel{ + {Name: stableChannel, CurrentCSVName: csvA.GetName()}, + {Name: alphaChannel, CurrentCSVName: csvABC.GetName()}, + }, + DefaultChannelName: stableChannel, + }, + { + PackageName: packageName2, + Channels: []registry.PackageChannel{ + {Name: stableChannel, CurrentCSVName: csvB.GetName()}, + }, + DefaultChannelName: stableChannel, + }, + } + + // Create PackageManifests 2 + // Contain csvC + manifests2 := []registry.PackageManifest{ + { + PackageName: packageName2, + Channels: []registry.PackageChannel{ + {Name: stableChannel, CurrentCSVName: csvC.GetName()}, + }, + DefaultChannelName: stableChannel, + }, + } + + catalogSourceName := genName("catsrc") + catsrc, cleanup := createInternalCatalogSource(t, kubeClient, crClient, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd, crd2}, []v1alpha1.ClusterServiceVersion{csvA, csvABC, csvB}) + defer cleanup() + + // Ensure that the catalog source is resolved before we create a subscription. + _, err := fetchCatalogSource(t, crClient, catsrc.GetName(), testNamespace, catalogSourceRegistryPodSynced) + require.NoError(t, err) + + subscriptionSpec := &v1alpha1.SubscriptionSpec{ + CatalogSource: catsrc.GetName(), + CatalogSourceNamespace: catsrc.GetNamespace(), + Package: packageName1, + Channel: stableChannel, + StartingCSV: csvA.GetName(), + InstallPlanApproval: v1alpha1.ApprovalAutomatic, + } + + catalogSourceName2 := genName("catsrc") + catsrc2, cleanup2 := createInternalCatalogSource(t, kubeClient, crClient, catalogSourceName2, testNamespace, manifests2, []apiextensions.CustomResourceDefinition{crd2}, []v1alpha1.ClusterServiceVersion{csvC}) + defer cleanup2() + + // Ensure that the catalog source is resolved before we create a subscription. + _, err = fetchCatalogSource(t, crClient, catsrc2.GetName(), testNamespace, catalogSourceRegistryPodSynced) + require.NoError(t, err) + + // Create a subscription that has a dependency + subscriptionName := genName("sub-") + cleanupSubscription := createSubscriptionForCatalogWithSpec(t, crClient, testNamespace, subscriptionName, subscriptionSpec) + defer cleanupSubscription() + + subscription, err := fetchSubscription(t, crClient, testNamespace, subscriptionName, subscriptionStateAtLatestChecker) + require.NoError(t, err) + require.NotNil(t, subscription) + + // Check that a single catalog source was used to resolve the InstallPlan + _, err = fetchInstallPlan(t, crClient, subscription.Status.InstallPlanRef.Name, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + require.NoError(t, err) + // Fetch CSVs A, B and C + _, err = fetchCSV(t, crClient, csvB.Name, testNamespace, csvSucceededChecker) + require.NoError(t, err) + _, err = fetchCSV(t, crClient, csvC.Name, testNamespace, csvSucceededChecker) + require.NoError(t, err) + _, err = fetchCSV(t, crClient, csvA.Name, testNamespace, csvSucceededChecker) + require.NoError(t, err) + // Ensure csvABC is not installed + _, err = crClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(csvABC.Name, metav1.GetOptions{}) + require.Error(t, err) } func checkDeploymentWithPodConfiguration(t *testing.T, client operatorclient.ClientInterface, csv *v1alpha1.ClusterServiceVersion, envVar []corev1.EnvVar, volumes []corev1.Volume, volumeMounts []corev1.VolumeMount) { diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore index 6b7d7d1e8b9..66be63a0057 100644 --- a/vendor/github.com/sirupsen/logrus/.gitignore +++ b/vendor/github.com/sirupsen/logrus/.gitignore @@ -1,2 +1 @@ logrus -vendor diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml index 848938a6d4e..a23296a53ba 100644 --- a/vendor/github.com/sirupsen/logrus/.travis.yml +++ b/vendor/github.com/sirupsen/logrus/.travis.yml @@ -1,25 +1,15 @@ language: go -go_import_path: github.com/sirupsen/logrus -git: - depth: 1 +go: + - 1.6.x + - 1.7.x + - 1.8.x + - tip env: - - GO111MODULE=on - - GO111MODULE=off -go: [ 1.11.x, 1.12.x ] -os: [ linux, osx ] -matrix: - exclude: - - go: 1.12.x - env: GO111MODULE=off - - go: 1.11.x - os: osx + - GOMAXPROCS=4 GORACE=halt_on_error=1 install: - - ./travis/install.sh - - if [[ "$GO111MODULE" == "on" ]]; then go mod download; fi - - if [[ "$GO111MODULE" == "off" ]]; then go get github.com/stretchr/testify/assert golang.org/x/sys/unix github.com/konsorten/go-windows-terminal-sequences; fi + - go get github.com/stretchr/testify/assert + - go get gopkg.in/gemnasium/logrus-airbrake-hook.v2 + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows script: - - ./travis/cross_build.sh - - export GOMAXPROCS=4 - - export GORACE=halt_on_error=1 - go test -race -v ./... - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then go test -race -v -tags appengine ./... ; fi diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md index 51a7ab0cab9..8236d8b6eea 100644 --- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -1,90 +1,3 @@ -# 1.4.2 - * Fixes build break for plan9, nacl, solaris -# 1.4.1 -This new release introduces: - * Enhance TextFormatter to not print caller information when they are empty (#944) - * Remove dependency on golang.org/x/crypto (#932, #943) - -Fixes: - * Fix Entry.WithContext method to return a copy of the initial entry (#941) - -# 1.4.0 -This new release introduces: - * Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848). - * Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter (#909, #911) - * Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919). - -Fixes: - * Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893). - * Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903) - * Fix infinite recursion on unknown `Level.String()` (#907) - * Fix race condition in `getCaller` (#916). - - -# 1.3.0 -This new release introduces: - * Log, Logf, Logln functions for Logger and Entry that take a Level - -Fixes: - * Building prometheus node_exporter on AIX (#840) - * Race condition in TextFormatter (#468) - * Travis CI import path (#868) - * Remove coloured output on Windows (#862) - * Pointer to func as field in JSONFormatter (#870) - * Properly marshal Levels (#873) - -# 1.2.0 -This new release introduces: - * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued - * A new trace level named `Trace` whose level is below `Debug` - * A configurable exit function to be called upon a Fatal trace - * The `Level` object now implements `encoding.TextUnmarshaler` interface - -# 1.1.1 -This is a bug fix release. - * fix the build break on Solaris - * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized - -# 1.1.0 -This new release introduces: - * several fixes: - * a fix for a race condition on entry formatting - * proper cleanup of previously used entries before putting them back in the pool - * the extra new line at the end of message in text formatter has been removed - * a new global public API to check if a level is activated: IsLevelEnabled - * the following methods have been added to the Logger object - * IsLevelEnabled - * SetFormatter - * SetOutput - * ReplaceHooks - * introduction of go module - * an indent configuration for the json formatter - * output colour support for windows - * the field sort function is now configurable for text formatter - * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater - -# 1.0.6 - -This new release introduces: - * a new api WithTime which allows to easily force the time of the log entry - which is mostly useful for logger wrapper - * a fix reverting the immutability of the entry given as parameter to the hooks - a new configuration field of the json formatter in order to put all the fields - in a nested dictionnary - * a new SetOutput method in the Logger - * a new configuration of the textformatter to configure the name of the default keys - * a new configuration of the text formatter to disable the level truncation - -# 1.0.5 - -* Fix hooks race (#707) -* Fix panic deadlock (#695) - -# 1.0.4 - -* Fix race when adding hooks (#612) -* Fix terminal check in AppEngine (#635) - # 1.0.3 * Replace example files with testable examples diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md index a4796eb07d4..5f656c3e176 100644 --- a/vendor/github.com/sirupsen/logrus/README.md +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -56,39 +56,8 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +exit status 1 ``` -To ensure this behaviour even if a TTY is attached, set your formatter as follows: - -```go - log.SetFormatter(&log.TextFormatter{ - DisableColors: true, - FullTimestamp: true, - }) -``` - -#### Logging Method Name - -If you wish to add the calling method as a field, instruct the logger via: -```go -log.SetReportCaller(true) -``` -This adds the caller as 'method' like so: - -```json -{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", -"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} -``` - -```text -time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin -``` -Note that this does add measurable overhead - the cost will depend on the version of Go, but is -between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your -environment via benchmarks: -``` -go test -bench=.*CallerTracing -``` - #### Case-sensitivity @@ -251,7 +220,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in ```go import ( log "github.com/sirupsen/logrus" - "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" "log/syslog" ) @@ -272,15 +241,62 @@ func init() { ``` Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). -A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) - +| Hook | Description | +| ----- | ----------- | +| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | +| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | +| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) | +| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | +| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage| +| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | +| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | +| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) | +| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| +| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/) +| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | +| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) | +| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | +| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | +| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | +| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | +| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) | +| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | +| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka | +| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | +| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) | +| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) | +| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | +| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | +| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | +| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | +| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) | +| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | +| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) | +| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | +| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | +| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) | +| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | +| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | +| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | +| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | +| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| +| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | +| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | +| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) | +| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| +| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | +| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. | +| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) | +| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) | +| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | +| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | +| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) | #### Level logging -Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. +Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. ```go -log.Trace("Something very low level.") log.Debug("Useful debugging information.") log.Info("Something noteworthy happened!") log.Warn("You should probably take a look at this.") @@ -352,20 +368,16 @@ The built-in logging formatters are: field to `true`. To force no colored output even if there is a TTY set the `DisableColors` field to `true`. For Windows, see [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). - * When colors are enabled, levels are truncated to 4 characters by default. To disable - truncation set the `DisableLevelTruncation` field to `true`. * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). * `logrus.JSONFormatter`. Logs fields as JSON. * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). Third party logging formatters: -* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. -* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html). +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can by parsed by Kubernetes and Google Container Engine. * [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. -* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure. You can define your formatter by implementing the `Formatter` interface, requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a @@ -479,7 +491,7 @@ logrus.RegisterExitHandler(handler) #### Thread safety -By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. Situation when locking is not needed includes: diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go index 8fd189e1cca..8af90637a99 100644 --- a/vendor/github.com/sirupsen/logrus/alt_exit.go +++ b/vendor/github.com/sirupsen/logrus/alt_exit.go @@ -51,9 +51,9 @@ func Exit(code int) { os.Exit(code) } -// RegisterExitHandler appends a Logrus Exit handler to the list of handlers, -// call logrus.Exit to invoke all handlers. The handlers will also be invoked when -// any Fatal log entry is made. +// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke +// all handlers. The handlers will also be invoked when any Fatal log entry is +// made. // // This method is useful when a caller wishes to use logrus to log a fatal // message but also needs to gracefully shutdown. An example usecase could be @@ -62,15 +62,3 @@ func Exit(code int) { func RegisterExitHandler(handler func()) { handlers = append(handlers, handler) } - -// DeferExitHandler prepends a Logrus Exit handler to the list of handlers, -// call logrus.Exit to invoke all handlers. The handlers will also be invoked when -// any Fatal log entry is made. -// -// This method is useful when a caller wishes to use logrus to log a fatal -// message but also needs to gracefully shutdown. An example usecase could be -// closing database connections, or sending a alert that the application is -// closing. -func DeferExitHandler(handler func()) { - handlers = append([]func(){handler}, handlers...) -} diff --git a/vendor/github.com/sirupsen/logrus/alt_exit_test.go b/vendor/github.com/sirupsen/logrus/alt_exit_test.go index 54d503cb480..a08b1a898f6 100644 --- a/vendor/github.com/sirupsen/logrus/alt_exit_test.go +++ b/vendor/github.com/sirupsen/logrus/alt_exit_test.go @@ -6,76 +6,19 @@ import ( "os" "os/exec" "path/filepath" - "runtime" - "strings" "testing" "time" ) func TestRegister(t *testing.T) { current := len(handlers) - - var results []string - - h1 := func() { results = append(results, "first") } - h2 := func() { results = append(results, "second") } - - RegisterExitHandler(h1) - RegisterExitHandler(h2) - - if len(handlers) != current+2 { - t.Fatalf("expected %d handlers, got %d", current+2, len(handlers)) - } - - runHandlers() - - if len(results) != 2 { - t.Fatalf("expected 2 handlers to be run, ran %d", len(results)) - } - - if results[0] != "first" { - t.Fatal("expected handler h1 to be run first, but it wasn't") - } - - if results[1] != "second" { - t.Fatal("expected handler h2 to be run second, but it wasn't") - } -} - -func TestDefer(t *testing.T) { - current := len(handlers) - - var results []string - - h1 := func() { results = append(results, "first") } - h2 := func() { results = append(results, "second") } - - DeferExitHandler(h1) - DeferExitHandler(h2) - - if len(handlers) != current+2 { - t.Fatalf("expected %d handlers, got %d", current+2, len(handlers)) - } - - runHandlers() - - if len(results) != 2 { - t.Fatalf("expected 2 handlers to be run, ran %d", len(results)) - } - - if results[0] != "second" { - t.Fatal("expected handler h2 to be run first, but it wasn't") - } - - if results[1] != "first" { - t.Fatal("expected handler h1 to be run second, but it wasn't") + RegisterExitHandler(func() {}) + if len(handlers) != current+1 { + t.Fatalf("expected %d handlers, got %d", current+1, len(handlers)) } } func TestHandler(t *testing.T) { - testprog := testprogleader - testprog = append(testprog, getPackage()...) - testprog = append(testprog, testprogtrailer...) tempDir, err := ioutil.TempDir("", "test_handler") if err != nil { log.Fatalf("can't create temp dir. %q", err) @@ -104,24 +47,13 @@ func TestHandler(t *testing.T) { } } -// getPackage returns the name of the current package, which makes running this -// test in a fork simpler -func getPackage() []byte { - pc, _, _, _ := runtime.Caller(0) - fullFuncName := runtime.FuncForPC(pc).Name() - idx := strings.LastIndex(fullFuncName, ".") - return []byte(fullFuncName[:idx]) // trim off function details -} - -var testprogleader = []byte(` +var testprog = []byte(` // Test program for atexit, gets output file and data as arguments and writes // data to output file in atexit handler. package main import ( - "`) -var testprogtrailer = []byte( - `" + "github.com/sirupsen/logrus" "flag" "fmt" "io/ioutil" diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go index 63e25583cb0..1fad45e0823 100644 --- a/vendor/github.com/sirupsen/logrus/entry.go +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -2,33 +2,13 @@ package logrus import ( "bytes" - "context" "fmt" "os" - "reflect" - "runtime" - "strings" "sync" "time" ) -var ( - bufferPool *sync.Pool - - // qualified package name, cached at first use - logrusPackage string - - // Positions in the call stack when tracing to report the calling method - minimumCallerDepth int - - // Used for caller information initialisation - callerInitOnce sync.Once -) - -const ( - maximumCallerDepth int = 25 - knownLogrusFrames int = 4 -) +var bufferPool *sync.Pool func init() { bufferPool = &sync.Pool{ @@ -36,18 +16,15 @@ func init() { return new(bytes.Buffer) }, } - - // start at the bottom of the stack before the package-name cache is primed - minimumCallerDepth = 1 } // Defines the key when adding errors using WithError. var ErrorKey = "error" // An entry is the final or intermediate Logrus logging entry. It contains all -// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, -// Info, Warn, Error, Fatal or Panic is called on it. These objects can be -// reused and passed around as much as you wish to avoid field duplication. +// the fields passed with WithField{,s}. It's finally logged when Debug, Info, +// Warn, Error, Fatal or Panic is called on it. These objects can be reused and +// passed around as much as you wish to avoid field duplication. type Entry struct { Logger *Logger @@ -57,31 +34,22 @@ type Entry struct { // Time at which the log entry was created Time time.Time - // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic + // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic // This field will be set on entry firing and the value will be equal to the one in Logger struct field. Level Level - // Calling method, with package name - Caller *runtime.Frame - - // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic + // Message passed to Debug, Info, Warn, Error, Fatal or Panic Message string - // When formatter is called in entry.log(), a Buffer may be set to entry + // When formatter is called in entry.log(), an Buffer may be set to entry Buffer *bytes.Buffer - - // Contains the context set by the user. Useful for hook processing etc. - Context context.Context - - // err may contain a field formatting error - err string } func NewEntry(logger *Logger) *Entry { return &Entry{ Logger: logger, - // Default is three fields, plus one optional. Give a little extra room. - Data: make(Fields, 6), + // Default is three fields, give a little extra room + Data: make(Fields, 5), } } @@ -101,11 +69,6 @@ func (entry *Entry) WithError(err error) *Entry { return entry.WithField(ErrorKey, err) } -// Add a context to the Entry. -func (entry *Entry) WithContext(ctx context.Context) *Entry { - return &Entry{Logger: entry.Logger, Data: entry.Data, Time: entry.Time, err: entry.err, Context: ctx} -} - // Add a single field to the Entry. func (entry *Entry) WithField(key string, value interface{}) *Entry { return entry.WithFields(Fields{key: value}) @@ -117,164 +80,59 @@ func (entry *Entry) WithFields(fields Fields) *Entry { for k, v := range entry.Data { data[k] = v } - fieldErr := entry.err for k, v := range fields { - isErrField := false - if t := reflect.TypeOf(v); t != nil { - switch t.Kind() { - case reflect.Func: - isErrField = true - case reflect.Ptr: - isErrField = t.Elem().Kind() == reflect.Func - } - } - if isErrField { - tmp := fmt.Sprintf("can not add field %q", k) - if fieldErr != "" { - fieldErr = entry.err + ", " + tmp - } else { - fieldErr = tmp - } - } else { - data[k] = v - } - } - return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context} -} - -// Overrides the time of the Entry. -func (entry *Entry) WithTime(t time.Time) *Entry { - return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err, Context: entry.Context} -} - -// getPackageName reduces a fully qualified function name to the package name -// There really ought to be to be a better way... -func getPackageName(f string) string { - for { - lastPeriod := strings.LastIndex(f, ".") - lastSlash := strings.LastIndex(f, "/") - if lastPeriod > lastSlash { - f = f[:lastPeriod] - } else { - break - } - } - - return f -} - -// getCaller retrieves the name of the first non-logrus calling function -func getCaller() *runtime.Frame { - - // cache this package's fully-qualified name - callerInitOnce.Do(func() { - pcs := make([]uintptr, 2) - _ = runtime.Callers(0, pcs) - logrusPackage = getPackageName(runtime.FuncForPC(pcs[1]).Name()) - - // now that we have the cache, we can skip a minimum count of known-logrus functions - // XXX this is dubious, the number of frames may vary - minimumCallerDepth = knownLogrusFrames - }) - - // Restrict the lookback frames to avoid runaway lookups - pcs := make([]uintptr, maximumCallerDepth) - depth := runtime.Callers(minimumCallerDepth, pcs) - frames := runtime.CallersFrames(pcs[:depth]) - - for f, again := frames.Next(); again; f, again = frames.Next() { - pkg := getPackageName(f.Function) - - // If the caller isn't part of this package, we're done - if pkg != logrusPackage { - return &f - } + data[k] = v } - - // if we got here, we failed to find the caller's context - return nil -} - -func (entry Entry) HasCaller() (has bool) { - return entry.Logger != nil && - entry.Logger.ReportCaller && - entry.Caller != nil + return &Entry{Logger: entry.Logger, Data: data} } // This function is not declared with a pointer value because otherwise // race conditions will occur when using multiple goroutines func (entry Entry) log(level Level, msg string) { var buffer *bytes.Buffer - - // Default to now, but allow users to override if they want. - // - // We don't have to worry about polluting future calls to Entry#log() - // with this assignment because this function is declared with a - // non-pointer receiver. - if entry.Time.IsZero() { - entry.Time = time.Now() - } - + entry.Time = time.Now() entry.Level = level entry.Message = msg - if entry.Logger.ReportCaller { - entry.Caller = getCaller() - } - - entry.fireHooks() + entry.Logger.mu.Lock() + err := entry.Logger.Hooks.Fire(level, &entry) + entry.Logger.mu.Unlock() + if err != nil { + entry.Logger.mu.Lock() + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + entry.Logger.mu.Unlock() + } buffer = bufferPool.Get().(*bytes.Buffer) buffer.Reset() defer bufferPool.Put(buffer) entry.Buffer = buffer - - entry.write() - + serialized, err := entry.Logger.Formatter.Format(&entry) entry.Buffer = nil - - // To avoid Entry#log() returning a value that only would make sense for - // panic() to use in Entry#Panic(), we avoid the allocation by checking - // directly here. - if level <= PanicLevel { - panic(&entry) - } -} - -func (entry *Entry) fireHooks() { - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - err := entry.Logger.Hooks.Fire(entry.Level, entry) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) - } -} - -func (entry *Entry) write() { - entry.Logger.mu.Lock() - defer entry.Logger.mu.Unlock() - serialized, err := entry.Logger.Formatter.Format(entry) if err != nil { + entry.Logger.mu.Lock() fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + entry.Logger.mu.Unlock() } else { + entry.Logger.mu.Lock() _, err = entry.Logger.Out.Write(serialized) if err != nil { fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) } + entry.Logger.mu.Unlock() } -} -func (entry *Entry) Log(level Level, args ...interface{}) { - if entry.Logger.IsLevelEnabled(level) { - entry.log(level, fmt.Sprint(args...)) + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) } } -func (entry *Entry) Trace(args ...interface{}) { - entry.Log(TraceLevel, args...) -} - func (entry *Entry) Debug(args ...interface{}) { - entry.Log(DebugLevel, args...) + if entry.Logger.level() >= DebugLevel { + entry.log(DebugLevel, fmt.Sprint(args...)) + } } func (entry *Entry) Print(args ...interface{}) { @@ -282,11 +140,15 @@ func (entry *Entry) Print(args ...interface{}) { } func (entry *Entry) Info(args ...interface{}) { - entry.Log(InfoLevel, args...) + if entry.Logger.level() >= InfoLevel { + entry.log(InfoLevel, fmt.Sprint(args...)) + } } func (entry *Entry) Warn(args ...interface{}) { - entry.Log(WarnLevel, args...) + if entry.Logger.level() >= WarnLevel { + entry.log(WarnLevel, fmt.Sprint(args...)) + } } func (entry *Entry) Warning(args ...interface{}) { @@ -294,37 +156,37 @@ func (entry *Entry) Warning(args ...interface{}) { } func (entry *Entry) Error(args ...interface{}) { - entry.Log(ErrorLevel, args...) + if entry.Logger.level() >= ErrorLevel { + entry.log(ErrorLevel, fmt.Sprint(args...)) + } } func (entry *Entry) Fatal(args ...interface{}) { - entry.Log(FatalLevel, args...) - entry.Logger.Exit(1) + if entry.Logger.level() >= FatalLevel { + entry.log(FatalLevel, fmt.Sprint(args...)) + } + Exit(1) } func (entry *Entry) Panic(args ...interface{}) { - entry.Log(PanicLevel, args...) + if entry.Logger.level() >= PanicLevel { + entry.log(PanicLevel, fmt.Sprint(args...)) + } panic(fmt.Sprint(args...)) } // Entry Printf family functions -func (entry *Entry) Logf(level Level, format string, args ...interface{}) { - if entry.Logger.IsLevelEnabled(level) { - entry.Log(level, fmt.Sprintf(format, args...)) - } -} - -func (entry *Entry) Tracef(format string, args ...interface{}) { - entry.Logf(TraceLevel, format, args...) -} - func (entry *Entry) Debugf(format string, args ...interface{}) { - entry.Logf(DebugLevel, format, args...) + if entry.Logger.level() >= DebugLevel { + entry.Debug(fmt.Sprintf(format, args...)) + } } func (entry *Entry) Infof(format string, args ...interface{}) { - entry.Logf(InfoLevel, format, args...) + if entry.Logger.level() >= InfoLevel { + entry.Info(fmt.Sprintf(format, args...)) + } } func (entry *Entry) Printf(format string, args ...interface{}) { @@ -332,7 +194,9 @@ func (entry *Entry) Printf(format string, args ...interface{}) { } func (entry *Entry) Warnf(format string, args ...interface{}) { - entry.Logf(WarnLevel, format, args...) + if entry.Logger.level() >= WarnLevel { + entry.Warn(fmt.Sprintf(format, args...)) + } } func (entry *Entry) Warningf(format string, args ...interface{}) { @@ -340,36 +204,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { } func (entry *Entry) Errorf(format string, args ...interface{}) { - entry.Logf(ErrorLevel, format, args...) + if entry.Logger.level() >= ErrorLevel { + entry.Error(fmt.Sprintf(format, args...)) + } } func (entry *Entry) Fatalf(format string, args ...interface{}) { - entry.Logf(FatalLevel, format, args...) - entry.Logger.Exit(1) + if entry.Logger.level() >= FatalLevel { + entry.Fatal(fmt.Sprintf(format, args...)) + } + Exit(1) } func (entry *Entry) Panicf(format string, args ...interface{}) { - entry.Logf(PanicLevel, format, args...) -} - -// Entry Println family functions - -func (entry *Entry) Logln(level Level, args ...interface{}) { - if entry.Logger.IsLevelEnabled(level) { - entry.Log(level, entry.sprintlnn(args...)) + if entry.Logger.level() >= PanicLevel { + entry.Panic(fmt.Sprintf(format, args...)) } } -func (entry *Entry) Traceln(args ...interface{}) { - entry.Logln(TraceLevel, args...) -} +// Entry Println family functions func (entry *Entry) Debugln(args ...interface{}) { - entry.Logln(DebugLevel, args...) + if entry.Logger.level() >= DebugLevel { + entry.Debug(entry.sprintlnn(args...)) + } } func (entry *Entry) Infoln(args ...interface{}) { - entry.Logln(InfoLevel, args...) + if entry.Logger.level() >= InfoLevel { + entry.Info(entry.sprintlnn(args...)) + } } func (entry *Entry) Println(args ...interface{}) { @@ -377,7 +241,9 @@ func (entry *Entry) Println(args ...interface{}) { } func (entry *Entry) Warnln(args ...interface{}) { - entry.Logln(WarnLevel, args...) + if entry.Logger.level() >= WarnLevel { + entry.Warn(entry.sprintlnn(args...)) + } } func (entry *Entry) Warningln(args ...interface{}) { @@ -385,16 +251,22 @@ func (entry *Entry) Warningln(args ...interface{}) { } func (entry *Entry) Errorln(args ...interface{}) { - entry.Logln(ErrorLevel, args...) + if entry.Logger.level() >= ErrorLevel { + entry.Error(entry.sprintlnn(args...)) + } } func (entry *Entry) Fatalln(args ...interface{}) { - entry.Logln(FatalLevel, args...) - entry.Logger.Exit(1) + if entry.Logger.level() >= FatalLevel { + entry.Fatal(entry.sprintlnn(args...)) + } + Exit(1) } func (entry *Entry) Panicln(args ...interface{}) { - entry.Logln(PanicLevel, args...) + if entry.Logger.level() >= PanicLevel { + entry.Panic(entry.sprintlnn(args...)) + } } // Sprintlnn => Sprint no newline. This is to get the behavior of how diff --git a/vendor/github.com/sirupsen/logrus/entry_test.go b/vendor/github.com/sirupsen/logrus/entry_test.go index f764085ef55..99c3b41d5f5 100644 --- a/vendor/github.com/sirupsen/logrus/entry_test.go +++ b/vendor/github.com/sirupsen/logrus/entry_test.go @@ -2,10 +2,8 @@ package logrus import ( "bytes" - "context" "fmt" "testing" - "time" "github.com/stretchr/testify/assert" ) @@ -34,19 +32,6 @@ func TestEntryWithError(t *testing.T) { } -func TestEntryWithContext(t *testing.T) { - assert := assert.New(t) - ctx := context.WithValue(context.Background(), "foo", "bar") - - assert.Equal(ctx, WithContext(ctx).Context) - - logger := New() - logger.Out = &bytes.Buffer{} - entry := NewEntry(logger) - - assert.Equal(ctx, entry.WithContext(ctx).Context) -} - func TestEntryPanicln(t *testing.T) { errBoom := fmt.Errorf("boom time") @@ -90,80 +75,3 @@ func TestEntryPanicf(t *testing.T) { entry := NewEntry(logger) entry.WithField("err", errBoom).Panicf("kaboom %v", true) } - -const ( - badMessage = "this is going to panic" - panicMessage = "this is broken" -) - -type panickyHook struct{} - -func (p *panickyHook) Levels() []Level { - return []Level{InfoLevel} -} - -func (p *panickyHook) Fire(entry *Entry) error { - if entry.Message == badMessage { - panic(panicMessage) - } - - return nil -} - -func TestEntryHooksPanic(t *testing.T) { - logger := New() - logger.Out = &bytes.Buffer{} - logger.Level = InfoLevel - logger.Hooks.Add(&panickyHook{}) - - defer func() { - p := recover() - assert.NotNil(t, p) - assert.Equal(t, panicMessage, p) - - entry := NewEntry(logger) - entry.Info("another message") - }() - - entry := NewEntry(logger) - entry.Info(badMessage) -} - -func TestEntryWithIncorrectField(t *testing.T) { - assert := assert.New(t) - - fn := func() {} - - e := Entry{} - eWithFunc := e.WithFields(Fields{"func": fn}) - eWithFuncPtr := e.WithFields(Fields{"funcPtr": &fn}) - - assert.Equal(eWithFunc.err, `can not add field "func"`) - assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) - - eWithFunc = eWithFunc.WithField("not_a_func", "it is a string") - eWithFuncPtr = eWithFuncPtr.WithField("not_a_func", "it is a string") - - assert.Equal(eWithFunc.err, `can not add field "func"`) - assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) - - eWithFunc = eWithFunc.WithTime(time.Now()) - eWithFuncPtr = eWithFuncPtr.WithTime(time.Now()) - - assert.Equal(eWithFunc.err, `can not add field "func"`) - assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`) -} - -func TestEntryLogfLevel(t *testing.T) { - logger := New() - buffer := &bytes.Buffer{} - logger.Out = buffer - logger.SetLevel(InfoLevel) - entry := NewEntry(logger) - - entry.Logf(DebugLevel, "%s", "debug") - assert.NotContains(t, buffer.String(), "debug", ) - - entry.Logf(WarnLevel, "%s", "warn") - assert.Contains(t, buffer.String(), "warn", ) -} \ No newline at end of file diff --git a/vendor/github.com/sirupsen/logrus/example_basic_test.go b/vendor/github.com/sirupsen/logrus/example_basic_test.go index 9ff56555b41..a2acf550c95 100644 --- a/vendor/github.com/sirupsen/logrus/example_basic_test.go +++ b/vendor/github.com/sirupsen/logrus/example_basic_test.go @@ -1,18 +1,16 @@ package logrus_test import ( - "os" - "github.com/sirupsen/logrus" + "os" ) func Example_basic() { var log = logrus.New() log.Formatter = new(logrus.JSONFormatter) log.Formatter = new(logrus.TextFormatter) //default - log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output - log.Level = logrus.TraceLevel + log.Level = logrus.DebugLevel log.Out = os.Stdout // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) @@ -37,11 +35,6 @@ func Example_basic() { } }() - log.WithFields(logrus.Fields{ - "animal": "walrus", - "number": 0, - }).Trace("Went to the beach") - log.WithFields(logrus.Fields{ "animal": "walrus", "number": 8, @@ -67,7 +60,6 @@ func Example_basic() { }).Panic("It's over 9000!") // Output: - // level=trace msg="Went to the beach" animal=walrus number=0 // level=debug msg="Started observing beach" animal=walrus number=8 // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 // level=warning msg="The group's number increased tremendously!" number=122 omg=true diff --git a/vendor/github.com/sirupsen/logrus/example_custom_caller_test.go b/vendor/github.com/sirupsen/logrus/example_custom_caller_test.go deleted file mode 100644 index e0023b9ad0d..00000000000 --- a/vendor/github.com/sirupsen/logrus/example_custom_caller_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package logrus_test - -import ( - "os" - "path" - "runtime" - "strings" - - "github.com/sirupsen/logrus" -) - -func ExampleCustomFormatter() { - l := logrus.New() - l.SetReportCaller(true) - l.Out = os.Stdout - l.Formatter = &logrus.JSONFormatter{ - DisableTimestamp: true, - CallerPrettyfier: func(f *runtime.Frame) (string, string) { - s := strings.Split(f.Function, ".") - funcname := s[len(s)-1] - _, filename := path.Split(f.File) - return funcname, filename - }, - } - l.Info("example of custom format caller") - // Output: - // {"file":"example_custom_caller_test.go","func":"ExampleCustomFormatter","level":"info","msg":"example of custom format caller"} -} diff --git a/vendor/github.com/sirupsen/logrus/example_default_field_value_test.go b/vendor/github.com/sirupsen/logrus/example_default_field_value_test.go deleted file mode 100644 index a72ece44a66..00000000000 --- a/vendor/github.com/sirupsen/logrus/example_default_field_value_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package logrus_test - -import ( - "github.com/sirupsen/logrus" - "os" -) - -type DefaultFieldHook struct { - GetValue func() string -} - -func (h *DefaultFieldHook) Levels() []logrus.Level { - return logrus.AllLevels -} - -func (h *DefaultFieldHook) Fire(e *logrus.Entry) error { - e.Data["aDefaultField"] = h.GetValue() - return nil -} - -func ExampleDefaultField() { - l := logrus.New() - l.Out = os.Stdout - l.Formatter = &logrus.TextFormatter{DisableTimestamp: true, DisableColors: true} - - l.AddHook(&DefaultFieldHook{GetValue: func() string { return "with its default value" }}) - l.Info("first log") - // Output: - // level=info msg="first log" aDefaultField="with its default value" -} diff --git a/vendor/github.com/sirupsen/logrus/example_global_hook_test.go b/vendor/github.com/sirupsen/logrus/example_global_hook_test.go deleted file mode 100644 index aaf2f4b1f72..00000000000 --- a/vendor/github.com/sirupsen/logrus/example_global_hook_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package logrus_test - -import ( - "github.com/sirupsen/logrus" - "os" -) - -var ( - mystring string -) - -type GlobalHook struct { -} - -func (h *GlobalHook) Levels() []logrus.Level { - return logrus.AllLevels -} - -func (h *GlobalHook) Fire(e *logrus.Entry) error { - e.Data["mystring"] = mystring - return nil -} - -func ExampleGlobalVariableHook() { - l := logrus.New() - l.Out = os.Stdout - l.Formatter = &logrus.TextFormatter{DisableTimestamp: true, DisableColors: true} - l.AddHook(&GlobalHook{}) - mystring = "first value" - l.Info("first log") - mystring = "another value" - l.Info("second log") - // Output: - // level=info msg="first log" mystring="first value" - // level=info msg="second log" mystring="another value" -} diff --git a/vendor/github.com/sirupsen/logrus/example_hook_test.go b/vendor/github.com/sirupsen/logrus/example_hook_test.go index dc0e69f192a..d4ddffca37f 100644 --- a/vendor/github.com/sirupsen/logrus/example_hook_test.go +++ b/vendor/github.com/sirupsen/logrus/example_hook_test.go @@ -1,24 +1,16 @@ -// +build !windows - package logrus_test import ( - "log/syslog" - "os" - "github.com/sirupsen/logrus" - slhooks "github.com/sirupsen/logrus/hooks/syslog" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" + "os" ) -// An example on how to use a hook func Example_hook() { var log = logrus.New() log.Formatter = new(logrus.TextFormatter) // default - log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output - if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err == nil { - log.Hooks.Add(sl) - } + log.Hooks.Add(airbrake.NewHook(123, "xyz", "development")) log.Out = os.Stdout log.WithFields(logrus.Fields{ diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go index 62fc2f2193c..013183edabf 100644 --- a/vendor/github.com/sirupsen/logrus/exported.go +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -1,9 +1,7 @@ package logrus import ( - "context" "io" - "time" ) var ( @@ -17,38 +15,37 @@ func StandardLogger() *Logger { // SetOutput sets the standard logger output. func SetOutput(out io.Writer) { - std.SetOutput(out) + std.mu.Lock() + defer std.mu.Unlock() + std.Out = out } // SetFormatter sets the standard logger formatter. func SetFormatter(formatter Formatter) { - std.SetFormatter(formatter) -} - -// SetReportCaller sets whether the standard logger will include the calling -// method as a field. -func SetReportCaller(include bool) { - std.SetReportCaller(include) + std.mu.Lock() + defer std.mu.Unlock() + std.Formatter = formatter } // SetLevel sets the standard logger level. func SetLevel(level Level) { + std.mu.Lock() + defer std.mu.Unlock() std.SetLevel(level) } // GetLevel returns the standard logger level. func GetLevel() Level { - return std.GetLevel() -} - -// IsLevelEnabled checks if the log level of the standard logger is greater than the level param -func IsLevelEnabled(level Level) bool { - return std.IsLevelEnabled(level) + std.mu.Lock() + defer std.mu.Unlock() + return std.level() } // AddHook adds a hook to the standard logger hooks. func AddHook(hook Hook) { - std.AddHook(hook) + std.mu.Lock() + defer std.mu.Unlock() + std.Hooks.Add(hook) } // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. @@ -56,11 +53,6 @@ func WithError(err error) *Entry { return std.WithField(ErrorKey, err) } -// WithContext creates an entry from the standard logger and adds a context to it. -func WithContext(ctx context.Context) *Entry { - return std.WithContext(ctx) -} - // WithField creates an entry from the standard logger and adds a field to // it. If you want multiple fields, use `WithFields`. // @@ -80,20 +72,6 @@ func WithFields(fields Fields) *Entry { return std.WithFields(fields) } -// WithTime creats an entry from the standard logger and overrides the time of -// logs generated with it. -// -// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal -// or Panic on the Entry it returns. -func WithTime(t time.Time) *Entry { - return std.WithTime(t) -} - -// Trace logs a message at level Trace on the standard logger. -func Trace(args ...interface{}) { - std.Trace(args...) -} - // Debug logs a message at level Debug on the standard logger. func Debug(args ...interface{}) { std.Debug(args...) @@ -129,16 +107,11 @@ func Panic(args ...interface{}) { std.Panic(args...) } -// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +// Fatal logs a message at level Fatal on the standard logger. func Fatal(args ...interface{}) { std.Fatal(args...) } -// Tracef logs a message at level Trace on the standard logger. -func Tracef(format string, args ...interface{}) { - std.Tracef(format, args...) -} - // Debugf logs a message at level Debug on the standard logger. func Debugf(format string, args ...interface{}) { std.Debugf(format, args...) @@ -174,16 +147,11 @@ func Panicf(format string, args ...interface{}) { std.Panicf(format, args...) } -// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +// Fatalf logs a message at level Fatal on the standard logger. func Fatalf(format string, args ...interface{}) { std.Fatalf(format, args...) } -// Traceln logs a message at level Trace on the standard logger. -func Traceln(args ...interface{}) { - std.Traceln(args...) -} - // Debugln logs a message at level Debug on the standard logger. func Debugln(args ...interface{}) { std.Debugln(args...) @@ -219,7 +187,7 @@ func Panicln(args ...interface{}) { std.Panicln(args...) } -// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +// Fatalln logs a message at level Fatal on the standard logger. func Fatalln(args ...interface{}) { std.Fatalln(args...) } diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go index 408883773eb..b183ff5b1db 100644 --- a/vendor/github.com/sirupsen/logrus/formatter.go +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -2,16 +2,7 @@ package logrus import "time" -// Default key names for the default fields -const ( - defaultTimestampFormat = time.RFC3339 - FieldKeyMsg = "msg" - FieldKeyLevel = "level" - FieldKeyTime = "time" - FieldKeyLogrusError = "logrus_error" - FieldKeyFunc = "func" - FieldKeyFile = "file" -) +const defaultTimestampFormat = time.RFC3339 // The Formatter interface is used to implement a custom Formatter. It takes an // `Entry`. It exposes all the fields, including the default ones: @@ -27,7 +18,7 @@ type Formatter interface { Format(*Entry) ([]byte, error) } -// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when +// This is to not silently overwrite `time`, `msg` and `level` fields when // dumping it. If this code wasn't there doing: // // logrus.WithField("level", 1).Info("hello") @@ -39,40 +30,16 @@ type Formatter interface { // // It's not exported because it's still using Data in an opinionated way. It's to // avoid code duplication between the two default formatters. -func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { - timeKey := fieldMap.resolve(FieldKeyTime) - if t, ok := data[timeKey]; ok { - data["fields."+timeKey] = t - delete(data, timeKey) +func prefixFieldClashes(data Fields) { + if t, ok := data["time"]; ok { + data["fields.time"] = t } - msgKey := fieldMap.resolve(FieldKeyMsg) - if m, ok := data[msgKey]; ok { - data["fields."+msgKey] = m - delete(data, msgKey) + if m, ok := data["msg"]; ok { + data["fields.msg"] = m } - levelKey := fieldMap.resolve(FieldKeyLevel) - if l, ok := data[levelKey]; ok { - data["fields."+levelKey] = l - delete(data, levelKey) - } - - logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) - if l, ok := data[logrusErrKey]; ok { - data["fields."+logrusErrKey] = l - delete(data, logrusErrKey) - } - - // If reportCaller is not set, 'func' will not conflict. - if reportCaller { - funcKey := fieldMap.resolve(FieldKeyFunc) - if l, ok := data[funcKey]; ok { - data["fields."+funcKey] = l - } - fileKey := fieldMap.resolve(FieldKeyFile) - if l, ok := data[fileKey]; ok { - data["fields."+fileKey] = l - } + if l, ok := data["level"]; ok { + data["fields.level"] = l } } diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod deleted file mode 100644 index 12fdf989847..00000000000 --- a/vendor/github.com/sirupsen/logrus/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/sirupsen/logrus - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.1 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.1.1 // indirect - github.com/stretchr/testify v1.2.2 - golang.org/x/sys v0.0.0-20190422165155-953cdadca894 -) diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum deleted file mode 100644 index 596c318b9f7..00000000000 --- a/vendor/github.com/sirupsen/logrus/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/sirupsen/logrus/hook_test.go b/vendor/github.com/sirupsen/logrus/hook_test.go index 28f193df95c..4fea7514e1b 100644 --- a/vendor/github.com/sirupsen/logrus/hook_test.go +++ b/vendor/github.com/sirupsen/logrus/hook_test.go @@ -1,16 +1,10 @@ -package logrus_test +package logrus import ( - "bytes" - "encoding/json" "sync" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - . "github.com/sirupsen/logrus" - . "github.com/sirupsen/logrus/internal/testutils" ) type TestHook struct { @@ -24,7 +18,6 @@ func (hook *TestHook) Fire(entry *Entry) error { func (hook *TestHook) Levels() []Level { return []Level{ - TraceLevel, DebugLevel, InfoLevel, WarnLevel, @@ -57,7 +50,6 @@ func (hook *ModifyHook) Fire(entry *Entry) error { func (hook *ModifyHook) Levels() []Level { return []Level{ - TraceLevel, DebugLevel, InfoLevel, WarnLevel, @@ -93,46 +85,6 @@ func TestCanFireMultipleHooks(t *testing.T) { }) } -type SingleLevelModifyHook struct { - ModifyHook -} - -func (h *SingleLevelModifyHook) Levels() []Level { - return []Level{InfoLevel} -} - -func TestHookEntryIsPristine(t *testing.T) { - l := New() - b := &bytes.Buffer{} - l.Formatter = &JSONFormatter{} - l.Out = b - l.AddHook(&SingleLevelModifyHook{}) - - l.Error("error message") - data := map[string]string{} - err := json.Unmarshal(b.Bytes(), &data) - require.NoError(t, err) - _, ok := data["wow"] - require.False(t, ok) - b.Reset() - - l.Info("error message") - data = map[string]string{} - err = json.Unmarshal(b.Bytes(), &data) - require.NoError(t, err) - _, ok = data["wow"] - require.True(t, ok) - b.Reset() - - l.Error("error message") - data = map[string]string{} - err = json.Unmarshal(b.Bytes(), &data) - require.NoError(t, err) - _, ok = data["wow"] - require.False(t, ok) - b.Reset() -} - type ErrorHook struct { Fired bool } @@ -190,27 +142,3 @@ func TestAddHookRace(t *testing.T) { // actually assert on the hook }) } - -type HookCallFunc struct { - F func() -} - -func (h *HookCallFunc) Levels() []Level { - return AllLevels -} - -func (h *HookCallFunc) Fire(e *Entry) error { - h.F() - return nil -} - -func TestHookFireOrder(t *testing.T) { - checkers := []string{} - h := LevelHooks{} - h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "first hook") }}) - h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "second hook") }}) - h.Add(&HookCallFunc{F: func() { checkers = append(checkers, "third hook") }}) - - h.Fire(InfoLevel, &Entry{}) - require.Equal(t, []string{"first hook", "second hook", "third hook"}, checkers) -} diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go index 02b8df38055..329ce0d60cb 100644 --- a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go +++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go @@ -43,7 +43,7 @@ func (hook *SyslogHook) Fire(entry *logrus.Entry) error { return hook.Writer.Warning(line) case logrus.InfoLevel: return hook.Writer.Info(line) - case logrus.DebugLevel, logrus.TraceLevel: + case logrus.DebugLevel: return hook.Writer.Debug(line) default: return nil diff --git a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go index bec6efd5ac8..5ec3a444548 100644 --- a/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go +++ b/vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go @@ -1,5 +1,3 @@ -// +build !windows,!nacl,!plan9 - package syslog import ( diff --git a/vendor/github.com/sirupsen/logrus/hooks/test/test.go b/vendor/github.com/sirupsen/logrus/hooks/test/test.go index 234a17dfa88..62c4845df7d 100644 --- a/vendor/github.com/sirupsen/logrus/hooks/test/test.go +++ b/vendor/github.com/sirupsen/logrus/hooks/test/test.go @@ -15,7 +15,7 @@ type Hook struct { // Entries is an array of all entries that have been received by this hook. // For safe access, use the AllEntries() method, rather than reading this // value directly. - Entries []logrus.Entry + Entries []*logrus.Entry mu sync.RWMutex } @@ -52,7 +52,7 @@ func NewNullLogger() (*logrus.Logger, *Hook) { func (t *Hook) Fire(e *logrus.Entry) error { t.mu.Lock() defer t.mu.Unlock() - t.Entries = append(t.Entries, *e) + t.Entries = append(t.Entries, e) return nil } @@ -68,7 +68,9 @@ func (t *Hook) LastEntry() *logrus.Entry { if i < 0 { return nil } - return &t.Entries[i] + // Make a copy, for safety + e := *t.Entries[i] + return &e } // AllEntries returns all entries that were logged. @@ -77,9 +79,10 @@ func (t *Hook) AllEntries() []*logrus.Entry { defer t.mu.RUnlock() // Make a copy so the returned value won't race with future log requests entries := make([]*logrus.Entry, len(t.Entries)) - for i := 0; i < len(t.Entries); i++ { + for i, entry := range t.Entries { // Make a copy, for safety - entries[i] = &t.Entries[i] + e := *entry + entries[i] = &e } return entries } @@ -88,5 +91,5 @@ func (t *Hook) AllEntries() []*logrus.Entry { func (t *Hook) Reset() { t.mu.Lock() defer t.mu.Unlock() - t.Entries = make([]logrus.Entry, 0) + t.Entries = make([]*logrus.Entry, 0) } diff --git a/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go b/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go index 636bad5126c..3f55cfe31ba 100644 --- a/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go +++ b/vendor/github.com/sirupsen/logrus/hooks/test/test_test.go @@ -1,16 +1,14 @@ package test import ( - "math/rand" - "sync" "testing" - "time" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) func TestAllHooks(t *testing.T) { + assert := assert.New(t) logger, hook := NewNullLogger() @@ -37,49 +35,5 @@ func TestAllHooks(t *testing.T) { assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) assert.Equal("Hello error", hook.LastEntry().Message) assert.Equal(1, len(hook.Entries)) -} - -func TestLoggingWithHooksRace(t *testing.T) { - - rand.Seed(time.Now().Unix()) - unlocker := rand.Int() % 100 - - assert := assert.New(t) - logger, hook := NewNullLogger() - - var wgOne, wgAll sync.WaitGroup - wgOne.Add(1) - wgAll.Add(100) - - for i := 0; i < 100; i++ { - go func(i int) { - logger.Info("info") - wgAll.Done() - if i == unlocker { - wgOne.Done() - } - }(i) - } - - wgOne.Wait() - assert.Equal(logrus.InfoLevel, hook.LastEntry().Level) - assert.Equal("info", hook.LastEntry().Message) - - wgAll.Wait() - - entries := hook.AllEntries() - assert.Equal(100, len(entries)) -} - -func TestFatalWithAlternateExit(t *testing.T) { - assert := assert.New(t) - - logger, hook := NewNullLogger() - logger.ExitFunc = func(code int) {} - - logger.Fatal("something went very wrong") - assert.Equal(logrus.FatalLevel, hook.LastEntry().Level) - assert.Equal("something went very wrong", hook.LastEntry().Message) - assert.Equal(1, len(hook.Entries)) } diff --git a/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go b/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go deleted file mode 100644 index 6e3a6203e00..00000000000 --- a/vendor/github.com/sirupsen/logrus/internal/testutils/testutils.go +++ /dev/null @@ -1,58 +0,0 @@ -package testutils - -import ( - "bytes" - "encoding/json" - "strconv" - "strings" - "testing" - - . "github.com/sirupsen/logrus" - - "github.com/stretchr/testify/require" -) - -func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { - var buffer bytes.Buffer - var fields Fields - - logger := New() - logger.Out = &buffer - logger.Formatter = new(JSONFormatter) - - log(logger) - - err := json.Unmarshal(buffer.Bytes(), &fields) - require.Nil(t, err) - - assertions(fields) -} - -func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { - var buffer bytes.Buffer - - logger := New() - logger.Out = &buffer - logger.Formatter = &TextFormatter{ - DisableColors: true, - } - - log(logger) - - fields := make(map[string]string) - for _, kv := range strings.Split(strings.TrimRight(buffer.String(), "\n"), " ") { - if !strings.Contains(kv, "=") { - continue - } - kvArr := strings.Split(kv, "=") - key := strings.TrimSpace(kvArr[0]) - val := kvArr[1] - if kvArr[1][0] == '"' { - var err error - val, err = strconv.Unquote(val) - require.NoError(t, err) - } - fields[key] = val - } - assertions(fields) -} diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go index 098a21a0679..fb01c1b1040 100644 --- a/vendor/github.com/sirupsen/logrus/json_formatter.go +++ b/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -1,10 +1,8 @@ package logrus import ( - "bytes" "encoding/json" "fmt" - "runtime" ) type fieldKey string @@ -12,6 +10,13 @@ type fieldKey string // FieldMap allows customization of the key names for default fields. type FieldMap map[fieldKey]string +// Default key names for the default fields +const ( + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" +) + func (f FieldMap) resolve(key fieldKey) string { if k, ok := f[key]; ok { return k @@ -28,34 +33,21 @@ type JSONFormatter struct { // DisableTimestamp allows disabling automatic timestamps in output DisableTimestamp bool - // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. - DataKey string - // FieldMap allows users to customize the names of keys for default fields. // As an example: // formatter := &JSONFormatter{ // FieldMap: FieldMap{ - // FieldKeyTime: "@timestamp", + // FieldKeyTime: "@timestamp", // FieldKeyLevel: "@level", - // FieldKeyMsg: "@message", - // FieldKeyFunc: "@caller", + // FieldKeyMsg: "@message", // }, // } FieldMap FieldMap - - // CallerPrettyfier can be set by the user to modify the content - // of the function and file keys in the json data when ReportCaller is - // activated. If any of the returned value is the empty string the - // corresponding key will be removed from json fields. - CallerPrettyfier func(*runtime.Frame) (function string, file string) - - // PrettyPrint will indent all json logs - PrettyPrint bool } // Format renders a single log entry func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { - data := make(Fields, len(entry.Data)+4) + data := make(Fields, len(entry.Data)+3) for k, v := range entry.Data { switch v := v.(type) { case error: @@ -66,56 +58,22 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { data[k] = v } } - - if f.DataKey != "" { - newData := make(Fields, 4) - newData[f.DataKey] = data - data = newData - } - - prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + prefixFieldClashes(data) timestampFormat := f.TimestampFormat if timestampFormat == "" { timestampFormat = defaultTimestampFormat } - if entry.err != "" { - data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err - } if !f.DisableTimestamp { data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) } data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() - if entry.HasCaller() { - funcVal := entry.Caller.Function - fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) - if f.CallerPrettyfier != nil { - funcVal, fileVal = f.CallerPrettyfier(entry.Caller) - } - if funcVal != "" { - data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal - } - if fileVal != "" { - data[f.FieldMap.resolve(FieldKeyFile)] = fileVal - } - } - var b *bytes.Buffer - if entry.Buffer != nil { - b = entry.Buffer - } else { - b = &bytes.Buffer{} + serialized, err := json.Marshal(data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) } - - encoder := json.NewEncoder(b) - if f.PrettyPrint { - encoder.SetIndent("", " ") - } - if err := encoder.Encode(data); err != nil { - return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err) - } - - return b.Bytes(), nil + return append(serialized, '\n'), nil } diff --git a/vendor/github.com/sirupsen/logrus/json_formatter_test.go b/vendor/github.com/sirupsen/logrus/json_formatter_test.go index 695c36e549f..51093a79bad 100644 --- a/vendor/github.com/sirupsen/logrus/json_formatter_test.go +++ b/vendor/github.com/sirupsen/logrus/json_formatter_test.go @@ -3,8 +3,6 @@ package logrus import ( "encoding/json" "errors" - "fmt" - "runtime" "strings" "testing" ) @@ -108,102 +106,6 @@ func TestFieldClashWithLevel(t *testing.T) { } } -func TestFieldClashWithRemappedFields(t *testing.T) { - formatter := &JSONFormatter{ - FieldMap: FieldMap{ - FieldKeyTime: "@timestamp", - FieldKeyLevel: "@level", - FieldKeyMsg: "@message", - }, - } - - b, err := formatter.Format(WithFields(Fields{ - "@timestamp": "@timestamp", - "@level": "@level", - "@message": "@message", - "timestamp": "timestamp", - "level": "level", - "msg": "msg", - })) - if err != nil { - t.Fatal("Unable to format entry: ", err) - } - - entry := make(map[string]interface{}) - err = json.Unmarshal(b, &entry) - if err != nil { - t.Fatal("Unable to unmarshal formatted entry: ", err) - } - - for _, field := range []string{"timestamp", "level", "msg"} { - if entry[field] != field { - t.Errorf("Expected field %v to be untouched; got %v", field, entry[field]) - } - - remappedKey := fmt.Sprintf("fields.%s", field) - if remapped, ok := entry[remappedKey]; ok { - t.Errorf("Expected %s to be empty; got %v", remappedKey, remapped) - } - } - - for _, field := range []string{"@timestamp", "@level", "@message"} { - if entry[field] == field { - t.Errorf("Expected field %v to be mapped to an Entry value", field) - } - - remappedKey := fmt.Sprintf("fields.%s", field) - if remapped, ok := entry[remappedKey]; ok { - if remapped != field { - t.Errorf("Expected field %v to be copied to %s; got %v", field, remappedKey, remapped) - } - } else { - t.Errorf("Expected field %v to be copied to %s; was absent", field, remappedKey) - } - } -} - -func TestFieldsInNestedDictionary(t *testing.T) { - formatter := &JSONFormatter{ - DataKey: "args", - } - - logEntry := WithFields(Fields{ - "level": "level", - "test": "test", - }) - logEntry.Level = InfoLevel - - b, err := formatter.Format(logEntry) - if err != nil { - t.Fatal("Unable to format entry: ", err) - } - - entry := make(map[string]interface{}) - err = json.Unmarshal(b, &entry) - if err != nil { - t.Fatal("Unable to unmarshal formatted entry: ", err) - } - - args := entry["args"].(map[string]interface{}) - - for _, field := range []string{"test", "level"} { - if value, present := args[field]; !present || value != field { - t.Errorf("Expected field %v to be present under 'args'; untouched", field) - } - } - - for _, field := range []string{"test", "fields.level"} { - if _, present := entry[field]; present { - t.Errorf("Expected field %v not to be present at top level", field) - } - } - - // with nested object, "level" shouldn't clash - if entry["level"] != "info" { - t.Errorf("Expected 'level' field to contain 'info'") - } -} - func TestJSONEntryEndsWithNewline(t *testing.T) { formatter := &JSONFormatter{} @@ -268,55 +170,6 @@ func TestJSONTimeKey(t *testing.T) { } } -func TestFieldDoesNotClashWithCaller(t *testing.T) { - SetReportCaller(false) - formatter := &JSONFormatter{} - - b, err := formatter.Format(WithField("func", "howdy pardner")) - if err != nil { - t.Fatal("Unable to format entry: ", err) - } - - entry := make(map[string]interface{}) - err = json.Unmarshal(b, &entry) - if err != nil { - t.Fatal("Unable to unmarshal formatted entry: ", err) - } - - if entry["func"] != "howdy pardner" { - t.Fatal("func field replaced when ReportCaller=false") - } -} - -func TestFieldClashWithCaller(t *testing.T) { - SetReportCaller(true) - formatter := &JSONFormatter{} - e := WithField("func", "howdy pardner") - e.Caller = &runtime.Frame{Function: "somefunc"} - b, err := formatter.Format(e) - if err != nil { - t.Fatal("Unable to format entry: ", err) - } - - entry := make(map[string]interface{}) - err = json.Unmarshal(b, &entry) - if err != nil { - t.Fatal("Unable to unmarshal formatted entry: ", err) - } - - if entry["fields.func"] != "howdy pardner" { - t.Fatalf("fields.func not set to original func field when ReportCaller=true (got '%s')", - entry["fields.func"]) - } - - if entry["func"] != "somefunc" { - t.Fatalf("func not set as expected when ReportCaller=true (got '%s')", - entry["func"]) - } - - SetReportCaller(false) // return to default value -} - func TestJSONDisableTimestamp(t *testing.T) { formatter := &JSONFormatter{ DisableTimestamp: true, diff --git a/vendor/github.com/sirupsen/logrus/level_test.go b/vendor/github.com/sirupsen/logrus/level_test.go deleted file mode 100644 index 78915c4f2b8..00000000000 --- a/vendor/github.com/sirupsen/logrus/level_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package logrus_test - -import ( - "bytes" - "encoding/json" - "testing" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" -) - -func TestLevelJsonEncoding(t *testing.T) { - type X struct { - Level logrus.Level - } - - var x X - x.Level = logrus.WarnLevel - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - require.NoError(t, enc.Encode(x)) - dec := json.NewDecoder(&buf) - var y X - require.NoError(t, dec.Decode(&y)) -} - -func TestLevelUnmarshalText(t *testing.T) { - var u logrus.Level - for _, level := range logrus.AllLevels { - t.Run(level.String(), func(t *testing.T) { - require.NoError(t, u.UnmarshalText([]byte(level.String()))) - require.Equal(t, level, u) - }) - } - t.Run("invalid", func(t *testing.T) { - require.Error(t, u.UnmarshalText([]byte("invalid"))) - }) -} - -func TestLevelMarshalText(t *testing.T) { - levelStrings := []string{ - "panic", - "fatal", - "error", - "warning", - "info", - "debug", - "trace", - } - for idx, val := range logrus.AllLevels { - level := val - t.Run(level.String(), func(t *testing.T) { - var cmp logrus.Level - b, err := level.MarshalText() - require.NoError(t, err) - require.Equal(t, levelStrings[idx], string(b)) - err = cmp.UnmarshalText(b) - require.NoError(t, err) - require.Equal(t, level, cmp) - }) - } -} diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go index c0c0b1e5590..fdaf8a65341 100644 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -1,18 +1,16 @@ package logrus import ( - "context" "io" "os" "sync" "sync/atomic" - "time" ) type Logger struct { // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a // file, or leave it default which is `os.Stderr`. You can also set this to - // something more adventurous, such as logging to Kafka. + // something more adventorous, such as logging to Kafka. Out io.Writer // Hooks for the logger instance. These allow firing events based on logging // levels and log entries. For example, to send errors to an error tracking @@ -25,10 +23,6 @@ type Logger struct { // own that implements the `Formatter` interface, see the `README` or included // formatters for examples. Formatter Formatter - - // Flag for whether to log caller info (off by default) - ReportCaller bool - // The logging level the logger should log at. This is typically (and defaults // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be // logged. @@ -37,12 +31,8 @@ type Logger struct { mu MutexWrap // Reusable empty entry entryPool sync.Pool - // Function to exit the application, defaults to `os.Exit()` - ExitFunc exitFunc } -type exitFunc func(int) - type MutexWrap struct { lock sync.Mutex disabled bool @@ -78,12 +68,10 @@ func (mw *MutexWrap) Disable() { // It's recommended to make this a global instance called `log`. func New() *Logger { return &Logger{ - Out: os.Stderr, - Formatter: new(TextFormatter), - Hooks: make(LevelHooks), - Level: InfoLevel, - ExitFunc: os.Exit, - ReportCaller: false, + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, } } @@ -96,12 +84,11 @@ func (logger *Logger) newEntry() *Entry { } func (logger *Logger) releaseEntry(entry *Entry) { - entry.Data = map[string]interface{}{} logger.entryPool.Put(entry) } // Adds a field to the log entry, note that it doesn't log until you call -// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. +// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. // If you want multiple fields, use `WithFields`. func (logger *Logger) WithField(key string, value interface{}) *Entry { entry := logger.newEntry() @@ -125,38 +112,20 @@ func (logger *Logger) WithError(err error) *Entry { return entry.WithError(err) } -// Add a context to the log entry. -func (logger *Logger) WithContext(ctx context.Context) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithContext(ctx) -} - -// Overrides the time of the log entry. -func (logger *Logger) WithTime(t time.Time) *Entry { - entry := logger.newEntry() - defer logger.releaseEntry(entry) - return entry.WithTime(t) -} - -func (logger *Logger) Logf(level Level, format string, args ...interface{}) { - if logger.IsLevelEnabled(level) { +func (logger *Logger) Debugf(format string, args ...interface{}) { + if logger.level() >= DebugLevel { entry := logger.newEntry() - entry.Logf(level, format, args...) + entry.Debugf(format, args...) logger.releaseEntry(entry) } } -func (logger *Logger) Tracef(format string, args ...interface{}) { - logger.Logf(TraceLevel, format, args...) -} - -func (logger *Logger) Debugf(format string, args ...interface{}) { - logger.Logf(DebugLevel, format, args...) -} - func (logger *Logger) Infof(format string, args ...interface{}) { - logger.Logf(InfoLevel, format, args...) + if logger.level() >= InfoLevel { + entry := logger.newEntry() + entry.Infof(format, args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Printf(format string, args ...interface{}) { @@ -166,91 +135,123 @@ func (logger *Logger) Printf(format string, args ...interface{}) { } func (logger *Logger) Warnf(format string, args ...interface{}) { - logger.Logf(WarnLevel, format, args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Warningf(format string, args ...interface{}) { - logger.Warnf(format, args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warnf(format, args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Errorf(format string, args ...interface{}) { - logger.Logf(ErrorLevel, format, args...) + if logger.level() >= ErrorLevel { + entry := logger.newEntry() + entry.Errorf(format, args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Fatalf(format string, args ...interface{}) { - logger.Logf(FatalLevel, format, args...) - logger.Exit(1) + if logger.level() >= FatalLevel { + entry := logger.newEntry() + entry.Fatalf(format, args...) + logger.releaseEntry(entry) + } + Exit(1) } func (logger *Logger) Panicf(format string, args ...interface{}) { - logger.Logf(PanicLevel, format, args...) -} - -func (logger *Logger) Log(level Level, args ...interface{}) { - if logger.IsLevelEnabled(level) { + if logger.level() >= PanicLevel { entry := logger.newEntry() - entry.Log(level, args...) + entry.Panicf(format, args...) logger.releaseEntry(entry) } } -func (logger *Logger) Trace(args ...interface{}) { - logger.Log(TraceLevel, args...) -} - func (logger *Logger) Debug(args ...interface{}) { - logger.Log(DebugLevel, args...) + if logger.level() >= DebugLevel { + entry := logger.newEntry() + entry.Debug(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Info(args ...interface{}) { - logger.Log(InfoLevel, args...) + if logger.level() >= InfoLevel { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Print(args ...interface{}) { entry := logger.newEntry() - entry.Print(args...) + entry.Info(args...) logger.releaseEntry(entry) } func (logger *Logger) Warn(args ...interface{}) { - logger.Log(WarnLevel, args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Warning(args ...interface{}) { - logger.Warn(args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warn(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Error(args ...interface{}) { - logger.Log(ErrorLevel, args...) + if logger.level() >= ErrorLevel { + entry := logger.newEntry() + entry.Error(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Fatal(args ...interface{}) { - logger.Log(FatalLevel, args...) - logger.Exit(1) + if logger.level() >= FatalLevel { + entry := logger.newEntry() + entry.Fatal(args...) + logger.releaseEntry(entry) + } + Exit(1) } func (logger *Logger) Panic(args ...interface{}) { - logger.Log(PanicLevel, args...) -} - -func (logger *Logger) Logln(level Level, args ...interface{}) { - if logger.IsLevelEnabled(level) { + if logger.level() >= PanicLevel { entry := logger.newEntry() - entry.Logln(level, args...) + entry.Panic(args...) logger.releaseEntry(entry) } } -func (logger *Logger) Traceln(args ...interface{}) { - logger.Logln(TraceLevel, args...) -} - func (logger *Logger) Debugln(args ...interface{}) { - logger.Logln(DebugLevel, args...) + if logger.level() >= DebugLevel { + entry := logger.newEntry() + entry.Debugln(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Infoln(args ...interface{}) { - logger.Logln(InfoLevel, args...) + if logger.level() >= InfoLevel { + entry := logger.newEntry() + entry.Infoln(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Println(args ...interface{}) { @@ -260,32 +261,44 @@ func (logger *Logger) Println(args ...interface{}) { } func (logger *Logger) Warnln(args ...interface{}) { - logger.Logln(WarnLevel, args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Warningln(args ...interface{}) { - logger.Warnln(args...) + if logger.level() >= WarnLevel { + entry := logger.newEntry() + entry.Warnln(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Errorln(args ...interface{}) { - logger.Logln(ErrorLevel, args...) + if logger.level() >= ErrorLevel { + entry := logger.newEntry() + entry.Errorln(args...) + logger.releaseEntry(entry) + } } func (logger *Logger) Fatalln(args ...interface{}) { - logger.Logln(FatalLevel, args...) - logger.Exit(1) + if logger.level() >= FatalLevel { + entry := logger.newEntry() + entry.Fatalln(args...) + logger.releaseEntry(entry) + } + Exit(1) } func (logger *Logger) Panicln(args ...interface{}) { - logger.Logln(PanicLevel, args...) -} - -func (logger *Logger) Exit(code int) { - runHandlers() - if logger.ExitFunc == nil { - logger.ExitFunc = os.Exit + if logger.level() >= PanicLevel { + entry := logger.newEntry() + entry.Panicln(args...) + logger.releaseEntry(entry) } - logger.ExitFunc(code) } //When file is opened with appending mode, it's safe to @@ -299,53 +312,12 @@ func (logger *Logger) level() Level { return Level(atomic.LoadUint32((*uint32)(&logger.Level))) } -// SetLevel sets the logger level. func (logger *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) } -// GetLevel returns the logger level. -func (logger *Logger) GetLevel() Level { - return logger.level() -} - -// AddHook adds a hook to the logger hooks. func (logger *Logger) AddHook(hook Hook) { logger.mu.Lock() defer logger.mu.Unlock() logger.Hooks.Add(hook) } - -// IsLevelEnabled checks if the log level of the logger is greater than the level param -func (logger *Logger) IsLevelEnabled(level Level) bool { - return logger.level() >= level -} - -// SetFormatter sets the logger formatter. -func (logger *Logger) SetFormatter(formatter Formatter) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.Formatter = formatter -} - -// SetOutput sets the logger output. -func (logger *Logger) SetOutput(output io.Writer) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.Out = output -} - -func (logger *Logger) SetReportCaller(reportCaller bool) { - logger.mu.Lock() - defer logger.mu.Unlock() - logger.ReportCaller = reportCaller -} - -// ReplaceHooks replaces the logger hooks and returns the old ones -func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { - logger.mu.Lock() - oldHooks := logger.Hooks - logger.Hooks = hooks - logger.mu.Unlock() - return oldHooks -} diff --git a/vendor/github.com/sirupsen/logrus/logger_bench_test.go b/vendor/github.com/sirupsen/logrus/logger_bench_test.go index f0a768439ac..dd23a3535ec 100644 --- a/vendor/github.com/sirupsen/logrus/logger_bench_test.go +++ b/vendor/github.com/sirupsen/logrus/logger_bench_test.go @@ -1,7 +1,6 @@ package logrus import ( - "io/ioutil" "os" "testing" ) @@ -60,26 +59,3 @@ func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fi } }) } - -func BenchmarkLoggerJSONFormatter(b *testing.B) { - doLoggerBenchmarkWithFormatter(b, &JSONFormatter{}) -} - -func BenchmarkLoggerTextFormatter(b *testing.B) { - doLoggerBenchmarkWithFormatter(b, &TextFormatter{}) -} - -func doLoggerBenchmarkWithFormatter(b *testing.B, f Formatter) { - b.SetParallelism(100) - log := New() - log.Formatter = f - log.Out = ioutil.Discard - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - log. - WithField("foo1", "bar1"). - WithField("foo2", "bar2"). - Info("this is a dummy log") - } - }) -} diff --git a/vendor/github.com/sirupsen/logrus/logger_test.go b/vendor/github.com/sirupsen/logrus/logger_test.go deleted file mode 100644 index 50433e60c8d..00000000000 --- a/vendor/github.com/sirupsen/logrus/logger_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package logrus - -import ( - "bytes" - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestFieldValueError(t *testing.T) { - buf := &bytes.Buffer{} - l := &Logger{ - Out: buf, - Formatter: new(JSONFormatter), - Hooks: make(LevelHooks), - Level: DebugLevel, - } - l.WithField("func", func() {}).Info("test") - fmt.Println(buf.String()) - var data map[string]interface{} - json.Unmarshal(buf.Bytes(), &data) - _, ok := data[FieldKeyLogrusError] - require.True(t, ok) -} - -func TestNoFieldValueError(t *testing.T) { - buf := &bytes.Buffer{} - l := &Logger{ - Out: buf, - Formatter: new(JSONFormatter), - Hooks: make(LevelHooks), - Level: DebugLevel, - } - l.WithField("str", "str").Info("test") - fmt.Println(buf.String()) - var data map[string]interface{} - json.Unmarshal(buf.Bytes(), &data) - _, ok := data[FieldKeyLogrusError] - require.False(t, ok) -} - -func TestWarninglnNotEqualToWarning(t *testing.T) { - buf := &bytes.Buffer{} - bufln := &bytes.Buffer{} - - formatter := new(TextFormatter) - formatter.DisableTimestamp = true - formatter.DisableLevelTruncation = true - - l := &Logger{ - Out: buf, - Formatter: formatter, - Hooks: make(LevelHooks), - Level: DebugLevel, - } - l.Warning("hello,", "world") - - l.SetOutput(bufln) - l.Warningln("hello,", "world") - - assert.NotEqual(t, buf.String(), bufln.String(), "Warning() and Wantingln() should not be equal") -} diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go index 8644761f73c..dd38999741e 100644 --- a/vendor/github.com/sirupsen/logrus/logrus.go +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -14,11 +14,22 @@ type Level uint32 // Convert the Level to a string. E.g. PanicLevel becomes "panic". func (level Level) String() string { - if b, err := level.MarshalText(); err == nil { - return string(b) - } else { - return "unknown" + switch level { + case DebugLevel: + return "debug" + case InfoLevel: + return "info" + case WarnLevel: + return "warning" + case ErrorLevel: + return "error" + case FatalLevel: + return "fatal" + case PanicLevel: + return "panic" } + + return "unknown" } // ParseLevel takes a string level and returns the Logrus log level constant. @@ -36,47 +47,12 @@ func ParseLevel(lvl string) (Level, error) { return InfoLevel, nil case "debug": return DebugLevel, nil - case "trace": - return TraceLevel, nil } var l Level return l, fmt.Errorf("not a valid logrus Level: %q", lvl) } -// UnmarshalText implements encoding.TextUnmarshaler. -func (level *Level) UnmarshalText(text []byte) error { - l, err := ParseLevel(string(text)) - if err != nil { - return err - } - - *level = Level(l) - - return nil -} - -func (level Level) MarshalText() ([]byte, error) { - switch level { - case TraceLevel: - return []byte("trace"), nil - case DebugLevel: - return []byte("debug"), nil - case InfoLevel: - return []byte("info"), nil - case WarnLevel: - return []byte("warning"), nil - case ErrorLevel: - return []byte("error"), nil - case FatalLevel: - return []byte("fatal"), nil - case PanicLevel: - return []byte("panic"), nil - } - - return nil, fmt.Errorf("not a valid logrus level %d", level) -} - // A constant exposing all logging levels var AllLevels = []Level{ PanicLevel, @@ -85,7 +61,6 @@ var AllLevels = []Level{ WarnLevel, InfoLevel, DebugLevel, - TraceLevel, } // These are the different logging levels. You can set the logging level to log @@ -94,7 +69,7 @@ const ( // PanicLevel level, highest level of severity. Logs and then calls panic with the // message passed to Debug, Info, ... PanicLevel Level = iota - // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the // logging level is set to Panic. FatalLevel // ErrorLevel level. Logs. Used for errors that should definitely be noted. @@ -107,8 +82,6 @@ const ( InfoLevel // DebugLevel level. Usually only enabled when debugging. Very verbose logging. DebugLevel - // TraceLevel level. Designates finer-grained informational events than the Debug. - TraceLevel ) // Won't compile if StdLogger can't be realized by a log.Logger @@ -167,20 +140,4 @@ type FieldLogger interface { Errorln(args ...interface{}) Fatalln(args ...interface{}) Panicln(args ...interface{}) - - // IsDebugEnabled() bool - // IsInfoEnabled() bool - // IsWarnEnabled() bool - // IsErrorEnabled() bool - // IsFatalEnabled() bool - // IsPanicEnabled() bool -} - -// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is -// here for consistancy. Do not use. Use Logger or Entry instead. -type Ext1FieldLogger interface { - FieldLogger - Tracef(format string, args ...interface{}) - Trace(args ...interface{}) - Traceln(args ...interface{}) } diff --git a/vendor/github.com/sirupsen/logrus/logrus_test.go b/vendor/github.com/sirupsen/logrus/logrus_test.go index 72b6ea254a7..78cbc282595 100644 --- a/vendor/github.com/sirupsen/logrus/logrus_test.go +++ b/vendor/github.com/sirupsen/logrus/logrus_test.go @@ -1,117 +1,67 @@ -package logrus_test +package logrus import ( "bytes" "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "runtime" + "strconv" + "strings" "sync" "testing" - "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - . "github.com/sirupsen/logrus" - . "github.com/sirupsen/logrus/internal/testutils" ) -// TestReportCaller verifies that when ReportCaller is set, the 'func' field -// is added, and when it is unset it is not set or modified -// Verify that functions within the Logrus package aren't considered when -// discovering the caller. -func TestReportCallerWhenConfigured(t *testing.T) { - LogAndAssertJSON(t, func(log *Logger) { - log.ReportCaller = false - log.Print("testNoCaller") - }, func(fields Fields) { - assert.Equal(t, "testNoCaller", fields["msg"]) - assert.Equal(t, "info", fields["level"]) - assert.Equal(t, nil, fields["func"]) - }) - - LogAndAssertJSON(t, func(log *Logger) { - log.ReportCaller = true - log.Print("testWithCaller") - }, func(fields Fields) { - assert.Equal(t, "testWithCaller", fields["msg"]) - assert.Equal(t, "info", fields["level"]) - assert.Equal(t, - "github.com/sirupsen/logrus_test.TestReportCallerWhenConfigured.func3", fields[FieldKeyFunc]) - }) - - LogAndAssertJSON(t, func(log *Logger) { - log.ReportCaller = true - log.Formatter.(*JSONFormatter).CallerPrettyfier = func(f *runtime.Frame) (string, string) { - return "somekindoffunc", "thisisafilename" - } - log.Print("testWithCallerPrettyfier") - }, func(fields Fields) { - assert.Equal(t, "somekindoffunc", fields[FieldKeyFunc]) - assert.Equal(t, "thisisafilename", fields[FieldKeyFile]) - }) - - LogAndAssertText(t, func(log *Logger) { - log.ReportCaller = true - log.Formatter.(*TextFormatter).CallerPrettyfier = func(f *runtime.Frame) (string, string) { - return "somekindoffunc", "thisisafilename" - } - log.Print("testWithCallerPrettyfier") - }, func(fields map[string]string) { - assert.Equal(t, "somekindoffunc", fields[FieldKeyFunc]) - assert.Equal(t, "thisisafilename", fields[FieldKeyFile]) - }) -} - -func logSomething(t *testing.T, message string) Fields { +func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) { var buffer bytes.Buffer var fields Fields logger := New() logger.Out = &buffer logger.Formatter = new(JSONFormatter) - logger.ReportCaller = true - entry := logger.WithFields(Fields{ - "foo": "bar", - }) - - entry.Info(message) + log(logger) err := json.Unmarshal(buffer.Bytes(), &fields) assert.Nil(t, err) - return fields + assertions(fields) } -// TestReportCallerHelperDirect - verify reference when logging from a regular function -func TestReportCallerHelperDirect(t *testing.T) { - fields := logSomething(t, "direct") +func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) { + var buffer bytes.Buffer - assert.Equal(t, "direct", fields["msg"]) - assert.Equal(t, "info", fields["level"]) - assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) -} + logger := New() + logger.Out = &buffer + logger.Formatter = &TextFormatter{ + DisableColors: true, + } -// TestReportCallerHelperDirect - verify reference when logging from a function called via pointer -func TestReportCallerHelperViaPointer(t *testing.T) { - fptr := logSomething - fields := fptr(t, "via pointer") + log(logger) - assert.Equal(t, "via pointer", fields["msg"]) - assert.Equal(t, "info", fields["level"]) - assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) + fields := make(map[string]string) + for _, kv := range strings.Split(buffer.String(), " ") { + if !strings.Contains(kv, "=") { + continue + } + kvArr := strings.Split(kv, "=") + key := strings.TrimSpace(kvArr[0]) + val := kvArr[1] + if kvArr[1][0] == '"' { + var err error + val, err = strconv.Unquote(val) + assert.NoError(t, err) + } + fields[key] = val + } + assertions(fields) } func TestPrint(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Print("test") }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) - assert.Equal(t, "info", fields["level"]) + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "info") }) } @@ -119,8 +69,8 @@ func TestInfo(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Info("test") }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) - assert.Equal(t, "info", fields["level"]) + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "info") }) } @@ -128,17 +78,8 @@ func TestWarn(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Warn("test") }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) - assert.Equal(t, "warning", fields["level"]) - }) -} - -func TestLog(t *testing.T) { - LogAndAssertJSON(t, func(log *Logger) { - log.Log(WarnLevel, "test") - }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) - assert.Equal(t, "warning", fields["level"]) + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["level"], "warning") }) } @@ -146,7 +87,7 @@ func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Infoln("test", "test") }, func(fields Fields) { - assert.Equal(t, "test test", fields["msg"]) + assert.Equal(t, fields["msg"], "test test") }) } @@ -154,7 +95,7 @@ func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Infoln("test", 10) }, func(fields Fields) { - assert.Equal(t, "test 10", fields["msg"]) + assert.Equal(t, fields["msg"], "test 10") }) } @@ -162,7 +103,7 @@ func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Infoln(10, 10) }, func(fields Fields) { - assert.Equal(t, "10 10", fields["msg"]) + assert.Equal(t, fields["msg"], "10 10") }) } @@ -170,7 +111,7 @@ func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Infoln(10, 10) }, func(fields Fields) { - assert.Equal(t, "10 10", fields["msg"]) + assert.Equal(t, fields["msg"], "10 10") }) } @@ -178,7 +119,7 @@ func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Info("test", 10) }, func(fields Fields) { - assert.Equal(t, "test10", fields["msg"]) + assert.Equal(t, fields["msg"], "test10") }) } @@ -186,7 +127,7 @@ func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.Info("test", "test") }, func(fields Fields) { - assert.Equal(t, "testtest", fields["msg"]) + assert.Equal(t, fields["msg"], "testtest") }) } @@ -224,7 +165,7 @@ func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.WithField("msg", "hello").Info("test") }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, fields["msg"], "test") }) } @@ -232,8 +173,8 @@ func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.WithField("msg", "hello").Info("test") }, func(fields Fields) { - assert.Equal(t, "test", fields["msg"]) - assert.Equal(t, "hello", fields["fields.msg"]) + assert.Equal(t, fields["msg"], "test") + assert.Equal(t, fields["fields.msg"], "hello") }) } @@ -241,7 +182,7 @@ func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.WithField("time", "hello").Info("test") }, func(fields Fields) { - assert.Equal(t, "hello", fields["fields.time"]) + assert.Equal(t, fields["fields.time"], "hello") }) } @@ -249,8 +190,8 @@ func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { LogAndAssertJSON(t, func(log *Logger) { log.WithField("level", 1).Info("test") }, func(fields Fields) { - assert.Equal(t, "info", fields["level"]) - assert.Equal(t, 1.0, fields["fields.level"]) // JSON has floats only + assert.Equal(t, fields["level"], "info") + assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only }) } @@ -268,65 +209,6 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) { }) } -func TestWithTimeShouldOverrideTime(t *testing.T) { - now := time.Now().Add(24 * time.Hour) - - LogAndAssertJSON(t, func(log *Logger) { - log.WithTime(now).Info("foobar") - }, func(fields Fields) { - assert.Equal(t, fields["time"], now.Format(time.RFC3339)) - }) -} - -func TestWithTimeShouldNotOverrideFields(t *testing.T) { - now := time.Now().Add(24 * time.Hour) - - LogAndAssertJSON(t, func(log *Logger) { - log.WithField("herp", "derp").WithTime(now).Info("blah") - }, func(fields Fields) { - assert.Equal(t, fields["time"], now.Format(time.RFC3339)) - assert.Equal(t, fields["herp"], "derp") - }) -} - -func TestWithFieldShouldNotOverrideTime(t *testing.T) { - now := time.Now().Add(24 * time.Hour) - - LogAndAssertJSON(t, func(log *Logger) { - log.WithTime(now).WithField("herp", "derp").Info("blah") - }, func(fields Fields) { - assert.Equal(t, fields["time"], now.Format(time.RFC3339)) - assert.Equal(t, fields["herp"], "derp") - }) -} - -func TestTimeOverrideMultipleLogs(t *testing.T) { - var buffer bytes.Buffer - var firstFields, secondFields Fields - - logger := New() - logger.Out = &buffer - formatter := new(JSONFormatter) - formatter.TimestampFormat = time.StampMilli - logger.Formatter = formatter - - llog := logger.WithField("herp", "derp") - llog.Info("foo") - - err := json.Unmarshal(buffer.Bytes(), &firstFields) - assert.NoError(t, err, "should have decoded first message") - - buffer.Reset() - - time.Sleep(10 * time.Millisecond) - llog.Info("bar") - - err = json.Unmarshal(buffer.Bytes(), &secondFields) - assert.NoError(t, err, "should have decoded second message") - - assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal") -} - func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { var buffer bytes.Buffer @@ -353,119 +235,13 @@ func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { err = json.Unmarshal(buffer.Bytes(), &fields) assert.NoError(t, err, "should have decoded second message") assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") - assert.Equal(t, "omg it is!", fields["msg"]) - assert.Equal(t, "eating raw fish", fields["context"]) - assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") - -} - -func TestNestedLoggingReportsCorrectCaller(t *testing.T) { - var buffer bytes.Buffer - var fields Fields - - logger := New() - logger.Out = &buffer - logger.Formatter = new(JSONFormatter) - logger.ReportCaller = true - - llog := logger.WithField("context", "eating raw fish") - - llog.Info("looks delicious") - _, _, line, _ := runtime.Caller(0) - - err := json.Unmarshal(buffer.Bytes(), &fields) - require.NoError(t, err, "should have decoded first message") - assert.Equal(t, 6, len(fields), "should have msg/time/level/func/context fields") - assert.Equal(t, "looks delicious", fields["msg"]) - assert.Equal(t, "eating raw fish", fields["context"]) - assert.Equal(t, - "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) - cwd, err := os.Getwd() - require.NoError(t, err) - assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string))) - - buffer.Reset() - - logger.WithFields(Fields{ - "Clyde": "Stubblefield", - }).WithFields(Fields{ - "Jab'o": "Starks", - }).WithFields(Fields{ - "uri": "https://www.youtube.com/watch?v=V5DTznu-9v0", - }).WithFields(Fields{ - "func": "y drummer", - }).WithFields(Fields{ - "James": "Brown", - }).Print("The hardest workin' man in show business") - _, _, line, _ = runtime.Caller(0) - - err = json.Unmarshal(buffer.Bytes(), &fields) - assert.NoError(t, err, "should have decoded second message") - assert.Equal(t, 11, len(fields), "should have all builtin fields plus foo,bar,baz,...") - assert.Equal(t, "Stubblefield", fields["Clyde"]) - assert.Equal(t, "Starks", fields["Jab'o"]) - assert.Equal(t, "https://www.youtube.com/watch?v=V5DTznu-9v0", fields["uri"]) - assert.Equal(t, "y drummer", fields["fields.func"]) - assert.Equal(t, "Brown", fields["James"]) - assert.Equal(t, "The hardest workin' man in show business", fields["msg"]) + assert.Equal(t, fields["msg"], "omg it is!") + assert.Equal(t, fields["context"], "eating raw fish") assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") - assert.Equal(t, - "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) - require.NoError(t, err) - assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string))) - logger.ReportCaller = false // return to default value -} - -func logLoop(iterations int, reportCaller bool) { - var buffer bytes.Buffer - - logger := New() - logger.Out = &buffer - logger.Formatter = new(JSONFormatter) - logger.ReportCaller = reportCaller - - for i := 0; i < iterations; i++ { - logger.Infof("round %d of %d", i, iterations) - } -} - -// Assertions for upper bounds to reporting overhead -func TestCallerReportingOverhead(t *testing.T) { - iterations := 5000 - before := time.Now() - logLoop(iterations, false) - during := time.Now() - logLoop(iterations, true) - after := time.Now() - - elapsedNotReporting := during.Sub(before).Nanoseconds() - elapsedReporting := after.Sub(during).Nanoseconds() - - maxDelta := 1 * time.Second - assert.WithinDuration(t, during, before, maxDelta, - "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", - iterations, maxDelta.Seconds(), elapsedNotReporting) - assert.WithinDuration(t, after, during, maxDelta, - "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", - iterations, maxDelta.Seconds(), elapsedReporting) -} - -// benchmarks for both with and without caller-function reporting -func BenchmarkWithoutCallerTracing(b *testing.B) { - for i := 0; i < b.N; i++ { - logLoop(1000, false) - } -} - -func BenchmarkWithCallerTracing(b *testing.B) { - for i := 0; i < b.N; i++ { - logLoop(1000, true) - } } func TestConvertLevelToString(t *testing.T) { - assert.Equal(t, "trace", TraceLevel.String()) assert.Equal(t, "debug", DebugLevel.String()) assert.Equal(t, "info", InfoLevel.String()) assert.Equal(t, "warning", WarnLevel.String()) @@ -531,25 +307,10 @@ func TestParseLevel(t *testing.T) { assert.Nil(t, err) assert.Equal(t, DebugLevel, l) - l, err = ParseLevel("trace") - assert.Nil(t, err) - assert.Equal(t, TraceLevel, l) - - l, err = ParseLevel("TRACE") - assert.Nil(t, err) - assert.Equal(t, TraceLevel, l) - l, err = ParseLevel("invalid") assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) } -func TestLevelString(t *testing.T) { - var loggerlevel Level - loggerlevel = 32000 - - _ = loggerlevel.String() -} - func TestGetSetLevelRace(t *testing.T) { wg := sync.WaitGroup{} for i := 0; i < 100; i++ { @@ -582,52 +343,10 @@ func TestLoggingRace(t *testing.T) { wg.Wait() } -func TestLoggingRaceWithHooksOnEntry(t *testing.T) { - logger := New() - hook := new(ModifyHook) - logger.AddHook(hook) - entry := logger.WithField("context", "clue") - - var wg sync.WaitGroup - wg.Add(100) - - for i := 0; i < 100; i++ { - go func() { - entry.Info("info") - wg.Done() - }() - } - wg.Wait() -} - -func TestReplaceHooks(t *testing.T) { - old, cur := &TestHook{}, &TestHook{} - - logger := New() - logger.SetOutput(ioutil.Discard) - logger.AddHook(old) - - hooks := make(LevelHooks) - hooks.Add(cur) - replaced := logger.ReplaceHooks(hooks) - - logger.Info("test") - - assert.Equal(t, old.Fired, false) - assert.Equal(t, cur.Fired, true) - - logger.ReplaceHooks(replaced) - logger.Info("test") - assert.Equal(t, old.Fired, true) -} - // Compile test -func TestLogrusInterfaces(t *testing.T) { +func TestLogrusInterface(t *testing.T) { var buffer bytes.Buffer - // This verifies FieldLogger and Ext1FieldLogger work as designed. - // Please don't use them. Use Logger and Entry directly. - fn := func(xl Ext1FieldLogger) { - var l FieldLogger = xl + fn := func(l FieldLogger) { b := l.WithField("key", "value") b.Debug("Test") } @@ -665,98 +384,3 @@ func TestEntryWriter(t *testing.T) { assert.Equal(t, fields["foo"], "bar") assert.Equal(t, fields["level"], "warning") } - -func TestLogLevelEnabled(t *testing.T) { - log := New() - log.SetLevel(PanicLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, false, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(FatalLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(ErrorLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(WarnLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(InfoLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(DebugLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) - - log.SetLevel(TraceLevel) - assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) - assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) - assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) - assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) - assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) - assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) - assert.Equal(t, true, log.IsLevelEnabled(TraceLevel)) -} - -func TestReportCallerOnTextFormatter(t *testing.T) { - l := New() - - l.Formatter.(*TextFormatter).ForceColors = true - l.Formatter.(*TextFormatter).DisableColors = false - l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") - - l.Formatter.(*TextFormatter).ForceColors = false - l.Formatter.(*TextFormatter).DisableColors = true - l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") -} - -func TestSetReportCallerRace(t *testing.T) { - l := New() - l.Out = ioutil.Discard - l.SetReportCaller(true) - - var wg sync.WaitGroup - wg.Add(100) - - for i := 0; i < 100; i++ { - go func() { - l.Error("Some Error") - wg.Done() - }() - } - wg.Wait() -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_bsd.go new file mode 100644 index 00000000000..d7b3893f3fe --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_bsd.go @@ -0,0 +1,10 @@ +// +build darwin freebsd openbsd netbsd dragonfly +// +build !appengine + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TIOCGETA + +type Termios unix.Termios diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go deleted file mode 100644 index 2403de98192..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build appengine - -package logrus - -import ( - "io" -) - -func checkIfTerminal(w io.Writer) bool { - return true -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go deleted file mode 100644 index 3c4f43f91cd..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd - -package logrus - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TIOCGETA - -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} - diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go deleted file mode 100644 index 97af92c68ea..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build js nacl plan9 - -package logrus - -import ( - "io" -) - -func checkIfTerminal(w io.Writer) bool { - return false -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go deleted file mode 100644 index 3293fb3caad..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build !appengine,!js,!windows,!nacl,!plan9 - -package logrus - -import ( - "io" - "os" -) - -func checkIfTerminal(w io.Writer) bool { - switch v := w.(type) { - case *os.File: - return isTerminal(int(v.Fd())) - default: - return false - } -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go deleted file mode 100644 index f6710b3bd0b..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go +++ /dev/null @@ -1,11 +0,0 @@ -package logrus - -import ( - "golang.org/x/sys/unix" -) - -// IsTerminal returns true if the given file descriptor is a terminal. -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermio(fd, unix.TCGETA) - return err == nil -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go deleted file mode 100644 index 355dc966f00..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build linux aix - -package logrus - -import "golang.org/x/sys/unix" - -const ioctlReadTermios = unix.TCGETS - -func isTerminal(fd int) bool { - _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) - return err == nil -} - diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go deleted file mode 100644 index 572889db216..00000000000 --- a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -// +build !appengine,!js,windows - -package logrus - -import ( - "io" - "os" - "syscall" - - sequences "github.com/konsorten/go-windows-terminal-sequences" -) - -func initTerminal(w io.Writer) { - switch v := w.(type) { - case *os.File: - sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) - } -} - -func checkIfTerminal(w io.Writer) bool { - var ret bool - switch v := w.(type) { - case *os.File: - var mode uint32 - err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) - ret = (err == nil) - default: - ret = false - } - if ret { - initTerminal(w) - } - return ret -} diff --git a/vendor/github.com/sirupsen/logrus/terminal_linux.go b/vendor/github.com/sirupsen/logrus/terminal_linux.go new file mode 100644 index 00000000000..88d7298e24f --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_linux.go @@ -0,0 +1,14 @@ +// Based on ssh/terminal: +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +package logrus + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS + +type Termios unix.Termios diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go index e01587c437d..be412aa948b 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -3,22 +3,28 @@ package logrus import ( "bytes" "fmt" + "io" "os" - "runtime" "sort" "strings" "sync" "time" + + "golang.org/x/crypto/ssh/terminal" ) const ( - red = 31 - yellow = 33 - blue = 36 - gray = 37 + nocolor = 0 + red = 31 + green = 32 + yellow = 33 + blue = 36 + gray = 37 ) -var baseTimestamp time.Time +var ( + baseTimestamp time.Time +) func init() { baseTimestamp = time.Now() @@ -32,9 +38,6 @@ type TextFormatter struct { // Force disabling colors. DisableColors bool - // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ - EnvironmentOverrideColors bool - // Disable timestamp logging. useful when output is redirected to logging // system that already adds timestamps. DisableTimestamp bool @@ -51,151 +54,69 @@ type TextFormatter struct { // be desired. DisableSorting bool - // The keys sorting function, when uninitialized it uses sort.Strings. - SortingFunc func([]string) - - // Disables the truncation of the level text to 4 characters. - DisableLevelTruncation bool - // QuoteEmptyFields will wrap empty fields in quotes if true QuoteEmptyFields bool // Whether the logger's out is to a terminal isTerminal bool - // FieldMap allows users to customize the names of keys for default fields. - // As an example: - // formatter := &TextFormatter{ - // FieldMap: FieldMap{ - // FieldKeyTime: "@timestamp", - // FieldKeyLevel: "@level", - // FieldKeyMsg: "@message"}} - FieldMap FieldMap - - // CallerPrettyfier can be set by the user to modify the content - // of the function and file keys in the data when ReportCaller is - // activated. If any of the returned value is the empty string the - // corresponding key will be removed from fields. - CallerPrettyfier func(*runtime.Frame) (function string, file string) - - terminalInitOnce sync.Once + sync.Once } func (f *TextFormatter) init(entry *Entry) { if entry.Logger != nil { - f.isTerminal = checkIfTerminal(entry.Logger.Out) + f.isTerminal = f.checkIfTerminal(entry.Logger.Out) } } -func (f *TextFormatter) isColored() bool { - isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows")) - - if f.EnvironmentOverrideColors { - if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { - isColored = true - } else if ok && force == "0" { - isColored = false - } else if os.Getenv("CLICOLOR") == "0" { - isColored = false - } +func (f *TextFormatter) checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return terminal.IsTerminal(int(v.Fd())) + default: + return false } - - return isColored && !f.DisableColors } // Format renders a single log entry func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { - data := make(Fields) - for k, v := range entry.Data { - data[k] = v - } - prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) - keys := make([]string, 0, len(data)) - for k := range data { + var b *bytes.Buffer + keys := make([]string, 0, len(entry.Data)) + for k := range entry.Data { keys = append(keys, k) } - var funcVal, fileVal string - - fixedKeys := make([]string, 0, 4+len(data)) - if !f.DisableTimestamp { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) - } - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) - if entry.Message != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) - } - if entry.err != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) - } - if entry.HasCaller() { - if f.CallerPrettyfier != nil { - funcVal, fileVal = f.CallerPrettyfier(entry.Caller) - } else { - funcVal = entry.Caller.Function - fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) - } - - if funcVal != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc)) - } - if fileVal != "" { - fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile)) - } - } - if !f.DisableSorting { - if f.SortingFunc == nil { - sort.Strings(keys) - fixedKeys = append(fixedKeys, keys...) - } else { - if !f.isColored() { - fixedKeys = append(fixedKeys, keys...) - f.SortingFunc(fixedKeys) - } else { - f.SortingFunc(keys) - } - } - } else { - fixedKeys = append(fixedKeys, keys...) + sort.Strings(keys) } - - var b *bytes.Buffer if entry.Buffer != nil { b = entry.Buffer } else { b = &bytes.Buffer{} } - f.terminalInitOnce.Do(func() { f.init(entry) }) + prefixFieldClashes(entry.Data) + + f.Do(func() { f.init(entry) }) + + isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors timestampFormat := f.TimestampFormat if timestampFormat == "" { timestampFormat = defaultTimestampFormat } - if f.isColored() { - f.printColored(b, entry, keys, data, timestampFormat) + if isColored { + f.printColored(b, entry, keys, timestampFormat) } else { - - for _, key := range fixedKeys { - var value interface{} - switch { - case key == f.FieldMap.resolve(FieldKeyTime): - value = entry.Time.Format(timestampFormat) - case key == f.FieldMap.resolve(FieldKeyLevel): - value = entry.Level.String() - case key == f.FieldMap.resolve(FieldKeyMsg): - value = entry.Message - case key == f.FieldMap.resolve(FieldKeyLogrusError): - value = entry.err - case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): - value = funcVal - case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): - value = fileVal - default: - value = data[key] - } - f.appendKeyValue(b, key, value) + if !f.DisableTimestamp { + f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) + } + f.appendKeyValue(b, "level", entry.Level.String()) + if entry.Message != "" { + f.appendKeyValue(b, "msg", entry.Message) + } + for _, key := range keys { + f.appendKeyValue(b, key, entry.Data[key]) } } @@ -203,10 +124,10 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { return b.Bytes(), nil } -func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) { +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { var levelColor int switch entry.Level { - case DebugLevel, TraceLevel: + case DebugLevel: levelColor = gray case WarnLevel: levelColor = yellow @@ -216,42 +137,17 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin levelColor = blue } - levelText := strings.ToUpper(entry.Level.String()) - if !f.DisableLevelTruncation { - levelText = levelText[0:4] - } - - // Remove a single newline if it already exists in the message to keep - // the behavior of logrus text_formatter the same as the stdlib log package - entry.Message = strings.TrimSuffix(entry.Message, "\n") - - caller := "" - if entry.HasCaller() { - funcVal := fmt.Sprintf("%s()", entry.Caller.Function) - fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) - - if f.CallerPrettyfier != nil { - funcVal, fileVal = f.CallerPrettyfier(entry.Caller) - } - - if fileVal == "" { - caller = funcVal - } else if funcVal == "" { - caller = fileVal - } else { - caller = fileVal + " " + funcVal - } - } + levelText := strings.ToUpper(entry.Level.String())[0:4] if f.DisableTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) } else if !f.FullTimestamp { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message) } else { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) } for _, k := range keys { - v := data[k] + v := entry.Data[k] fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) f.appendValue(b, v) } diff --git a/vendor/github.com/sirupsen/logrus/text_formatter_test.go b/vendor/github.com/sirupsen/logrus/text_formatter_test.go index 9c5e6f0a1ed..d93b931e518 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter_test.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter_test.go @@ -4,15 +4,9 @@ import ( "bytes" "errors" "fmt" - "os" - "runtime" - "sort" "strings" "testing" "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestFormatting(t *testing.T) { @@ -134,44 +128,6 @@ func TestTimestampFormat(t *testing.T) { checkTimeStr("") } -func TestDisableLevelTruncation(t *testing.T) { - entry := &Entry{ - Time: time.Now(), - Message: "testing", - } - keys := []string{} - timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006" - checkDisableTruncation := func(disabled bool, level Level) { - tf := &TextFormatter{DisableLevelTruncation: disabled} - var b bytes.Buffer - entry.Level = level - tf.printColored(&b, entry, keys, nil, timestampFormat) - logLine := (&b).String() - if disabled { - expected := strings.ToUpper(level.String()) - if !strings.Contains(logLine, expected) { - t.Errorf("level string expected to be %s when truncation disabled", expected) - } - } else { - expected := strings.ToUpper(level.String()) - if len(level.String()) > 4 { - if strings.Contains(logLine, expected) { - t.Errorf("level string %s expected to be truncated to %s when truncation is enabled", expected, expected[0:4]) - } - } else { - if !strings.Contains(logLine, expected) { - t.Errorf("level string expected to be %s when truncation is enabled and level string is below truncation threshold", expected) - } - } - } - } - - checkDisableTruncation(true, DebugLevel) - checkDisableTruncation(true, InfoLevel) - checkDisableTruncation(false, ErrorLevel) - checkDisableTruncation(false, InfoLevel) -} - func TestDisableTimestampWithColoredOutput(t *testing.T) { tf := &TextFormatter{DisableTimestamp: true, ForceColors: true} @@ -181,305 +137,5 @@ func TestDisableTimestampWithColoredOutput(t *testing.T) { } } -func TestNewlineBehavior(t *testing.T) { - tf := &TextFormatter{ForceColors: true} - - // Ensure a single new line is removed as per stdlib log - e := NewEntry(StandardLogger()) - e.Message = "test message\n" - b, _ := tf.Format(e) - if bytes.Contains(b, []byte("test message\n")) { - t.Error("first newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected newline to be removed.") - } - - // Ensure a double new line is reduced to a single new line - e = NewEntry(StandardLogger()) - e.Message = "test message\n\n" - b, _ = tf.Format(e) - if bytes.Contains(b, []byte("test message\n\n")) { - t.Error("Double newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected single newline") - } - if !bytes.Contains(b, []byte("test message\n")) { - t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting") - } -} - -func TestTextFormatterFieldMap(t *testing.T) { - formatter := &TextFormatter{ - DisableColors: true, - FieldMap: FieldMap{ - FieldKeyMsg: "message", - FieldKeyLevel: "somelevel", - FieldKeyTime: "timeywimey", - }, - } - - entry := &Entry{ - Message: "oh hi", - Level: WarnLevel, - Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC), - Data: Fields{ - "field1": "f1", - "message": "messagefield", - "somelevel": "levelfield", - "timeywimey": "timeywimeyfield", - }, - } - - b, err := formatter.Format(entry) - if err != nil { - t.Fatal("Unable to format entry: ", err) - } - - assert.Equal(t, - `timeywimey="1981-02-24T04:28:03Z" `+ - `somelevel=warning `+ - `message="oh hi" `+ - `field1=f1 `+ - `fields.message=messagefield `+ - `fields.somelevel=levelfield `+ - `fields.timeywimey=timeywimeyfield`+"\n", - string(b), - "Formatted output doesn't respect FieldMap") -} - -func TestTextFormatterIsColored(t *testing.T) { - params := []struct { - name string - expectedResult bool - isTerminal bool - disableColor bool - forceColor bool - envColor bool - clicolorIsSet bool - clicolorForceIsSet bool - clicolorVal string - clicolorForceVal string - }{ - // Default values - { - name: "testcase1", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: false, - clicolorIsSet: false, - clicolorForceIsSet: false, - }, - // Output on terminal - { - name: "testcase2", - expectedResult: true, - isTerminal: true, - disableColor: false, - forceColor: false, - envColor: false, - clicolorIsSet: false, - clicolorForceIsSet: false, - }, - // Output on terminal with color disabled - { - name: "testcase3", - expectedResult: false, - isTerminal: true, - disableColor: true, - forceColor: false, - envColor: false, - clicolorIsSet: false, - clicolorForceIsSet: false, - }, - // Output not on terminal with color disabled - { - name: "testcase4", - expectedResult: false, - isTerminal: false, - disableColor: true, - forceColor: false, - envColor: false, - clicolorIsSet: false, - clicolorForceIsSet: false, - }, - // Output not on terminal with color forced - { - name: "testcase5", - expectedResult: true, - isTerminal: false, - disableColor: false, - forceColor: true, - envColor: false, - clicolorIsSet: false, - clicolorForceIsSet: false, - }, - // Output on terminal with clicolor set to "0" - { - name: "testcase6", - expectedResult: false, - isTerminal: true, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "0", - }, - // Output on terminal with clicolor set to "1" - { - name: "testcase7", - expectedResult: true, - isTerminal: true, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "1", - }, - // Output not on terminal with clicolor set to "0" - { - name: "testcase8", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "0", - }, - // Output not on terminal with clicolor set to "1" - { - name: "testcase9", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "1", - }, - // Output not on terminal with clicolor set to "1" and force color - { - name: "testcase10", - expectedResult: true, - isTerminal: false, - disableColor: false, - forceColor: true, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "1", - }, - // Output not on terminal with clicolor set to "0" and force color - { - name: "testcase11", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: true, - envColor: true, - clicolorIsSet: true, - clicolorForceIsSet: false, - clicolorVal: "0", - }, - // Output not on terminal with clicolor_force set to "1" - { - name: "testcase12", - expectedResult: true, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: false, - clicolorForceIsSet: true, - clicolorForceVal: "1", - }, - // Output not on terminal with clicolor_force set to "0" - { - name: "testcase13", - expectedResult: false, - isTerminal: false, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: false, - clicolorForceIsSet: true, - clicolorForceVal: "0", - }, - // Output on terminal with clicolor_force set to "0" - { - name: "testcase14", - expectedResult: false, - isTerminal: true, - disableColor: false, - forceColor: false, - envColor: true, - clicolorIsSet: false, - clicolorForceIsSet: true, - clicolorForceVal: "0", - }, - } - - cleanenv := func() { - os.Unsetenv("CLICOLOR") - os.Unsetenv("CLICOLOR_FORCE") - } - - defer cleanenv() - - for _, val := range params { - t.Run("textformatter_"+val.name, func(subT *testing.T) { - tf := TextFormatter{ - isTerminal: val.isTerminal, - DisableColors: val.disableColor, - ForceColors: val.forceColor, - EnvironmentOverrideColors: val.envColor, - } - cleanenv() - if val.clicolorIsSet { - os.Setenv("CLICOLOR", val.clicolorVal) - } - if val.clicolorForceIsSet { - os.Setenv("CLICOLOR_FORCE", val.clicolorForceVal) - } - res := tf.isColored() - if runtime.GOOS == "windows" && !tf.ForceColors && !val.clicolorForceIsSet { - assert.Equal(subT, false, res) - } else { - assert.Equal(subT, val.expectedResult, res) - } - }) - } -} - -func TestCustomSorting(t *testing.T) { - formatter := &TextFormatter{ - DisableColors: true, - SortingFunc: func(keys []string) { - sort.Slice(keys, func(i, j int) bool { - if keys[j] == "prefix" { - return false - } - if keys[i] == "prefix" { - return true - } - return strings.Compare(keys[i], keys[j]) == -1 - }) - }, - } - - entry := &Entry{ - Message: "Testing custom sort function", - Time: time.Now(), - Level: InfoLevel, - Data: Fields{ - "test": "testvalue", - "prefix": "the application prefix", - "blablabla": "blablabla", - }, - } - b, err := formatter.Format(entry) - require.NoError(t, err) - require.True(t, strings.HasPrefix(string(b), "prefix="), "format output is %q", string(b)) -} +// TODO add tests for sorting etc., this requires a parser for the text +// formatter output. diff --git a/vendor/github.com/sirupsen/logrus/travis/cross_build.sh b/vendor/github.com/sirupsen/logrus/travis/cross_build.sh deleted file mode 100755 index 545d8c32986..00000000000 --- a/vendor/github.com/sirupsen/logrus/travis/cross_build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -if [[ "$TRAVIS_GO_VERSION" =~ ^1.\12\. ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - /tmp/gox/gox -build-lib -all -fi diff --git a/vendor/github.com/sirupsen/logrus/travis/install.sh b/vendor/github.com/sirupsen/logrus/travis/install.sh deleted file mode 100755 index 07f45327863..00000000000 --- a/vendor/github.com/sirupsen/logrus/travis/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - -if [[ "$TRAVIS_GO_VERSION" =~ ^1.\12\. ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - git clone https://github.com/dgsb/gox.git /tmp/gox - pushd /tmp/gox - git checkout new_master - go build ./ - popd -fi diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go index 9e1f7513597..7bdebedc60b 100644 --- a/vendor/github.com/sirupsen/logrus/writer.go +++ b/vendor/github.com/sirupsen/logrus/writer.go @@ -24,8 +24,6 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { var printFunc func(args ...interface{}) switch level { - case TraceLevel: - printFunc = entry.Trace case DebugLevel: printFunc = entry.Debug case InfoLevel: diff --git a/vendor/k8s.io/api/go.sum b/vendor/k8s.io/api/go.sum index 3a9fde2aa96..e9de18764bd 100644 --- a/vendor/k8s.io/api/go.sum +++ b/vendor/k8s.io/api/go.sum @@ -97,7 +97,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/apimachinery v0.17.1 h1:zUjS3szTxoUjTDYNvdFkYt2uMEXLcthcbp+7uZvWhYM= k8s.io/apimachinery v0.17.1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= diff --git a/vendor/k8s.io/apiserver/.github/PULL_REQUEST_TEMPLATE.md b/vendor/k8s.io/apiserver/.github/PULL_REQUEST_TEMPLATE.md index e7e5eb834b2..e559c074bb5 100644 --- a/vendor/k8s.io/apiserver/.github/PULL_REQUEST_TEMPLATE.md +++ b/vendor/k8s.io/apiserver/.github/PULL_REQUEST_TEMPLATE.md @@ -1,2 +1,2 @@ -Sorry, we do not accept changes directly against this repository. Please see +Sorry, we do not accept changes directly against this repository. Please see CONTRIBUTING.md for information on where and how to contribute instead. diff --git a/vendor/k8s.io/apiserver/.import-restrictions b/vendor/k8s.io/apiserver/.import-restrictions index 87723dcfc80..c80e742d557 100644 --- a/vendor/k8s.io/apiserver/.import-restrictions +++ b/vendor/k8s.io/apiserver/.import-restrictions @@ -1,5 +1,10 @@ -rules: - # prevent import of k8s.io/kubernetes - - selectorRegexp: k8s[.]io/kubernetes - forbiddenPrefixes: - - '' +{ + "Rules": [ + { + "SelectorRegexp": "k8s[.]io/kubernetes", + "ForbiddenPrefixes": [ + "" + ] + } + ] +} diff --git a/vendor/k8s.io/apiserver/CONTRIBUTING.md b/vendor/k8s.io/apiserver/CONTRIBUTING.md index 511739f5992..94a28899367 100644 --- a/vendor/k8s.io/apiserver/CONTRIBUTING.md +++ b/vendor/k8s.io/apiserver/CONTRIBUTING.md @@ -4,4 +4,4 @@ Do not open pull requests directly against this repository, they will be ignored This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/apiserver](https://git.k8s.io/kubernetes/staging/src/k8s.io/apiserver) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). -Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/apiserver/Godeps/Godeps.json b/vendor/k8s.io/apiserver/Godeps/Godeps.json index 092951e509f..c1df12b7cd3 100644 --- a/vendor/k8s.io/apiserver/Godeps/Godeps.json +++ b/vendor/k8s.io/apiserver/Godeps/Godeps.json @@ -1,638 +1,2002 @@ { "ImportPath": "k8s.io/apiserver", - "GoVersion": "unknown", - "GodepVersion": "gen-godeps", + "GoVersion": "go1.11", + "GodepVersion": "v80", "Packages": [ "./..." ], "Deps": [ { - "ImportPath": "cloud.google.com/go", - "Rev": "v0.38.0" + "ImportPath": "bitbucket.org/ww/goautoneg", + "Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675" }, { "ImportPath": "github.com/Azure/go-ansiterm", - "Rev": "d6e3b3328b78" + "Rev": "d6e3b3328b783f23731bc4d058875b0371ff8109" }, { - "ImportPath": "github.com/Azure/go-autorest/autorest", - "Rev": "v0.9.6" + "ImportPath": "github.com/Azure/go-ansiterm/winterm", + "Rev": "d6e3b3328b783f23731bc4d058875b0371ff8109" }, { - "ImportPath": "github.com/Azure/go-autorest/autorest/adal", - "Rev": "v0.8.2" + "ImportPath": "github.com/NYTimes/gziphandler", + "Rev": "56545f4a5d46df9a6648819d1664c3a03a13ffdb" }, { - "ImportPath": "github.com/Azure/go-autorest/autorest/date", - "Rev": "v0.2.0" + "ImportPath": "github.com/PuerkitoBio/purell", + "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" }, { - "ImportPath": "github.com/Azure/go-autorest/autorest/mocks", - "Rev": "v0.3.0" + "ImportPath": "github.com/PuerkitoBio/urlesc", + "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" }, { - "ImportPath": "github.com/Azure/go-autorest/logger", - "Rev": "v0.1.0" + "ImportPath": "github.com/beorn7/perks/quantile", + "Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4" }, { - "ImportPath": "github.com/Azure/go-autorest/tracing", - "Rev": "v0.5.0" + "ImportPath": "github.com/coreos/bbolt", + "Rev": "48ea1b39c25fc1bab3506fbc712ecbaa842c4d2d" }, { - "ImportPath": "github.com/BurntSushi/toml", - "Rev": "v0.3.1" + "ImportPath": "github.com/coreos/etcd/alarm", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/NYTimes/gziphandler", - "Rev": "56545f4a5d46" + "ImportPath": "github.com/coreos/etcd/auth", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/PuerkitoBio/purell", - "Rev": "v1.1.1" + "ImportPath": "github.com/coreos/etcd/auth/authpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/PuerkitoBio/urlesc", - "Rev": "de5bf2ad4578" + "ImportPath": "github.com/coreos/etcd/client", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/alecthomas/template", - "Rev": "a0175ee3bccc" + "ImportPath": "github.com/coreos/etcd/clientv3", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/alecthomas/units", - "Rev": "2efee857e7cf" + "ImportPath": "github.com/coreos/etcd/clientv3/concurrency", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/beorn7/perks", - "Rev": "v1.0.0" + "ImportPath": "github.com/coreos/etcd/clientv3/namespace", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/bgentry/speakeasy", - "Rev": "v0.1.0" + "ImportPath": "github.com/coreos/etcd/clientv3/naming", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/blang/semver", - "Rev": "v3.5.0" + "ImportPath": "github.com/coreos/etcd/compactor", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/census-instrumentation/opencensus-proto", - "Rev": "v0.2.1" + "ImportPath": "github.com/coreos/etcd/discovery", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/client9/misspell", - "Rev": "v0.3.4" + "ImportPath": "github.com/coreos/etcd/embed", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/cockroachdb/datadriven", - "Rev": "80d97fb3cbaa" + "ImportPath": "github.com/coreos/etcd/error", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/coreos/go-oidc", - "Rev": "v2.1.0" + "ImportPath": "github.com/coreos/etcd/etcdserver", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/coreos/go-semver", - "Rev": "v0.3.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/api", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/coreos/go-systemd", - "Rev": "95778dfbb74e" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/etcdhttp", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/coreos/pkg", - "Rev": "97fdf19511ea" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/creack/pty", - "Rev": "v1.1.7" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2http/httptypes", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/davecgh/go-spew", - "Rev": "v1.1.1" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v2v3", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/dgrijalva/jwt-go", - "Rev": "v3.2.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3client", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/docker/spdystream", - "Rev": "449fdfce4d96" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3election", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/docopt/docopt-go", - "Rev": "ee0de3bc6815" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3election/v3electionpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/dustin/go-humanize", - "Rev": "v1.0.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3election/v3electionpb/gw", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/elazarl/goproxy", - "Rev": "947c36da3153" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3lock", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/emicklei/go-restful", - "Rev": "v2.9.5" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3lock/v3lockpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/envoyproxy/go-control-plane", - "Rev": "5f8ba28d4473" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3lock/v3lockpb/gw", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/envoyproxy/protoc-gen-validate", - "Rev": "v0.1.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/evanphx/json-patch", - "Rev": "v4.2.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/fatih/color", - "Rev": "v1.7.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/auth", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/fsnotify/fsnotify", - "Rev": "v1.4.9" + "ImportPath": "github.com/coreos/etcd/etcdserver/etcdserverpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" }, { - "ImportPath": "github.com/ghodss/yaml", - "Rev": "v1.0.0" + "ImportPath": "github.com/coreos/etcd/etcdserver/etcdserverpb/gw", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/membership", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/etcdserver/stats", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/integration", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/lease", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/lease/leasehttp", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/lease/leasepb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc/backend", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/mvcc/mvccpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/adt", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/contention", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/cors", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/cpuutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/crc", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/debugutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/fileutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/httputil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/idutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/ioutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/logutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/netutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/pathutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/pbutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/runtime", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/schedule", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/srv", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/testutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/tlsutil", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/transport", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/types", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/pkg/wait", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy/adapter", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/proxy/grpcproxy/cache", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/raft", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/raft/raftpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/rafthttp", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/snap", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/snap/snappb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/store", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/version", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/wal", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/etcd/wal/walpb", + "Rev": "27fc7e2296f506182f58ce846e48f36b34fe6842" + }, + { + "ImportPath": "github.com/coreos/go-oidc", + "Rev": "065b426bd41667456c1a924468f507673629c46b" + }, + { + "ImportPath": "github.com/coreos/go-semver/semver", + "Rev": "e214231b295a8ea9479f11b70b35d5acf3556d9b" + }, + { + "ImportPath": "github.com/coreos/go-systemd/daemon", + "Rev": "39ca1b05acc7ad1220e09f133283b8859a8b71ab" + }, + { + "ImportPath": "github.com/coreos/go-systemd/journal", + "Rev": "39ca1b05acc7ad1220e09f133283b8859a8b71ab" + }, + { + "ImportPath": "github.com/coreos/pkg/capnslog", + "Rev": "97fdf19511ea361ae1c100dd393cc47f8dcfa1e1" + }, + { + "ImportPath": "github.com/davecgh/go-spew/spew", + "Rev": "782f4967f2dc4564575ca782fe2d04090b5faca8" + }, + { + "ImportPath": "github.com/dgrijalva/jwt-go", + "Rev": "01aeca54ebda6e0fbfafd0a524d234159c05ec20" + }, + { + "ImportPath": "github.com/docker/docker/pkg/term", + "Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d" + }, + { + "ImportPath": "github.com/docker/docker/pkg/term/windows", + "Rev": "a9fbbdc8dd8794b20af358382ab780559bca589d" + }, + { + "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/go-kit/kit", - "Rev": "v0.8.0" + "ImportPath": "github.com/emicklei/go-restful/log", + "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" }, { - "ImportPath": "github.com/go-logfmt/logfmt", - "Rev": "v0.3.0" + "ImportPath": "github.com/evanphx/json-patch", + "Rev": "5858425f75500d40c52783dce87d085a483ce135" }, { - "ImportPath": "github.com/go-logr/logr", - "Rev": "v0.1.0" + "ImportPath": "github.com/ghodss/yaml", + "Rev": "c7ce16629ff4cd059ed96ed06419dd3856fd3577" }, { "ImportPath": "github.com/go-openapi/jsonpointer", - "Rev": "v0.19.3" + "Rev": "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" }, { "ImportPath": "github.com/go-openapi/jsonreference", - "Rev": "v0.19.3" + "Rev": "8483a886a90412cd6858df4ea3483dce9c8e35a3" }, { "ImportPath": "github.com/go-openapi/spec", - "Rev": "v0.19.3" + "Rev": "5bae59e25b21498baea7f9d46e9c147ec106a42e" }, { "ImportPath": "github.com/go-openapi/swag", - "Rev": "v0.19.5" + "Rev": "5899d5c5e619fda5fa86e14795a835f473ca284c" }, { - "ImportPath": "github.com/go-stack/stack", - "Rev": "v1.8.0" + "ImportPath": "github.com/gogo/protobuf/gogoproto", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" }, { - "ImportPath": "github.com/gogo/protobuf", - "Rev": "v1.3.1" + "ImportPath": "github.com/gogo/protobuf/proto", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" }, { - "ImportPath": "github.com/golang/glog", - "Rev": "23def4e6c14b" + "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" }, { - "ImportPath": "github.com/golang/groupcache", - "Rev": "02826c3e7903" + "ImportPath": "github.com/gogo/protobuf/sortkeys", + "Rev": "342cbe0a04158f6dcb03ca0079991a51a4248c02" }, { - "ImportPath": "github.com/golang/mock", - "Rev": "v1.2.0" + "ImportPath": "github.com/golang/groupcache/lru", + "Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433" }, { - "ImportPath": "github.com/golang/protobuf", - "Rev": "v1.3.3" + "ImportPath": "github.com/golang/protobuf/jsonpb", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/btree", - "Rev": "v1.0.0" + "ImportPath": "github.com/golang/protobuf/proto", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/go-cmp", - "Rev": "v0.4.0" + "ImportPath": "github.com/golang/protobuf/ptypes", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/gofuzz", - "Rev": "v1.1.0" + "ImportPath": "github.com/golang/protobuf/ptypes/any", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/martian", - "Rev": "v2.1.0" + "ImportPath": "github.com/golang/protobuf/ptypes/duration", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/pprof", - "Rev": "3ea8567a2e57" + "ImportPath": "github.com/golang/protobuf/ptypes/struct", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/google/uuid", - "Rev": "v1.1.1" + "ImportPath": "github.com/golang/protobuf/ptypes/timestamp", + "Rev": "b4deda0973fb4c70b50d226b1af49f3da59f5265" }, { - "ImportPath": "github.com/googleapis/gax-go/v2", - "Rev": "v2.0.4" + "ImportPath": "github.com/google/btree", + "Rev": "7d79101e329e5a3adf994758c578dab82b90c017" + }, + { + "ImportPath": "github.com/google/gofuzz", + "Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c" + }, + { + "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" + }, + { + "ImportPath": "github.com/googleapis/gnostic/compiler", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" }, { - "ImportPath": "github.com/googleapis/gnostic", - "Rev": "v0.4.1" + "ImportPath": "github.com/googleapis/gnostic/extensions", + "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba" }, { "ImportPath": "github.com/gorilla/websocket", - "Rev": "v1.4.0" + "Rev": "4201258b820c74ac8e6922fc9e6b52f71fe46f8d" }, { "ImportPath": "github.com/gregjones/httpcache", - "Rev": "9cad4c3443a7" + "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" + }, + { + "ImportPath": "github.com/gregjones/httpcache/diskcache", + "Rev": "787624de3eb7bd915c329cba748687a3b22666a6" }, { "ImportPath": "github.com/grpc-ecosystem/go-grpc-middleware", - "Rev": "f849b5445de4" + "Rev": "498ae206fc3cfe81cd82e48c1d4354026fa5f9ec" }, { "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", - "Rev": "v1.2.0" + "Rev": "2500245aa6110c562d17020fb31a2c133d737799" }, { - "ImportPath": "github.com/grpc-ecosystem/grpc-gateway", - "Rev": "v1.9.5" + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime", + "Rev": "8cc3a55af3bcf171a1c23a90c4df9cf591706104" }, { - "ImportPath": "github.com/hashicorp/golang-lru", - "Rev": "v0.5.1" + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/runtime/internal", + "Rev": "8cc3a55af3bcf171a1c23a90c4df9cf591706104" }, { - "ImportPath": "github.com/hpcloud/tail", - "Rev": "v1.0.0" + "ImportPath": "github.com/grpc-ecosystem/grpc-gateway/utilities", + "Rev": "8cc3a55af3bcf171a1c23a90c4df9cf591706104" }, { - "ImportPath": "github.com/imdario/mergo", - "Rev": "v0.3.5" + "ImportPath": "github.com/hashicorp/golang-lru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + }, + { + "ImportPath": "github.com/hashicorp/golang-lru/simplelru", + "Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" }, { - "ImportPath": "github.com/inconshreveable/mousetrap", - "Rev": "v1.0.0" + "ImportPath": "github.com/imdario/mergo", + "Rev": "9316a62528ac99aaecb4e47eadd6dc8aa6533d58" }, { "ImportPath": "github.com/jonboulle/clockwork", - "Rev": "v0.1.0" + "Rev": "72f9bd7c4e0c2a40055ab3d0f09654f730cce982" }, { "ImportPath": "github.com/json-iterator/go", - "Rev": "v1.1.8" + "Rev": "ab8a2e0c74be9d3be70b3184d9acc634935ded82" }, { - "ImportPath": "github.com/jstemmer/go-junit-report", - "Rev": "af01ea7f8024" + "ImportPath": "github.com/mailru/easyjson/buffer", + "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" }, { - "ImportPath": "github.com/julienschmidt/httprouter", - "Rev": "v1.2.0" + "ImportPath": "github.com/mailru/easyjson/jlexer", + "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" }, { - "ImportPath": "github.com/kisielk/errcheck", - "Rev": "v1.2.0" + "ImportPath": "github.com/mailru/easyjson/jwriter", + "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" }, { - "ImportPath": "github.com/kisielk/gotool", - "Rev": "v1.0.0" + "ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil", + "Rev": "c12348ce28de40eed0136aa2b644d0ee0650e56c" }, { - "ImportPath": "github.com/konsorten/go-windows-terminal-sequences", - "Rev": "v1.0.2" + "ImportPath": "github.com/modern-go/concurrent", + "Rev": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + }, + { + "ImportPath": "github.com/modern-go/reflect2", + "Rev": "94122c33edd36123c84d5368cfb2b69df93a0ec8" }, { - "ImportPath": "github.com/kr/logfmt", - "Rev": "b84e30acd515" + "ImportPath": "github.com/pborman/uuid", + "Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4" }, { - "ImportPath": "github.com/kr/pretty", - "Rev": "v0.2.0" + "ImportPath": "github.com/peterbourgon/diskv", + "Rev": "5f041e8faa004a95c88a202771f4cc3e991971e6" }, { - "ImportPath": "github.com/kr/pty", - "Rev": "v1.1.5" + "ImportPath": "github.com/pmezard/go-difflib/difflib", + "Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d" }, { - "ImportPath": "github.com/kr/text", - "Rev": "v0.1.0" + "ImportPath": "github.com/pquerna/cachecontrol", + "Rev": "0dec1b30a0215bb68605dfc568e8855066c9202d" }, { - "ImportPath": "github.com/mailru/easyjson", - "Rev": "v0.7.0" + "ImportPath": "github.com/pquerna/cachecontrol/cacheobject", + "Rev": "0dec1b30a0215bb68605dfc568e8855066c9202d" }, { - "ImportPath": "github.com/mattn/go-colorable", - "Rev": "v0.0.9" + "ImportPath": "github.com/prometheus/client_golang/prometheus", + "Rev": "e7e903064f5e9eb5da98208bae10b475d4db0f8c" }, { - "ImportPath": "github.com/mattn/go-isatty", - "Rev": "v0.0.4" + "ImportPath": "github.com/prometheus/client_golang/prometheus/promhttp", + "Rev": "e7e903064f5e9eb5da98208bae10b475d4db0f8c" }, { - "ImportPath": "github.com/mattn/go-runewidth", - "Rev": "v0.0.2" + "ImportPath": "github.com/prometheus/client_model/go", + "Rev": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6" }, { - "ImportPath": "github.com/matttproud/golang_protobuf_extensions", - "Rev": "c182affec369" + "ImportPath": "github.com/prometheus/common/expfmt", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" }, { - "ImportPath": "github.com/moby/term", - "Rev": "672ec06f55cd" + "ImportPath": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" }, { - "ImportPath": "github.com/modern-go/concurrent", - "Rev": "bacd9c7ef1dd" + "ImportPath": "github.com/prometheus/common/model", + "Rev": "13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207" }, { - "ImportPath": "github.com/modern-go/reflect2", - "Rev": "v1.0.1" + "ImportPath": "github.com/prometheus/procfs", + "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" }, { - "ImportPath": "github.com/munnerz/goautoneg", - "Rev": "a7dc8b61c822" + "ImportPath": "github.com/prometheus/procfs/xfs", + "Rev": "65c1f6f8f0fc1e2185eb9863a3bc751496404259" }, { - "ImportPath": "github.com/mwitkow/go-conntrack", - "Rev": "cc309e4a2223" + "ImportPath": "github.com/sirupsen/logrus", + "Rev": "89742aefa4b206dcf400792f3bd35b542998eb3b" }, { - "ImportPath": "github.com/mxk/go-flowrate", - "Rev": "cca7078d478f" + "ImportPath": "github.com/soheilhy/cmux", + "Rev": "bb79a83465015a27a175925ebd155e660f55e9f1" }, { - "ImportPath": "github.com/olekukonko/tablewriter", - "Rev": "a0225b3f23b5" + "ImportPath": "github.com/spf13/pflag", + "Rev": "583c0c0531f06d5278b7d917446061adc344b5cd" }, { - "ImportPath": "github.com/onsi/ginkgo", - "Rev": "v1.11.0" + "ImportPath": "github.com/stretchr/testify/assert", + "Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69" }, { - "ImportPath": "github.com/onsi/gomega", - "Rev": "v1.7.0" + "ImportPath": "github.com/stretchr/testify/require", + "Rev": "c679ae2cc0cb27ec3293fea7e254e47386f05d69" }, { - "ImportPath": "github.com/peterbourgon/diskv", - "Rev": "v2.0.1" + "ImportPath": "github.com/tmc/grpc-websocket-proxy/wsproxy", + "Rev": "89b8d40f7ca833297db804fcb3be53a76d01c238" }, { - "ImportPath": "github.com/pkg/errors", - "Rev": "v0.9.1" + "ImportPath": "github.com/ugorji/go/codec", + "Rev": "bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57" }, { - "ImportPath": "github.com/pmezard/go-difflib", - "Rev": "v1.0.0" + "ImportPath": "github.com/xiang90/probing", + "Rev": "07dd2e8dfe18522e9c447ba95f2fe95262f63bb2" }, { - "ImportPath": "github.com/pquerna/cachecontrol", - "Rev": "0dec1b30a021" + "ImportPath": "go.uber.org/atomic", + "Rev": "8dc6146f7569370a472715e178d8ae31172ee6da" }, { - "ImportPath": "github.com/prometheus/client_golang", - "Rev": "v1.0.0" + "ImportPath": "go.uber.org/multierr", + "Rev": "ddea229ff1dff9e6fe8a6c0344ac73b09e81fce5" }, { - "ImportPath": "github.com/prometheus/client_model", - "Rev": "v0.2.0" + "ImportPath": "go.uber.org/zap", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/prometheus/common", - "Rev": "v0.4.1" + "ImportPath": "go.uber.org/zap/buffer", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/prometheus/procfs", - "Rev": "v0.0.5" + "ImportPath": "go.uber.org/zap/internal/bufferpool", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/rogpeppe/fastuuid", - "Rev": "6724a57986af" + "ImportPath": "go.uber.org/zap/internal/color", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/sirupsen/logrus", - "Rev": "v1.4.2" + "ImportPath": "go.uber.org/zap/internal/exit", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/soheilhy/cmux", - "Rev": "v0.1.4" + "ImportPath": "go.uber.org/zap/zapcore", + "Rev": "67bc79d13d155c02fd008f721863ff8cc5f30659" }, { - "ImportPath": "github.com/spf13/afero", - "Rev": "v1.2.2" + "ImportPath": "golang.org/x/crypto/bcrypt", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/spf13/cobra", - "Rev": "v0.0.3" + "ImportPath": "golang.org/x/crypto/blowfish", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/spf13/pflag", - "Rev": "v1.0.5" + "ImportPath": "golang.org/x/crypto/cryptobyte", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/stretchr/objx", - "Rev": "v0.2.0" + "ImportPath": "golang.org/x/crypto/cryptobyte/asn1", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/stretchr/testify", - "Rev": "v1.4.0" + "ImportPath": "golang.org/x/crypto/ed25519", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/tmc/grpc-websocket-proxy", - "Rev": "89b8d40f7ca8" + "ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/urfave/cli", - "Rev": "v1.20.0" + "ImportPath": "golang.org/x/crypto/internal/subtle", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "github.com/xiang90/probing", - "Rev": "43a291ad63a2" + "ImportPath": "golang.org/x/crypto/nacl/secretbox", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "go.etcd.io/bbolt", - "Rev": "v1.3.3" + "ImportPath": "golang.org/x/crypto/poly1305", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "go.etcd.io/etcd", - "Rev": "e694b7bb0875" + "ImportPath": "golang.org/x/crypto/salsa20/salsa", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "go.opencensus.io", - "Rev": "v0.21.0" + "ImportPath": "golang.org/x/crypto/ssh/terminal", + "Rev": "de0752318171da717af4ce24d0a2e8626afaeb11" }, { - "ImportPath": "go.uber.org/atomic", - "Rev": "v1.3.2" + "ImportPath": "golang.org/x/net/context", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "go.uber.org/multierr", - "Rev": "v1.1.0" + "ImportPath": "golang.org/x/net/http2", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "go.uber.org/zap", - "Rev": "v1.10.0" + "ImportPath": "golang.org/x/net/http2/hpack", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" + }, + { + "ImportPath": "golang.org/x/net/idna", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "golang.org/x/crypto", - "Rev": "bac4c82f6975" + "ImportPath": "golang.org/x/net/internal/timeseries", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "golang.org/x/exp", - "Rev": "509febef88a4" + "ImportPath": "golang.org/x/net/lex/httplex", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "golang.org/x/lint", - "Rev": "d0100b6bd8b3" + "ImportPath": "golang.org/x/net/trace", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { - "ImportPath": "golang.org/x/net", - "Rev": "d3edc9973b7e" + "ImportPath": "golang.org/x/net/websocket", + "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" }, { "ImportPath": "golang.org/x/oauth2", - "Rev": "0f29369cfe45" + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/oauth2/internal", + "Rev": "a6bd8cefa1811bd24b86f8902872e4e8225f74c4" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" }, { - "ImportPath": "golang.org/x/sync", - "Rev": "cd5d95a43a6e" + "ImportPath": "golang.org/x/sys/windows", + "Rev": "95c6576299259db960f6c5b9b69ea52422860fce" }, { - "ImportPath": "golang.org/x/sys", - "Rev": "fde4db37ae7a" + "ImportPath": "golang.org/x/text/cases", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "golang.org/x/text", - "Rev": "v0.3.2" + "ImportPath": "golang.org/x/text/internal", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "golang.org/x/time", - "Rev": "555d28b269f0" + "ImportPath": "golang.org/x/text/internal/tag", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "golang.org/x/tools", - "Rev": "65e3620a7ae7" + "ImportPath": "golang.org/x/text/language", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "golang.org/x/xerrors", - "Rev": "9bdfabe68543" + "ImportPath": "golang.org/x/text/runes", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "google.golang.org/api", - "Rev": "v0.4.0" + "ImportPath": "golang.org/x/text/secure/bidirule", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "google.golang.org/appengine", - "Rev": "v1.5.0" + "ImportPath": "golang.org/x/text/secure/precis", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" }, { - "ImportPath": "google.golang.org/genproto", - "Rev": "f3c370f40bfb" + "ImportPath": "golang.org/x/text/transform", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/unicode/bidi", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/unicode/norm", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/text/width", + "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" + }, + { + "ImportPath": "golang.org/x/time/rate", + "Rev": "f51c12702a4d776e4c1fa9b0fabab841babae631" + }, + { + "ImportPath": "google.golang.org/genproto/googleapis/rpc/status", + "Rev": "09f6ed296fc66555a25fe4ce95173148778dfa85" }, { "ImportPath": "google.golang.org/grpc", - "Rev": "v1.26.0" + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/balancer", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/balancer/base", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/balancer/roundrobin", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" }, { - "ImportPath": "gopkg.in/alecthomas/kingpin.v2", - "Rev": "v2.2.6" + "ImportPath": "google.golang.org/grpc/codes", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" }, { - "ImportPath": "gopkg.in/check.v1", - "Rev": "41f04d3bba15" + "ImportPath": "google.golang.org/grpc/connectivity", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" }, { - "ImportPath": "gopkg.in/cheggaaa/pb.v1", - "Rev": "v1.0.25" + "ImportPath": "google.golang.org/grpc/credentials", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" }, { - "ImportPath": "gopkg.in/fsnotify.v1", - "Rev": "v1.4.7" + "ImportPath": "google.golang.org/grpc/encoding", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/encoding/proto", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/grpclog", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/health", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/health/grpc_health_v1", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/internal", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/internal/backoff", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/internal/channelz", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/internal/grpcrand", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/keepalive", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/metadata", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/naming", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/peer", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/resolver", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/resolver/dns", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/resolver/passthrough", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/stats", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/status", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/tap", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" + }, + { + "ImportPath": "google.golang.org/grpc/transport", + "Rev": "168a6198bcb0ef175f7dacec0b8691fc141dc9b8" }, { "ImportPath": "gopkg.in/inf.v0", - "Rev": "v0.9.1" + "Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" }, { "ImportPath": "gopkg.in/natefinch/lumberjack.v2", - "Rev": "v2.0.0" + "Rev": "20b71e5b60d756d3d2f80def009790325acc2b23" }, { - "ImportPath": "gopkg.in/resty.v1", - "Rev": "v1.12.0" + "ImportPath": "gopkg.in/square/go-jose.v2", + "Rev": "89060dee6a84df9a4dae49f676f0c755037834f1" }, { - "ImportPath": "gopkg.in/square/go-jose.v2", - "Rev": "v2.2.2" + "ImportPath": "gopkg.in/square/go-jose.v2/cipher", + "Rev": "89060dee6a84df9a4dae49f676f0c755037834f1" }, { - "ImportPath": "gopkg.in/tomb.v1", - "Rev": "dd632973f1e7" + "ImportPath": "gopkg.in/square/go-jose.v2/json", + "Rev": "89060dee6a84df9a4dae49f676f0c755037834f1" }, { "ImportPath": "gopkg.in/yaml.v2", - "Rev": "v2.2.8" + "Rev": "5420a8b6744d3b0345ab293f6fcba19c978f1183" }, { - "ImportPath": "gotest.tools", - "Rev": "v2.2.0" + "ImportPath": "k8s.io/api/admission/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "gotest.tools/v3", - "Rev": "v3.0.2" + "ImportPath": "k8s.io/api/admissionregistration/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "honnef.co/go/tools", - "Rev": "ea95bdfd59fc" + "ImportPath": "k8s.io/api/admissionregistration/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/api", - "Rev": "673a95751663" + "ImportPath": "k8s.io/api/apps/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/apimachinery", - "Rev": "15d95c0b2af3" + "ImportPath": "k8s.io/api/apps/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/client-go", - "Rev": "573f9163af85" + "ImportPath": "k8s.io/api/apps/v1beta2", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/component-base", - "Rev": "a40075959cea" + "ImportPath": "k8s.io/api/auditregistration/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/gengo", - "Rev": "0689ccc1d7d6" + "ImportPath": "k8s.io/api/authentication/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" }, { - "ImportPath": "k8s.io/klog", - "Rev": "v1.0.0" + "ImportPath": "k8s.io/api/authentication/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/authorization/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/authorization/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/autoscaling/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/autoscaling/v2beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/autoscaling/v2beta2", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/batch/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/batch/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/batch/v2alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/certificates/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/coordination/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/core/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/events/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/extensions/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/networking/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/policy/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/rbac/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/rbac/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/rbac/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/scheduling/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/scheduling/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/settings/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/storage/v1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/storage/v1alpha1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/api/storage/v1beta1", + "Rev": "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/apitesting", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/fuzzer", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/roundtrip", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/equality", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/errors", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/meta", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/resource", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/validation", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/api/validation/path", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/validation", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/fields", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/labels", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/selection", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/types", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/cache", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/clock", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/diff", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/errors", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/framer", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/intstr", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/json", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/naming", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/net", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/rand", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/runtime", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/sets", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/uuid", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/wait", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/waitgroup", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/util/yaml", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/version", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/pkg/watch", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", + "Rev": "86fb29eff6288413d76bd8506874fddd9fccdff0" + }, + { + "ImportPath": "k8s.io/client-go/discovery", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/discovery/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/dynamic", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/admissionregistration", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/admissionregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/admissionregistration/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/apps/v1beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/auditregistration", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/auditregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling/v2beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/autoscaling/v2beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/batch/v2alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/certificates", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/certificates/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/coordination", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/coordination/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/core", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/core/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/events", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/events/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/extensions", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/extensions/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/internalinterfaces", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/networking", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/networking/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/policy", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/policy/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/rbac/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/scheduling", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/scheduling/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/scheduling/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/settings", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/settings/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/informers/storage/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/scheme", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/apps/v1beta2/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/auditregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/auditregistration/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authentication/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/authorization/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/autoscaling/v2beta2/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/batch/v2alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/certificates/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/coordination/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/coordination/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/core/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/events/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/events/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/networking/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/policy/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/rbac/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/scheduling/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/scheduling/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/settings/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/admissionregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/admissionregistration/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/apps/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/apps/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/apps/v1beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/auditregistration/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/autoscaling/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/autoscaling/v2beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/autoscaling/v2beta2", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/batch/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/batch/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/batch/v2alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/certificates/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/coordination/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/core/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/events/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/extensions/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/networking/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/policy/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/rbac/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/rbac/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/rbac/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/scheduling/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/scheduling/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/settings/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/storage/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/storage/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/listers/storage/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/pkg/version", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/plugin/pkg/client/auth/exec", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/rest", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/rest/watch", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/testing", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/auth", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/cache", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/latest", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/clientcmd/api/v1", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/metrics", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/pager", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/record", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/tools/reference", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/transport", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/buffer", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/cert", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/connrotation", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/flowcontrol", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/homedir", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/integer", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/client-go/util/retry", + "Rev": "b40b2a5939e43f7ffe0028ad67586b7ce50bb675" + }, + { + "ImportPath": "k8s.io/klog", + "Rev": "8139d8cb77af419532b33dfa7dd09fbc5f1d344f" + }, + { + "ImportPath": "k8s.io/kube-openapi/pkg/builder", + "Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d" + }, + { + "ImportPath": "k8s.io/kube-openapi/pkg/common", + "Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d" }, { - "ImportPath": "k8s.io/kube-openapi", - "Rev": "e1beb1bd0f35" + "ImportPath": "k8s.io/kube-openapi/pkg/handler", + "Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d" }, { - "ImportPath": "k8s.io/utils", - "Rev": "a9aa75ae1b89" + "ImportPath": "k8s.io/kube-openapi/pkg/util", + "Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d" }, { - "ImportPath": "sigs.k8s.io/apiserver-network-proxy/konnectivity-client", - "Rev": "v0.0.7" + "ImportPath": "k8s.io/kube-openapi/pkg/util/proto", + "Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d" }, { - "ImportPath": "sigs.k8s.io/structured-merge-diff/v3", - "Rev": "v3.0.0" + "ImportPath": "k8s.io/utils/pointer", + "Rev": "66066c83e385e385ccc3c964b44fd7dcd413d0ed" }, { "ImportPath": "sigs.k8s.io/yaml", - "Rev": "v1.2.0" + "Rev": "fd68e9863619f6ec2fdd8625fe1f02e7c877e480" } ] -} \ No newline at end of file +} diff --git a/vendor/k8s.io/apiserver/Godeps/OWNERS b/vendor/k8s.io/apiserver/Godeps/OWNERS new file mode 100644 index 00000000000..3d49f30605a --- /dev/null +++ b/vendor/k8s.io/apiserver/Godeps/OWNERS @@ -0,0 +1,2 @@ +approvers: +- dep-approvers diff --git a/vendor/k8s.io/apiserver/Godeps/Readme b/vendor/k8s.io/apiserver/Godeps/Readme new file mode 100644 index 00000000000..4cdaa53d56d --- /dev/null +++ b/vendor/k8s.io/apiserver/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/vendor/k8s.io/apiserver/OWNERS b/vendor/k8s.io/apiserver/OWNERS index 2223b2bcd6a..9617c277817 100644 --- a/vendor/k8s.io/apiserver/OWNERS +++ b/vendor/k8s.io/apiserver/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - lavalamp - smarterclayton @@ -19,9 +17,6 @@ reviewers: - enj - hzxuzhonghu - CaoShuFeng -- jennybuckley -- apelisse -- jpbetz labels: - sig/api-machinery - area/apiserver diff --git a/vendor/k8s.io/apiserver/README.md b/vendor/k8s.io/apiserver/README.md index 7a8e78d053f..90160ce911e 100644 --- a/vendor/k8s.io/apiserver/README.md +++ b/vendor/k8s.io/apiserver/README.md @@ -5,7 +5,7 @@ Generic library for building a Kubernetes aggregated API server. ## Purpose -This library contains code to create Kubernetes aggregation server complete with delegated authentication and authorization, +This library contains code to create Kubernetes aggregation server complete with delegated authentication and authorization, `kubectl` compatible discovery information, optional admission chain, and versioned types. It's first consumers are `k8s.io/kubernetes`, `k8s.io/kube-aggregator`, and `github.com/kubernetes-incubator/service-catalog`. diff --git a/vendor/k8s.io/apiserver/SECURITY_CONTACTS b/vendor/k8s.io/apiserver/SECURITY_CONTACTS index 6df6a4d6a16..0648a8ebff7 100644 --- a/vendor/k8s.io/apiserver/SECURITY_CONTACTS +++ b/vendor/k8s.io/apiserver/SECURITY_CONTACTS @@ -1,17 +1,17 @@ # Defined below are the security contacts for this repo. # -# They are the contact point for the Product Security Committee to reach out +# They are the contact point for the Product Security Team to reach out # to for triaging and handling of incoming issues. # # The below names agree to abide by the -# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy) # and will be removed and replaced if they violate that agreement. # # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE # INSTRUCTIONS AT https://kubernetes.io/security/ cjcullen -joelsmith +jessfraz liggitt philips tallclair diff --git a/vendor/k8s.io/apiserver/go.mod b/vendor/k8s.io/apiserver/go.mod deleted file mode 100644 index f016d4a3af0..00000000000 --- a/vendor/k8s.io/apiserver/go.mod +++ /dev/null @@ -1,62 +0,0 @@ -// This is a generated file. Do not edit directly. - -module k8s.io/apiserver - -go 1.13 - -require ( - github.com/coreos/go-oidc v2.1.0+incompatible - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e - github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea - github.com/davecgh/go-spew v1.1.1 - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/emicklei/go-restful v2.9.5+incompatible - github.com/evanphx/json-patch v4.2.0+incompatible - github.com/go-openapi/jsonreference v0.19.3 // indirect - github.com/go-openapi/spec v0.19.3 - github.com/gogo/protobuf v1.3.1 - github.com/google/go-cmp v0.4.0 - github.com/google/gofuzz v1.1.0 - github.com/google/uuid v1.1.1 - github.com/googleapis/gnostic v0.4.1 - github.com/gorilla/websocket v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/hashicorp/golang-lru v0.5.1 - github.com/mailru/easyjson v0.7.0 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 - github.com/pkg/errors v0.9.1 - github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect - github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.4.0 - go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 - go.uber.org/zap v1.10.0 - golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 - golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e - golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd - google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb // indirect - google.golang.org/grpc v1.26.0 - gopkg.in/natefinch/lumberjack.v2 v2.0.0 - gopkg.in/square/go-jose.v2 v2.2.2 - gopkg.in/yaml.v2 v2.2.8 - k8s.io/api v0.0.0-20200501081438-673a95751663 - k8s.io/apimachinery v0.0.0-20200425221929-15d95c0b2af3 - k8s.io/client-go v0.0.0-20200429082053-573f9163af85 - k8s.io/component-base v0.0.0-20200430003135-a40075959cea - k8s.io/klog v1.0.0 - k8s.io/kube-openapi v0.0.0-20200403204345-e1beb1bd0f35 - k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 - sigs.k8s.io/structured-merge-diff/v3 v3.0.0 - sigs.k8s.io/yaml v1.2.0 -) - -replace ( - golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13 - golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13 - k8s.io/api => k8s.io/api v0.0.0-20200501081438-673a95751663 - k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200425221929-15d95c0b2af3 - k8s.io/client-go => k8s.io/client-go v0.0.0-20200429082053-573f9163af85 - k8s.io/component-base => k8s.io/component-base v0.0.0-20200430003135-a40075959cea -) diff --git a/vendor/k8s.io/apiserver/go.sum b/vendor/k8s.io/apiserver/go.sum deleted file mode 100644 index 03ac42313f7..00000000000 --- a/vendor/k8s.io/apiserver/go.sum +++ /dev/null @@ -1,385 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 h1:C7kWARE8r64ppRadl40yfNo6pag+G6ocvGU2xZ6yNes= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb h1:ADPHZzpzM4tk4V4S5cnCrr5SwzvlrPRmqqCuJDB8UTs= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20200501081438-673a95751663/go.mod h1:raky3QQIV2+BF6omFznvh5TLtBeHdXVNLZPfX9Jc9SM= -k8s.io/apimachinery v0.0.0-20200425221929-15d95c0b2af3/go.mod h1:imoz42hIYwpLTRWXU8pdJ9IE8DbxUsnU9lyVN8Y1SNo= -k8s.io/client-go v0.0.0-20200429082053-573f9163af85/go.mod h1:ICJYNJrbQC1/XOy1vJSpjnLO8ngMi32d8XgKSg2FlVU= -k8s.io/component-base v0.0.0-20200430003135-a40075959cea/go.mod h1:On6EhlKc1CoLdfJW1gv6rcDitKkXOuLtMoBhCCshIhk= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200403204345-e1beb1bd0f35 h1:FDWYFE3itI1G8UFOMjUuLbROZExo+Rrfm/Qaf473rm4= -k8s.io/kube-openapi v0.0.0-20200403204345-e1beb1bd0f35/go.mod h1:NwPpO8COeh/j9Q9ModsqBxwHcWDo/PmrJOPyquZCC1A= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 h1:uuHDyjllyzRyCIvvn0OBjiRB0SgBZGqHNYAmjR7fO50= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/vendor/k8s.io/apiserver/pkg/admission/attributes.go b/vendor/k8s.io/apiserver/pkg/admission/attributes.go index 1d291f6b22e..c8973cc629b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/attributes.go +++ b/vendor/k8s.io/apiserver/pkg/admission/attributes.go @@ -24,7 +24,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/authentication/user" ) @@ -35,7 +34,6 @@ type attributesRecord struct { resource schema.GroupVersionResource subresource string operation Operation - options runtime.Object dryRun bool object runtime.Object oldObject runtime.Object @@ -43,31 +41,22 @@ type attributesRecord struct { // other elements are always accessed in single goroutine. // But ValidatingAdmissionWebhook add annotations concurrently. - annotations map[string]annotation + annotations map[string]string annotationsLock sync.RWMutex - - reinvocationContext ReinvocationContext -} - -type annotation struct { - level auditinternal.Level - value string } -func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind schema.GroupVersionKind, namespace, name string, resource schema.GroupVersionResource, subresource string, operation Operation, operationOptions runtime.Object, dryRun bool, userInfo user.Info) Attributes { +func NewAttributesRecord(object runtime.Object, oldObject runtime.Object, kind schema.GroupVersionKind, namespace, name string, resource schema.GroupVersionResource, subresource string, operation Operation, dryRun bool, userInfo user.Info) Attributes { return &attributesRecord{ - kind: kind, - namespace: namespace, - name: name, - resource: resource, - subresource: subresource, - operation: operation, - options: operationOptions, - dryRun: dryRun, - object: object, - oldObject: oldObject, - userInfo: userInfo, - reinvocationContext: &reinvocationContext{}, + kind: kind, + namespace: namespace, + name: name, + resource: resource, + subresource: subresource, + operation: operation, + dryRun: dryRun, + object: object, + oldObject: oldObject, + userInfo: userInfo, } } @@ -95,10 +84,6 @@ func (record *attributesRecord) GetOperation() Operation { return record.operation } -func (record *attributesRecord) GetOperationOptions() runtime.Object { - return record.options -} - func (record *attributesRecord) IsDryRun() bool { return record.dryRun } @@ -117,7 +102,7 @@ func (record *attributesRecord) GetUserInfo() user.Info { // getAnnotations implements privateAnnotationsGetter.It's a private method used // by WithAudit decorator. -func (record *attributesRecord) getAnnotations(maxLevel auditinternal.Level) map[string]string { +func (record *attributesRecord) getAnnotations() map[string]string { record.annotationsLock.RLock() defer record.annotationsLock.RUnlock() @@ -126,79 +111,29 @@ func (record *attributesRecord) getAnnotations(maxLevel auditinternal.Level) map } cp := make(map[string]string, len(record.annotations)) for key, value := range record.annotations { - if value.level.Less(maxLevel) || value.level == maxLevel { - cp[key] = value.value - } + cp[key] = value } return cp } -// AddAnnotation adds an annotation to attributesRecord with Metadata audit level func (record *attributesRecord) AddAnnotation(key, value string) error { - return record.AddAnnotationWithLevel(key, value, auditinternal.LevelMetadata) -} - -func (record *attributesRecord) AddAnnotationWithLevel(key, value string, level auditinternal.Level) error { if err := checkKeyFormat(key); err != nil { return err } - if level.Less(auditinternal.LevelMetadata) { - return fmt.Errorf("admission annotations are not allowed to be set at audit level lower than Metadata, key: %q, level: %s", key, level) - } + record.annotationsLock.Lock() defer record.annotationsLock.Unlock() if record.annotations == nil { - record.annotations = make(map[string]annotation) + record.annotations = make(map[string]string) } - annotation := annotation{level: level, value: value} - if v, ok := record.annotations[key]; ok && v != annotation { - return fmt.Errorf("admission annotations are not allowd to be overwritten, key:%q, old value: %v, new value: %v", key, record.annotations[key], annotation) + if v, ok := record.annotations[key]; ok && v != value { + return fmt.Errorf("admission annotations are not allowd to be overwritten, key:%q, old value: %q, new value:%q", key, record.annotations[key], value) } - record.annotations[key] = annotation + record.annotations[key] = value return nil } -func (record *attributesRecord) GetReinvocationContext() ReinvocationContext { - return record.reinvocationContext -} - -type reinvocationContext struct { - // isReinvoke is true when admission plugins are being reinvoked - isReinvoke bool - // reinvokeRequested is true when an admission plugin requested a re-invocation of the chain - reinvokeRequested bool - // values stores reinvoke context values per plugin. - values map[string]interface{} -} - -func (rc *reinvocationContext) IsReinvoke() bool { - return rc.isReinvoke -} - -func (rc *reinvocationContext) SetIsReinvoke() { - rc.isReinvoke = true -} - -func (rc *reinvocationContext) ShouldReinvoke() bool { - return rc.reinvokeRequested -} - -func (rc *reinvocationContext) SetShouldReinvoke() { - rc.reinvokeRequested = true -} - -func (rc *reinvocationContext) SetValue(plugin string, v interface{}) { - if rc.values == nil { - rc.values = map[string]interface{}{} - } - rc.values[plugin] = v -} - -func (rc *reinvocationContext) Value(plugin string) interface{} { - return rc.values[plugin] -} - func checkKeyFormat(key string) error { parts := strings.Split(key, "/") if len(parts) != 2 { diff --git a/vendor/k8s.io/apiserver/pkg/admission/attributes_test.go b/vendor/k8s.io/apiserver/pkg/admission/attributes_test.go index d4f886e30f9..d54780d9998 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/attributes_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/attributes_test.go @@ -20,7 +20,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - auditinternal "k8s.io/apiserver/pkg/apis/audit" ) func TestAddAnnotation(t *testing.T) { @@ -29,13 +28,13 @@ func TestAddAnnotation(t *testing.T) { // test AddAnnotation attr.AddAnnotation("podsecuritypolicy.admission.k8s.io/validate-policy", "privileged") attr.AddAnnotation("podsecuritypolicy.admission.k8s.io/admit-policy", "privileged") - annotations := attr.getAnnotations(auditinternal.LevelMetadata) + annotations := attr.getAnnotations() assert.Equal(t, annotations["podsecuritypolicy.admission.k8s.io/validate-policy"], "privileged") // test overwrite assert.Error(t, attr.AddAnnotation("podsecuritypolicy.admission.k8s.io/validate-policy", "privileged-overwrite"), "admission annotations should not be allowd to be overwritten") - annotations = attr.getAnnotations(auditinternal.LevelMetadata) + annotations = attr.getAnnotations() assert.Equal(t, annotations["podsecuritypolicy.admission.k8s.io/validate-policy"], "privileged", "admission annotations should not be overwritten") // test invalid plugin names @@ -48,7 +47,7 @@ func TestAddAnnotation(t *testing.T) { for name, invalidKey := range testCases { err := attr.AddAnnotation(invalidKey, "value-foo") assert.Error(t, err) - annotations = attr.getAnnotations(auditinternal.LevelMetadata) + annotations = attr.getAnnotations() assert.Equal(t, annotations[invalidKey], "", name+": invalid pluginName is not allowed ") } diff --git a/vendor/k8s.io/apiserver/pkg/admission/audit.go b/vendor/k8s.io/apiserver/pkg/admission/audit.go index d1e103cfc62..13d86b33b96 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/audit.go +++ b/vendor/k8s.io/apiserver/pkg/admission/audit.go @@ -17,7 +17,6 @@ limitations under the License. package admission import ( - "context" "fmt" auditinternal "k8s.io/apiserver/pkg/apis/audit" @@ -45,7 +44,7 @@ func WithAudit(i Interface, ae *auditinternal.Event) Interface { return &auditHandler{i, ae} } -func (handler auditHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (handler auditHandler) Admit(a Attributes) error { if !handler.Interface.Handles(a.GetOperation()) { return nil } @@ -54,13 +53,13 @@ func (handler auditHandler) Admit(ctx context.Context, a Attributes, o ObjectInt } var err error if mutator, ok := handler.Interface.(MutationInterface); ok { - err = mutator.Admit(ctx, a, o) + err = mutator.Admit(a) handler.logAnnotations(a) } return err } -func (handler auditHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (handler auditHandler) Validate(a Attributes) error { if !handler.Interface.Handles(a.GetOperation()) { return nil } @@ -69,7 +68,7 @@ func (handler auditHandler) Validate(ctx context.Context, a Attributes, o Object } var err error if validator, ok := handler.Interface.(ValidationInterface); ok { - err = validator.Validate(ctx, a, o) + err = validator.Validate(a) handler.logAnnotations(a) } return err @@ -85,18 +84,11 @@ func ensureAnnotationGetter(a Attributes) error { } func (handler auditHandler) logAnnotations(a Attributes) { - if handler.ae == nil { - return - } switch a := a.(type) { case privateAnnotationsGetter: - for key, value := range a.getAnnotations(handler.ae.Level) { - audit.LogAnnotation(handler.ae, key, value) - } + audit.LogAnnotations(handler.ae, a.getAnnotations()) case AnnotationsGetter: - for key, value := range a.GetAnnotations(handler.ae.Level) { - audit.LogAnnotation(handler.ae, key, value) - } + audit.LogAnnotations(handler.ae, a.GetAnnotations()) default: // this will never happen, because we have already checked it in ensureAnnotationGetter } diff --git a/vendor/k8s.io/apiserver/pkg/admission/audit_test.go b/vendor/k8s.io/apiserver/pkg/admission/audit_test.go index 3e1d3d20126..2dd88e9c9f4 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/audit_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/audit_test.go @@ -17,7 +17,6 @@ limitations under the License. package admission import ( - "context" "fmt" "testing" @@ -46,14 +45,14 @@ var _ Interface = &fakeHandler{} var _ MutationInterface = &fakeHandler{} var _ ValidationInterface = &fakeHandler{} -func (h fakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (h fakeHandler) Admit(a Attributes) error { for k, v := range h.admitAnnotations { a.AddAnnotation(k, v) } return h.admit } -func (h fakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (h fakeHandler) Validate(a Attributes) error { for k, v := range h.validateAnnotations { a.AddAnnotation(k, v) } @@ -65,7 +64,7 @@ func (h fakeHandler) Handles(o Operation) bool { } func attributes() Attributes { - return NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", nil, false, nil) + return NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", false, nil) } func TestWithAudit(t *testing.T) { @@ -150,13 +149,13 @@ func TestWithAudit(t *testing.T) { require.True(t, ok) auditMutator, ok := auditHandler.(MutationInterface) require.True(t, ok) - assert.Equal(t, mutator.Admit(context.TODO(), a, nil), auditMutator.Admit(context.TODO(), a, nil), tcName+": WithAudit decorator should not effect the return value") + assert.Equal(t, mutator.Admit(a), auditMutator.Admit(a), tcName+": WithAudit decorator should not effect the return value") validator, ok := handler.(ValidationInterface) require.True(t, ok) auditValidator, ok := auditHandler.(ValidationInterface) require.True(t, ok) - assert.Equal(t, validator.Validate(context.TODO(), a, nil), auditValidator.Validate(context.TODO(), a, nil), tcName+": WithAudit decorator should not effect the return value") + assert.Equal(t, validator.Validate(a), auditValidator.Validate(a), tcName+": WithAudit decorator should not effect the return value") annotations := make(map[string]string, len(tc.admitAnnotations)+len(tc.validateAnnotations)) for k, v := range tc.admitAnnotations { diff --git a/vendor/k8s.io/apiserver/pkg/admission/chain.go b/vendor/k8s.io/apiserver/pkg/admission/chain.go index f2af01ef3c5..011641ff065 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/chain.go +++ b/vendor/k8s.io/apiserver/pkg/admission/chain.go @@ -16,8 +16,6 @@ limitations under the License. package admission -import "context" - // chainAdmissionHandler is an instance of admission.NamedHandler that performs admission control using // a chain of admission handlers type chainAdmissionHandler []Interface @@ -28,13 +26,13 @@ func NewChainHandler(handlers ...Interface) chainAdmissionHandler { } // Admit performs an admission control check using a chain of handlers, and returns immediately on first error -func (admissionHandler chainAdmissionHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (admissionHandler chainAdmissionHandler) Admit(a Attributes) error { for _, handler := range admissionHandler { if !handler.Handles(a.GetOperation()) { continue } if mutator, ok := handler.(MutationInterface); ok { - err := mutator.Admit(ctx, a, o) + err := mutator.Admit(a) if err != nil { return err } @@ -44,13 +42,13 @@ func (admissionHandler chainAdmissionHandler) Admit(ctx context.Context, a Attri } // Validate performs an admission control check using a chain of handlers, and returns immediately on first error -func (admissionHandler chainAdmissionHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { +func (admissionHandler chainAdmissionHandler) Validate(a Attributes) error { for _, handler := range admissionHandler { if !handler.Handles(a.GetOperation()) { continue } if validator, ok := handler.(ValidationInterface); ok { - err := validator.Validate(ctx, a, o) + err := validator.Validate(a) if err != nil { return err } diff --git a/vendor/k8s.io/apiserver/pkg/admission/chain_test.go b/vendor/k8s.io/apiserver/pkg/admission/chain_test.go index ec72a28ad51..7c3d940e1ed 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/chain_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/chain_test.go @@ -17,12 +17,10 @@ limitations under the License. package admission import ( - "context" "fmt" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -33,7 +31,7 @@ type FakeHandler struct { validate, validateCalled bool } -func (h *FakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { +func (h *FakeHandler) Admit(a Attributes) (err error) { h.admitCalled = true if h.admit { return nil @@ -41,7 +39,7 @@ func (h *FakeHandler) Admit(ctx context.Context, a Attributes, o ObjectInterface return fmt.Errorf("Don't admit") } -func (h *FakeHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) { +func (h *FakeHandler) Validate(a Attributes) (err error) { h.validateCalled = true if h.validate { return nil @@ -65,7 +63,6 @@ func TestAdmitAndValidate(t *testing.T) { name string ns string operation Operation - options runtime.Object chain chainAdmissionHandler accept bool calls map[string]bool @@ -74,7 +71,6 @@ func TestAdmitAndValidate(t *testing.T) { name: "all accept", ns: sysns, operation: Create, - options: &metav1.CreateOptions{}, chain: []Interface{ makeHandler("a", true, Update, Delete, Create), makeHandler("b", true, Delete, Create), @@ -87,7 +83,6 @@ func TestAdmitAndValidate(t *testing.T) { name: "ignore handler", ns: otherns, operation: Create, - options: &metav1.CreateOptions{}, chain: []Interface{ makeHandler("a", true, Update, Delete, Create), makeHandler("b", false, Delete), @@ -100,7 +95,6 @@ func TestAdmitAndValidate(t *testing.T) { name: "ignore all", ns: sysns, operation: Connect, - options: nil, chain: []Interface{ makeHandler("a", true, Update, Delete, Create), makeHandler("b", false, Delete), @@ -113,7 +107,6 @@ func TestAdmitAndValidate(t *testing.T) { name: "reject one", ns: otherns, operation: Delete, - options: &metav1.DeleteOptions{}, chain: []Interface{ makeHandler("a", true, Update, Delete, Create), makeHandler("b", false, Delete), @@ -126,7 +119,7 @@ func TestAdmitAndValidate(t *testing.T) { for _, test := range tests { t.Logf("testcase = %s", test.name) // call admit and check that validate was not called at all - err := test.chain.Admit(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) + err := test.chain.Admit(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) accepted := (err == nil) if accepted != test.accept { t.Errorf("unexpected result of admit call: %v", accepted) @@ -147,7 +140,7 @@ func TestAdmitAndValidate(t *testing.T) { } // call validate and check that admit was not called at all - err = test.chain.Validate(context.TODO(), NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) + err = test.chain.Validate(NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) accepted = (err == nil) if accepted != test.accept { t.Errorf("unexpected result of validate call: %v\n", accepted) diff --git a/vendor/k8s.io/apiserver/pkg/admission/config.go b/vendor/k8s.io/apiserver/pkg/admission/config.go index fb8226ca8de..ffda2f3262c 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/config.go +++ b/vendor/k8s.io/apiserver/pkg/admission/config.go @@ -32,7 +32,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/apis/apiserver" - apiserverv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" + apiserverv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" ) func makeAbs(path, base string) (string, error) { @@ -87,6 +87,7 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string, con } return configProvider{ config: decodedConfig, + scheme: configScheme, }, nil } // we got an error where the decode wasn't related to a missing type @@ -110,11 +111,11 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string, con // previously read input from a non-versioned file configuration to the // current input file. legacyPluginsWithUnversionedConfig := sets.NewString("ImagePolicyWebhook", "PodNodeSelector") - externalConfig := &apiserverv1.AdmissionConfiguration{} + externalConfig := &apiserverv1alpha1.AdmissionConfiguration{} for _, pluginName := range pluginNames { if legacyPluginsWithUnversionedConfig.Has(pluginName) { externalConfig.Plugins = append(externalConfig.Plugins, - apiserverv1.AdmissionPluginConfiguration{ + apiserverv1alpha1.AdmissionPluginConfiguration{ Name: pluginName, Path: configFilePath}) } @@ -126,11 +127,13 @@ func ReadAdmissionConfiguration(pluginNames []string, configFilePath string, con } return configProvider{ config: internalConfig, + scheme: configScheme, }, nil } type configProvider struct { config *apiserver.AdmissionConfiguration + scheme *runtime.Scheme } // GetAdmissionPluginConfigurationFor returns a reader that holds the admission plugin configuration. diff --git a/vendor/k8s.io/apiserver/pkg/admission/config_test.go b/vendor/k8s.io/apiserver/pkg/admission/config_test.go index 4cccc91fad1..6e6ec449b06 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/config_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/config_test.go @@ -27,7 +27,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/json" "k8s.io/apiserver/pkg/apis/apiserver" - apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" ) @@ -77,48 +76,6 @@ func TestReadAdmissionConfiguration(t *testing.T) { ConfigBody: `{ "apiVersion": "apiserver.k8s.io/v1alpha1", "kind": "AdmissionConfiguration", -"plugins": [ - {"name": "ImagePolicyWebhook", "path": "/tmp/image-policy-webhook.json"}, - {"name": "ResourceQuota"} -]}`, - ExpectedAdmissionConfig: &apiserver.AdmissionConfiguration{ - Plugins: []apiserver.AdmissionPluginConfiguration{ - { - Name: "ImagePolicyWebhook", - Path: "/tmp/image-policy-webhook.json", - }, - { - Name: "ResourceQuota", - }, - }, - }, - PluginNames: []string{}, - }, - "v1 configuration - path fixup": { - ConfigBody: `{ -"apiVersion": "apiserver.config.k8s.io/v1", -"kind": "AdmissionConfiguration", -"plugins": [ - {"name": "ImagePolicyWebhook", "path": "image-policy-webhook.json"}, - {"name": "ResourceQuota"} -]}`, - ExpectedAdmissionConfig: &apiserver.AdmissionConfiguration{ - Plugins: []apiserver.AdmissionPluginConfiguration{ - { - Name: "ImagePolicyWebhook", - Path: imagePolicyWebhookFile, - }, - { - Name: "ResourceQuota", - }, - }, - }, - PluginNames: []string{}, - }, - "v1 configuration - abspath": { - ConfigBody: `{ -"apiVersion": "apiserver.config.k8s.io/v1", -"kind": "AdmissionConfiguration", "plugins": [ {"name": "ImagePolicyWebhook", "path": "/tmp/image-policy-webhook.json"}, {"name": "ResourceQuota"} @@ -184,7 +141,6 @@ func TestReadAdmissionConfiguration(t *testing.T) { scheme := runtime.NewScheme() require.NoError(t, apiserver.AddToScheme(scheme)) require.NoError(t, apiserverapiv1alpha1.AddToScheme(scheme)) - require.NoError(t, apiserverapiv1.AddToScheme(scheme)) for testName, testCase := range testCases { if err = ioutil.WriteFile(configFileName, []byte(testCase.ConfigBody), 0644); err != nil { @@ -215,7 +171,7 @@ func TestEmbeddedConfiguration(t *testing.T) { ConfigBody string ExpectedConfig string }{ - "v1alpha1 versioned configuration": { + "versioned configuration": { ConfigBody: `{ "apiVersion": "apiserver.k8s.io/v1alpha1", "kind": "AdmissionConfiguration", @@ -235,7 +191,7 @@ func TestEmbeddedConfiguration(t *testing.T) { "foo": "bar" }`, }, - "v1alpha1 legacy configuration": { + "legacy configuration": { ConfigBody: `{ "apiVersion": "apiserver.k8s.io/v1alpha1", "kind": "AdmissionConfiguration", @@ -251,49 +207,12 @@ func TestEmbeddedConfiguration(t *testing.T) { "foo": "bar" }`, }, - "v1 versioned configuration": { - ConfigBody: `{ - "apiVersion": "apiserver.config.k8s.io/v1", - "kind": "AdmissionConfiguration", - "plugins": [ - { - "name": "Foo", - "configuration": { - "apiVersion": "foo.admission.k8s.io/v1alpha1", - "kind": "Configuration", - "foo": "bar" - } - } - ]}`, - ExpectedConfig: `{ - "apiVersion": "foo.admission.k8s.io/v1alpha1", - "kind": "Configuration", - "foo": "bar" - }`, - }, - "v1 legacy configuration": { - ConfigBody: `{ - "apiVersion": "apiserver.config.k8s.io/v1", - "kind": "AdmissionConfiguration", - "plugins": [ - { - "name": "Foo", - "configuration": { - "foo": "bar" - } - } - ]}`, - ExpectedConfig: `{ - "foo": "bar" - }`, - }, } for desc, test := range testCases { scheme := runtime.NewScheme() require.NoError(t, apiserver.AddToScheme(scheme)) require.NoError(t, apiserverapiv1alpha1.AddToScheme(scheme)) - require.NoError(t, apiserverapiv1.AddToScheme(scheme)) if err = ioutil.WriteFile(configFileName, []byte(test.ConfigBody), 0644); err != nil { t.Errorf("[%s] unexpected err writing temp file: %v", desc, err) diff --git a/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager.go new file mode 100644 index 00000000000..f2b7e909942 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager.go @@ -0,0 +1,88 @@ +/* +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 ( + "fmt" + "reflect" + "sort" + + "k8s.io/klog" + + "k8s.io/api/admissionregistration/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type InitializerConfigurationLister interface { + List(opts metav1.ListOptions) (*v1alpha1.InitializerConfigurationList, error) +} + +type InitializerConfigurationManager struct { + *poller +} + +func NewInitializerConfigurationManager(c InitializerConfigurationLister) *InitializerConfigurationManager { + getFn := func() (runtime.Object, error) { + list, err := c.List(metav1.ListOptions{}) + if err != nil { + if errors.IsNotFound(err) || errors.IsForbidden(err) { + klog.V(5).Infof("Initializers are disabled due to an error: %v", err) + return nil, ErrDisabled + } + return nil, err + } + return mergeInitializerConfigurations(list), nil + } + return &InitializerConfigurationManager{ + newPoller(getFn), + } +} + +// Initializers returns the merged InitializerConfiguration. +func (im *InitializerConfigurationManager) Initializers() (*v1alpha1.InitializerConfiguration, error) { + configuration, err := im.poller.configuration() + if err != nil { + return nil, err + } + initializerConfiguration, ok := configuration.(*v1alpha1.InitializerConfiguration) + if !ok { + return nil, fmt.Errorf("expected type %v, got type %v", reflect.TypeOf(initializerConfiguration), reflect.TypeOf(configuration)) + } + return initializerConfiguration, nil +} + +func (im *InitializerConfigurationManager) Run(stopCh <-chan struct{}) { + im.poller.Run(stopCh) +} + +func mergeInitializerConfigurations(initializerConfigurationList *v1alpha1.InitializerConfigurationList) *v1alpha1.InitializerConfiguration { + configurations := initializerConfigurationList.Items + sort.SliceStable(configurations, InitializerConfigurationSorter(configurations).ByName) + var ret v1alpha1.InitializerConfiguration + for _, c := range configurations { + ret.Initializers = append(ret.Initializers, c.Initializers...) + } + return &ret +} + +type InitializerConfigurationSorter []v1alpha1.InitializerConfiguration + +func (a InitializerConfigurationSorter) ByName(i, j int) bool { + return a[i].Name < a[j].Name +} diff --git a/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager_test.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager_test.go new file mode 100644 index 00000000000..783e67a5b7b --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/initializer_manager_test.go @@ -0,0 +1,182 @@ +/* +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 ( + "fmt" + "reflect" + "testing" + "time" + + "k8s.io/api/admissionregistration/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type mockLister struct { + invoked int + successes int + failures int + configurationList v1alpha1.InitializerConfigurationList + t *testing.T +} + +func newMockLister(successes, failures int, configurationList v1alpha1.InitializerConfigurationList, t *testing.T) *mockLister { + return &mockLister{ + failures: failures, + successes: successes, + configurationList: configurationList, + t: t, + } +} + +// The first List will be successful; the next m.failures List will +// fail; the next m.successes List will be successful +// List should only be called 1+m.failures+m.successes times. +func (m *mockLister) List(options metav1.ListOptions) (*v1alpha1.InitializerConfigurationList, error) { + m.invoked++ + if m.invoked == 1 { + return &m.configurationList, nil + } + if m.invoked <= 1+m.failures { + return nil, fmt.Errorf("some error") + } + if m.invoked <= 1+m.failures+m.successes { + return &m.configurationList, nil + } + m.t.Fatalf("unexpected call to List, should only be called %d times", 1+m.successes+m.failures) + return nil, nil +} + +var _ InitializerConfigurationLister = &mockLister{} + +func TestConfiguration(t *testing.T) { + cases := []struct { + name string + failures int + // note that the first call to mockLister is always a success. + successes int + expectReady bool + }{ + { + name: "number of failures hasn't reached failureThreshold", + failures: defaultFailureThreshold - 1, + expectReady: true, + }, + { + name: "number of failures just reaches failureThreshold", + failures: defaultFailureThreshold, + expectReady: false, + }, + { + name: "number of failures exceeds failureThreshold", + failures: defaultFailureThreshold + 1, + expectReady: false, + }, + { + name: "number of failures exceeds failureThreshold, but then get another success", + failures: defaultFailureThreshold + 1, + successes: 1, + expectReady: true, + }, + } + for _, c := range cases { + mock := newMockLister(c.successes, c.failures, v1alpha1.InitializerConfigurationList{}, t) + manager := NewInitializerConfigurationManager(mock) + manager.interval = 1 * time.Millisecond + for i := 0; i < 1+c.successes+c.failures; i++ { + manager.sync() + } + _, err := manager.Initializers() + if err != nil && c.expectReady { + t.Errorf("case %s, expect ready, got: %v", c.name, err) + } + if err == nil && !c.expectReady { + t.Errorf("case %s, expect not ready", c.name) + } + } +} + +func TestMergeInitializerConfigurations(t *testing.T) { + configurationsList := v1alpha1.InitializerConfigurationList{ + Items: []v1alpha1.InitializerConfiguration{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "provider_2", + }, + Initializers: []v1alpha1.Initializer{ + { + Name: "initializer_a", + }, + { + Name: "initializer_b", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "provider_1", + }, + Initializers: []v1alpha1.Initializer{ + { + Name: "initializer_c", + }, + { + Name: "initializer_d", + }, + }, + }, + }, + } + + expected := &v1alpha1.InitializerConfiguration{ + Initializers: []v1alpha1.Initializer{ + { + Name: "initializer_c", + }, + { + Name: "initializer_d", + }, + { + Name: "initializer_a", + }, + { + Name: "initializer_b", + }, + }, + } + + got := mergeInitializerConfigurations(&configurationsList) + if !reflect.DeepEqual(got, expected) { + 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/apiserver/pkg/admission/configuration/mutating_webhook_manager.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager.go index d9b28ad7856..4b2256e118b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager.go +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager.go @@ -21,13 +21,12 @@ import ( "sort" "sync/atomic" - "k8s.io/api/admissionregistration/v1" + "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/labels" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/admission/plugin/webhook" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" "k8s.io/client-go/informers" - admissionregistrationlisters "k8s.io/client-go/listers/admissionregistration/v1" + admissionregistrationlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" "k8s.io/client-go/tools/cache" ) @@ -41,7 +40,7 @@ type mutatingWebhookConfigurationManager struct { var _ generic.Source = &mutatingWebhookConfigurationManager{} func NewMutatingWebhookConfigurationManager(f informers.SharedInformerFactory) generic.Source { - informer := f.Admissionregistration().V1().MutatingWebhookConfigurations() + informer := f.Admissionregistration().V1beta1().MutatingWebhookConfigurations() manager := &mutatingWebhookConfigurationManager{ configuration: &atomic.Value{}, lister: informer.Lister(), @@ -49,7 +48,7 @@ func NewMutatingWebhookConfigurationManager(f informers.SharedInformerFactory) g } // Start with an empty list - manager.configuration.Store([]webhook.WebhookAccessor{}) + manager.configuration.Store(&v1beta1.MutatingWebhookConfiguration{}) // On any change, rebuild the config informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -62,8 +61,8 @@ func NewMutatingWebhookConfigurationManager(f informers.SharedInformerFactory) g } // Webhooks returns the merged MutatingWebhookConfiguration. -func (m *mutatingWebhookConfigurationManager) Webhooks() []webhook.WebhookAccessor { - return m.configuration.Load().([]webhook.WebhookAccessor) +func (m *mutatingWebhookConfigurationManager) Webhooks() []v1beta1.Webhook { + return m.configuration.Load().(*v1beta1.MutatingWebhookConfiguration).Webhooks } func (m *mutatingWebhookConfigurationManager) HasSynced() bool { @@ -79,27 +78,19 @@ func (m *mutatingWebhookConfigurationManager) updateConfiguration() { m.configuration.Store(mergeMutatingWebhookConfigurations(configurations)) } -func mergeMutatingWebhookConfigurations(configurations []*v1.MutatingWebhookConfiguration) []webhook.WebhookAccessor { +func mergeMutatingWebhookConfigurations(configurations []*v1beta1.MutatingWebhookConfiguration) *v1beta1.MutatingWebhookConfiguration { + var ret v1beta1.MutatingWebhookConfiguration // The internal order of webhooks for each configuration is provided by the user // but configurations themselves can be in any order. As we are going to run these // webhooks in serial, they are sorted here to have a deterministic order. sort.SliceStable(configurations, MutatingWebhookConfigurationSorter(configurations).ByName) - accessors := []webhook.WebhookAccessor{} for _, c := range configurations { - // webhook names are not validated for uniqueness, so we check for duplicates and - // add a int suffix to distinguish between them - names := map[string]int{} - for i := range c.Webhooks { - n := c.Webhooks[i].Name - uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n]) - names[n]++ - accessors = append(accessors, webhook.NewMutatingWebhookAccessor(uid, c.Name, &c.Webhooks[i])) - } + ret.Webhooks = append(ret.Webhooks, c.Webhooks...) } - return accessors + return &ret } -type MutatingWebhookConfigurationSorter []*v1.MutatingWebhookConfiguration +type MutatingWebhookConfigurationSorter []*v1beta1.MutatingWebhookConfiguration func (a MutatingWebhookConfigurationSorter) ByName(i, j int) bool { return a[i].Name < a[j].Name diff --git a/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager_test.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager_test.go index 398f47b5827..9bc037f5a40 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/mutating_webhook_manager_test.go @@ -20,7 +20,7 @@ import ( "reflect" "testing" - "k8s.io/api/admissionregistration/v1" + "k8s.io/api/admissionregistration/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" @@ -43,12 +43,12 @@ func TestGetMutatingWebhookConfig(t *testing.T) { t.Errorf("expected empty webhooks, but got %v", configurations) } - webhookConfiguration := &v1.MutatingWebhookConfiguration{ + webhookConfiguration := &v1beta1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{Name: "webhook1"}, - Webhooks: []v1.MutatingWebhook{{Name: "webhook1.1"}}, + Webhooks: []v1beta1.Webhook{{Name: "webhook1.1"}}, } - mutatingInformer := informerFactory.Admissionregistration().V1().MutatingWebhookConfigurations() + mutatingInformer := informerFactory.Admissionregistration().V1beta1().MutatingWebhookConfigurations() mutatingInformer.Informer().GetIndexer().Add(webhookConfiguration) configManager.updateConfiguration() @@ -57,14 +57,7 @@ func TestGetMutatingWebhookConfig(t *testing.T) { if len(configurations) == 0 { t.Errorf("expected non empty webhooks") } - for i := range configurations { - h, ok := configurations[i].GetMutatingWebhook() - if !ok { - t.Errorf("Expected mutating webhook") - continue - } - if !reflect.DeepEqual(h, &webhookConfiguration.Webhooks[i]) { - t.Errorf("Expected\n%#v\ngot\n%#v", &webhookConfiguration.Webhooks[i], h) - } + if !reflect.DeepEqual(configurations, webhookConfiguration.Webhooks) { + t.Errorf("Expected\n%#v\ngot\n%#v", webhookConfiguration.Webhooks, configurations) } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager.go index 37062b082e1..9258258f64b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager.go +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager.go @@ -21,13 +21,12 @@ import ( "sort" "sync/atomic" - "k8s.io/api/admissionregistration/v1" + "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/labels" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/admission/plugin/webhook" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" "k8s.io/client-go/informers" - admissionregistrationlisters "k8s.io/client-go/listers/admissionregistration/v1" + admissionregistrationlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" "k8s.io/client-go/tools/cache" ) @@ -41,7 +40,7 @@ type validatingWebhookConfigurationManager struct { var _ generic.Source = &validatingWebhookConfigurationManager{} func NewValidatingWebhookConfigurationManager(f informers.SharedInformerFactory) generic.Source { - informer := f.Admissionregistration().V1().ValidatingWebhookConfigurations() + informer := f.Admissionregistration().V1beta1().ValidatingWebhookConfigurations() manager := &validatingWebhookConfigurationManager{ configuration: &atomic.Value{}, lister: informer.Lister(), @@ -49,7 +48,7 @@ func NewValidatingWebhookConfigurationManager(f informers.SharedInformerFactory) } // Start with an empty list - manager.configuration.Store([]webhook.WebhookAccessor{}) + manager.configuration.Store(&v1beta1.ValidatingWebhookConfiguration{}) // On any change, rebuild the config informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -62,8 +61,8 @@ func NewValidatingWebhookConfigurationManager(f informers.SharedInformerFactory) } // Webhooks returns the merged ValidatingWebhookConfiguration. -func (v *validatingWebhookConfigurationManager) Webhooks() []webhook.WebhookAccessor { - return v.configuration.Load().([]webhook.WebhookAccessor) +func (v *validatingWebhookConfigurationManager) Webhooks() []v1beta1.Webhook { + return v.configuration.Load().(*v1beta1.ValidatingWebhookConfiguration).Webhooks } // HasSynced returns true if the shared informers have synced. @@ -80,24 +79,18 @@ func (v *validatingWebhookConfigurationManager) updateConfiguration() { v.configuration.Store(mergeValidatingWebhookConfigurations(configurations)) } -func mergeValidatingWebhookConfigurations(configurations []*v1.ValidatingWebhookConfiguration) []webhook.WebhookAccessor { +func mergeValidatingWebhookConfigurations( + configurations []*v1beta1.ValidatingWebhookConfiguration, +) *v1beta1.ValidatingWebhookConfiguration { sort.SliceStable(configurations, ValidatingWebhookConfigurationSorter(configurations).ByName) - accessors := []webhook.WebhookAccessor{} + var ret v1beta1.ValidatingWebhookConfiguration for _, c := range configurations { - // webhook names are not validated for uniqueness, so we check for duplicates and - // add a int suffix to distinguish between them - names := map[string]int{} - for i := range c.Webhooks { - n := c.Webhooks[i].Name - uid := fmt.Sprintf("%s/%s/%d", c.Name, n, names[n]) - names[n]++ - accessors = append(accessors, webhook.NewValidatingWebhookAccessor(uid, c.Name, &c.Webhooks[i])) - } + ret.Webhooks = append(ret.Webhooks, c.Webhooks...) } - return accessors + return &ret } -type ValidatingWebhookConfigurationSorter []*v1.ValidatingWebhookConfiguration +type ValidatingWebhookConfigurationSorter []*v1beta1.ValidatingWebhookConfiguration func (a ValidatingWebhookConfigurationSorter) ByName(i, j int) bool { return a[i].Name < a[j].Name diff --git a/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager_test.go b/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager_test.go index 2e79605886f..153b4df486f 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/configuration/validating_webhook_manager_test.go @@ -20,7 +20,7 @@ import ( "reflect" "testing" - "k8s.io/api/admissionregistration/v1" + "k8s.io/api/admissionregistration/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" @@ -44,12 +44,12 @@ func TestGetValidatingWebhookConfig(t *testing.T) { t.Errorf("expected empty webhooks, but got %v", configurations) } - webhookConfiguration := &v1.ValidatingWebhookConfiguration{ + webhookConfiguration := &v1beta1.ValidatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{Name: "webhook1"}, - Webhooks: []v1.ValidatingWebhook{{Name: "webhook1.1"}}, + Webhooks: []v1beta1.Webhook{{Name: "webhook1.1"}}, } - validatingInformer := informerFactory.Admissionregistration().V1().ValidatingWebhookConfigurations() + validatingInformer := informerFactory.Admissionregistration().V1beta1().ValidatingWebhookConfigurations() validatingInformer.Informer().GetIndexer().Add(webhookConfiguration) if validatingConfig, ok := manager.(*validatingWebhookConfigurationManager); ok { validatingConfig.updateConfiguration() @@ -59,14 +59,7 @@ func TestGetValidatingWebhookConfig(t *testing.T) { if len(configurations) == 0 { t.Errorf("expected non empty webhooks") } - for i := range configurations { - h, ok := configurations[i].GetValidatingWebhook() - if !ok { - t.Errorf("Expected validating webhook") - continue - } - if !reflect.DeepEqual(h, &webhookConfiguration.Webhooks[i]) { - t.Errorf("Expected\n%#v\ngot\n%#v", &webhookConfiguration.Webhooks[i], h) - } + if !reflect.DeepEqual(configurations, webhookConfiguration.Webhooks) { + t.Errorf("Expected\n%#v\ngot\n%#v", webhookConfiguration.Webhooks, configurations) } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/errors_test.go b/vendor/k8s.io/apiserver/pkg/admission/errors_test.go index 5c60c91f605..871d7a57156 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/errors_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/errors_test.go @@ -36,7 +36,6 @@ func TestNewForbidden(t *testing.T) { schema.GroupVersionResource{Group: "foo", Version: "bar", Resource: "baz"}, "", Create, - nil, false, nil) err := errors.New("some error") diff --git a/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer.go b/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer.go index 613baf8efaf..abe764bb94d 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer.go +++ b/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer.go @@ -17,45 +17,39 @@ limitations under the License. package initializer import ( + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" - "k8s.io/component-base/featuregate" ) type pluginInitializer struct { externalClient kubernetes.Interface externalInformers informers.SharedInformerFactory authorizer authorizer.Authorizer - featureGates featuregate.FeatureGate + scheme *runtime.Scheme } // New creates an instance of admission plugins initializer. -// This constructor is public with a long param list so that callers immediately know that new information can be expected -// during compilation when they update a level. +// TODO(p0lyn0mial): make the parameters public, this construction seems to be redundant. func New( extClientset kubernetes.Interface, extInformers informers.SharedInformerFactory, authz authorizer.Authorizer, - featureGates featuregate.FeatureGate, + scheme *runtime.Scheme, ) pluginInitializer { return pluginInitializer{ externalClient: extClientset, externalInformers: extInformers, authorizer: authz, - featureGates: featureGates, + scheme: scheme, } } // Initialize checks the initialization interfaces implemented by a plugin // and provide the appropriate initialization data func (i pluginInitializer) Initialize(plugin admission.Interface) { - // First tell the plugin about enabled features, so it can decide whether to start informers or not - if wants, ok := plugin.(WantsFeatures); ok { - wants.InspectFeatureGates(i.featureGates) - } - if wants, ok := plugin.(WantsExternalKubeClientSet); ok { wants.SetExternalKubeClientSet(i.externalClient) } @@ -67,6 +61,10 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) { if wants, ok := plugin.(WantsAuthorizer); ok { wants.SetAuthorizer(i.authorizer) } + + if wants, ok := plugin.(WantsScheme); ok { + wants.SetScheme(i.scheme) + } } var _ admission.PluginInitializer = pluginInitializer{} diff --git a/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go b/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go index d989b50cb01..6a72d909059 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go @@ -17,10 +17,10 @@ limitations under the License. package initializer_test import ( - "context" "testing" "time" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/authorization/authorizer" @@ -29,6 +29,18 @@ import ( "k8s.io/client-go/kubernetes/fake" ) +// TestWantsScheme ensures that the scheme is injected when +// the WantsScheme interface is implemented by a plugin. +func TestWantsScheme(t *testing.T) { + scheme := runtime.NewScheme() + target := initializer.New(nil, nil, nil, scheme) + wantSchemeAdmission := &WantSchemeAdmission{} + target.Initialize(wantSchemeAdmission) + if wantSchemeAdmission.scheme != scheme { + t.Errorf("expected scheme to be initialized") + } +} + // TestWantsAuthorizer ensures that the authorizer is injected // when the WantsAuthorizer interface is implemented by a plugin. func TestWantsAuthorizer(t *testing.T) { @@ -73,9 +85,7 @@ type WantExternalKubeInformerFactory struct { func (self *WantExternalKubeInformerFactory) SetExternalKubeInformerFactory(sf informers.SharedInformerFactory) { self.sf = sf } -func (self *WantExternalKubeInformerFactory) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { - return nil -} +func (self *WantExternalKubeInformerFactory) Admit(a admission.Attributes) error { return nil } func (self *WantExternalKubeInformerFactory) Handles(o admission.Operation) bool { return false } func (self *WantExternalKubeInformerFactory) ValidateInitialization() error { return nil } @@ -87,14 +97,10 @@ type WantExternalKubeClientSet struct { cs kubernetes.Interface } -func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { - self.cs = cs -} -func (self *WantExternalKubeClientSet) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { - return nil -} -func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false } -func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil } +func (self *WantExternalKubeClientSet) SetExternalKubeClientSet(cs kubernetes.Interface) { self.cs = cs } +func (self *WantExternalKubeClientSet) Admit(a admission.Attributes) error { return nil } +func (self *WantExternalKubeClientSet) Handles(o admission.Operation) bool { return false } +func (self *WantExternalKubeClientSet) ValidateInitialization() error { return nil } var _ admission.Interface = &WantExternalKubeClientSet{} var _ initializer.WantsExternalKubeClientSet = &WantExternalKubeClientSet{} @@ -105,11 +111,9 @@ type WantAuthorizerAdmission struct { } func (self *WantAuthorizerAdmission) SetAuthorizer(a authorizer.Authorizer) { self.auth = a } -func (self *WantAuthorizerAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { - return nil -} -func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false } -func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil } +func (self *WantAuthorizerAdmission) Admit(a admission.Attributes) error { return nil } +func (self *WantAuthorizerAdmission) Handles(o admission.Operation) bool { return false } +func (self *WantAuthorizerAdmission) ValidateInitialization() error { return nil } var _ admission.Interface = &WantAuthorizerAdmission{} var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{} @@ -117,7 +121,7 @@ var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{} // TestAuthorizer is a test stub that fulfills the WantsAuthorizer interface. type TestAuthorizer struct{} -func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { +func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { return authorizer.DecisionNoOpinion, "", nil } @@ -126,9 +130,20 @@ type clientCertWanter struct { gotCert, gotKey []byte } -func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key } -func (s *clientCertWanter) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { - return nil -} +func (s *clientCertWanter) SetClientCert(cert, key []byte) { s.gotCert, s.gotKey = cert, key } +func (s *clientCertWanter) Admit(a admission.Attributes) error { return nil } func (s *clientCertWanter) Handles(o admission.Operation) bool { return false } func (s *clientCertWanter) ValidateInitialization() error { return nil } + +// WantSchemeAdmission is a test stub that fulfills the WantsScheme interface. +type WantSchemeAdmission struct { + scheme *runtime.Scheme +} + +func (self *WantSchemeAdmission) SetScheme(s *runtime.Scheme) { self.scheme = s } +func (self *WantSchemeAdmission) Admit(a admission.Attributes) error { return nil } +func (self *WantSchemeAdmission) Handles(o admission.Operation) bool { return false } +func (self *WantSchemeAdmission) ValidateInitialization() error { return nil } + +var _ admission.Interface = &WantSchemeAdmission{} +var _ initializer.WantsScheme = &WantSchemeAdmission{} diff --git a/vendor/k8s.io/apiserver/pkg/admission/initializer/interfaces.go b/vendor/k8s.io/apiserver/pkg/admission/initializer/interfaces.go index 2b3031aa279..98a07585406 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/initializer/interfaces.go +++ b/vendor/k8s.io/apiserver/pkg/admission/initializer/interfaces.go @@ -17,11 +17,11 @@ limitations under the License. package initializer import ( + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" - "k8s.io/component-base/featuregate" ) // WantsExternalKubeClientSet defines a function which sets external ClientSet for admission plugins that need it @@ -42,13 +42,8 @@ type WantsAuthorizer interface { admission.InitializationValidator } -// WantsFeatureGate defines a function which passes the featureGates for inspection by an admission plugin. -// Admission plugins should not hold a reference to the featureGates. Instead, they should query a particular one -// and assign it to a simple bool in the admission plugin struct. -// func (a *admissionPlugin) InspectFeatureGates(features featuregate.FeatureGate){ -// a.myFeatureIsOn = features.Enabled("my-feature") -// } -type WantsFeatures interface { - InspectFeatureGates(featuregate.FeatureGate) +// WantsScheme defines a function that accepts runtime.Scheme for admission plugins that need it. +type WantsScheme interface { + SetScheme(*runtime.Scheme) admission.InitializationValidator } diff --git a/vendor/k8s.io/apiserver/pkg/admission/interfaces.go b/vendor/k8s.io/apiserver/pkg/admission/interfaces.go index 8882680b2c5..a17c28990ab 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/interfaces.go +++ b/vendor/k8s.io/apiserver/pkg/admission/interfaces.go @@ -17,12 +17,10 @@ limitations under the License. package admission import ( - "context" "io" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/authentication/user" ) @@ -43,8 +41,6 @@ type Attributes interface { GetSubresource() string // GetOperation is the operation being performed GetOperation() Operation - // GetOperationOptions is the options for the operation being performed - GetOperationOptions() runtime.Object // IsDryRun indicates that modifications will definitely not be persisted for this request. This is to prevent // admission controllers with side effects and a method of reconciliation from being overwhelmed. // However, a value of false for this does not mean that the modification will be persisted, because it @@ -63,60 +59,18 @@ type Attributes interface { // "podsecuritypolicy" is the name of the plugin, "admission.k8s.io" is the name of the organization, "admit-policy" is the key name. // An error is returned if the format of key is invalid. When trying to overwrite annotation with a new value, an error is returned. // Both ValidationInterface and MutationInterface are allowed to add Annotations. - // By default, an annotation gets logged into audit event if the request's audit level is greater or - // equal to Metadata. AddAnnotation(key, value string) error - - // AddAnnotationWithLevel sets annotation according to key-value pair with additional intended audit level. - // An Annotation gets logged into audit event if the request's audit level is greater or equal to the - // intended audit level. - AddAnnotationWithLevel(key, value string, level auditinternal.Level) error - - // GetReinvocationContext tracks the admission request information relevant to the re-invocation policy. - GetReinvocationContext() ReinvocationContext -} - -// ObjectInterfaces is an interface used by AdmissionController to get object interfaces -// such as Converter or Defaulter. These interfaces are normally coming from Request Scope -// to handle special cases like CRDs. -type ObjectInterfaces interface { - // GetObjectCreater is the ObjectCreator appropriate for the requested object. - GetObjectCreater() runtime.ObjectCreater - // GetObjectTyper is the ObjectTyper appropriate for the requested object. - GetObjectTyper() runtime.ObjectTyper - // GetObjectDefaulter is the ObjectDefaulter appropriate for the requested object. - GetObjectDefaulter() runtime.ObjectDefaulter - // GetObjectConvertor is the ObjectConvertor appropriate for the requested object. - GetObjectConvertor() runtime.ObjectConvertor - // GetEquivalentResourceMapper is the EquivalentResourceMapper appropriate for finding equivalent resources and expected kind for the requested object. - GetEquivalentResourceMapper() runtime.EquivalentResourceMapper } // privateAnnotationsGetter is a private interface which allows users to get annotations from Attributes. type privateAnnotationsGetter interface { - getAnnotations(maxLevel auditinternal.Level) map[string]string + getAnnotations() map[string]string } // AnnotationsGetter allows users to get annotations from Attributes. An alternate Attribute should implement // this interface. type AnnotationsGetter interface { - GetAnnotations(maxLevel auditinternal.Level) map[string]string -} - -// ReinvocationContext provides access to the admission related state required to implement the re-invocation policy. -type ReinvocationContext interface { - // IsReinvoke returns true if the current admission check is a re-invocation. - IsReinvoke() bool - // SetIsReinvoke sets the current admission check as a re-invocation. - SetIsReinvoke() - // ShouldReinvoke returns true if any plugin has requested a re-invocation. - ShouldReinvoke() bool - // SetShouldReinvoke signals that a re-invocation is desired. - SetShouldReinvoke() - // AddValue set a value for a plugin name, possibly overriding a previous value. - SetValue(plugin string, v interface{}) - // Value reads a value for a webhook. - Value(plugin string) interface{} + GetAnnotations() map[string]string } // Interface is an abstract, pluggable interface for Admission Control decisions. @@ -129,9 +83,8 @@ type Interface interface { type MutationInterface interface { Interface - // Admit makes an admission decision based on the request attributes. - // Context is used only for timeout/deadline/cancellation and tracing information. - Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) + // Admit makes an admission decision based on the request attributes + Admit(a Attributes) (err error) } // ValidationInterface is an abstract, pluggable interface for Admission Control decisions. @@ -139,8 +92,7 @@ type ValidationInterface interface { Interface // Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate - // Context is used only for timeout/deadline/cancellation and tracing information. - Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error) + Validate(a Attributes) (err error) } // Operation is the type of resource operation being checked for admission control diff --git a/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics.go b/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics.go index c9edb48b418..a5ab97a74d5 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics.go +++ b/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics.go @@ -17,36 +17,23 @@ limitations under the License. package metrics import ( - "context" "fmt" "strconv" "time" + "github.com/prometheus/client_golang/prometheus" + "k8s.io/apiserver/pkg/admission" - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" ) -// WebhookRejectionErrorType defines different error types that happen in a webhook rejection. -type WebhookRejectionErrorType string - const ( namespace = "apiserver" subsystem = "admission" - - // WebhookRejectionCallingWebhookError identifies a calling webhook error which causes - // a webhook admission to reject a request - WebhookRejectionCallingWebhookError WebhookRejectionErrorType = "calling_webhook_error" - // WebhookRejectionAPIServerInternalError identifies an apiserver internal error which - // causes a webhook admission to reject a request - WebhookRejectionAPIServerInternalError WebhookRejectionErrorType = "apiserver_internal_error" - // WebhookRejectionNoError identifies a webhook properly rejected a request - WebhookRejectionNoError WebhookRejectionErrorType = "no_error" ) var ( - // Use buckets ranging from 5 ms to 2.5 seconds (admission webhooks timeout at 30 seconds by default). - latencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 2.5} + // Use buckets ranging from 25 ms to ~2.5 seconds. + latencyBuckets = prometheus.ExponentialBuckets(25000, 2.5, 5) latencySummaryMaxAge = 5 * time.Hour // Metrics provides access to all admission metrics. @@ -88,37 +75,36 @@ type pluginHandlerWithMetrics struct { } // Admit performs a mutating admission control check and emit metrics. -func (p pluginHandlerWithMetrics) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { +func (p pluginHandlerWithMetrics) Admit(a admission.Attributes) error { mutatingHandler, ok := p.Interface.(admission.MutationInterface) if !ok { return nil } start := time.Now() - err := mutatingHandler.Admit(ctx, a, o) + err := mutatingHandler.Admit(a) p.observer(time.Since(start), err != nil, a, stepAdmit, p.extraLabels...) return err } // Validate performs a non-mutating admission control check and emits metrics. -func (p pluginHandlerWithMetrics) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { +func (p pluginHandlerWithMetrics) Validate(a admission.Attributes) error { validatingHandler, ok := p.Interface.(admission.ValidationInterface) if !ok { return nil } start := time.Now() - err := validatingHandler.Validate(ctx, a, o) + err := validatingHandler.Validate(a) p.observer(time.Since(start), err != nil, a, stepValidate, p.extraLabels...) return err } // AdmissionMetrics instruments admission with prometheus metrics. type AdmissionMetrics struct { - step *metricSet - controller *metricSet - webhook *metricSet - webhookRejection *metrics.CounterVec + step *metricSet + controller *metricSet + webhook *metricSet } // newAdmissionMetrics create a new AdmissionMetrics, configured with default metric names. @@ -139,21 +125,10 @@ func newAdmissionMetrics() *AdmissionMetrics { []string{"name", "type", "operation", "rejected"}, "Admission webhook %s, identified by name and broken out for each operation and API resource and type (validate or admit).", false) - webhookRejection := metrics.NewCounterVec( - &metrics.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "webhook_rejection_count", - Help: "Admission webhook rejection count, identified by name and broken out for each admission type (validating or admit) and operation. Additional labels specify an error type (calling_webhook_error or apiserver_internal_error if an error occurred; no_error otherwise) and optionally a non-zero rejection code if the webhook rejects the request with an HTTP status code (honored by the apiserver when the code is greater or equal to 400). Codes greater than 600 are truncated to 600, to keep the metrics cardinality bounded.", - StabilityLevel: metrics.ALPHA, - }, - []string{"name", "type", "operation", "error_type", "rejection_code"}) - step.mustRegister() controller.mustRegister() webhook.mustRegister() - legacyregistry.MustRegister(webhookRejection) - return &AdmissionMetrics{step: step, controller: controller, webhook: webhook, webhookRejection: webhookRejection} + return &AdmissionMetrics{step: step, controller: controller, webhook: webhook} } func (m *AdmissionMetrics) reset() { @@ -177,46 +152,34 @@ func (m *AdmissionMetrics) ObserveWebhook(elapsed time.Duration, rejected bool, m.webhook.observe(elapsed, append(extraLabels, stepType, string(attr.GetOperation()), strconv.FormatBool(rejected))...) } -// ObserveWebhookRejection records admission related metrics for an admission webhook rejection. -func (m *AdmissionMetrics) ObserveWebhookRejection(name, stepType, operation string, errorType WebhookRejectionErrorType, rejectionCode int) { - // We truncate codes greater than 600 to keep the cardinality bounded. - // This should be rarely done by a malfunctioning webhook server. - if rejectionCode > 600 { - rejectionCode = 600 - } - m.webhookRejection.WithLabelValues(name, stepType, operation, string(errorType), strconv.Itoa(rejectionCode)).Inc() -} - type metricSet struct { - latencies *metrics.HistogramVec - latenciesSummary *metrics.SummaryVec + latencies *prometheus.HistogramVec + latenciesSummary *prometheus.SummaryVec } func newMetricSet(name string, labels []string, helpTemplate string, hasSummary bool) *metricSet { - var summary *metrics.SummaryVec + var summary *prometheus.SummaryVec if hasSummary { - summary = metrics.NewSummaryVec( - &metrics.SummaryOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: fmt.Sprintf("%s_admission_duration_seconds_summary", name), - Help: fmt.Sprintf(helpTemplate, "latency summary in seconds"), - MaxAge: latencySummaryMaxAge, - StabilityLevel: metrics.ALPHA, + summary = prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: fmt.Sprintf("%s_admission_latencies_seconds_summary", name), + Help: fmt.Sprintf(helpTemplate, "latency summary"), + MaxAge: latencySummaryMaxAge, }, labels, ) } return &metricSet{ - latencies: metrics.NewHistogramVec( - &metrics.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: fmt.Sprintf("%s_admission_duration_seconds", name), - Help: fmt.Sprintf(helpTemplate, "latency histogram in seconds"), - Buckets: latencyBuckets, - StabilityLevel: metrics.ALPHA, + latencies: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: fmt.Sprintf("%s_admission_latencies_seconds", name), + Help: fmt.Sprintf(helpTemplate, "latency histogram"), + Buckets: latencyBuckets, }, labels, ), @@ -227,9 +190,9 @@ func newMetricSet(name string, labels []string, helpTemplate string, hasSummary // MustRegister registers all the prometheus metrics in the metricSet. func (m *metricSet) mustRegister() { - legacyregistry.MustRegister(m.latencies) + prometheus.MustRegister(m.latencies) if m.latenciesSummary != nil { - legacyregistry.MustRegister(m.latenciesSummary) + prometheus.MustRegister(m.latenciesSummary) } } @@ -243,9 +206,9 @@ func (m *metricSet) reset() { // Observe records an observed admission event to all metrics in the metricSet. func (m *metricSet) observe(elapsed time.Duration, labels ...string) { - elapsedSeconds := elapsed.Seconds() - m.latencies.WithLabelValues(labels...).Observe(elapsedSeconds) + elapsedMicroseconds := float64(elapsed / time.Microsecond) + m.latencies.WithLabelValues(labels...).Observe(elapsedMicroseconds) if m.latenciesSummary != nil { - m.latenciesSummary.WithLabelValues(labels...).Observe(elapsedSeconds) + m.latenciesSummary.WithLabelValues(labels...).Observe(elapsedMicroseconds) } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go b/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go index e3b92e8649e..92c8314da03 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/metrics/metrics_test.go @@ -17,13 +17,10 @@ limitations under the License. package metrics import ( - "context" "fmt" "testing" "time" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" ) @@ -31,50 +28,42 @@ import ( var ( kind = schema.GroupVersionKind{Group: "kgroup", Version: "kversion", Kind: "kind"} resource = schema.GroupVersionResource{Group: "rgroup", Version: "rversion", Resource: "resource"} - attr = admission.NewAttributesRecord(nil, nil, kind, "ns", "name", resource, "subresource", admission.Create, &metav1.CreateOptions{}, false, nil) + attr = admission.NewAttributesRecord(nil, nil, kind, "ns", "name", resource, "subresource", admission.Create, false, nil) ) func TestObserveAdmissionStep(t *testing.T) { Metrics.reset() handler := WithStepMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}) - if err := handler.(admission.MutationInterface).Admit(context.TODO(), attr, nil); err != nil { - t.Errorf("Unexpected error in admit: %v", err) - } - if err := handler.(admission.ValidationInterface).Validate(context.TODO(), attr, nil); err != nil { - t.Errorf("Unexpected error in validate: %v", err) - } + handler.(admission.MutationInterface).Admit(attr) + handler.(admission.ValidationInterface).Validate(attr) wantLabels := map[string]string{ "operation": string(admission.Create), "type": "admit", "rejected": "false", } - expectHistogramCountTotal(t, "apiserver_admission_step_admission_duration_seconds", wantLabels, 1) - expectFindMetric(t, "apiserver_admission_step_admission_duration_seconds_summary", wantLabels) + expectHistogramCountTotal(t, "apiserver_admission_step_admission_latencies_seconds", wantLabels, 1) + expectFindMetric(t, "apiserver_admission_step_admission_latencies_seconds_summary", wantLabels) wantLabels["type"] = "validate" - expectHistogramCountTotal(t, "apiserver_admission_step_admission_duration_seconds", wantLabels, 1) - expectFindMetric(t, "apiserver_admission_step_admission_duration_seconds_summary", wantLabels) + expectHistogramCountTotal(t, "apiserver_admission_step_admission_latencies_seconds", wantLabels, 1) + expectFindMetric(t, "apiserver_admission_step_admission_latencies_seconds_summary", wantLabels) } func TestObserveAdmissionController(t *testing.T) { Metrics.reset() handler := WithControllerMetrics(&mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create), true, true}, "a") - if err := handler.(admission.MutationInterface).Admit(context.TODO(), attr, nil); err != nil { - t.Errorf("Unexpected error in admit: %v", err) - } - if err := handler.(admission.ValidationInterface).Validate(context.TODO(), attr, nil); err != nil { - t.Errorf("Unexpected error in validate: %v", err) - } + handler.(admission.MutationInterface).Admit(attr) + handler.(admission.ValidationInterface).Validate(attr) wantLabels := map[string]string{ "name": "a", "operation": string(admission.Create), "type": "admit", "rejected": "false", } - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", wantLabels, 1) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", wantLabels, 1) wantLabels["type"] = "validate" - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", wantLabels, 1) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", wantLabels, 1) } func TestObserveWebhook(t *testing.T) { @@ -86,38 +75,7 @@ func TestObserveWebhook(t *testing.T) { "type": "admit", "rejected": "false", } - expectHistogramCountTotal(t, "apiserver_admission_webhook_admission_duration_seconds", wantLabels, 1) -} - -func TestObserveWebhookRejection(t *testing.T) { - Metrics.reset() - Metrics.ObserveWebhookRejection("x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 500) - Metrics.ObserveWebhookRejection("x", stepAdmit, string(admission.Create), WebhookRejectionNoError, 654) - Metrics.ObserveWebhookRejection("x", stepValidate, string(admission.Update), WebhookRejectionCallingWebhookError, 0) - wantLabels := map[string]string{ - "name": "x", - "operation": string(admission.Create), - "type": "admit", - "error_type": "no_error", - "rejection_code": "500", - } - wantLabels600 := map[string]string{ - "name": "x", - "operation": string(admission.Create), - "type": "admit", - "error_type": "no_error", - "rejection_code": "600", - } - wantLabelsCallingWebhookError := map[string]string{ - "name": "x", - "operation": string(admission.Update), - "type": "validate", - "error_type": "calling_webhook_error", - "rejection_code": "0", - } - expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels, 1) - expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabels600, 1) - expectCounterValue(t, "apiserver_admission_webhook_rejection_count", wantLabelsCallingWebhookError, 1) + expectHistogramCountTotal(t, "apiserver_admission_webhook_admission_latencies_seconds", wantLabels, 1) } func TestWithMetrics(t *testing.T) { @@ -127,7 +85,6 @@ func TestWithMetrics(t *testing.T) { name string ns string operation admission.Operation - options runtime.Object handler admission.Interface admit, validate bool } @@ -136,7 +93,6 @@ func TestWithMetrics(t *testing.T) { "both-interfaces-admit-and-validate", "some-ns", admission.Create, - &metav1.CreateOptions{}, &mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), true, true}, true, true, }, @@ -144,7 +100,6 @@ func TestWithMetrics(t *testing.T) { "both-interfaces-dont-admit", "some-ns", admission.Create, - &metav1.CreateOptions{}, &mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), false, true}, false, true, }, @@ -152,7 +107,6 @@ func TestWithMetrics(t *testing.T) { "both-interfaces-admit-dont-validate", "some-ns", admission.Create, - &metav1.CreateOptions{}, &mutatingAndValidatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), true, false}, true, false, }, @@ -160,7 +114,6 @@ func TestWithMetrics(t *testing.T) { "validate-interfaces-validate", "some-ns", admission.Create, - &metav1.CreateOptions{}, &validatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), true}, true, true, }, @@ -168,7 +121,6 @@ func TestWithMetrics(t *testing.T) { "validate-interfaces-dont-validate", "some-ns", admission.Create, - &metav1.CreateOptions{}, &validatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), false}, true, false, }, @@ -176,7 +128,6 @@ func TestWithMetrics(t *testing.T) { "mutating-interfaces-admit", "some-ns", admission.Create, - &metav1.CreateOptions{}, &mutatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), true}, true, true, }, @@ -184,7 +135,6 @@ func TestWithMetrics(t *testing.T) { "mutating-interfaces-dont-admit", "some-ns", admission.Create, - &metav1.CreateOptions{}, &mutatingFakeHandler{admission.NewHandler(admission.Create, admission.Update), false}, false, true, }, @@ -194,7 +144,7 @@ func TestWithMetrics(t *testing.T) { h := WithMetrics(test.handler, Metrics.ObserveAdmissionController, test.name) // test mutation - err := h.(admission.MutationInterface).Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) + err := h.(admission.MutationInterface).Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) if test.admit && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue @@ -208,9 +158,9 @@ func TestWithMetrics(t *testing.T) { filter["rejected"] = "true" } if _, mutating := test.handler.(admission.MutationInterface); mutating { - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", filter, 1) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", filter, 1) } else { - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", filter, 0) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", filter, 0) } if err != nil { @@ -219,7 +169,7 @@ func TestWithMetrics(t *testing.T) { } // test validation - err = h.(admission.ValidationInterface).Validate(context.TODO(), admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, test.options, false, nil), nil) + err = h.(admission.ValidationInterface).Validate(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, test.ns, "", schema.GroupVersionResource{}, "", test.operation, false, nil)) if test.validate && err != nil { t.Errorf("expected admit to succeed, but failed: %v", err) continue @@ -233,9 +183,9 @@ func TestWithMetrics(t *testing.T) { filter["rejected"] = "true" } if _, validating := test.handler.(admission.ValidationInterface); validating { - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", filter, 1) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", filter, 1) } else { - expectHistogramCountTotal(t, "apiserver_admission_controller_admission_duration_seconds", filter, 0) + expectHistogramCountTotal(t, "apiserver_admission_controller_admission_latencies_seconds", filter, 0) } } } @@ -246,14 +196,14 @@ type mutatingAndValidatingFakeHandler struct { validate bool } -func (h *mutatingAndValidatingFakeHandler) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingAndValidatingFakeHandler) Admit(a admission.Attributes) (err error) { if h.admit { return nil } return fmt.Errorf("don't admit") } -func (h *mutatingAndValidatingFakeHandler) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingAndValidatingFakeHandler) Validate(a admission.Attributes) (err error) { if h.validate { return nil } @@ -265,7 +215,7 @@ type validatingFakeHandler struct { validate bool } -func (h *validatingFakeHandler) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *validatingFakeHandler) Validate(a admission.Attributes) (err error) { if h.validate { return nil } @@ -277,7 +227,7 @@ type mutatingFakeHandler struct { admit bool } -func (h *mutatingFakeHandler) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (h *mutatingFakeHandler) Admit(a admission.Attributes) (err error) { if h.admit { return nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/metrics/testutil_test.go b/vendor/k8s.io/apiserver/pkg/admission/metrics/testutil_test.go index 121778b8e25..af5ee79a8b6 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/metrics/testutil_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/metrics/testutil_test.go @@ -19,42 +19,49 @@ package metrics import ( "testing" - "k8s.io/component-base/metrics/legacyregistry" - "k8s.io/component-base/metrics/testutil" + "github.com/prometheus/client_golang/prometheus" + ptype "github.com/prometheus/client_model/go" ) +func labelsMatch(metric *ptype.Metric, labelFilter map[string]string) bool { + for _, lp := range metric.GetLabel() { + if value, ok := labelFilter[lp.GetName()]; ok && lp.GetValue() != value { + return false + } + } + return true +} + // expectFindMetric find a metric with the given name nad labels or reports a fatal test error. -func expectFindMetric(t *testing.T, name string, expectedLabels map[string]string) { - metrics, err := legacyregistry.DefaultGatherer.Gather() +func expectFindMetric(t *testing.T, name string, expectedLabels map[string]string) *ptype.Metric { + metrics, err := prometheus.DefaultGatherer.Gather() if err != nil { t.Fatalf("Failed to gather metrics: %s", err) } - if len(metrics) == 0 { - t.Fatalf("No metric found with name %s and labels %#+v", name, expectedLabels) - } - for _, mf := range metrics { if mf.GetName() == name { for _, metric := range mf.GetMetric() { - if testutil.LabelsMatch(metric, expectedLabels) { + if labelsMatch(metric, expectedLabels) { gotLabelCount := len(metric.GetLabel()) wantLabelCount := len(expectedLabels) if wantLabelCount != gotLabelCount { t.Errorf("Got metric with %d labels, but wanted %d labels. Wanted %#+v for %s", gotLabelCount, wantLabelCount, expectedLabels, metric.String()) - continue } + return metric } } } } + t.Fatalf("No metric found with name %s and labels %#+v", name, expectedLabels) + return nil } // expectHistogramCountTotal ensures that the sum of counts of metrics matching the labelFilter is as // expected. func expectHistogramCountTotal(t *testing.T, name string, labelFilter map[string]string, wantCount int) { - metrics, err := legacyregistry.DefaultGatherer.Gather() + metrics, err := prometheus.DefaultGatherer.Gather() if err != nil { t.Fatalf("Failed to gather metrics: %s", err) } @@ -65,7 +72,7 @@ func expectHistogramCountTotal(t *testing.T, name string, labelFilter map[string continue // Ignore other metrics. } for _, metric := range mf.GetMetric() { - if !testutil.LabelsMatch(metric, labelFilter) { + if !labelsMatch(metric, labelFilter) { continue } counterSum += int(metric.GetHistogram().GetSampleCount()) @@ -82,35 +89,3 @@ func expectHistogramCountTotal(t *testing.T, name string, labelFilter map[string } } } - -// expectCounterValue ensures that the counts of metrics matching the labelFilter is as -// expected. -func expectCounterValue(t *testing.T, name string, labelFilter map[string]string, wantCount int) { - metrics, err := legacyregistry.DefaultGatherer.Gather() - if err != nil { - t.Fatalf("Failed to gather metrics: %s", err) - } - - counterSum := 0 - for _, mf := range metrics { - if mf.GetName() != name { - continue // Ignore other metrics. - } - for _, metric := range mf.GetMetric() { - if !testutil.LabelsMatch(metric, labelFilter) { - continue - } - counterSum += int(metric.GetCounter().GetValue()) - } - } - if wantCount != counterSum { - t.Errorf("Wanted count %d, got %d for metric %s with labels %#+v", wantCount, counterSum, name, labelFilter) - for _, mf := range metrics { - if mf.GetName() == name { - for _, metric := range mf.GetMetric() { - t.Logf("\tnear match: %s", metric.String()) - } - } - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization.go new file mode 100644 index 00000000000..d4d184a5747 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization.go @@ -0,0 +1,369 @@ +/* +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 initialization + +import ( + "fmt" + "io" + "strings" + + "k8s.io/klog" + + "k8s.io/api/admissionregistration/v1alpha1" + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/api/validation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/configuration" + "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/features" + utilfeature "k8s.io/apiserver/pkg/util/feature" + clientset "k8s.io/client-go/kubernetes" +) + +const ( + // Name of admission plug-in + PluginName = "Initializers" +) + +// Register registers a plugin +func Register(plugins *admission.Plugins) { + plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) { + return NewInitializer(), nil + }) +} + +type initializerOptions struct { + Initializers []string +} + +// InitializationConfig specifies initialization config +type InitializationConfig interface { + Run(stopCh <-chan struct{}) + Initializers() (*v1alpha1.InitializerConfiguration, error) +} + +type initializer struct { + config InitializationConfig + authorizer authorizer.Authorizer +} + +// NewInitializer creates a new initializer plugin which assigns newly created resources initializers +// based on configuration loaded from the admission API group. +// FUTURE: this may be moved to the storage layer of the apiserver, but for now this is an alpha feature +// that can be disabled. +func NewInitializer() admission.Interface { + return &initializer{} +} + +// ValidateInitialization implements the InitializationValidator interface. +func (i *initializer) ValidateInitialization() error { + if i.config == nil { + return fmt.Errorf("the Initializer admission plugin requires a Kubernetes client to be provided") + } + if i.authorizer == nil { + return fmt.Errorf("the Initializer admission plugin requires an authorizer to be provided") + } + + if !utilfeature.DefaultFeatureGate.Enabled(features.Initializers) { + if err := utilfeature.DefaultFeatureGate.Set(string(features.Initializers) + "=true"); err != nil { + klog.Errorf("error enabling Initializers feature as part of admission plugin setup: %v", err) + } else { + klog.Infof("enabled Initializers feature as part of admission plugin setup") + } + } + + i.config.Run(wait.NeverStop) + return nil +} + +// SetExternalKubeClientSet implements the WantsExternalKubeClientSet interface. +func (i *initializer) SetExternalKubeClientSet(client clientset.Interface) { + i.config = configuration.NewInitializerConfigurationManager(client.AdmissionregistrationV1alpha1().InitializerConfigurations()) +} + +// SetAuthorizer implements the WantsAuthorizer interface. +func (i *initializer) SetAuthorizer(a authorizer.Authorizer) { + i.authorizer = a +} + +var initializerFieldPath = field.NewPath("metadata", "initializers") + +// readConfig holds requests instead of failing them if the server is not yet initialized +// or is unresponsive. It formats the returned error for client use if necessary. +func (i *initializer) readConfig(a admission.Attributes) (*v1alpha1.InitializerConfiguration, error) { + // read initializers from config + config, err := i.config.Initializers() + if err == nil { + return config, nil + } + + // if initializer configuration is disabled, fail open + if err == configuration.ErrDisabled { + return &v1alpha1.InitializerConfiguration{}, nil + } + + e := errors.NewServerTimeout(a.GetResource().GroupResource(), "create", 1) + if err == configuration.ErrNotReady { + e.ErrStatus.Message = fmt.Sprintf("Waiting for initialization configuration to load: %v", err) + e.ErrStatus.Reason = "LoadingConfiguration" + e.ErrStatus.Details.Causes = append(e.ErrStatus.Details.Causes, metav1.StatusCause{ + Type: "InitializerConfigurationPending", + Message: "The server is waiting for the initializer configuration to be loaded.", + }) + } else { + e.ErrStatus.Message = fmt.Sprintf("Unable to refresh the initializer configuration: %v", err) + e.ErrStatus.Reason = "LoadingConfiguration" + e.ErrStatus.Details.Causes = append(e.ErrStatus.Details.Causes, metav1.StatusCause{ + Type: "InitializerConfigurationFailure", + Message: "An error has occurred while refreshing the initializer configuration, no resources can be created until a refresh succeeds.", + }) + } + return nil, e +} + +// Admit checks for create requests to add initializers, or update request to enforce invariants. +// The admission controller fails open if the object doesn't have ObjectMeta (can't be initialized). +// A client with sufficient permission ("initialize" verb on resource) can specify its own initializers +// or an empty initializers struct (which bypasses initialization). Only clients with the initialize verb +// can update objects that have not completed initialization. Sub resources can still be modified on +// resources that are undergoing initialization. +// TODO: once this logic is ready for beta, move it into the REST storage layer. +func (i *initializer) Admit(a admission.Attributes) (err error) { + switch a.GetOperation() { + case admission.Create, admission.Update: + default: + return nil + } + + // TODO: should sub-resource action should be denied until the object is initialized? + if len(a.GetSubresource()) > 0 { + return nil + } + + switch a.GetOperation() { + case admission.Create: + accessor, err := meta.Accessor(a.GetObject()) + if err != nil { + // objects without meta accessor cannot be checked for initialization, and it is possible to make calls + // via our API that don't have ObjectMeta + return nil + } + existing := accessor.GetInitializers() + if existing != nil { + klog.V(5).Infof("Admin bypassing initialization for %s", a.GetResource()) + + // it must be possible for some users to bypass initialization - for now, check the initialize operation + if err := i.canInitialize(a, "create with initializers denied"); err != nil { + return err + } + // allow administrators to bypass initialization by setting an empty initializers struct + if len(existing.Pending) == 0 && existing.Result == nil { + accessor.SetInitializers(nil) + return nil + } + } else { + klog.V(5).Infof("Checking initialization for %s", a.GetResource()) + + config, err := i.readConfig(a) + if err != nil { + return err + } + + // Mirror pods are exempt from initialization because they are created and initialized + // on the Kubelet before they appear in the API. + // TODO: once this moves to REST storage layer, this becomes a pod specific concern + if a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Pod").GroupKind() { + accessor, err := meta.Accessor(a.GetObject()) + if err != nil { + return err + } + annotations := accessor.GetAnnotations() + if _, isMirror := annotations[v1.MirrorPodAnnotationKey]; isMirror { + return nil + } + } + + names := findInitializers(config, a.GetResource()) + if len(names) == 0 { + klog.V(5).Infof("No initializers needed") + return nil + } + + klog.V(5).Infof("Found initializers for %s: %v", a.GetResource(), names) + accessor.SetInitializers(newInitializers(names)) + } + + case admission.Update: + accessor, err := meta.Accessor(a.GetObject()) + if err != nil { + // objects without meta accessor cannot be checked for initialization, and it is possible to make calls + // via our API that don't have ObjectMeta + return nil + } + updated := accessor.GetInitializers() + + // controllers deployed with an empty initializers.pending have their initializers set to nil + // but should be able to update without changing their manifest + if updated != nil && len(updated.Pending) == 0 && updated.Result == nil { + accessor.SetInitializers(nil) + updated = nil + } + + existingAccessor, err := meta.Accessor(a.GetOldObject()) + if err != nil { + // if the old object does not have an accessor, but the new one does, error out + return fmt.Errorf("initialized resources must be able to set initializers (%T): %v", a.GetOldObject(), err) + } + existing := existingAccessor.GetInitializers() + + // updates on initialized resources are allowed + if updated == nil && existing == nil { + return nil + } + + klog.V(5).Infof("Modifying uninitialized resource %s", a.GetResource()) + + // because we are called before validation, we need to ensure the update transition is valid. + if errs := validation.ValidateInitializersUpdate(updated, existing, initializerFieldPath); len(errs) > 0 { + return errors.NewInvalid(a.GetKind().GroupKind(), a.GetName(), errs) + } + + // caller must have the ability to mutate un-initialized resources + if err := i.canInitialize(a, "update to uninitialized resource denied"); err != nil { + return err + } + + // TODO: restrict initialization list changes to specific clients? + } + + return nil +} + +func (i *initializer) canInitialize(a admission.Attributes, message string) error { + // caller must have the ability to mutate un-initialized resources + decision, reason, err := i.authorizer.Authorize(authorizer.AttributesRecord{ + Name: a.GetName(), + ResourceRequest: true, + User: a.GetUserInfo(), + Verb: "initialize", + Namespace: a.GetNamespace(), + APIGroup: a.GetResource().Group, + APIVersion: a.GetResource().Version, + Resource: a.GetResource().Resource, + }) + if err != nil { + return err + } + if decision != authorizer.DecisionAllow { + return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("%s: %s", message, reason)) + } + return nil +} + +// Handles returns true if this admission controller can handle the given operation +// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT +func (i *initializer) Handles(op admission.Operation) bool { + return op == admission.Create || op == admission.Update +} + +// newInitializers populates an Initializers struct. +func newInitializers(names []string) *metav1.Initializers { + if len(names) == 0 { + return nil + } + var init []metav1.Initializer + for _, name := range names { + init = append(init, metav1.Initializer{Name: name}) + } + return &metav1.Initializers{ + Pending: init, + } +} + +// findInitializers returns the list of initializer names that apply to a config. It returns an empty list +// if no initializers apply. +func findInitializers(initializers *v1alpha1.InitializerConfiguration, gvr schema.GroupVersionResource) []string { + var names []string + for _, init := range initializers.Initializers { + if !matchRule(init.Rules, gvr) { + continue + } + names = append(names, init.Name) + } + return names +} + +// matchRule returns true if any rule matches the provided group version resource. +func matchRule(rules []v1alpha1.Rule, gvr schema.GroupVersionResource) bool { + for _, rule := range rules { + if !hasGroup(rule.APIGroups, gvr.Group) { + return false + } + if !hasVersion(rule.APIVersions, gvr.Version) { + return false + } + if !hasResource(rule.Resources, gvr.Resource) { + return false + } + } + return len(rules) > 0 +} + +func hasGroup(groups []string, group string) bool { + if groups[0] == "*" { + return true + } + for _, g := range groups { + if g == group { + return true + } + } + return false +} + +func hasVersion(versions []string, version string) bool { + if versions[0] == "*" { + return true + } + for _, v := range versions { + if v == version { + return true + } + } + return false +} + +func hasResource(resources []string, resource string) bool { + if resources[0] == "*" || resources[0] == "*/*" { + return true + } + for _, r := range resources { + if strings.Contains(r, "/") { + continue + } + if r == resource { + return true + } + } + return false +} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go new file mode 100644 index 00000000000..fd9e1fa7748 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/initialization/initialization_test.go @@ -0,0 +1,194 @@ +/* +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 initialization + +import ( + "reflect" + "strings" + "testing" + + "k8s.io/api/admissionregistration/v1alpha1" + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/authorization/authorizer" +) + +func newInitializer(name string, rules ...v1alpha1.Rule) *v1alpha1.InitializerConfiguration { + return addInitializer(&v1alpha1.InitializerConfiguration{}, name, rules...) +} + +func addInitializer(base *v1alpha1.InitializerConfiguration, name string, rules ...v1alpha1.Rule) *v1alpha1.InitializerConfiguration { + base.Initializers = append(base.Initializers, v1alpha1.Initializer{ + Name: name, + Rules: rules, + }) + return base +} + +func TestFindInitializers(t *testing.T) { + type args struct { + initializers *v1alpha1.InitializerConfiguration + gvr schema.GroupVersionResource + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "empty", + args: args{ + gvr: schema.GroupVersionResource{}, + initializers: newInitializer("1"), + }, + }, + { + name: "everything", + args: args{ + gvr: schema.GroupVersionResource{}, + initializers: newInitializer("1", v1alpha1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}}), + }, + want: []string{"1"}, + }, + { + name: "empty group", + args: args{ + gvr: schema.GroupVersionResource{}, + initializers: newInitializer("1", v1alpha1.Rule{APIGroups: []string{""}, APIVersions: []string{"*"}, Resources: []string{"*"}}), + }, + want: []string{"1"}, + }, + { + name: "pod", + args: args{ + gvr: schema.GroupVersionResource{Resource: "pods"}, + initializers: addInitializer( + newInitializer("1", v1alpha1.Rule{APIGroups: []string{""}, APIVersions: []string{"*"}, Resources: []string{"pods"}}), + "2", v1alpha1.Rule{APIGroups: []string{""}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, + ), + }, + want: []string{"1", "2"}, + }, + { + name: "multiple matches", + args: args{ + gvr: schema.GroupVersionResource{Resource: "pods"}, + initializers: newInitializer("1", v1alpha1.Rule{APIGroups: []string{""}, APIVersions: []string{"*"}, Resources: []string{"pods"}}), + }, + want: []string{"1"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := findInitializers(tt.args.initializers, tt.args.gvr); !reflect.DeepEqual(got, tt.want) { + t.Errorf("findInitializers() = %v, want %v", got, tt.want) + } + }) + } +} + +type fakeAuthorizer struct { + accept bool +} + +func (f *fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) { + if f.accept { + return authorizer.DecisionAllow, "", nil + } + return authorizer.DecisionNoOpinion, "denied", nil +} + +func TestAdmitUpdate(t *testing.T) { + tests := []struct { + name string + oldInitializers *metav1.Initializers + newInitializers *metav1.Initializers + verifyUpdatedObj func(runtime.Object) (pass bool, reason string) + err string + }{ + { + name: "updates on initialized resources are allowed", + oldInitializers: nil, + newInitializers: nil, + err: "", + }, + { + name: "updates on initialized resources are allowed", + oldInitializers: &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}}, + newInitializers: &metav1.Initializers{}, + verifyUpdatedObj: func(obj runtime.Object) (bool, string) { + accessor, err := meta.Accessor(obj) + if err != nil { + return false, "cannot get accessor" + } + if accessor.GetInitializers() != nil { + return false, "expect nil initializers" + } + return true, "" + }, + err: "", + }, + { + name: "initializers may not be set once initialized", + oldInitializers: nil, + newInitializers: &metav1.Initializers{Pending: []metav1.Initializer{{Name: "init.k8s.io"}}}, + err: "field is immutable once initialization has completed", + }, + { + name: "empty initializer list is treated as nil initializer", + oldInitializers: nil, + newInitializers: &metav1.Initializers{}, + verifyUpdatedObj: func(obj runtime.Object) (bool, string) { + accessor, err := meta.Accessor(obj) + if err != nil { + return false, "cannot get accessor" + } + if accessor.GetInitializers() != nil { + return false, "expect nil initializers" + } + return true, "" + }, + err: "", + }, + } + + plugin := initializer{ + config: nil, + authorizer: &fakeAuthorizer{true}, + } + for _, tc := range tests { + oldObj := &v1.Pod{} + oldObj.Initializers = tc.oldInitializers + newObj := &v1.Pod{} + newObj.Initializers = tc.newInitializers + a := admission.NewAttributesRecord(newObj, oldObj, schema.GroupVersionKind{}, "", "foo", schema.GroupVersionResource{}, "", admission.Update, false, nil) + err := plugin.Admit(a) + switch { + case tc.err == "" && err != nil: + t.Errorf("%q: unexpected error: %v", tc.name, err) + case tc.err != "" && err == nil: + t.Errorf("%q: unexpected no error, expected %s", tc.name, tc.err) + case tc.err != "" && err != nil && !strings.Contains(err.Error(), tc.err): + t.Errorf("%q: expected %s, got %v", tc.name, tc.err, err) + } + } + +} 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 779ab425d82..d7bb0215b98 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 @@ -17,14 +17,13 @@ limitations under the License. package lifecycle import ( - "context" "fmt" "io" "time" "k8s.io/klog" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -74,7 +73,7 @@ var _ = initializer.WantsExternalKubeInformerFactory(&Lifecycle{}) var _ = initializer.WantsExternalKubeClientSet(&Lifecycle{}) // Admit makes an admission decision based on the request attributes -func (l *Lifecycle) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { +func (l *Lifecycle) Admit(a admission.Attributes) error { // prevent deletion of immortal namespaces if a.GetOperation() == admission.Delete && a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() && l.immortalNamespaces.Has(a.GetName()) { return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("this namespace may not be deleted")) @@ -154,7 +153,7 @@ func (l *Lifecycle) Admit(ctx context.Context, a admission.Attributes, o admissi // refuse to operate on non-existent namespaces if !exists || forceLiveLookup { // as a last resort, make a call directly to storage - namespace, err = l.client.CoreV1().Namespaces().Get(context.TODO(), a.GetNamespace(), metav1.GetOptions{}) + namespace, err = l.client.CoreV1().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{}) switch { case errors.IsNotFound(err): return err @@ -170,15 +169,8 @@ func (l *Lifecycle) Admit(ctx context.Context, a admission.Attributes, o admissi return nil } - err := admission.NewForbidden(a, fmt.Errorf("unable to create new content in namespace %s because it is being terminated", a.GetNamespace())) - if apierr, ok := err.(*errors.StatusError); ok { - apierr.ErrStatus.Details.Causes = append(apierr.ErrStatus.Details.Causes, metav1.StatusCause{ - Type: v1.NamespaceTerminatingCause, - Message: fmt.Sprintf("namespace %s is being terminated", a.GetNamespace()), - Field: "metadata.namespace", - }) - } - return err + // TODO: This should probably not be a 403 + return admission.NewForbidden(a, fmt.Errorf("unable to create new content in namespace %s because it is being terminated", a.GetNamespace())) } 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 71b1edf6d8b..8a56cc3e86c 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 @@ -17,19 +17,15 @@ limitations under the License. package lifecycle import ( - "context" "fmt" - "reflect" "testing" "time" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" @@ -108,7 +104,7 @@ func TestAccessReviewCheckOnMissingNamespace(t *testing.T) { } informerFactory.Start(wait.NeverStop) - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "LocalSubjectAccesReview"}, namespace, "", schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "localsubjectaccessreviews"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "authorization.k8s.io", Version: "v1", Kind: "LocalSubjectAccesReview"}, namespace, "", schema.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1", Resource: "localsubjectaccessreviews"}, "", admission.Create, false, nil)) if err != nil { t.Error(err) } @@ -128,7 +124,7 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err == nil { actions := "" for _, action := range mockClient.Actions() { @@ -138,19 +134,19 @@ func TestAdmissionNamespaceDoesNotExist(t *testing.T) { } // verify create operations in the namespace cause an error - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, 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(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil) + 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, false, 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(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) + 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, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } @@ -170,7 +166,7 @@ func TestAdmissionNamespaceActive(t *testing.T) { informerFactory.Start(wait.NeverStop) pod := newPod(namespace) - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err != nil { t.Errorf("unexpected error returned from admission handler") } @@ -191,39 +187,31 @@ func TestAdmissionNamespaceTerminating(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace cause an error - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is terminating") } - expectedCause := metav1.StatusCause{ - Type: v1.NamespaceTerminatingCause, - Message: fmt.Sprintf("namespace %s is being terminated", namespace), - Field: "metadata.namespace", - } - if cause, ok := errors.StatusCause(err, v1.NamespaceTerminatingCause); !ok || !reflect.DeepEqual(expectedCause, cause) { - t.Errorf("Expected status cause indicating the namespace is terminating: %t %s", ok, diff.ObjectReflectDiff(expectedCause, cause)) - } // verify update operations in the namespace can proceed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil) + 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, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete operations in the namespace can proceed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) + 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, false, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete of namespace default can never proceed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", metav1.NamespaceDefault, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err == nil { t.Errorf("Expected an error that this namespace can never be deleted") } // verify delete of namespace other than default can proceed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), "", "other", v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Did not expect an error %v", err) } @@ -250,7 +238,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { pod := newPod(namespace) // verify create operations in the namespace is allowed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err != nil { t.Errorf("Unexpected error rejecting creates in an active namespace") } @@ -260,7 +248,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { getCalls = 0 // verify delete of namespace can proceed - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), namespace, namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, &metav1.DeleteOptions{}, false, nil), nil) + err = handler.Admit(admission.NewAttributesRecord(nil, nil, v1.SchemeGroupVersion.WithKind("Namespace").GroupKind().WithVersion("version"), namespace, namespace, v1.Resource("namespaces").WithVersion("version"), "", admission.Delete, false, nil)) if err != nil { t.Errorf("Expected namespace deletion to be allowed") } @@ -273,7 +261,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { phases[namespace] = v1.NamespaceTerminating // verify create operations in the namespace cause an error - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -286,7 +274,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(forceLiveLookupTTL) // verify create operations in the namespace cause an error - err = handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + 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, false, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace right after deleting it") } @@ -299,7 +287,7 @@ func TestAdmissionNamespaceForceLiveLookup(t *testing.T) { fakeClock.Step(time.Millisecond) // verify create operations in the namespace don't force a live lookup after the timeout - handler.Admit(context.TODO(), admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil) + handler.Admit(admission.NewAttributesRecord(&pod, nil, v1.SchemeGroupVersion.WithKind("Pod").GroupKind().WithVersion("version"), pod.Namespace, pod.Name, v1.Resource("pods").WithVersion("version"), "", admission.Create, false, nil)) if getCalls != 0 { t.Errorf("Expected no live lookup of the namespace at t=forceLiveLookupTTL+1ms, got %d", getCalls) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors.go deleted file mode 100644 index 0cbc21c8267..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors.go +++ /dev/null @@ -1,297 +0,0 @@ -/* -Copyright 2019 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 webhook - -import ( - "sync" - - "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - webhookutil "k8s.io/apiserver/pkg/util/webhook" - "k8s.io/client-go/rest" -) - -// WebhookAccessor provides a common interface to both mutating and validating webhook types. -type WebhookAccessor interface { - // GetUID gets a string that uniquely identifies the webhook. - GetUID() string - - // GetConfigurationName gets the name of the webhook configuration that owns this webhook. - GetConfigurationName() string - - // GetRESTClient gets the webhook client - GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error) - // GetParsedNamespaceSelector gets the webhook NamespaceSelector field. - GetParsedNamespaceSelector() (labels.Selector, error) - // GetParsedObjectSelector gets the webhook ObjectSelector field. - GetParsedObjectSelector() (labels.Selector, error) - - // GetName gets the webhook Name field. Note that the name is scoped to the webhook - // configuration and does not provide a globally unique identity, if a unique identity is - // needed, use GetUID. - GetName() string - // GetClientConfig gets the webhook ClientConfig field. - GetClientConfig() v1.WebhookClientConfig - // GetRules gets the webhook Rules field. - GetRules() []v1.RuleWithOperations - // GetFailurePolicy gets the webhook FailurePolicy field. - GetFailurePolicy() *v1.FailurePolicyType - // GetMatchPolicy gets the webhook MatchPolicy field. - GetMatchPolicy() *v1.MatchPolicyType - // GetNamespaceSelector gets the webhook NamespaceSelector field. - GetNamespaceSelector() *metav1.LabelSelector - // GetObjectSelector gets the webhook ObjectSelector field. - GetObjectSelector() *metav1.LabelSelector - // GetSideEffects gets the webhook SideEffects field. - GetSideEffects() *v1.SideEffectClass - // GetTimeoutSeconds gets the webhook TimeoutSeconds field. - GetTimeoutSeconds() *int32 - // GetAdmissionReviewVersions gets the webhook AdmissionReviewVersions field. - GetAdmissionReviewVersions() []string - - // GetMutatingWebhook if the accessor contains a MutatingWebhook, returns it and true, else returns false. - GetMutatingWebhook() (*v1.MutatingWebhook, bool) - // GetValidatingWebhook if the accessor contains a ValidatingWebhook, returns it and true, else returns false. - GetValidatingWebhook() (*v1.ValidatingWebhook, bool) -} - -// NewMutatingWebhookAccessor creates an accessor for a MutatingWebhook. -func NewMutatingWebhookAccessor(uid, configurationName string, h *v1.MutatingWebhook) WebhookAccessor { - return &mutatingWebhookAccessor{uid: uid, configurationName: configurationName, MutatingWebhook: h} -} - -type mutatingWebhookAccessor struct { - *v1.MutatingWebhook - uid string - configurationName string - - initObjectSelector sync.Once - objectSelector labels.Selector - objectSelectorErr error - - initNamespaceSelector sync.Once - namespaceSelector labels.Selector - namespaceSelectorErr error - - initClient sync.Once - client *rest.RESTClient - clientErr error -} - -func (m *mutatingWebhookAccessor) GetUID() string { - return m.uid -} - -func (m *mutatingWebhookAccessor) GetConfigurationName() string { - return m.configurationName -} - -func (m *mutatingWebhookAccessor) GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error) { - m.initClient.Do(func() { - m.client, m.clientErr = clientManager.HookClient(hookClientConfigForWebhook(m)) - }) - return m.client, m.clientErr -} - -func (m *mutatingWebhookAccessor) GetParsedNamespaceSelector() (labels.Selector, error) { - m.initNamespaceSelector.Do(func() { - m.namespaceSelector, m.namespaceSelectorErr = metav1.LabelSelectorAsSelector(m.NamespaceSelector) - }) - return m.namespaceSelector, m.namespaceSelectorErr -} - -func (m *mutatingWebhookAccessor) GetParsedObjectSelector() (labels.Selector, error) { - m.initObjectSelector.Do(func() { - m.objectSelector, m.objectSelectorErr = metav1.LabelSelectorAsSelector(m.ObjectSelector) - }) - return m.objectSelector, m.objectSelectorErr -} - -func (m *mutatingWebhookAccessor) GetName() string { - return m.Name -} - -func (m *mutatingWebhookAccessor) GetClientConfig() v1.WebhookClientConfig { - return m.ClientConfig -} - -func (m *mutatingWebhookAccessor) GetRules() []v1.RuleWithOperations { - return m.Rules -} - -func (m *mutatingWebhookAccessor) GetFailurePolicy() *v1.FailurePolicyType { - return m.FailurePolicy -} - -func (m *mutatingWebhookAccessor) GetMatchPolicy() *v1.MatchPolicyType { - return m.MatchPolicy -} - -func (m *mutatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector { - return m.NamespaceSelector -} - -func (m *mutatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector { - return m.ObjectSelector -} - -func (m *mutatingWebhookAccessor) GetSideEffects() *v1.SideEffectClass { - return m.SideEffects -} - -func (m *mutatingWebhookAccessor) GetTimeoutSeconds() *int32 { - return m.TimeoutSeconds -} - -func (m *mutatingWebhookAccessor) GetAdmissionReviewVersions() []string { - return m.AdmissionReviewVersions -} - -func (m *mutatingWebhookAccessor) GetMutatingWebhook() (*v1.MutatingWebhook, bool) { - return m.MutatingWebhook, true -} - -func (m *mutatingWebhookAccessor) GetValidatingWebhook() (*v1.ValidatingWebhook, bool) { - return nil, false -} - -// NewValidatingWebhookAccessor creates an accessor for a ValidatingWebhook. -func NewValidatingWebhookAccessor(uid, configurationName string, h *v1.ValidatingWebhook) WebhookAccessor { - return &validatingWebhookAccessor{uid: uid, configurationName: configurationName, ValidatingWebhook: h} -} - -type validatingWebhookAccessor struct { - *v1.ValidatingWebhook - uid string - configurationName string - - initObjectSelector sync.Once - objectSelector labels.Selector - objectSelectorErr error - - initNamespaceSelector sync.Once - namespaceSelector labels.Selector - namespaceSelectorErr error - - initClient sync.Once - client *rest.RESTClient - clientErr error -} - -func (v *validatingWebhookAccessor) GetUID() string { - return v.uid -} - -func (v *validatingWebhookAccessor) GetConfigurationName() string { - return v.configurationName -} - -func (v *validatingWebhookAccessor) GetRESTClient(clientManager *webhookutil.ClientManager) (*rest.RESTClient, error) { - v.initClient.Do(func() { - v.client, v.clientErr = clientManager.HookClient(hookClientConfigForWebhook(v)) - }) - return v.client, v.clientErr -} - -func (v *validatingWebhookAccessor) GetParsedNamespaceSelector() (labels.Selector, error) { - v.initNamespaceSelector.Do(func() { - v.namespaceSelector, v.namespaceSelectorErr = metav1.LabelSelectorAsSelector(v.NamespaceSelector) - }) - return v.namespaceSelector, v.namespaceSelectorErr -} - -func (v *validatingWebhookAccessor) GetParsedObjectSelector() (labels.Selector, error) { - v.initObjectSelector.Do(func() { - v.objectSelector, v.objectSelectorErr = metav1.LabelSelectorAsSelector(v.ObjectSelector) - }) - return v.objectSelector, v.objectSelectorErr -} - -func (v *validatingWebhookAccessor) GetName() string { - return v.Name -} - -func (v *validatingWebhookAccessor) GetClientConfig() v1.WebhookClientConfig { - return v.ClientConfig -} - -func (v *validatingWebhookAccessor) GetRules() []v1.RuleWithOperations { - return v.Rules -} - -func (v *validatingWebhookAccessor) GetFailurePolicy() *v1.FailurePolicyType { - return v.FailurePolicy -} - -func (v *validatingWebhookAccessor) GetMatchPolicy() *v1.MatchPolicyType { - return v.MatchPolicy -} - -func (v *validatingWebhookAccessor) GetNamespaceSelector() *metav1.LabelSelector { - return v.NamespaceSelector -} - -func (v *validatingWebhookAccessor) GetObjectSelector() *metav1.LabelSelector { - return v.ObjectSelector -} - -func (v *validatingWebhookAccessor) GetSideEffects() *v1.SideEffectClass { - return v.SideEffects -} - -func (v *validatingWebhookAccessor) GetTimeoutSeconds() *int32 { - return v.TimeoutSeconds -} - -func (v *validatingWebhookAccessor) GetAdmissionReviewVersions() []string { - return v.AdmissionReviewVersions -} - -func (v *validatingWebhookAccessor) GetMutatingWebhook() (*v1.MutatingWebhook, bool) { - return nil, false -} - -func (v *validatingWebhookAccessor) GetValidatingWebhook() (*v1.ValidatingWebhook, bool) { - return v.ValidatingWebhook, true -} - -// hookClientConfigForWebhook construct a webhookutil.ClientConfig using a WebhookAccessor to access -// v1beta1.MutatingWebhook and v1beta1.ValidatingWebhook API objects. webhookutil.ClientConfig is used -// to create a HookClient and the purpose of the config struct is to share that with other packages -// that need to create a HookClient. -func hookClientConfigForWebhook(w WebhookAccessor) webhookutil.ClientConfig { - ret := webhookutil.ClientConfig{Name: w.GetName(), CABundle: w.GetClientConfig().CABundle} - if w.GetClientConfig().URL != nil { - ret.URL = *w.GetClientConfig().URL - } - if w.GetClientConfig().Service != nil { - ret.Service = &webhookutil.ClientConfigService{ - Name: w.GetClientConfig().Service.Name, - Namespace: w.GetClientConfig().Service.Namespace, - } - if w.GetClientConfig().Service.Port != nil { - ret.Service.Port = *w.GetClientConfig().Service.Port - } else { - ret.Service.Port = 443 - } - if w.GetClientConfig().Service.Path != nil { - ret.Service.Path = *w.GetClientConfig().Service.Path - } - } - return ret -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors_test.go deleted file mode 100644 index e26e3d95f28..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/accessors_test.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2019 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 webhook - -import ( - "fmt" - "reflect" - "testing" - - fuzz "github.com/google/gofuzz" - "k8s.io/api/admissionregistration/v1" - "k8s.io/apimachinery/pkg/util/diff" -) - -func TestMutatingWebhookAccessor(t *testing.T) { - f := fuzz.New() - for i := 0; i < 100; i++ { - t.Run(fmt.Sprintf("Run %d/100", i), func(t *testing.T) { - orig := &v1.MutatingWebhook{} - f.Fuzz(orig) - - // zero out any accessor type specific fields not included in the accessor - orig.ReinvocationPolicy = nil - - uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name) - accessor := NewMutatingWebhookAccessor(uid, "test.configuration.admission", orig) - if uid != accessor.GetUID() { - t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid) - } - m, ok := accessor.GetMutatingWebhook() - if !ok { - t.Errorf("expected GetMutatingWebhook to return ok for mutating webhook accessor") - } - if !reflect.DeepEqual(orig, m) { - t.Errorf("expected GetMutatingWebhook to return original webhook, diff:\n%s", diff.ObjectReflectDiff(orig, m)) - } - if _, ok := accessor.GetValidatingWebhook(); ok { - t.Errorf("expected GetValidatingWebhook to be nil for mutating webhook accessor") - } - copy := &v1.MutatingWebhook{ - Name: accessor.GetName(), - ClientConfig: accessor.GetClientConfig(), - Rules: accessor.GetRules(), - FailurePolicy: accessor.GetFailurePolicy(), - MatchPolicy: accessor.GetMatchPolicy(), - NamespaceSelector: accessor.GetNamespaceSelector(), - ObjectSelector: accessor.GetObjectSelector(), - SideEffects: accessor.GetSideEffects(), - TimeoutSeconds: accessor.GetTimeoutSeconds(), - AdmissionReviewVersions: accessor.GetAdmissionReviewVersions(), - } - if !reflect.DeepEqual(orig, copy) { - t.Errorf("expected mutatingWebhook to round trip through WebhookAccessor, diff:\n%s", diff.ObjectReflectDiff(orig, copy)) - } - }) - } -} - -func TestValidatingWebhookAccessor(t *testing.T) { - f := fuzz.New() - for i := 0; i < 100; i++ { - t.Run(fmt.Sprintf("Run %d/100", i), func(t *testing.T) { - orig := &v1.ValidatingWebhook{} - f.Fuzz(orig) - uid := fmt.Sprintf("test.configuration.admission/%s/0", orig.Name) - accessor := NewValidatingWebhookAccessor(uid, "test.configuration.admission", orig) - if uid != accessor.GetUID() { - t.Errorf("expected GetUID to return %s, but got %s", accessor.GetUID(), uid) - } - m, ok := accessor.GetValidatingWebhook() - if !ok { - t.Errorf("expected GetValidatingWebhook to return ok for validating webhook accessor") - } - if !reflect.DeepEqual(orig, m) { - t.Errorf("expected GetValidatingWebhook to return original webhook, diff:\n%s", diff.ObjectReflectDiff(orig, m)) - } - if _, ok := accessor.GetMutatingWebhook(); ok { - t.Errorf("expected GetMutatingWebhook to be nil for validating webhook accessor") - } - copy := &v1.ValidatingWebhook{ - Name: accessor.GetName(), - ClientConfig: accessor.GetClientConfig(), - Rules: accessor.GetRules(), - FailurePolicy: accessor.GetFailurePolicy(), - MatchPolicy: accessor.GetMatchPolicy(), - NamespaceSelector: accessor.GetNamespaceSelector(), - ObjectSelector: accessor.GetObjectSelector(), - SideEffects: accessor.GetSideEffects(), - TimeoutSeconds: accessor.GetTimeoutSeconds(), - AdmissionReviewVersions: accessor.GetAdmissionReviewVersions(), - } - if !reflect.DeepEqual(orig, copy) { - t.Errorf("expected validatingWebhook to round trip through WebhookAccessor, diff:\n%s", diff.ObjectReflectDiff(orig, copy)) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/install/install.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/install/install.go index b724c346afc..b08fe72ea81 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/install/install.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/install/install.go @@ -22,14 +22,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission" - v1 "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1" "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1" ) // Install registers the API group and adds types to a scheme func Install(scheme *runtime.Scheme) { utilruntime.Must(webhookadmission.AddToScheme(scheme)) - utilruntime.Must(v1.AddToScheme(scheme)) utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1alpha1.SchemeGroupVersion)) + utilruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion)) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/register.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/register.go index 2f49b897615..c958d15baa5 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/register.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/register.go @@ -43,11 +43,9 @@ func Resource(resource string) schema.GroupResource { } func addKnownTypes(scheme *runtime.Scheme) error { + // TODO this will get cleaned up with the scheme types are fixed scheme.AddKnownTypes(SchemeGroupVersion, &WebhookAdmission{}, ) - scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("WebhookAdmissionConfiguration"), - &WebhookAdmission{}, - ) return nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/register.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/register.go deleted file mode 100644 index 4a9c0a689b0..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/register.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2019 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 v1 - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// GroupName is the group name use in this package -const GroupName = "apiserver.config.k8s.io" - -// SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("WebhookAdmissionConfiguration"), - &WebhookAdmission{}, - ) - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/types.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/types.go deleted file mode 100644 index 632427d7df9..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/types.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2019 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 v1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// WebhookAdmission provides configuration for the webhook admission controller. -type WebhookAdmission struct { - metav1.TypeMeta `json:",inline"` - - // KubeConfigFile is the path to the kubeconfig file. - KubeConfigFile string `json:"kubeConfigFile"` -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.conversion.go deleted file mode 100644 index 65eb414fcc3..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.conversion.go +++ /dev/null @@ -1,67 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1 - -import ( - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - webhookadmission "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*WebhookAdmission)(nil), (*webhookadmission.WebhookAdmission)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_WebhookAdmission_To_webhookadmission_WebhookAdmission(a.(*WebhookAdmission), b.(*webhookadmission.WebhookAdmission), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*webhookadmission.WebhookAdmission)(nil), (*WebhookAdmission)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_webhookadmission_WebhookAdmission_To_v1_WebhookAdmission(a.(*webhookadmission.WebhookAdmission), b.(*WebhookAdmission), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1_WebhookAdmission_To_webhookadmission_WebhookAdmission(in *WebhookAdmission, out *webhookadmission.WebhookAdmission, s conversion.Scope) error { - out.KubeConfigFile = in.KubeConfigFile - return nil -} - -// Convert_v1_WebhookAdmission_To_webhookadmission_WebhookAdmission is an autogenerated conversion function. -func Convert_v1_WebhookAdmission_To_webhookadmission_WebhookAdmission(in *WebhookAdmission, out *webhookadmission.WebhookAdmission, s conversion.Scope) error { - return autoConvert_v1_WebhookAdmission_To_webhookadmission_WebhookAdmission(in, out, s) -} - -func autoConvert_webhookadmission_WebhookAdmission_To_v1_WebhookAdmission(in *webhookadmission.WebhookAdmission, out *WebhookAdmission, s conversion.Scope) error { - out.KubeConfigFile = in.KubeConfigFile - return nil -} - -// Convert_webhookadmission_WebhookAdmission_To_v1_WebhookAdmission is an autogenerated conversion function. -func Convert_webhookadmission_WebhookAdmission_To_v1_WebhookAdmission(in *webhookadmission.WebhookAdmission, out *WebhookAdmission, s conversion.Scope) error { - return autoConvert_webhookadmission_WebhookAdmission_To_v1_WebhookAdmission(in, out, s) -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.deepcopy.go deleted file mode 100644 index 99fc6a6fa7e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.deepcopy.go +++ /dev/null @@ -1,50 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WebhookAdmission) DeepCopyInto(out *WebhookAdmission) { - *out = *in - out.TypeMeta = in.TypeMeta - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookAdmission. -func (in *WebhookAdmission) DeepCopy() *WebhookAdmission { - if in == nil { - return nil - } - out := new(WebhookAdmission) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *WebhookAdmission) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.defaults.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.defaults.go deleted file mode 100644 index cce2e603a69..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig.go index 78f5312a475..3f5d22f954e 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig.go @@ -27,7 +27,6 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission" - "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1" "k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1alpha1" ) @@ -38,7 +37,6 @@ var ( func init() { utilruntime.Must(webhookadmission.AddToScheme(scheme)) - utilruntime.Must(v1.AddToScheme(scheme)) utilruntime.Must(v1alpha1.AddToScheme(scheme)) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig_test.go deleted file mode 100644 index 101e6868053..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/kubeconfig_test.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2019 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 config - -import ( - "bytes" - "strings" - "testing" -) - -func TestLoadConfig(t *testing.T) { - testcases := []struct { - name string - input string - expectErr string - expectKubeconfig string - }{ - { - name: "empty", - input: "", - expectErr: `'Kind' is missing in ''`, - }, - { - name: "unknown kind", - input: `{"kind":"Unknown","apiVersion":"v1"}`, - expectErr: `no kind "Unknown" is registered for version "v1"`, - }, - { - name: "valid v1alpha1", - input: ` -kind: WebhookAdmission -apiVersion: apiserver.config.k8s.io/v1alpha1 -kubeConfigFile: /foo -`, - expectKubeconfig: "/foo", - }, - { - name: "valid v1", - input: ` -kind: WebhookAdmissionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -kubeConfigFile: /foo -`, - expectKubeconfig: "/foo", - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - kubeconfig, err := LoadConfig(bytes.NewBufferString(tc.input)) - if len(tc.expectErr) > 0 { - if err == nil { - t.Fatal("expected err, got none") - } - if !strings.Contains(err.Error(), tc.expectErr) { - t.Fatalf("expected err containing %q, got %v", tc.expectErr, err) - } - return - } - if err != nil { - t.Fatal(err) - } - if kubeconfig != tc.expectKubeconfig { - t.Fatalf("expected %q, got %q", tc.expectKubeconfig, kubeconfig) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror.go index 00bbf54d2cd..df38afdcb04 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror.go @@ -18,7 +18,6 @@ package errors import ( "fmt" - "net/http" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -33,15 +32,6 @@ func ToStatusErr(webhookName string, result *metav1.Status) *apierrors.StatusErr result = &metav1.Status{Status: metav1.StatusFailure} } - // Make sure we don't return < 400 status codes along with a rejection - if result.Code < http.StatusBadRequest { - result.Code = http.StatusBadRequest - } - // Make sure we don't return "" or "Success" status along with a rejection - if result.Status == "" || result.Status == metav1.StatusSuccess { - result.Status = metav1.StatusFailure - } - switch { case len(result.Message) > 0: result.Message = fmt.Sprintf("%s: %s", deniedBy, result.Message) diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror_test.go index eea28327e24..98b780b4517 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/errors/statuserror_test.go @@ -27,18 +27,14 @@ func TestToStatusErr(t *testing.T) { hookName := "foo" deniedBy := fmt.Sprintf("admission webhook %q denied the request", hookName) tests := []struct { - name string - result *metav1.Status - expectedError string - expectedCode int32 - expectedStatus string + name string + result *metav1.Status + expectedError string }{ { "nil result", nil, deniedBy + " without explanation", - 400, - metav1.StatusFailure, }, { "only message", @@ -46,8 +42,6 @@ func TestToStatusErr(t *testing.T) { Message: "you shall not pass", }, deniedBy + ": you shall not pass", - 400, - metav1.StatusFailure, }, { "only reason", @@ -55,8 +49,6 @@ func TestToStatusErr(t *testing.T) { Reason: metav1.StatusReasonForbidden, }, deniedBy + ": Forbidden", - 400, - metav1.StatusFailure, }, { "message and reason", @@ -65,78 +57,11 @@ func TestToStatusErr(t *testing.T) { Reason: metav1.StatusReasonForbidden, }, deniedBy + ": you shall not pass", - 400, - metav1.StatusFailure, }, { "no message, no reason", &metav1.Status{}, deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "custom 4xx status code", - &metav1.Status{Code: 401}, - deniedBy + " without explanation", - 401, - metav1.StatusFailure, - }, - { - "custom 5xx status code", - &metav1.Status{Code: 500}, - deniedBy + " without explanation", - 500, - metav1.StatusFailure, - }, - { - "200 status code", - &metav1.Status{Code: 200}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "300 status code", - &metav1.Status{Code: 300}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "399 status code", - &metav1.Status{Code: 399}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "missing status", - &metav1.Status{}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "success status overridden", - &metav1.Status{Status: metav1.StatusSuccess}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "failure status preserved", - &metav1.Status{Status: metav1.StatusFailure}, - deniedBy + " without explanation", - 400, - metav1.StatusFailure, - }, - { - "custom status preserved", - &metav1.Status{Status: "custom"}, - deniedBy + " without explanation", - 400, - "custom", }, } for _, test := range tests { @@ -144,11 +69,5 @@ func TestToStatusErr(t *testing.T) { if err == nil || err.Error() != test.expectedError { t.Errorf("%s: expected an error saying %q, but got %v", test.name, test.expectedError, err) } - if err.ErrStatus.Code != test.expectedCode { - t.Errorf("%s: expected code %d, got %d", test.name, test.expectedCode, err.ErrStatus.Code) - } - if err.ErrStatus.Status != test.expectedStatus { - t.Errorf("%s: expected code %q, got %q", test.name, test.expectedStatus, err.ErrStatus.Status) - } } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion.go index f0e0ed79c1b..a75c63fa9fe 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion.go @@ -17,96 +17,39 @@ limitations under the License. package generic import ( + "fmt" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/admission" ) +// convertor converts objects to the desired version. +type convertor struct { + Scheme *runtime.Scheme +} + // ConvertToGVK converts object to the desired gvk. -func ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind, o admission.ObjectInterfaces) (runtime.Object, error) { +func (c *convertor) ConvertToGVK(obj runtime.Object, gvk schema.GroupVersionKind) (runtime.Object, error) { // Unlike other resources, custom resources do not have internal version, so // if obj is a custom resource, it should not need conversion. if obj.GetObjectKind().GroupVersionKind() == gvk { return obj, nil } - out, err := o.GetObjectCreater().New(gvk) + out, err := c.Scheme.New(gvk) if err != nil { return nil, err } - err = o.GetObjectConvertor().Convert(obj, out, nil) + err = c.Scheme.Convert(obj, out, nil) if err != nil { return nil, err } - // Explicitly set the GVK - out.GetObjectKind().SetGroupVersionKind(gvk) return out, nil } -// NewVersionedAttributes returns versioned attributes with the old and new object (if non-nil) converted to the requested kind -func NewVersionedAttributes(attr admission.Attributes, gvk schema.GroupVersionKind, o admission.ObjectInterfaces) (*VersionedAttributes, error) { - // convert the old and new objects to the requested version - versionedAttr := &VersionedAttributes{ - Attributes: attr, - VersionedKind: gvk, - } - if oldObj := attr.GetOldObject(); oldObj != nil { - out, err := ConvertToGVK(oldObj, gvk, o) - if err != nil { - return nil, err - } - versionedAttr.VersionedOldObject = out - } - if obj := attr.GetObject(); obj != nil { - out, err := ConvertToGVK(obj, gvk, o) - if err != nil { - return nil, err - } - versionedAttr.VersionedObject = out - } - return versionedAttr, nil -} - -// ConvertVersionedAttributes converts VersionedObject and VersionedOldObject to the specified kind, if needed. -// If attr.VersionedKind already matches the requested kind, no conversion is performed. -// If conversion is required: -// * attr.VersionedObject is used as the source for the new object if Dirty=true (and is round-tripped through attr.Attributes.Object, clearing Dirty in the process) -// * attr.Attributes.Object is used as the source for the new object if Dirty=false -// * attr.Attributes.OldObject is used as the source for the old object -func ConvertVersionedAttributes(attr *VersionedAttributes, gvk schema.GroupVersionKind, o admission.ObjectInterfaces) error { - // we already have the desired kind, we're done - if attr.VersionedKind == gvk { - return nil +// Validate checks if the conversion has a scheme. +func (c *convertor) Validate() error { + if c.Scheme == nil { + return fmt.Errorf("the convertor requires a scheme") } - - // convert the original old object to the desired GVK - if oldObj := attr.Attributes.GetOldObject(); oldObj != nil { - out, err := ConvertToGVK(oldObj, gvk, o) - if err != nil { - return err - } - attr.VersionedOldObject = out - } - - if attr.VersionedObject != nil { - // convert the existing versioned object to internal - if attr.Dirty { - err := o.GetObjectConvertor().Convert(attr.VersionedObject, attr.Attributes.GetObject(), nil) - if err != nil { - return err - } - } - - // and back to external - out, err := ConvertToGVK(attr.Attributes.GetObject(), gvk, o) - if err != nil { - return err - } - attr.VersionedObject = out - } - - // Remember we converted to this version - attr.VersionedKind = gvk - attr.Dirty = false - return nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion_test.go index 4e609f060ef..499853566fe 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/conversion_test.go @@ -17,7 +17,6 @@ limitations under the License. package generic import ( - "encoding/json" "reflect" "testing" @@ -27,8 +26,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/diff" - "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/apis/example" examplev1 "k8s.io/apiserver/pkg/apis/example/v1" example2v1 "k8s.io/apiserver/pkg/apis/example2/v1" @@ -44,7 +41,7 @@ func initiateScheme(t *testing.T) *runtime.Scheme { func TestConvertToGVK(t *testing.T) { scheme := initiateScheme(t) - o := admission.NewObjectInterfacesFromScheme(scheme) + c := convertor{Scheme: scheme} table := map[string]struct { obj runtime.Object gvk schema.GroupVersionKind @@ -64,10 +61,6 @@ func TestConvertToGVK(t *testing.T) { }, gvk: examplev1.SchemeGroupVersion.WithKind("Pod"), expectedObj: &examplev1.Pod{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "example.apiserver.k8s.io/v1", - Kind: "Pod", - }, ObjectMeta: metav1.ObjectMeta{ Name: "pod1", Labels: map[string]string{ @@ -93,10 +86,6 @@ func TestConvertToGVK(t *testing.T) { }, gvk: example2v1.SchemeGroupVersion.WithKind("ReplicaSet"), expectedObj: &example2v1.ReplicaSet{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "example2.apiserver.k8s.io/v1", - Kind: "ReplicaSet", - }, ObjectMeta: metav1.ObjectMeta{ Name: "rs1", Labels: map[string]string{ @@ -133,7 +122,7 @@ func TestConvertToGVK(t *testing.T) { for name, test := range table { t.Run(name, func(t *testing.T) { - actual, err := ConvertToGVK(test.obj, test.gvk, o) + actual, err := c.ConvertToGVK(test.obj, test.gvk) if err != nil { t.Error(err) } @@ -162,203 +151,3 @@ func TestRuntimeSchemeConvert(t *testing.T) { t.Errorf("unexpected mutation of self-converted Unstructured: obj=%#v, clone=%#v", obj, clone) } } - -func TestConvertVersionedAttributes(t *testing.T) { - scheme := initiateScheme(t) - o := admission.NewObjectInterfacesFromScheme(scheme) - - gvk := func(g, v, k string) schema.GroupVersionKind { - return schema.GroupVersionKind{g, v, k} - } - attrs := func(obj, oldObj runtime.Object) admission.Attributes { - return admission.NewAttributesRecord(obj, oldObj, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", "", nil, false, nil) - } - u := func(data string) *unstructured.Unstructured { - t.Helper() - m := map[string]interface{}{} - if err := json.Unmarshal([]byte(data), &m); err != nil { - t.Fatal(err) - } - return &unstructured.Unstructured{Object: m} - } - testcases := []struct { - Name string - Attrs *VersionedAttributes - GVK schema.GroupVersionKind - ExpectedAttrs *VersionedAttributes - }{ - { - Name: "noop", - Attrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - VersionedObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpodversioned"}}, - VersionedKind: examplev1.SchemeGroupVersion.WithKind("Pod"), - Dirty: true, - }, - GVK: examplev1.SchemeGroupVersion.WithKind("Pod"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - VersionedObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpodversioned"}}, - VersionedKind: examplev1.SchemeGroupVersion.WithKind("Pod"), - Dirty: true, - }, - }, - { - Name: "clean, typed", - Attrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - VersionedObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpodversioned"}}, - VersionedKind: gvk("g", "v", "k"), - }, - GVK: examplev1.SchemeGroupVersion.WithKind("Pod"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - // name gets overwritten from converted attributes, type gets set explicitly - VersionedObject: &examplev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "example.apiserver.k8s.io/v1", Kind: "Pod"}, ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - VersionedOldObject: &examplev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "example.apiserver.k8s.io/v1", Kind: "Pod"}, ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - VersionedKind: examplev1.SchemeGroupVersion.WithKind("Pod"), - }, - }, - { - Name: "clean, unstructured", - Attrs: &VersionedAttributes{ - Attributes: attrs( - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobj"}}`), - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - ), - VersionedObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobjversioned"}}`), - VersionedOldObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobjversioned"}}`), - VersionedKind: gvk("g", "v", "k"), // claim a different current version to trigger conversion - }, - GVK: gvk("mygroup.k8s.io", "v1", "Flunder"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobj"}}`), - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - ), - VersionedObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobj"}}`), - VersionedOldObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - VersionedKind: gvk("mygroup.k8s.io", "v1", "Flunder"), - }, - }, - { - Name: "dirty, typed", - Attrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - VersionedObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpodversioned"}}, - VersionedKind: gvk("g", "v", "k"), // claim a different current version to trigger conversion - Dirty: true, - }, - GVK: examplev1.SchemeGroupVersion.WithKind("Pod"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - ), - // new name gets preserved from versioned object, type gets set explicitly - VersionedObject: &examplev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "example.apiserver.k8s.io/v1", Kind: "Pod"}, ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - // old name gets overwritten from converted attributes, type gets set explicitly - VersionedOldObject: &examplev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "example.apiserver.k8s.io/v1", Kind: "Pod"}, ObjectMeta: metav1.ObjectMeta{Name: "oldpod"}}, - VersionedKind: examplev1.SchemeGroupVersion.WithKind("Pod"), - Dirty: false, - }, - }, - { - Name: "dirty, unstructured", - Attrs: &VersionedAttributes{ - Attributes: attrs( - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobj"}}`), - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - ), - VersionedObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobjversioned"}}`), - VersionedOldObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobjversioned"}}`), - VersionedKind: gvk("g", "v", "k"), // claim a different current version to trigger conversion - Dirty: true, - }, - GVK: gvk("mygroup.k8s.io", "v1", "Flunder"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobjversioned"}}`), - u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - ), - // new name gets preserved from versioned object, type gets set explicitly - VersionedObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"newobjversioned"}}`), - // old name gets overwritten from converted attributes, type gets set explicitly - VersionedOldObject: u(`{"apiVersion": "mygroup.k8s.io/v1","kind": "Flunder","metadata":{"name":"oldobj"}}`), - VersionedKind: gvk("mygroup.k8s.io", "v1", "Flunder"), - Dirty: false, - }, - }, - { - Name: "nil old object", - Attrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpod"}}, - nil, - ), - VersionedObject: &examplev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: nil, - VersionedKind: gvk("g", "v", "k"), // claim a different current version to trigger conversion - Dirty: true, - }, - GVK: examplev1.SchemeGroupVersion.WithKind("Pod"), - ExpectedAttrs: &VersionedAttributes{ - Attributes: attrs( - &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - nil, - ), - // new name gets preserved from versioned object, type gets set explicitly - VersionedObject: &examplev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "example.apiserver.k8s.io/v1", Kind: "Pod"}, ObjectMeta: metav1.ObjectMeta{Name: "newpodversioned"}}, - VersionedOldObject: nil, - VersionedKind: examplev1.SchemeGroupVersion.WithKind("Pod"), - Dirty: false, - }, - }, - } - - for _, tc := range testcases { - t.Run(tc.Name, func(t *testing.T) { - err := ConvertVersionedAttributes(tc.Attrs, tc.GVK, o) - if err != nil { - t.Fatal(err) - } - if e, a := tc.ExpectedAttrs.Attributes.GetObject(), tc.Attrs.Attributes.GetObject(); !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - if e, a := tc.ExpectedAttrs.Attributes.GetOldObject(), tc.Attrs.Attributes.GetOldObject(); !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - if e, a := tc.ExpectedAttrs.VersionedKind, tc.Attrs.VersionedKind; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - if e, a := tc.ExpectedAttrs.VersionedObject, tc.Attrs.VersionedObject; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - if e, a := tc.ExpectedAttrs.VersionedOldObject, tc.Attrs.VersionedOldObject; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - if e, a := tc.ExpectedAttrs.Dirty, tc.Attrs.Dirty; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected diff:\n%s", diff.ObjectReflectDiff(e, a)) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/interfaces.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/interfaces.go index 4381691ef81..3a7edb526d6 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/interfaces.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/interfaces.go @@ -19,57 +19,27 @@ package generic import ( "context" + "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" ) // Source can list dynamic webhook plugins. type Source interface { - Webhooks() []webhook.WebhookAccessor + Webhooks() []v1beta1.Webhook HasSynced() bool } // VersionedAttributes is a wrapper around the original admission attributes, adding versioned // variants of the object and old object. type VersionedAttributes struct { - // Attributes holds the original admission attributes admission.Attributes - // VersionedOldObject holds Attributes.OldObject (if non-nil), converted to VersionedKind. - // It must never be mutated. VersionedOldObject runtime.Object - // VersionedObject holds Attributes.Object (if non-nil), converted to VersionedKind. - // If mutated, Dirty must be set to true by the mutator. - VersionedObject runtime.Object - // VersionedKind holds the fully qualified kind - VersionedKind schema.GroupVersionKind - // Dirty indicates VersionedObject has been modified since being converted from Attributes.Object - Dirty bool -} - -// GetObject overrides the Attributes.GetObject() -func (v *VersionedAttributes) GetObject() runtime.Object { - if v.VersionedObject != nil { - return v.VersionedObject - } - return v.Attributes.GetObject() -} - -// WebhookInvocation describes how to call a webhook, including the resource and subresource the webhook registered for, -// and the kind that should be sent to the webhook. -type WebhookInvocation struct { - Webhook webhook.WebhookAccessor - Resource schema.GroupVersionResource - Subresource string - Kind schema.GroupVersionKind + VersionedObject runtime.Object } // Dispatcher dispatches webhook call to a list of webhooks with admission attributes as argument. type Dispatcher interface { - // Dispatch a request to the webhooks. Dispatcher may choose not to - // call a hook, either because the rules of the hook does not match, or - // the namespaceSelector or the objectSelector of the hook does not - // match. A non-nil error means the request is rejected. - Dispatch(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces, hooks []webhook.WebhookAccessor) error + // Dispatch a request to the webhooks using the given webhooks. A non-nil error means the request is rejected. + Dispatch(ctx context.Context, a *VersionedAttributes, hooks []*v1beta1.Webhook) error } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go index 6fc0eff297d..13b898bca9b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go @@ -21,19 +21,16 @@ import ( "fmt" "io" - admissionv1 "k8s.io/api/admission/v1" admissionv1beta1 "k8s.io/api/admission/v1beta1" - "k8s.io/api/admissionregistration/v1" + "k8s.io/api/admissionregistration/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" genericadmissioninit "k8s.io/apiserver/pkg/admission/initializer" - "k8s.io/apiserver/pkg/admission/plugin/webhook" "k8s.io/apiserver/pkg/admission/plugin/webhook/config" "k8s.io/apiserver/pkg/admission/plugin/webhook/namespace" - "k8s.io/apiserver/pkg/admission/plugin/webhook/object" "k8s.io/apiserver/pkg/admission/plugin/webhook/rules" - webhookutil "k8s.io/apiserver/pkg/util/webhook" + "k8s.io/apiserver/pkg/util/webhook" "k8s.io/client-go/informers" clientset "k8s.io/client-go/kubernetes" ) @@ -45,9 +42,9 @@ type Webhook struct { sourceFactory sourceFactory hookSource Source - clientManager *webhookutil.ClientManager + clientManager *webhook.ClientManager + convertor *convertor namespaceMatcher *namespace.Matcher - objectMatcher *object.Matcher dispatcher Dispatcher } @@ -57,7 +54,7 @@ var ( ) type sourceFactory func(f informers.SharedInformerFactory) Source -type dispatcherFactory func(cm *webhookutil.ClientManager) Dispatcher +type dispatcherFactory func(cm *webhook.ClientManager) Dispatcher // NewWebhook creates a new generic admission webhook. func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory sourceFactory, dispatcherFactory dispatcherFactory) (*Webhook, error) { @@ -66,31 +63,24 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory return nil, err } - cm, err := webhookutil.NewClientManager( - []schema.GroupVersion{ - admissionv1beta1.SchemeGroupVersion, - admissionv1.SchemeGroupVersion, - }, - admissionv1beta1.AddToScheme, - admissionv1.AddToScheme, - ) + cm, err := webhook.NewClientManager(admissionv1beta1.SchemeGroupVersion, admissionv1beta1.AddToScheme) if err != nil { return nil, err } - authInfoResolver, err := webhookutil.NewDefaultAuthenticationInfoResolver(kubeconfigFile) + authInfoResolver, err := webhook.NewDefaultAuthenticationInfoResolver(kubeconfigFile) if err != nil { return nil, err } // Set defaults which may be overridden later. cm.SetAuthenticationInfoResolver(authInfoResolver) - cm.SetServiceResolver(webhookutil.NewDefaultServiceResolver()) + cm.SetServiceResolver(webhook.NewDefaultServiceResolver()) return &Webhook{ Handler: handler, sourceFactory: sourceFactory, clientManager: &cm, + convertor: &convertor{}, namespaceMatcher: &namespace.Matcher{}, - objectMatcher: &object.Matcher{}, dispatcher: dispatcherFactory(&cm), }, nil } @@ -98,16 +88,23 @@ func NewWebhook(handler *admission.Handler, configFile io.Reader, sourceFactory // SetAuthenticationInfoResolverWrapper sets the // AuthenticationInfoResolverWrapper. // TODO find a better way wire this, but keep this pull small for now. -func (a *Webhook) SetAuthenticationInfoResolverWrapper(wrapper webhookutil.AuthenticationInfoResolverWrapper) { +func (a *Webhook) SetAuthenticationInfoResolverWrapper(wrapper webhook.AuthenticationInfoResolverWrapper) { a.clientManager.SetAuthenticationInfoResolverWrapper(wrapper) } // SetServiceResolver sets a service resolver for the webhook admission plugin. // Passing a nil resolver does not have an effect, instead a default one will be used. -func (a *Webhook) SetServiceResolver(sr webhookutil.ServiceResolver) { +func (a *Webhook) SetServiceResolver(sr webhook.ServiceResolver) { a.clientManager.SetServiceResolver(sr) } +// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme +func (a *Webhook) SetScheme(scheme *runtime.Scheme) { + if scheme != nil { + a.convertor.Scheme = scheme + } +} + // SetExternalKubeClientSet implements the WantsExternalKubeInformerFactory interface. // It sets external ClientSet for admission plugins that need it func (a *Webhook) SetExternalKubeClientSet(client clientset.Interface) { @@ -135,83 +132,31 @@ func (a *Webhook) ValidateInitialization() error { if err := a.clientManager.Validate(); err != nil { return fmt.Errorf("clientManager is not properly setup: %v", err) } + if err := a.convertor.Validate(); err != nil { + return fmt.Errorf("convertor is not properly setup: %v", err) + } return nil } -// ShouldCallHook returns invocation details if the webhook should be called, nil if the webhook should not be called, -// or an error if an error was encountered during evaluation. -func (a *Webhook) ShouldCallHook(h webhook.WebhookAccessor, attr admission.Attributes, o admission.ObjectInterfaces) (*WebhookInvocation, *apierrors.StatusError) { - var err *apierrors.StatusError - var invocation *WebhookInvocation - for _, r := range h.GetRules() { +// ShouldCallHook makes a decision on whether to call the webhook or not by the attribute. +func (a *Webhook) ShouldCallHook(h *v1beta1.Webhook, attr admission.Attributes) (bool, *apierrors.StatusError) { + var matches bool + for _, r := range h.Rules { m := rules.Matcher{Rule: r, Attr: attr} if m.Matches() { - invocation = &WebhookInvocation{ - Webhook: h, - Resource: attr.GetResource(), - Subresource: attr.GetSubresource(), - Kind: attr.GetKind(), - } + matches = true break } } - if invocation == nil && h.GetMatchPolicy() != nil && *h.GetMatchPolicy() == v1.Equivalent { - attrWithOverride := &attrWithResourceOverride{Attributes: attr} - equivalents := o.GetEquivalentResourceMapper().EquivalentResourcesFor(attr.GetResource(), attr.GetSubresource()) - // honor earlier rules first - OuterLoop: - for _, r := range h.GetRules() { - // see if the rule matches any of the equivalent resources - for _, equivalent := range equivalents { - if equivalent == attr.GetResource() { - // exclude attr.GetResource(), which we already checked - continue - } - attrWithOverride.resource = equivalent - m := rules.Matcher{Rule: r, Attr: attrWithOverride} - if m.Matches() { - kind := o.GetEquivalentResourceMapper().KindFor(equivalent, attr.GetSubresource()) - if kind.Empty() { - return nil, apierrors.NewInternalError(fmt.Errorf("unable to convert to %v: unknown kind", equivalent)) - } - invocation = &WebhookInvocation{ - Webhook: h, - Resource: equivalent, - Subresource: attr.GetSubresource(), - Kind: kind, - } - break OuterLoop - } - } - } - } - - if invocation == nil { - return nil, nil - } - - matches, err := a.namespaceMatcher.MatchNamespaceSelector(h, attr) - if !matches || err != nil { - return nil, err + if !matches { + return false, nil } - matches, err = a.objectMatcher.MatchObjectSelector(h, attr) - if !matches || err != nil { - return nil, err - } - - return invocation, nil -} - -type attrWithResourceOverride struct { - admission.Attributes - resource schema.GroupVersionResource + return a.namespaceMatcher.MatchNamespaceSelector(h, attr) } -func (a *attrWithResourceOverride) GetResource() schema.GroupVersionResource { return a.resource } - // Dispatch is called by the downstream Validate or Admit methods. -func (a *Webhook) Dispatch(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { +func (a *Webhook) Dispatch(attr admission.Attributes) error { if rules.IsWebhookConfigurationResource(attr) { return nil } @@ -219,5 +164,42 @@ func (a *Webhook) Dispatch(ctx context.Context, attr admission.Attributes, o adm return admission.NewForbidden(attr, fmt.Errorf("not yet ready to handle request")) } hooks := a.hookSource.Webhooks() - return a.dispatcher.Dispatch(ctx, attr, o, hooks) + // TODO: Figure out if adding one second timeout make sense here. + ctx := context.TODO() + + var relevantHooks []*v1beta1.Webhook + for i := range hooks { + call, err := a.ShouldCallHook(&hooks[i], attr) + if err != nil { + return err + } + if call { + relevantHooks = append(relevantHooks, &hooks[i]) + } + } + + if len(relevantHooks) == 0 { + // no matching hooks + return nil + } + + // convert the object to the external version before sending it to the webhook + versionedAttr := VersionedAttributes{ + Attributes: attr, + } + if oldObj := attr.GetOldObject(); oldObj != nil { + out, err := a.convertor.ConvertToGVK(oldObj, attr.GetKind()) + if err != nil { + return apierrors.NewInternalError(err) + } + versionedAttr.VersionedOldObject = out + } + if obj := attr.GetObject(); obj != nil { + out, err := a.convertor.ConvertToGVK(obj, attr.GetKind()) + if err != nil { + return apierrors.NewInternalError(err) + } + versionedAttr.VersionedObject = out + } + return a.dispatcher.Dispatch(ctx, &versionedAttr, relevantHooks) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook_test.go deleted file mode 100644 index 1f34f1242ab..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook_test.go +++ /dev/null @@ -1,331 +0,0 @@ -/* -Copyright 2019 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 generic - -import ( - "fmt" - "strings" - "testing" - - "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" - "k8s.io/apiserver/pkg/admission/plugin/webhook/namespace" - "k8s.io/apiserver/pkg/admission/plugin/webhook/object" -) - -func TestShouldCallHook(t *testing.T) { - a := &Webhook{namespaceMatcher: &namespace.Matcher{}, objectMatcher: &object.Matcher{}} - - allScopes := v1.AllScopes - exactMatch := v1.Exact - equivalentMatch := v1.Equivalent - - mapper := runtime.NewEquivalentResourceRegistryWithIdentity(func(resource schema.GroupResource) string { - if resource.Resource == "deployments" { - // co-locate deployments in all API groups - return "/deployments" - } - return "" - }) - mapper.RegisterKindFor(schema.GroupVersionResource{"extensions", "v1beta1", "deployments"}, "", schema.GroupVersionKind{"extensions", "v1beta1", "Deployment"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1", "deployments"}, "", schema.GroupVersionKind{"apps", "v1", "Deployment"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1beta1", "deployments"}, "", schema.GroupVersionKind{"apps", "v1beta1", "Deployment"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1alpha1", "deployments"}, "", schema.GroupVersionKind{"apps", "v1alpha1", "Deployment"}) - - mapper.RegisterKindFor(schema.GroupVersionResource{"extensions", "v1beta1", "deployments"}, "scale", schema.GroupVersionKind{"extensions", "v1beta1", "Scale"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", schema.GroupVersionKind{"autoscaling", "v1", "Scale"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1beta1", "deployments"}, "scale", schema.GroupVersionKind{"apps", "v1beta1", "Scale"}) - mapper.RegisterKindFor(schema.GroupVersionResource{"apps", "v1alpha1", "deployments"}, "scale", schema.GroupVersionKind{"apps", "v1alpha1", "Scale"}) - - // register invalid kinds to trigger an error - mapper.RegisterKindFor(schema.GroupVersionResource{"example.com", "v1", "widgets"}, "", schema.GroupVersionKind{"", "", ""}) - mapper.RegisterKindFor(schema.GroupVersionResource{"example.com", "v2", "widgets"}, "", schema.GroupVersionKind{"", "", ""}) - - interfaces := &admission.RuntimeObjectInterfaces{EquivalentResourceMapper: mapper} - - testcases := []struct { - name string - - webhook *v1.ValidatingWebhook - attrs admission.Attributes - - expectCall bool - expectErr string - expectCallResource schema.GroupVersionResource - expectCallSubresource string - expectCallKind schema.GroupVersionKind - }{ - { - name: "no rules (just write)", - webhook: &v1.ValidatingWebhook{Rules: []v1.RuleWithOperations{}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "invalid kind lookup", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - MatchPolicy: &equivalentMatch, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"example.com"}, APIVersions: []string{"v1"}, Resources: []string{"widgets"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"example.com", "v2", "Widget"}, "ns", "name", schema.GroupVersionResource{"example.com", "v2", "widgets"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - expectErr: "unknown kind", - }, - { - name: "wildcard rule, match as requested", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"apps", "v1", "Deployment"}, - expectCallResource: schema.GroupVersionResource{"apps", "v1", "deployments"}, - expectCallSubresource: "", - }, - { - name: "specific rules, prefer exact match", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"apps", "v1", "Deployment"}, - expectCallResource: schema.GroupVersionResource{"apps", "v1", "deployments"}, - expectCallSubresource: "", - }, - { - name: "specific rules, match miss", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "specific rules, exact match miss", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &exactMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "specific rules, equivalent match, prefer extensions", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &equivalentMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"extensions", "v1beta1", "Deployment"}, - expectCallResource: schema.GroupVersionResource{"extensions", "v1beta1", "deployments"}, - expectCallSubresource: "", - }, - { - name: "specific rules, equivalent match, prefer apps", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &equivalentMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"apps", "v1", "Deployment"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"apps", "v1beta1", "Deployment"}, - expectCallResource: schema.GroupVersionResource{"apps", "v1beta1", "deployments"}, - expectCallSubresource: "", - }, - - { - name: "specific rules, subresource prefer exact match", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, - expectCallResource: schema.GroupVersionResource{"apps", "v1", "deployments"}, - expectCallSubresource: "scale", - }, - { - name: "specific rules, subresource match miss", - webhook: &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "specific rules, subresource exact match miss", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &exactMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "specific rules, subresource equivalent match, prefer extensions", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &equivalentMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"extensions", "v1beta1", "Scale"}, - expectCallResource: schema.GroupVersionResource{"extensions", "v1beta1", "deployments"}, - expectCallSubresource: "scale", - }, - { - name: "specific rules, subresource equivalent match, prefer apps", - webhook: &v1.ValidatingWebhook{ - MatchPolicy: &equivalentMatch, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }, { - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, - }}}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{"autoscaling", "v1", "Scale"}, "ns", "name", schema.GroupVersionResource{"apps", "v1", "deployments"}, "scale", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - expectCallKind: schema.GroupVersionKind{"apps", "v1beta1", "Scale"}, - expectCallResource: schema.GroupVersionResource{"apps", "v1beta1", "deployments"}, - expectCallSubresource: "scale", - }, - } - - for i, testcase := range testcases { - t.Run(testcase.name, func(t *testing.T) { - invocation, err := a.ShouldCallHook(webhook.NewValidatingWebhookAccessor(fmt.Sprintf("webhook-%d", i), fmt.Sprintf("webhook-cfg-%d", i), testcase.webhook), testcase.attrs, interfaces) - if err != nil { - if len(testcase.expectErr) == 0 { - t.Fatal(err) - } - if !strings.Contains(err.Error(), testcase.expectErr) { - t.Fatalf("expected error containing %q, got %s", testcase.expectErr, err.Error()) - } - return - } else if len(testcase.expectErr) > 0 { - t.Fatalf("expected error %q, got no error and %#v", testcase.expectErr, invocation) - } - - if invocation == nil { - if testcase.expectCall { - t.Fatal("expected invocation, got nil") - } - return - } - - if !testcase.expectCall { - t.Fatal("unexpected invocation") - } - - if invocation.Kind != testcase.expectCallKind { - t.Fatalf("expected %#v, got %#v", testcase.expectCallKind, invocation.Kind) - } - if invocation.Resource != testcase.expectCallResource { - t.Fatalf("expected %#v, got %#v", testcase.expectCallResource, invocation.Resource) - } - if invocation.Subresource != testcase.expectCallSubresource { - t.Fatalf("expected %#v, got %#v", testcase.expectCallSubresource, invocation.Subresource) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer.go index 2e821aad210..702c11a8f02 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer.go @@ -32,7 +32,7 @@ type WantsServiceResolver interface { // ServiceResolver knows how to convert a service reference into an actual // location. type ServiceResolver interface { - ResolveEndpoint(namespace, name string, port int32) (*url.URL, error) + ResolveEndpoint(namespace, name string) (*url.URL, error) } // WantsAuthenticationInfoResolverWrapper defines a function that wraps the standard AuthenticationInfoResolver diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer_test.go index bc48a34eff2..52abeeabe95 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/initializer/initializer_test.go @@ -30,7 +30,7 @@ func (doNothingAdmission) Handles(o admission.Operation) bool { return false } type fakeServiceResolver struct{} -func (f *fakeServiceResolver) ResolveEndpoint(namespace, name string, port int32) (*url.URL, error) { +func (f *fakeServiceResolver) ResolveEndpoint(namespace, name string) (*url.URL, error) { return nil, nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go index 1d337fb435a..d646bacb535 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher.go @@ -24,286 +24,124 @@ import ( "time" jsonpatch "github.com/evanphx/json-patch" - - apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/klog" - admissionv1 "k8s.io/api/admission/v1" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + admissionv1beta1 "k8s.io/api/admission/v1beta1" + "k8s.io/api/admissionregistration/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/serializer/json" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/admission" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" - "k8s.io/apiserver/pkg/admission/plugin/webhook" webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" - webhookrequest "k8s.io/apiserver/pkg/admission/plugin/webhook/request" - auditinternal "k8s.io/apiserver/pkg/apis/audit" - webhookutil "k8s.io/apiserver/pkg/util/webhook" - utiltrace "k8s.io/utils/trace" -) - -const ( - // PatchAuditAnnotationPrefix is a prefix for persisting webhook patch in audit annotation. - // Audit handler decides whether annotation with this prefix should be logged based on audit level. - // Since mutating webhook patches the request body, audit level must be greater or equal to Request - // for the annotation to be logged - PatchAuditAnnotationPrefix = "patch.webhook.admission.k8s.io/" - // MutationAuditAnnotationPrefix is a prefix for presisting webhook mutation existence in audit annotation. - MutationAuditAnnotationPrefix = "mutation.webhook.admission.k8s.io/" + "k8s.io/apiserver/pkg/admission/plugin/webhook/request" + "k8s.io/apiserver/pkg/admission/plugin/webhook/util" + "k8s.io/apiserver/pkg/util/webhook" ) -var encodingjson = json.CaseSensitiveJsonIterator() - type mutatingDispatcher struct { - cm *webhookutil.ClientManager + cm *webhook.ClientManager plugin *Plugin } -func newMutatingDispatcher(p *Plugin) func(cm *webhookutil.ClientManager) generic.Dispatcher { - return func(cm *webhookutil.ClientManager) generic.Dispatcher { +func newMutatingDispatcher(p *Plugin) func(cm *webhook.ClientManager) generic.Dispatcher { + return func(cm *webhook.ClientManager) generic.Dispatcher { return &mutatingDispatcher{cm, p} } } var _ generic.Dispatcher = &mutatingDispatcher{} -func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces, hooks []webhook.WebhookAccessor) error { - reinvokeCtx := attr.GetReinvocationContext() - var webhookReinvokeCtx *webhookReinvokeContext - if v := reinvokeCtx.Value(PluginName); v != nil { - webhookReinvokeCtx = v.(*webhookReinvokeContext) - } else { - webhookReinvokeCtx = &webhookReinvokeContext{} - reinvokeCtx.SetValue(PluginName, webhookReinvokeCtx) - } - - if reinvokeCtx.IsReinvoke() && webhookReinvokeCtx.IsOutputChangedSinceLastWebhookInvocation(attr.GetObject()) { - // If the object has changed, we know the in-tree plugin re-invocations have mutated the object, - // and we need to reinvoke all eligible webhooks. - webhookReinvokeCtx.RequireReinvokingPreviouslyInvokedPlugins() - } - defer func() { - webhookReinvokeCtx.SetLastWebhookInvocationOutput(attr.GetObject()) - }() - var versionedAttr *generic.VersionedAttributes - for i, hook := range hooks { - attrForCheck := attr - if versionedAttr != nil { - attrForCheck = versionedAttr - } - invocation, statusErr := a.plugin.ShouldCallHook(hook, attrForCheck, o) - if statusErr != nil { - return statusErr - } - if invocation == nil { - continue - } - hook, ok := invocation.Webhook.GetMutatingWebhook() - if !ok { - return fmt.Errorf("mutating webhook dispatch requires v1.MutatingWebhook, but got %T", hook) - } - // This means that during reinvocation, a webhook will not be - // called for the first time. For example, if the webhook is - // skipped in the first round because of mismatching labels, - // even if the labels become matching, the webhook does not - // get called during reinvocation. - if reinvokeCtx.IsReinvoke() && !webhookReinvokeCtx.ShouldReinvokeWebhook(invocation.Webhook.GetUID()) { - continue - } - - if versionedAttr == nil { - // First webhook, create versioned attributes - var err error - if versionedAttr, err = generic.NewVersionedAttributes(attr, invocation.Kind, o); err != nil { - return apierrors.NewInternalError(err) - } - } else { - // Subsequent webhook, convert existing versioned attributes to this webhook's version - if err := generic.ConvertVersionedAttributes(versionedAttr, invocation.Kind, o); err != nil { - return apierrors.NewInternalError(err) - } - } - +func (a *mutatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, relevantHooks []*v1beta1.Webhook) error { + for _, hook := range relevantHooks { t := time.Now() - round := 0 - if reinvokeCtx.IsReinvoke() { - round = 1 - } - changed, err := a.callAttrMutatingHook(ctx, hook, invocation, versionedAttr, o, round, i) - ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == admissionregistrationv1.Ignore - rejected := false - if err != nil { - switch err := err.(type) { - case *webhookutil.ErrCallingWebhook: - if !ignoreClientCallFailures { - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0) - } - case *webhookutil.ErrWebhookRejection: - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code)) - default: - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "admit", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0) - } - } - admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "admit", hook.Name) - if changed { - // Patch had changed the object. Prepare to reinvoke all previous webhooks that are eligible for re-invocation. - webhookReinvokeCtx.RequireReinvokingPreviouslyInvokedPlugins() - reinvokeCtx.SetShouldReinvoke() - } - if hook.ReinvocationPolicy != nil && *hook.ReinvocationPolicy == admissionregistrationv1.IfNeededReinvocationPolicy { - webhookReinvokeCtx.AddReinvocableWebhookToPreviouslyInvoked(invocation.Webhook.GetUID()) - } + err := a.callAttrMutatingHook(ctx, hook, attr) + admissionmetrics.Metrics.ObserveWebhook(time.Since(t), err != nil, attr.Attributes, "admit", hook.Name) if err == nil { continue } - if callErr, ok := err.(*webhookutil.ErrCallingWebhook); ok { + ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore + if callErr, ok := err.(*webhook.ErrCallingWebhook); ok { if ignoreClientCallFailures { klog.Warningf("Failed calling webhook, failing open %v: %v", hook.Name, callErr) utilruntime.HandleError(callErr) - - select { - case <-ctx.Done(): - // parent context is canceled or timed out, no point in continuing - return apierrors.NewTimeoutError("request did not complete within requested timeout", 0) - default: - // individual webhook timed out, but parent context did not, continue - continue - } + continue } klog.Warningf("Failed calling webhook, failing closed %v: %v", hook.Name, err) - return apierrors.NewInternalError(err) - } - if rejectionErr, ok := err.(*webhookutil.ErrWebhookRejection); ok { - return rejectionErr.Status } - return err + return apierrors.NewInternalError(err) } - // convert versionedAttr.VersionedObject to the internal version in the underlying admission.Attributes - if versionedAttr != nil && versionedAttr.VersionedObject != nil && versionedAttr.Dirty { - return o.GetObjectConvertor().Convert(versionedAttr.VersionedObject, versionedAttr.Attributes.GetObject(), nil) + // convert attr.VersionedObject to the internal version in the underlying admission.Attributes + if attr.VersionedObject != nil { + return a.plugin.scheme.Convert(attr.VersionedObject, attr.Attributes.GetObject(), nil) } - return nil } // note that callAttrMutatingHook updates attr - -func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admissionregistrationv1.MutatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes, o admission.ObjectInterfaces, round, idx int) (bool, error) { - configurationName := invocation.Webhook.GetConfigurationName() - annotator := newWebhookAnnotator(attr, round, idx, h.Name, configurationName) - changed := false - defer func() { annotator.addMutationAnnotation(changed) }() - if attr.Attributes.IsDryRun() { +func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *v1beta1.Webhook, attr *generic.VersionedAttributes) error { + if attr.IsDryRun() { if h.SideEffects == nil { - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")} + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")} } - if !(*h.SideEffects == admissionregistrationv1.SideEffectClassNone || *h.SideEffects == admissionregistrationv1.SideEffectClassNoneOnDryRun) { - return false, webhookerrors.NewDryRunUnsupportedErr(h.Name) + if !(*h.SideEffects == v1beta1.SideEffectClassNone || *h.SideEffects == v1beta1.SideEffectClassNoneOnDryRun) { + return webhookerrors.NewDryRunUnsupportedErr(h.Name) } } - uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation) - if err != nil { - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} - } // Make the webhook request - client, err := invocation.Webhook.GetRESTClient(a.cm) + request := request.CreateAdmissionReview(attr) + client, err := a.cm.HookClient(util.HookClientConfigForWebhook(h)) if err != nil { - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} - } - trace := utiltrace.New("Call mutating webhook", - utiltrace.Field{"configuration", configurationName}, - utiltrace.Field{"webhook", h.Name}, - utiltrace.Field{"resource", attr.GetResource()}, - utiltrace.Field{"subresource", attr.GetSubresource()}, - utiltrace.Field{"operation", attr.GetOperation()}, - utiltrace.Field{"UID", uid}) - defer trace.LogIfLong(500 * time.Millisecond) - - // if the webhook has a specific timeout, wrap the context to apply it - if h.TimeoutSeconds != nil { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, time.Duration(*h.TimeoutSeconds)*time.Second) - defer cancel() - } - - r := client.Post().Body(request) - - // if the context has a deadline, set it as a parameter to inform the backend - if deadline, hasDeadline := ctx.Deadline(); hasDeadline { - // compute the timeout - if timeout := time.Until(deadline); timeout > 0 { - // if it's not an even number of seconds, round up to the nearest second - if truncated := timeout.Truncate(time.Second); truncated != timeout { - timeout = truncated + time.Second - } - // set the timeout - r.Timeout(timeout) - } + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err} } - - if err := r.Do(ctx).Into(response); err != nil { - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} + response := &admissionv1beta1.AdmissionReview{} + if err := client.Post().Context(ctx).Body(&request).Do().Into(response); err != nil { + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err} } - trace.Step("Request completed") - result, err := webhookrequest.VerifyAdmissionResponse(uid, true, response) - if err != nil { - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} + if response.Response == nil { + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")} } - for k, v := range result.AuditAnnotations { + for k, v := range response.Response.AuditAnnotations { key := h.Name + "/" + k - if err := attr.Attributes.AddAnnotation(key, v); err != nil { + if err := attr.AddAnnotation(key, v); err != nil { klog.Warningf("Failed to set admission audit annotation %s to %s for mutating webhook %s: %v", key, v, h.Name, err) } } - if !result.Allowed { - return false, &webhookutil.ErrWebhookRejection{Status: webhookerrors.ToStatusErr(h.Name, result.Result)} + if !response.Response.Allowed { + return webhookerrors.ToStatusErr(h.Name, response.Response.Result) } - if len(result.Patch) == 0 { - return false, nil + patchJS := response.Response.Patch + if len(patchJS) == 0 { + return nil } - patchObj, err := jsonpatch.DecodePatch(result.Patch) + patchObj, err := jsonpatch.DecodePatch(patchJS) if err != nil { - return false, apierrors.NewInternalError(err) + return apierrors.NewInternalError(err) } - if len(patchObj) == 0 { - return false, nil + return nil } // if a non-empty patch was provided, and we have no object we can apply it to (e.g. a DELETE admission operation), error if attr.VersionedObject == nil { - return false, apierrors.NewInternalError(fmt.Errorf("admission webhook %q attempted to modify the object, which is not supported for this operation", h.Name)) + return apierrors.NewInternalError(fmt.Errorf("admission webhook %q attempted to modify the object, which is not supported for this operation", h.Name)) } - var patchedJS []byte - jsonSerializer := json.NewSerializer(json.DefaultMetaFactory, o.GetObjectCreater(), o.GetObjectTyper(), false) - switch result.PatchType { - // VerifyAdmissionResponse normalizes to v1 patch types, regardless of the AdmissionReview version used - case admissionv1.PatchTypeJSONPatch: - objJS, err := runtime.Encode(jsonSerializer, attr.VersionedObject) - if err != nil { - return false, apierrors.NewInternalError(err) - } - patchedJS, err = patchObj.Apply(objJS) - if err != nil { - return false, apierrors.NewInternalError(err) - } - default: - return false, &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("unsupported patch type %q", result.PatchType)} + objJS, err := runtime.Encode(a.plugin.jsonSerializer, attr.VersionedObject) + if err != nil { + return apierrors.NewInternalError(err) + } + patchedJS, err := patchObj.Apply(objJS) + if err != nil { + return apierrors.NewInternalError(err) } var newVersionedObject runtime.Object @@ -312,115 +150,17 @@ func (a *mutatingDispatcher) callAttrMutatingHook(ctx context.Context, h *admiss // They are represented as Unstructured. newVersionedObject = &unstructured.Unstructured{} } else { - newVersionedObject, err = o.GetObjectCreater().New(attr.VersionedKind) + newVersionedObject, err = a.plugin.scheme.New(attr.GetKind()) if err != nil { - return false, apierrors.NewInternalError(err) + return apierrors.NewInternalError(err) } } - // TODO: if we have multiple mutating webhooks, we can remember the json // instead of encoding and decoding for each one. - if newVersionedObject, _, err = jsonSerializer.Decode(patchedJS, nil, newVersionedObject); err != nil { - return false, apierrors.NewInternalError(err) + if _, _, err := a.plugin.jsonSerializer.Decode(patchedJS, nil, newVersionedObject); err != nil { + return apierrors.NewInternalError(err) } - - changed = !apiequality.Semantic.DeepEqual(attr.VersionedObject, newVersionedObject) - trace.Step("Patch applied") - annotator.addPatchAnnotation(patchObj, result.PatchType) - attr.Dirty = true attr.VersionedObject = newVersionedObject - o.GetObjectDefaulter().Default(attr.VersionedObject) - return changed, nil -} - -type webhookAnnotator struct { - attr *generic.VersionedAttributes - patchAnnotationKey string - mutationAnnotationKey string - webhook string - configuration string -} - -func newWebhookAnnotator(attr *generic.VersionedAttributes, round, idx int, webhook, configuration string) *webhookAnnotator { - return &webhookAnnotator{ - attr: attr, - patchAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", PatchAuditAnnotationPrefix, round, idx), - mutationAnnotationKey: fmt.Sprintf("%sround_%d_index_%d", MutationAuditAnnotationPrefix, round, idx), - webhook: webhook, - configuration: configuration, - } -} - -func (w *webhookAnnotator) addMutationAnnotation(mutated bool) { - if w.attr == nil || w.attr.Attributes == nil { - return - } - value, err := mutationAnnotationValue(w.configuration, w.webhook, mutated) - if err != nil { - klog.Warningf("unexpected error composing mutating webhook annotation: %v", err) - return - } - if err := w.attr.Attributes.AddAnnotation(w.mutationAnnotationKey, value); err != nil { - klog.Warningf("failed to set mutation annotation for mutating webhook key %s to %s: %v", w.mutationAnnotationKey, value, err) - } -} - -func (w *webhookAnnotator) addPatchAnnotation(patch interface{}, patchType admissionv1.PatchType) { - if w.attr == nil || w.attr.Attributes == nil { - return - } - var value string - var err error - switch patchType { - case admissionv1.PatchTypeJSONPatch: - value, err = jsonPatchAnnotationValue(w.configuration, w.webhook, patch) - if err != nil { - klog.Warningf("unexpected error composing mutating webhook JSON patch annotation: %v", err) - return - } - default: - klog.Warningf("unsupported patch type for mutating webhook annotation: %v", patchType) - return - } - if err := w.attr.Attributes.AddAnnotationWithLevel(w.patchAnnotationKey, value, auditinternal.LevelRequest); err != nil { - // NOTE: we don't log actual patch in kube-apiserver log to avoid potentially - // leaking information - klog.Warningf("failed to set patch annotation for mutating webhook key %s; confugiration name: %s, webhook name: %s", w.patchAnnotationKey, w.configuration, w.webhook) - } -} - -// MutationAuditAnnotation logs if a webhook invocation mutated the request object -type MutationAuditAnnotation struct { - Configuration string `json:"configuration"` - Webhook string `json:"webhook"` - Mutated bool `json:"mutated"` -} - -// PatchAuditAnnotation logs a patch from a mutating webhook -type PatchAuditAnnotation struct { - Configuration string `json:"configuration"` - Webhook string `json:"webhook"` - Patch interface{} `json:"patch,omitempty"` - PatchType string `json:"patchType,omitempty"` -} - -func mutationAnnotationValue(configuration, webhook string, mutated bool) (string, error) { - m := MutationAuditAnnotation{ - Configuration: configuration, - Webhook: webhook, - Mutated: mutated, - } - bytes, err := encodingjson.Marshal(m) - return string(bytes), err -} - -func jsonPatchAnnotationValue(configuration, webhook string, patch interface{}) (string, error) { - p := PatchAuditAnnotation{ - Configuration: configuration, - Webhook: webhook, - Patch: patch, - PatchType: string(admissionv1.PatchTypeJSONPatch), - } - bytes, err := encodingjson.Marshal(p) - return string(bytes), err + a.plugin.scheme.Default(attr.VersionedObject) + return nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go index d64dd15f327..ccea2686243 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/dispatcher_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,116 +17,121 @@ limitations under the License. package mutating import ( - "encoding/json" + "context" "reflect" "testing" - jsonpatch "github.com/evanphx/json-patch" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" + "k8s.io/apiserver/pkg/apis/example" + examplev1 "k8s.io/apiserver/pkg/apis/example/v1" + example2v1 "k8s.io/apiserver/pkg/apis/example2/v1" ) -func TestMutationAnnotationValue(t *testing.T) { - tcs := []struct { - config string - webhook string - mutated bool - expected string - }{ - { - config: "test-config", - webhook: "test-webhook", - mutated: true, - expected: `{"configuration":"test-config","webhook":"test-webhook","mutated":true}`, - }, - { - config: "test-config", - webhook: "test-webhook", - mutated: false, - expected: `{"configuration":"test-config","webhook":"test-webhook","mutated":false}`, +var sampleCRD = unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "mygroup.k8s.io/v1", + "kind": "Flunder", + "data": map[string]interface{}{ + "Key": "Value", }, - } - - for _, tc := range tcs { - actual, err := mutationAnnotationValue(tc.config, tc.webhook, tc.mutated) - assert.NoError(t, err, "unexpected error") - if actual != tc.expected { - t.Errorf("composed mutation annotation value doesn't match, want: %s, got: %s", tc.expected, actual) - } - } + }, } -func TestJSONPatchAnnotationValue(t *testing.T) { - tcs := []struct { - name string - config string - webhook string - patch []byte - expected string +func TestDispatch(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, example.AddToScheme(scheme)) + require.NoError(t, examplev1.AddToScheme(scheme)) + require.NoError(t, example2v1.AddToScheme(scheme)) + + tests := []struct { + name string + in runtime.Object + out runtime.Object + expectedObj runtime.Object }{ { - name: "valid patch annotation", - config: "test-config", - webhook: "test-webhook", - patch: []byte(`[{"op": "add", "path": "/metadata/labels/a", "value": "true"}]`), - expected: `{"configuration":"test-config","webhook":"test-webhook","patch":[{"op":"add","path":"/metadata/labels/a","value":"true"}],"patchType":"JSONPatch"}`, + name: "convert example/v1#Pod to example#Pod", + in: &examplev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Labels: map[string]string{ + "key": "value", + }, + }, + Spec: examplev1.PodSpec{ + RestartPolicy: examplev1.RestartPolicy("never"), + }, + }, + out: &example.Pod{}, + expectedObj: &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Labels: map[string]string{ + "key": "value", + }, + }, + Spec: example.PodSpec{ + RestartPolicy: example.RestartPolicy("never"), + }, + }, }, { - name: "empty configuration", - config: "", - webhook: "test-webhook", - patch: []byte(`[{"op": "add", "path": "/metadata/labels/a", "value": "true"}]`), - expected: `{"configuration":"","webhook":"test-webhook","patch":[{"op":"add","path":"/metadata/labels/a","value":"true"}],"patchType":"JSONPatch"}`, + name: "convert example2/v1#replicaset to example#replicaset", + in: &example2v1.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rs1", + Labels: map[string]string{ + "key": "value", + }, + }, + Spec: example2v1.ReplicaSetSpec{ + Replicas: func() *int32 { var i int32; i = 1; return &i }(), + }, + }, + out: &example.ReplicaSet{}, + expectedObj: &example.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rs1", + Labels: map[string]string{ + "key": "value", + }, + }, + Spec: example.ReplicaSetSpec{ + Replicas: 1, + }, + }, }, { - name: "empty webhook", - config: "test-config", - webhook: "", - patch: []byte(`[{"op": "add", "path": "/metadata/labels/a", "value": "true"}]`), - expected: `{"configuration":"test-config","webhook":"","patch":[{"op":"add","path":"/metadata/labels/a","value":"true"}],"patchType":"JSONPatch"}`, - }, - { - name: "valid JSON patch empty operation", - config: "test-config", - webhook: "test-webhook", - patch: []byte("[{}]"), - expected: `{"configuration":"test-config","webhook":"test-webhook","patch":[{}],"patchType":"JSONPatch"}`, - }, - { - name: "empty slice patch", - config: "test-config", - webhook: "test-webhook", - patch: []byte("[]"), - expected: `{"configuration":"test-config","webhook":"test-webhook","patch":[],"patchType":"JSONPatch"}`, + name: "no conversion if the object is the same", + in: &sampleCRD, + out: &sampleCRD, + expectedObj: &sampleCRD, }, } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - jsonPatch, err := jsonpatch.DecodePatch(tc.patch) - assert.NoError(t, err, "unexpected error decode patch") - actual, err := jsonPatchAnnotationValue(tc.config, tc.webhook, jsonPatch) - assert.NoError(t, err, "unexpected error getting json patch annotation") - if actual != tc.expected { - t.Errorf("composed patch annotation value doesn't match, want: %s, got: %s", tc.expected, actual) - } - - var p map[string]interface{} - if err := json.Unmarshal([]byte(actual), &p); err != nil { - t.Errorf("unexpected error unmarshaling patch annotation: %v", err) - } - if p["configuration"] != tc.config { - t.Errorf("unmarshaled configuration doesn't match, want: %s, got: %v", tc.config, p["configuration"]) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + a := &mutatingDispatcher{ + plugin: &Plugin{ + scheme: scheme, + }, } - if p["webhook"] != tc.webhook { - t.Errorf("unmarshaled webhook doesn't match, want: %s, got: %v", tc.webhook, p["webhook"]) + attr := generic.VersionedAttributes{ + Attributes: admission.NewAttributesRecord(test.out, nil, schema.GroupVersionKind{}, "", "", schema.GroupVersionResource{}, "", admission.Operation(""), false, nil), + VersionedOldObject: nil, + VersionedObject: test.in, } - var expectedPatch interface{} - err = json.Unmarshal(tc.patch, &expectedPatch) - if err != nil { - t.Errorf("unexpected error unmarshaling patch: %v, %v", tc.patch, err) + if err := a.Dispatch(context.TODO(), &attr, nil); err != nil { + t.Fatalf("%s: unexpected error: %v", test.name, err) } - if !reflect.DeepEqual(expectedPatch, p["patch"]) { - t.Errorf("unmarshaled patch doesn't match, want: %v, got: %v", expectedPatch, p["patch"]) + if !reflect.DeepEqual(attr.Attributes.GetObject(), test.expectedObj) { + t.Errorf("\nexpected:\n%#v\ngot:\n %#v\n", test.expectedObj, test.out) } }) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin.go index fb07a61c1b8..33572b24b5b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin.go @@ -17,9 +17,11 @@ limitations under the License. package mutating import ( - "context" + "fmt" "io" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer/json" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/configuration" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" @@ -45,6 +47,9 @@ func Register(plugins *admission.Plugins) { // Plugin is an implementation of admission.Interface. type Plugin struct { *generic.Webhook + + scheme *runtime.Scheme + jsonSerializer *json.Serializer } var _ admission.MutationInterface = &Plugin{} @@ -62,15 +67,30 @@ func NewMutatingWebhook(configFile io.Reader) (*Plugin, error) { return p, nil } +// SetScheme sets a serializer(NegotiatedSerializer) which is derived from the scheme +func (a *Plugin) SetScheme(scheme *runtime.Scheme) { + a.Webhook.SetScheme(scheme) + if scheme != nil { + a.scheme = scheme + a.jsonSerializer = json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false) + } +} + // ValidateInitialization implements the InitializationValidator interface. func (a *Plugin) ValidateInitialization() error { if err := a.Webhook.ValidateInitialization(); err != nil { return err } + if a.scheme == nil { + return fmt.Errorf("scheme is not properly setup") + } + if a.jsonSerializer == nil { + return fmt.Errorf("jsonSerializer is not properly setup") + } return nil } // Admit makes an admission decision based on the request attributes. -func (a *Plugin) Admit(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { - return a.Webhook.Dispatch(ctx, attr, o) +func (a *Plugin) Admit(attr admission.Attributes) error { + return a.Webhook.Dispatch(attr) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin_test.go index a7f5bd1d96f..e41f84aee43 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/plugin_test.go @@ -17,96 +17,29 @@ limitations under the License. package mutating import ( - "context" - "fmt" "net/url" - "os" "reflect" "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/api/admission/v1beta1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing" - auditinternal "k8s.io/apiserver/pkg/apis/audit" ) -// BenchmarkAdmit tests the performance cost of invoking a mutating webhook -func BenchmarkAdmit(b *testing.B) { - testServerURL := os.Getenv("WEBHOOK_TEST_SERVER_URL") - if len(testServerURL) == 0 { - b.Log("warning, WEBHOOK_TEST_SERVER_URL not set, starting in-process server, benchmarks will include webhook cost.") - b.Log("to run a standalone server, run:") - b.Log("go run ./vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main/main.go") - testServer := webhooktesting.NewTestServer(b) - testServer.StartTLS() - defer testServer.Close() - testServerURL = testServer.URL - } - - serverURL, err := url.ParseRequestURI(testServerURL) - if err != nil { - b.Fatalf("this should never happen? %v", err) - } - - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - - stopCh := make(chan struct{}) - defer close(stopCh) - - testCases := append(webhooktesting.NewMutatingTestCases(serverURL, "test-webhooks"), - webhooktesting.ConvertToMutatingTestCases(webhooktesting.NewNonMutatingTestCases(serverURL), "test-webhooks")...) - - for _, tt := range testCases { - // For now, skip failure cases or tests that explicitly skip benchmarking - if !tt.ExpectAllow || tt.SkipBenchmark { - continue - } - b.Run(tt.Name, func(b *testing.B) { - wh, err := NewMutatingWebhook(nil) - if err != nil { - b.Errorf("failed to create mutating webhook: %v", err) - return - } - - ns := "webhook-test" - client, informer := webhooktesting.NewFakeMutatingDataSource(ns, tt.Webhooks, stopCh) - - wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32)))) - wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) - wh.SetExternalKubeClientSet(client) - wh.SetExternalKubeInformerFactory(informer) - - informer.Start(stopCh) - informer.WaitForCacheSync(stopCh) - - if err = wh.ValidateInitialization(); err != nil { - b.Errorf("failed to validate initialization: %v", err) - return - } - - var attr admission.Attributes - if tt.IsCRD { - attr = webhooktesting.NewAttributeUnstructured(ns, tt.AdditionalLabels, tt.IsDryRun) - } else { - attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun) - } - - b.ResetTimer() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - wh.Admit(context.TODO(), attr, objectInterfaces) - } - }) - }) - } -} - // TestAdmit tests that MutatingWebhook#Admit works as expected func TestAdmit(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, v1beta1.AddToScheme(scheme)) + require.NoError(t, corev1.AddToScheme(scheme)) + testServer := webhooktesting.NewTestServer(t) testServer.StartTLS() defer testServer.Close() @@ -115,91 +48,80 @@ func TestAdmit(t *testing.T) { t.Fatalf("this should never happen? %v", err) } - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - stopCh := make(chan struct{}) defer close(stopCh) - testCases := append(webhooktesting.NewMutatingTestCases(serverURL, "test-webhooks"), - webhooktesting.ConvertToMutatingTestCases(webhooktesting.NewNonMutatingTestCases(serverURL), "test-webhooks")...) + testCases := append(webhooktesting.NewMutatingTestCases(serverURL), + webhooktesting.NewNonMutatingTestCases(serverURL)...) for _, tt := range testCases { - t.Run(tt.Name, func(t *testing.T) { - wh, err := NewMutatingWebhook(nil) - if err != nil { - t.Errorf("failed to create mutating webhook: %v", err) - return - } + wh, err := NewMutatingWebhook(nil) + if err != nil { + t.Errorf("%s: failed to create mutating webhook: %v", tt.Name, err) + continue + } - ns := "webhook-test" - client, informer := webhooktesting.NewFakeMutatingDataSource(ns, tt.Webhooks, stopCh) + ns := "webhook-test" + client, informer := webhooktesting.NewFakeDataSource(ns, tt.Webhooks, true, stopCh) - wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32)))) - wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) - wh.SetExternalKubeClientSet(client) - wh.SetExternalKubeInformerFactory(informer) + wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32)))) + wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) + wh.SetScheme(scheme) + wh.SetExternalKubeClientSet(client) + wh.SetExternalKubeInformerFactory(informer) - informer.Start(stopCh) - informer.WaitForCacheSync(stopCh) + informer.Start(stopCh) + informer.WaitForCacheSync(stopCh) - if err = wh.ValidateInitialization(); err != nil { - t.Errorf("failed to validate initialization: %v", err) - return - } + if err = wh.ValidateInitialization(); err != nil { + t.Errorf("%s: failed to validate initialization: %v", tt.Name, err) + continue + } - var attr admission.Attributes - if tt.IsCRD { - attr = webhooktesting.NewAttributeUnstructured(ns, tt.AdditionalLabels, tt.IsDryRun) - } else { - attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun) - } + var attr admission.Attributes + if tt.IsCRD { + attr = webhooktesting.NewAttributeUnstructured(ns, tt.AdditionalLabels, tt.IsDryRun) + } else { + attr = webhooktesting.NewAttribute(ns, tt.AdditionalLabels, tt.IsDryRun) + } - err = wh.Admit(context.TODO(), attr, objectInterfaces) - if tt.ExpectAllow != (err == nil) { - t.Errorf("expected allowed=%v, but got err=%v", tt.ExpectAllow, err) - } - if tt.ExpectLabels != nil { - if !reflect.DeepEqual(tt.ExpectLabels, attr.GetObject().(metav1.Object).GetLabels()) { - t.Errorf("expected labels '%v', but got '%v'", tt.ExpectLabels, attr.GetObject().(metav1.Object).GetLabels()) - } - } - // ErrWebhookRejected is not an error for our purposes - if tt.ErrorContains != "" { - if err == nil || !strings.Contains(err.Error(), tt.ErrorContains) { - t.Errorf("expected an error saying %q, but got: %v", tt.ErrorContains, err) - } - } - if statusErr, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr { - t.Errorf("expected a StatusError, got %T", err) - } else if isStatusErr { - if statusErr.ErrStatus.Code != tt.ExpectStatusCode { - t.Errorf("expected status code %d, got %d", tt.ExpectStatusCode, statusErr.ErrStatus.Code) - } - } - fakeAttr, ok := attr.(*webhooktesting.FakeAttributes) - if !ok { - t.Errorf("Unexpected error, failed to convert attr to webhooktesting.FakeAttributes") - return - } - if len(tt.ExpectAnnotations) == 0 { - assert.Empty(t, fakeAttr.GetAnnotations(auditinternal.LevelMetadata), tt.Name+": annotations not set as expected.") - } else { - assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(auditinternal.LevelMetadata), tt.Name+": annotations not set as expected.") + err = wh.Admit(attr) + if tt.ExpectAllow != (err == nil) { + t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) + } + if tt.ExpectLabels != nil { + if !reflect.DeepEqual(tt.ExpectLabels, attr.GetObject().(metav1.Object).GetLabels()) { + t.Errorf("%s: expected labels '%v', but got '%v'", tt.Name, tt.ExpectLabels, attr.GetObject().(metav1.Object).GetLabels()) } - reinvocationCtx := fakeAttr.Attributes.GetReinvocationContext() - reinvocationCtx.SetIsReinvoke() - for webhook, expectReinvoke := range tt.ExpectReinvokeWebhooks { - shouldReinvoke := reinvocationCtx.Value(PluginName).(*webhookReinvokeContext).ShouldReinvokeWebhook(fmt.Sprintf("test-webhooks/%s/0", webhook)) - if expectReinvoke != shouldReinvoke { - t.Errorf("expected reinvocationContext.ShouldReinvokeWebhook(%s)=%t, but got %t", webhook, expectReinvoke, shouldReinvoke) - } + } + // ErrWebhookRejected is not an error for our purposes + if tt.ErrorContains != "" { + if err == nil || !strings.Contains(err.Error(), tt.ErrorContains) { + t.Errorf("%s: expected an error saying %q, but got: %v", tt.Name, tt.ErrorContains, err) } - }) + } + if _, isStatusErr := err.(*errors.StatusError); err != nil && !isStatusErr { + t.Errorf("%s: expected a StatusError, got %T", tt.Name, err) + } + fakeAttr, ok := attr.(*webhooktesting.FakeAttributes) + if !ok { + t.Errorf("Unexpected error, failed to convert attr to webhooktesting.FakeAttributes") + continue + } + if len(tt.ExpectAnnotations) == 0 { + assert.Empty(t, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.") + } else { + assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.") + } } } // TestAdmitCachedClient tests that MutatingWebhook#Admit should cache restClient func TestAdmitCachedClient(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, v1beta1.AddToScheme(scheme)) + require.NoError(t, corev1.AddToScheme(scheme)) + testServer := webhooktesting.NewTestServer(t) testServer.StartTLS() defer testServer.Close() @@ -208,8 +130,6 @@ func TestAdmitCachedClient(t *testing.T) { t.Fatalf("this should never happen? %v", err) } - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - stopCh := make(chan struct{}) defer close(stopCh) @@ -218,10 +138,11 @@ func TestAdmitCachedClient(t *testing.T) { t.Fatalf("Failed to create mutating webhook: %v", err) } wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) + wh.SetScheme(scheme) for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) { ns := "webhook-test" - client, informer := webhooktesting.NewFakeMutatingDataSource(ns, webhooktesting.ConvertToMutatingWebhooks(tt.Webhooks), stopCh) + client, informer := webhooktesting.NewFakeDataSource(ns, tt.Webhooks, true, stopCh) // override the webhook source. The client cache will stay the same. cacheMisses := new(int32) @@ -237,7 +158,7 @@ func TestAdmitCachedClient(t *testing.T) { continue } - err = wh.Admit(context.TODO(), webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) + err = wh.Admit(webhooktesting.NewAttribute(ns, nil, false)) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/reinvocationcontext.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/reinvocationcontext.go deleted file mode 100644 index de0af221e13..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating/reinvocationcontext.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2019 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 mutating - -import ( - apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" -) - -type webhookReinvokeContext struct { - // lastWebhookOutput holds the result of the last webhook admission plugin call - lastWebhookOutput runtime.Object - // previouslyInvokedReinvocableWebhooks holds the set of webhooks that have been invoked and - // should be reinvoked if a later mutation occurs - previouslyInvokedReinvocableWebhooks sets.String - // reinvokeWebhooks holds the set of webhooks that should be reinvoked - reinvokeWebhooks sets.String -} - -func (rc *webhookReinvokeContext) ShouldReinvokeWebhook(webhook string) bool { - return rc.reinvokeWebhooks.Has(webhook) -} - -func (rc *webhookReinvokeContext) IsOutputChangedSinceLastWebhookInvocation(object runtime.Object) bool { - return !apiequality.Semantic.DeepEqual(rc.lastWebhookOutput, object) -} - -func (rc *webhookReinvokeContext) SetLastWebhookInvocationOutput(object runtime.Object) { - if object == nil { - rc.lastWebhookOutput = nil - return - } - rc.lastWebhookOutput = object.DeepCopyObject() -} - -func (rc *webhookReinvokeContext) AddReinvocableWebhookToPreviouslyInvoked(webhook string) { - if rc.previouslyInvokedReinvocableWebhooks == nil { - rc.previouslyInvokedReinvocableWebhooks = sets.NewString() - } - rc.previouslyInvokedReinvocableWebhooks.Insert(webhook) -} - -func (rc *webhookReinvokeContext) RequireReinvokingPreviouslyInvokedPlugins() { - if len(rc.previouslyInvokedReinvocableWebhooks) > 0 { - if rc.reinvokeWebhooks == nil { - rc.reinvokeWebhooks = sets.NewString() - } - for s := range rc.previouslyInvokedReinvocableWebhooks { - rc.reinvokeWebhooks.Insert(s) - } - rc.previouslyInvokedReinvocableWebhooks = sets.NewString() - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher.go index 183be7b39a4..a0541191539 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher.go @@ -17,16 +17,15 @@ limitations under the License. package namespace import ( - "context" "fmt" + "k8s.io/api/admissionregistration/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" clientset "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" ) @@ -77,7 +76,7 @@ func (m *Matcher) GetNamespaceLabels(attr admission.Attributes) (map[string]stri } if apierrors.IsNotFound(err) { // in case of latency in our caches, make a call direct to storage to verify that it truly exists or not - namespace, err = m.Client.CoreV1().Namespaces().Get(context.TODO(), namespaceName, metav1.GetOptions{}) + namespace, err = m.Client.CoreV1().Namespaces().Get(namespaceName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -87,7 +86,7 @@ func (m *Matcher) GetNamespaceLabels(attr admission.Attributes) (map[string]stri // MatchNamespaceSelector decideds whether the request matches the // namespaceSelctor of the webhook. Only when they match, the webhook is called. -func (m *Matcher) MatchNamespaceSelector(h webhook.WebhookAccessor, attr admission.Attributes) (bool, *apierrors.StatusError) { +func (m *Matcher) MatchNamespaceSelector(h *v1beta1.Webhook, attr admission.Attributes) (bool, *apierrors.StatusError) { namespaceName := attr.GetNamespace() if len(namespaceName) == 0 && attr.GetResource().Resource != "namespaces" { // If the request is about a cluster scoped resource, and it is not a @@ -96,14 +95,6 @@ func (m *Matcher) MatchNamespaceSelector(h webhook.WebhookAccessor, attr admissi // Also update the comment in types.go return true, nil } - selector, err := h.GetParsedNamespaceSelector() - if err != nil { - return false, apierrors.NewInternalError(err) - } - if selector.Empty() { - return true, nil - } - namespaceLabels, err := m.GetNamespaceLabels(attr) // this means the namespace is not found, for backwards compatibility, // return a 404 @@ -117,5 +108,10 @@ func (m *Matcher) MatchNamespaceSelector(h webhook.WebhookAccessor, attr admissi if err != nil { return false, apierrors.NewInternalError(err) } + // TODO: adding an LRU cache to cache the translation + selector, err := metav1.LabelSelectorAsSelector(h.NamespaceSelector) + if err != nil { + return false, apierrors.NewInternalError(err) + } return selector.Matches(labels.Set(namespaceLabels)), nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go index 331f0dd9228..bf7dee828c9 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/namespace/matcher_test.go @@ -20,14 +20,13 @@ import ( "reflect" "testing" - registrationv1 "k8s.io/api/admissionregistration/v1" + registrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" ) type fakeNamespaceLister struct { @@ -76,27 +75,27 @@ func TestGetNamespaceLabels(t *testing.T) { }{ { name: "request is for creating namespace, the labels should be from the object itself", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, "", namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, "", namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Create, false, nil), expectedLabels: namespace2Labels, }, { name: "request is for updating namespace, the labels should be from the new object", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace2.Name, namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Update, &metav1.UpdateOptions{}, false, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace2.Name, namespace2.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Update, false, nil), expectedLabels: namespace2Labels, }, { name: "request is for deleting namespace, the labels should be from the cache", - attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace1.Name, namespace1.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Delete, &metav1.DeleteOptions{}, false, nil), + attr: admission.NewAttributesRecord(&namespace2, nil, schema.GroupVersionKind{}, namespace1.Name, namespace1.Name, schema.GroupVersionResource{Resource: "namespaces"}, "", admission.Delete, false, nil), expectedLabels: namespace1Labels, }, { name: "request is for namespace/finalizer", - attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "namespaces"}, "finalizers", admission.Create, &metav1.CreateOptions{}, false, nil), + attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "namespaces"}, "finalizers", admission.Create, false, nil), expectedLabels: namespace1Labels, }, { name: "request is for pod", - attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "pods"}, "", admission.Create, &metav1.CreateOptions{}, false, nil), + attr: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, namespace1.Name, "mock-name", schema.GroupVersionResource{Resource: "pods"}, "", admission.Create, false, nil), expectedLabels: namespace1Labels, }, } @@ -115,12 +114,12 @@ func TestGetNamespaceLabels(t *testing.T) { } func TestNotExemptClusterScopedResource(t *testing.T) { - hook := ®istrationv1.ValidatingWebhook{ + hook := ®istrationv1beta1.Webhook{ NamespaceSelector: &metav1.LabelSelector{}, } - attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, &metav1.CreateOptions{}, false, nil) + attr := admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "mock-name", schema.GroupVersionResource{Version: "v1", Resource: "nodes"}, "", admission.Create, false, nil) matcher := Matcher{} - matches, err := matcher.MatchNamespaceSelector(webhook.NewValidatingWebhookAccessor("mock-hook", "mock-cfg", hook), attr) + matches, err := matcher.MatchNamespaceSelector(hook, attr) if err != nil { t.Fatal(err) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/doc.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/doc.go deleted file mode 100644 index 93c47344095..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2019 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 object defines the utilities that are used by the webhook plugin to -// decide if a webhook should run, as long as either the old object or the new -// object has labels matching the webhook config's objectSelector. -package object // import "k8s.io/apiserver/pkg/admission/plugin/webhook/object" diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher.go deleted file mode 100644 index da1b1e0394c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2019 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 object - -import ( - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" - "k8s.io/klog" -) - -// Matcher decides if a request selected by the ObjectSelector. -type Matcher struct { -} - -func matchObject(obj runtime.Object, selector labels.Selector) bool { - if obj == nil { - return false - } - accessor, err := meta.Accessor(obj) - if err != nil { - klog.V(5).Infof("cannot access metadata of %v: %v", obj, err) - return false - } - return selector.Matches(labels.Set(accessor.GetLabels())) - -} - -// MatchObjectSelector decideds whether the request matches the ObjectSelector -// of the webhook. Only when they match, the webhook is called. -func (m *Matcher) MatchObjectSelector(h webhook.WebhookAccessor, attr admission.Attributes) (bool, *apierrors.StatusError) { - selector, err := h.GetParsedObjectSelector() - if err != nil { - return false, apierrors.NewInternalError(err) - } - if selector.Empty() { - return true, nil - } - return matchObject(attr.GetObject(), selector) || matchObject(attr.GetOldObject(), selector), nil -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher_test.go deleted file mode 100644 index 33d64d12e1b..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/object/matcher_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2019 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 object - -import ( - "testing" - - "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" -) - -func TestObjectSelector(t *testing.T) { - nodeLevel1 := &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "runlevel": "1", - }, - }, - } - nodeLevel2 := &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "runlevel": "2", - }, - }, - } - runLevel1Excluder := &metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Key: "runlevel", - Operator: metav1.LabelSelectorOpNotIn, - Values: []string{"1"}, - }, - }, - } - matcher := &Matcher{} - allScopes := v1.AllScopes - testcases := []struct { - name string - - objectSelector *metav1.LabelSelector - attrs admission.Attributes - - expectCall bool - }{ - { - name: "empty object selector matches everything", - objectSelector: &metav1.LabelSelector{}, - attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - }, - { - name: "matches new object", - objectSelector: runLevel1Excluder, - attrs: admission.NewAttributesRecord(nodeLevel2, nil, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - }, - { - name: "matches old object", - objectSelector: runLevel1Excluder, - attrs: admission.NewAttributesRecord(nil, nodeLevel2, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Delete, &metav1.DeleteOptions{}, false, nil), - expectCall: true, - }, - { - name: "does not match new object", - objectSelector: runLevel1Excluder, - attrs: admission.NewAttributesRecord(nodeLevel1, nil, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "does not match old object", - objectSelector: runLevel1Excluder, - attrs: admission.NewAttributesRecord(nil, nodeLevel1, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "does not match object that does not implement Object interface", - objectSelector: runLevel1Excluder, - attrs: admission.NewAttributesRecord(&corev1.NodeProxyOptions{}, nil, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: false, - }, - { - name: "empty selector matches everything, including object that does not implement Object interface", - objectSelector: &metav1.LabelSelector{}, - attrs: admission.NewAttributesRecord(&corev1.NodeProxyOptions{}, nil, schema.GroupVersionKind{}, "", "name", schema.GroupVersionResource{}, "", admission.Create, &metav1.CreateOptions{}, false, nil), - expectCall: true, - }, - } - - for _, testcase := range testcases { - hook := &v1.ValidatingWebhook{ - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: testcase.objectSelector, - Rules: []v1.RuleWithOperations{{ - Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, - }}} - - t.Run(testcase.name, func(t *testing.T) { - match, err := matcher.MatchObjectSelector(webhook.NewValidatingWebhookAccessor("mock-hook", "mock-cfg", hook), testcase.attrs) - if err != nil { - t.Error(err) - } - if testcase.expectCall && !match { - t.Errorf("expected the webhook to be called") - } - if !testcase.expectCall && match { - t.Errorf("expected the webhook to be called") - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go index 5ea28d446b5..cec41315c2b 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go @@ -17,211 +17,18 @@ limitations under the License. package request import ( - "fmt" - - admissionv1 "k8s.io/api/admission/v1" admissionv1beta1 "k8s.io/api/admission/v1beta1" authenticationv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" ) -// AdmissionResponse contains the fields extracted from an AdmissionReview response -type AdmissionResponse struct { - AuditAnnotations map[string]string - Allowed bool - Patch []byte - PatchType admissionv1.PatchType - Result *metav1.Status -} - -// VerifyAdmissionResponse checks the validity of the provided admission review object, and returns the -// audit annotations, whether the response allowed the request, any provided patch/patchType/status, -// or an error if the provided admission review was not valid. -func VerifyAdmissionResponse(uid types.UID, mutating bool, review runtime.Object) (*AdmissionResponse, error) { - switch r := review.(type) { - case *admissionv1.AdmissionReview: - if r.Response == nil { - return nil, fmt.Errorf("webhook response was absent") - } - - // Verify UID matches - if r.Response.UID != uid { - return nil, fmt.Errorf("expected response.uid=%q, got %q", uid, r.Response.UID) - } - - // Verify GVK - v1GVK := admissionv1.SchemeGroupVersion.WithKind("AdmissionReview") - if r.GroupVersionKind() != v1GVK { - return nil, fmt.Errorf("expected webhook response of %v, got %v", v1GVK.String(), r.GroupVersionKind().String()) - } - - patch := []byte(nil) - patchType := admissionv1.PatchType("") - - if mutating { - // Ensure a mutating webhook provides both patch and patchType together - if len(r.Response.Patch) > 0 && r.Response.PatchType == nil { - return nil, fmt.Errorf("webhook returned response.patch but not response.patchType") - } - if len(r.Response.Patch) == 0 && r.Response.PatchType != nil { - return nil, fmt.Errorf("webhook returned response.patchType but not response.patch") - } - patch = r.Response.Patch - if r.Response.PatchType != nil { - patchType = *r.Response.PatchType - if len(patchType) == 0 { - return nil, fmt.Errorf("webhook returned invalid response.patchType of %q", patchType) - } - } - } else { - // Ensure a validating webhook doesn't return patch or patchType - if len(r.Response.Patch) > 0 { - return nil, fmt.Errorf("validating webhook may not return response.patch") - } - if r.Response.PatchType != nil { - return nil, fmt.Errorf("validating webhook may not return response.patchType") - } - } - - return &AdmissionResponse{ - AuditAnnotations: r.Response.AuditAnnotations, - Allowed: r.Response.Allowed, - Patch: patch, - PatchType: patchType, - Result: r.Response.Result, - }, nil - - case *admissionv1beta1.AdmissionReview: - if r.Response == nil { - return nil, fmt.Errorf("webhook response was absent") - } - - // Response GVK and response.uid were not verified in v1beta1 handling, allow any - - patch := []byte(nil) - patchType := admissionv1.PatchType("") - if mutating { - patch = r.Response.Patch - if len(r.Response.Patch) > 0 { - // patch type was not verified in v1beta1 admissionreview handling. pin to only supported version if a patch is provided. - patchType = admissionv1.PatchTypeJSONPatch - } - } - - return &AdmissionResponse{ - AuditAnnotations: r.Response.AuditAnnotations, - Allowed: r.Response.Allowed, - Patch: patch, - PatchType: patchType, - Result: r.Response.Result, - }, nil - - default: - return nil, fmt.Errorf("unexpected response type %T", review) - } -} - -// CreateAdmissionObjects returns the unique request uid, the AdmissionReview object to send the webhook and to decode the response into, -// or an error if the webhook does not support receiving any of the admission review versions we know to send -func CreateAdmissionObjects(versionedAttributes *generic.VersionedAttributes, invocation *generic.WebhookInvocation) (uid types.UID, request, response runtime.Object, err error) { - for _, version := range invocation.Webhook.GetAdmissionReviewVersions() { - switch version { - case admissionv1.SchemeGroupVersion.Version: - uid := types.UID(uuid.NewUUID()) - request := CreateV1AdmissionReview(uid, versionedAttributes, invocation) - response := &admissionv1.AdmissionReview{} - return uid, request, response, nil - - case admissionv1beta1.SchemeGroupVersion.Version: - uid := types.UID(uuid.NewUUID()) - request := CreateV1beta1AdmissionReview(uid, versionedAttributes, invocation) - response := &admissionv1beta1.AdmissionReview{} - return uid, request, response, nil - - } - } - return "", nil, nil, fmt.Errorf("webhook does not accept known AdmissionReview versions (v1, v1beta1)") -} - -// CreateV1AdmissionReview creates an AdmissionReview for the provided admission.Attributes -func CreateV1AdmissionReview(uid types.UID, versionedAttributes *generic.VersionedAttributes, invocation *generic.WebhookInvocation) *admissionv1.AdmissionReview { - attr := versionedAttributes.Attributes - gvk := invocation.Kind - gvr := invocation.Resource - subresource := invocation.Subresource - requestGVK := attr.GetKind() - requestGVR := attr.GetResource() - requestSubResource := attr.GetSubresource() - aUserInfo := attr.GetUserInfo() - userInfo := authenticationv1.UserInfo{ - Extra: make(map[string]authenticationv1.ExtraValue), - Groups: aUserInfo.GetGroups(), - UID: aUserInfo.GetUID(), - Username: aUserInfo.GetName(), - } - dryRun := attr.IsDryRun() - - // Convert the extra information in the user object - for key, val := range aUserInfo.GetExtra() { - userInfo.Extra[key] = authenticationv1.ExtraValue(val) - } - - return &admissionv1.AdmissionReview{ - Request: &admissionv1.AdmissionRequest{ - UID: uid, - Kind: metav1.GroupVersionKind{ - Group: gvk.Group, - Kind: gvk.Kind, - Version: gvk.Version, - }, - Resource: metav1.GroupVersionResource{ - Group: gvr.Group, - Resource: gvr.Resource, - Version: gvr.Version, - }, - SubResource: subresource, - RequestKind: &metav1.GroupVersionKind{ - Group: requestGVK.Group, - Kind: requestGVK.Kind, - Version: requestGVK.Version, - }, - RequestResource: &metav1.GroupVersionResource{ - Group: requestGVR.Group, - Resource: requestGVR.Resource, - Version: requestGVR.Version, - }, - RequestSubResource: requestSubResource, - Name: attr.GetName(), - Namespace: attr.GetNamespace(), - Operation: admissionv1.Operation(attr.GetOperation()), - UserInfo: userInfo, - Object: runtime.RawExtension{ - Object: versionedAttributes.VersionedObject, - }, - OldObject: runtime.RawExtension{ - Object: versionedAttributes.VersionedOldObject, - }, - DryRun: &dryRun, - Options: runtime.RawExtension{ - Object: attr.GetOperationOptions(), - }, - }, - } -} - -// CreateV1beta1AdmissionReview creates an AdmissionReview for the provided admission.Attributes -func CreateV1beta1AdmissionReview(uid types.UID, versionedAttributes *generic.VersionedAttributes, invocation *generic.WebhookInvocation) *admissionv1beta1.AdmissionReview { - attr := versionedAttributes.Attributes - gvk := invocation.Kind - gvr := invocation.Resource - subresource := invocation.Subresource - requestGVK := attr.GetKind() - requestGVR := attr.GetResource() - requestSubResource := attr.GetSubresource() +// CreateAdmissionReview creates an AdmissionReview for the provided admission.Attributes +func CreateAdmissionReview(attr *generic.VersionedAttributes) admissionv1beta1.AdmissionReview { + gvk := attr.GetKind() + gvr := attr.GetResource() aUserInfo := attr.GetUserInfo() userInfo := authenticationv1.UserInfo{ Extra: make(map[string]authenticationv1.ExtraValue), @@ -236,9 +43,9 @@ func CreateV1beta1AdmissionReview(uid types.UID, versionedAttributes *generic.Ve userInfo.Extra[key] = authenticationv1.ExtraValue(val) } - return &admissionv1beta1.AdmissionReview{ + return admissionv1beta1.AdmissionReview{ Request: &admissionv1beta1.AdmissionRequest{ - UID: uid, + UID: uuid.NewUUID(), Kind: metav1.GroupVersionKind{ Group: gvk.Group, Kind: gvk.Kind, @@ -249,32 +56,18 @@ func CreateV1beta1AdmissionReview(uid types.UID, versionedAttributes *generic.Ve Resource: gvr.Resource, Version: gvr.Version, }, - SubResource: subresource, - RequestKind: &metav1.GroupVersionKind{ - Group: requestGVK.Group, - Kind: requestGVK.Kind, - Version: requestGVK.Version, - }, - RequestResource: &metav1.GroupVersionResource{ - Group: requestGVR.Group, - Resource: requestGVR.Resource, - Version: requestGVR.Version, - }, - RequestSubResource: requestSubResource, - Name: attr.GetName(), - Namespace: attr.GetNamespace(), - Operation: admissionv1beta1.Operation(attr.GetOperation()), - UserInfo: userInfo, + SubResource: attr.GetSubresource(), + Name: attr.GetName(), + Namespace: attr.GetNamespace(), + Operation: admissionv1beta1.Operation(attr.GetOperation()), + UserInfo: userInfo, Object: runtime.RawExtension{ - Object: versionedAttributes.VersionedObject, + Object: attr.VersionedObject, }, OldObject: runtime.RawExtension{ - Object: versionedAttributes.VersionedOldObject, + Object: attr.VersionedOldObject, }, DryRun: &dryRun, - Options: runtime.RawExtension{ - Object: attr.GetOperationOptions(), - }, }, } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview_test.go deleted file mode 100644 index dd70409ab8a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview_test.go +++ /dev/null @@ -1,618 +0,0 @@ -/* -Copyright 2019 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 request - -import ( - "reflect" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - - admissionv1 "k8s.io/api/admission/v1" - admissionv1beta1 "k8s.io/api/admission/v1beta1" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - appsv1 "k8s.io/api/apps/v1" - authenticationv1 "k8s.io/api/authentication/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/admission/plugin/webhook" - "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" - "k8s.io/apiserver/pkg/authentication/user" - utilpointer "k8s.io/utils/pointer" -) - -func TestVerifyAdmissionResponse(t *testing.T) { - v1beta1JSONPatch := admissionv1beta1.PatchTypeJSONPatch - v1JSONPatch := admissionv1.PatchTypeJSONPatch - - emptyv1beta1Patch := admissionv1beta1.PatchType("") - emptyv1Patch := admissionv1.PatchType("") - - invalidv1beta1Patch := admissionv1beta1.PatchType("Foo") - invalidv1Patch := admissionv1.PatchType("Foo") - - testcases := []struct { - name string - uid types.UID - mutating bool - review runtime.Object - - expectAuditAnnotations map[string]string - expectAllowed bool - expectPatch []byte - expectPatchType admissionv1.PatchType - expectResult *metav1.Status - expectErr string - }{ - // Allowed validating - { - name: "v1beta1 allowed validating", - uid: "123", - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{Allowed: true}, - }, - expectAllowed: true, - }, - { - name: "v1 allowed validating", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{UID: "123", Allowed: true}, - }, - expectAllowed: true, - }, - // Allowed mutating - { - name: "v1beta1 allowed mutating", - uid: "123", - mutating: true, - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{Allowed: true}, - }, - expectAllowed: true, - }, - { - name: "v1 allowed mutating", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{UID: "123", Allowed: true}, - }, - expectAllowed: true, - }, - - // Audit annotations - { - name: "v1beta1 auditAnnotations", - uid: "123", - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: true, - AuditAnnotations: map[string]string{"foo": "bar"}, - }, - }, - expectAllowed: true, - expectAuditAnnotations: map[string]string{"foo": "bar"}, - }, - { - name: "v1 auditAnnotations", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - AuditAnnotations: map[string]string{"foo": "bar"}, - }, - }, - expectAllowed: true, - expectAuditAnnotations: map[string]string{"foo": "bar"}, - }, - - // Patch - { - name: "v1beta1 patch", - uid: "123", - mutating: true, - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - }, - }, - expectAllowed: true, - expectPatch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - expectPatchType: "JSONPatch", - }, - { - name: "v1 patch", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &v1JSONPatch, - }, - }, - expectAllowed: true, - expectPatch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - expectPatchType: "JSONPatch", - }, - - // Result - { - name: "v1beta1 result", - uid: "123", - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: false, - Result: &metav1.Status{Status: "Failure", Message: "Foo", Code: 401}, - }, - }, - expectAllowed: false, - expectResult: &metav1.Status{Status: "Failure", Message: "Foo", Code: 401}, - }, - { - name: "v1 result", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: false, - Result: &metav1.Status{Status: "Failure", Message: "Foo", Code: 401}, - }, - }, - expectAllowed: false, - expectResult: &metav1.Status{Status: "Failure", Message: "Foo", Code: 401}, - }, - - // Missing response - { - name: "v1beta1 no response", - uid: "123", - review: &admissionv1beta1.AdmissionReview{}, - expectErr: "response was absent", - }, - { - name: "v1 no response", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - }, - expectErr: "response was absent", - }, - - // v1 invalid responses - { - name: "v1 wrong group", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io2/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - }, - }, - expectErr: "expected webhook response of admission.k8s.io/v1, Kind=AdmissionReview", - }, - { - name: "v1 wrong version", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v2", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - }, - }, - expectErr: "expected webhook response of admission.k8s.io/v1, Kind=AdmissionReview", - }, - { - name: "v1 wrong kind", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview2"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - }, - }, - expectErr: "expected webhook response of admission.k8s.io/v1, Kind=AdmissionReview", - }, - { - name: "v1 wrong uid", - uid: "123", - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "1234", - Allowed: true, - }, - }, - expectErr: `expected response.uid="123"`, - }, - { - name: "v1 patch without patch type", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - }, - }, - expectErr: `webhook returned response.patch but not response.patchType`, - }, - { - name: "v1 patch type without patch", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - PatchType: &v1JSONPatch, - }, - }, - expectErr: `webhook returned response.patchType but not response.patch`, - }, - { - name: "v1 empty patch type", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &emptyv1Patch, - }, - }, - expectErr: `webhook returned invalid response.patchType of ""`, - }, - { - name: "v1 invalid patch type", - uid: "123", - mutating: true, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &invalidv1Patch, - }, - }, - expectAllowed: true, - expectPatch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - expectPatchType: invalidv1Patch, // invalid patch types are caught when the mutating dispatcher evaluates the patch - }, - { - name: "v1 patch for validating webhook", - uid: "123", - mutating: false, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - }, - }, - expectErr: `validating webhook may not return response.patch`, - }, - { - name: "v1 patch type for validating webhook", - uid: "123", - mutating: false, - review: &admissionv1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io/v1", Kind: "AdmissionReview"}, - Response: &admissionv1.AdmissionResponse{ - UID: "123", - Allowed: true, - PatchType: &invalidv1Patch, - }, - }, - expectErr: `validating webhook may not return response.patchType`, - }, - - // v1beta1 invalid responses that we have to allow/fixup for compatibility - { - name: "v1beta1 wrong group/version/kind", - uid: "123", - review: &admissionv1beta1.AdmissionReview{ - TypeMeta: metav1.TypeMeta{APIVersion: "admission.k8s.io2/v2", Kind: "AdmissionReview2"}, - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: true, - }, - }, - expectAllowed: true, - }, - { - name: "v1beta1 wrong uid", - uid: "123", - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - UID: "1234", - Allowed: true, - }, - }, - expectAllowed: true, - }, - { - name: "v1beta1 validating returns patch/patchType", - uid: "123", - mutating: false, - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - UID: "1234", - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &v1beta1JSONPatch, - }, - }, - expectAllowed: true, - }, - { - name: "v1beta1 empty patch type", - uid: "123", - mutating: true, - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &emptyv1beta1Patch, - }, - }, - expectAllowed: true, - expectPatch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - expectPatchType: admissionv1.PatchTypeJSONPatch, - }, - { - name: "v1beta1 invalid patchType", - uid: "123", - mutating: true, - review: &admissionv1beta1.AdmissionReview{ - Response: &admissionv1beta1.AdmissionResponse{ - Allowed: true, - Patch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - PatchType: &invalidv1beta1Patch, - }, - }, - expectAllowed: true, - expectPatch: []byte(`[{"op":"add","path":"/foo","value":"bar"}]`), - expectPatchType: admissionv1.PatchTypeJSONPatch, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - result, err := VerifyAdmissionResponse(tc.uid, tc.mutating, tc.review) - if err != nil { - if len(tc.expectErr) > 0 { - if !strings.Contains(err.Error(), tc.expectErr) { - t.Errorf("expected error '%s', got %v", tc.expectErr, err) - } - } else { - t.Errorf("unexpected error %v", err) - } - return - } else if len(tc.expectErr) > 0 { - t.Errorf("expected error '%s', got none", tc.expectErr) - return - } - - if e, a := tc.expectAuditAnnotations, result.AuditAnnotations; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - if e, a := tc.expectAllowed, result.Allowed; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - if e, a := tc.expectPatch, result.Patch; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - if e, a := tc.expectPatchType, result.PatchType; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - if e, a := tc.expectResult, result.Result; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - }) - } -} - -func TestCreateAdmissionObjects(t *testing.T) { - internalObj := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{ResourceVersion: "2", Name: "myname", Namespace: "myns"}} - internalObjOld := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{ResourceVersion: "1", Name: "myname", Namespace: "myns"}} - versionedObj := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{ResourceVersion: "2", Name: "myname", Namespace: "myns"}} - versionedObjOld := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{ResourceVersion: "1", Name: "myname", Namespace: "myns"}} - userInfo := &user.DefaultInfo{ - Name: "myuser", - Groups: []string{"mygroup"}, - UID: "myuid", - Extra: map[string][]string{"extrakey": {"value1", "value2"}}, - } - attrs := admission.NewAttributesRecord( - internalObj.DeepCopyObject(), - internalObjOld.DeepCopyObject(), - schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - "myns", - "myname", - schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, - "", - admission.Update, - &metav1.UpdateOptions{FieldManager: "foo"}, - false, - userInfo, - ) - - testcases := []struct { - name string - attrs *generic.VersionedAttributes - invocation *generic.WebhookInvocation - - expectRequest func(uid types.UID) runtime.Object - expectResponse runtime.Object - expectErr string - }{ - { - name: "no supported versions", - invocation: &generic.WebhookInvocation{ - Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1.MutatingWebhook{}), - }, - expectErr: "webhook does not accept known AdmissionReview versions", - }, - { - name: "no known supported versions", - invocation: &generic.WebhookInvocation{ - Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"vX"}, - }), - }, - expectErr: "webhook does not accept known AdmissionReview versions", - }, - { - name: "v1", - attrs: &generic.VersionedAttributes{ - VersionedObject: versionedObj.DeepCopyObject(), - VersionedOldObject: versionedObjOld.DeepCopyObject(), - Attributes: attrs, - }, - invocation: &generic.WebhookInvocation{ - Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"}, - Subresource: "", - Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}, - Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"v1", "v1beta1"}, - }), - }, - expectRequest: func(uid types.UID) runtime.Object { - return &admissionv1.AdmissionReview{ - Request: &admissionv1.AdmissionRequest{ - UID: uid, - Kind: metav1.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}, - Resource: metav1.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"}, - SubResource: "", - RequestKind: &metav1.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - RequestResource: &metav1.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, - RequestSubResource: "", - Name: "myname", - Namespace: "myns", - Operation: "UPDATE", - UserInfo: authenticationv1.UserInfo{ - Username: "myuser", - UID: "myuid", - Groups: []string{"mygroup"}, - Extra: map[string]authenticationv1.ExtraValue{"extrakey": {"value1", "value2"}}, - }, - Object: runtime.RawExtension{Object: versionedObj}, - OldObject: runtime.RawExtension{Object: versionedObjOld}, - DryRun: utilpointer.BoolPtr(false), - Options: runtime.RawExtension{Object: &metav1.UpdateOptions{FieldManager: "foo"}}, - }, - } - }, - expectResponse: &admissionv1.AdmissionReview{}, - }, - { - name: "v1beta1", - attrs: &generic.VersionedAttributes{ - VersionedObject: versionedObj.DeepCopyObject(), - VersionedOldObject: versionedObjOld.DeepCopyObject(), - Attributes: attrs, - }, - invocation: &generic.WebhookInvocation{ - Resource: schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"}, - Subresource: "", - Kind: schema.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}, - Webhook: webhook.NewMutatingWebhookAccessor("mywebhook", "mycfg", &admissionregistrationv1.MutatingWebhook{ - AdmissionReviewVersions: []string{"v1beta1", "v1"}, - }), - }, - expectRequest: func(uid types.UID) runtime.Object { - return &admissionv1beta1.AdmissionReview{ - Request: &admissionv1beta1.AdmissionRequest{ - UID: uid, - Kind: metav1.GroupVersionKind{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}, - Resource: metav1.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "deployments"}, - SubResource: "", - RequestKind: &metav1.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, - RequestResource: &metav1.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, - RequestSubResource: "", - Name: "myname", - Namespace: "myns", - Operation: "UPDATE", - UserInfo: authenticationv1.UserInfo{ - Username: "myuser", - UID: "myuid", - Groups: []string{"mygroup"}, - Extra: map[string]authenticationv1.ExtraValue{"extrakey": {"value1", "value2"}}, - }, - Object: runtime.RawExtension{Object: versionedObj}, - OldObject: runtime.RawExtension{Object: versionedObjOld}, - DryRun: utilpointer.BoolPtr(false), - Options: runtime.RawExtension{Object: &metav1.UpdateOptions{FieldManager: "foo"}}, - }, - } - }, - expectResponse: &admissionv1beta1.AdmissionReview{}, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - uid, request, response, err := CreateAdmissionObjects(tc.attrs, tc.invocation) - if err != nil { - if len(tc.expectErr) > 0 { - if !strings.Contains(err.Error(), tc.expectErr) { - t.Errorf("expected error '%s', got %v", tc.expectErr, err) - } - } else { - t.Errorf("unexpected error %v", err) - } - return - } else if len(tc.expectErr) > 0 { - t.Errorf("expected error '%s', got none", tc.expectErr) - return - } - - if len(uid) == 0 { - t.Errorf("expected uid, got none") - } - if e, a := tc.expectRequest(uid), request; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - if e, a := tc.expectResponse, response; !reflect.DeepEqual(e, a) { - t.Errorf("unexpected: %v", cmp.Diff(e, a)) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules.go index 924e79bcc9f..096ab5021d1 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules.go @@ -19,22 +19,19 @@ package rules import ( "strings" - "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apiserver/pkg/admission" ) // Matcher determines if the Attr matches the Rule. type Matcher struct { - Rule v1.RuleWithOperations + Rule v1beta1.RuleWithOperations Attr admission.Attributes } // Matches returns if the Attr matches the Rule. func (r *Matcher) Matches() bool { - return r.scope() && - r.operation() && + return r.operation() && r.group() && r.version() && r.resource() @@ -53,25 +50,6 @@ func exactOrWildcard(items []string, requested string) bool { return false } -var namespaceResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"} - -func (r *Matcher) scope() bool { - if r.Rule.Scope == nil || *r.Rule.Scope == v1.AllScopes { - return true - } - // attr.GetNamespace() is set to the name of the namespace for requests of the namespace object itself. - switch *r.Rule.Scope { - case v1.NamespacedScope: - // first make sure that we are not requesting a namespace object (namespace objects are cluster-scoped) - return r.Attr.GetResource() != namespaceResource && r.Attr.GetNamespace() != metav1.NamespaceNone - case v1.ClusterScope: - // also return true if the request is for a namespace object (namespace objects are cluster-scoped) - return r.Attr.GetResource() == namespaceResource || r.Attr.GetNamespace() == metav1.NamespaceNone - default: - return false - } -} - func (r *Matcher) group() bool { return exactOrWildcard(r.Rule.APIGroups, r.Attr.GetResource().Group) } @@ -83,12 +61,12 @@ func (r *Matcher) version() bool { func (r *Matcher) operation() bool { attrOp := r.Attr.GetOperation() for _, op := range r.Rule.Operations { - if op == v1.OperationAll { + if op == v1beta1.OperationAll { return true } // The constants are the same such that this is a valid cast (and this // is tested). - if op == v1.OperationType(attrOp) { + if op == v1beta1.OperationType(attrOp) { return true } } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go index a3604462b22..2827558af2f 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/rules/rules_test.go @@ -17,14 +17,10 @@ limitations under the License. package rules import ( - "fmt" "testing" - adreg "k8s.io/api/admissionregistration/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" + adreg "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" ) @@ -35,40 +31,13 @@ type ruleTest struct { } type tests map[string]ruleTest -func a(group, version, resource, subresource, name string, operation admission.Operation, operationOptions runtime.Object) admission.Attributes { +func a(group, version, resource, subresource, name string, operation admission.Operation) admission.Attributes { return admission.NewAttributesRecord( nil, nil, schema.GroupVersionKind{Group: group, Version: version, Kind: "k" + resource}, "ns", name, schema.GroupVersionResource{Group: group, Version: version, Resource: resource}, subresource, operation, - operationOptions, - false, - nil, - ) -} - -func namespacedAttributes(group, version, resource, subresource, name string, operation admission.Operation, operationOptions runtime.Object) admission.Attributes { - return admission.NewAttributesRecord( - nil, nil, - schema.GroupVersionKind{Group: group, Version: version, Kind: "k" + resource}, - "ns", name, - schema.GroupVersionResource{Group: group, Version: version, Resource: resource}, subresource, - operation, - operationOptions, - false, - nil, - ) -} - -func clusterScopedAttributes(group, version, resource, subresource, name string, operation admission.Operation, operationOptions runtime.Object) admission.Attributes { - return admission.NewAttributesRecord( - nil, nil, - schema.GroupVersionKind{Group: group, Version: version, Kind: "k" + resource}, - "", name, - schema.GroupVersionResource{Group: group, Version: version, Resource: resource}, subresource, - operation, - operationOptions, false, nil, ) @@ -87,7 +56,7 @@ func TestGroup(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), ), }, "exact": { @@ -97,12 +66,12 @@ func TestGroup(t *testing.T) { }, }, match: attrList( - a("g1", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g2", "v2", "r3", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g1", "v", "r", "", "name", admission.Create), + a("g2", "v2", "r3", "", "name", admission.Create), ), noMatch: attrList( - a("g3", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g4", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g3", "v", "r", "", "name", admission.Create), + a("g4", "v", "r", "", "name", admission.Create), ), }, } @@ -132,7 +101,7 @@ func TestVersion(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), ), }, "exact": { @@ -142,12 +111,12 @@ func TestVersion(t *testing.T) { }, }, match: attrList( - a("g1", "v1", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g2", "v2", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g1", "v1", "r", "", "name", admission.Create), + a("g2", "v2", "r", "", "name", admission.Create), ), noMatch: attrList( - a("g1", "v3", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g2", "v4", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g1", "v3", "r", "", "name", admission.Create), + a("g2", "v4", "r", "", "name", admission.Create), ), }, } @@ -172,65 +141,65 @@ func TestOperation(t *testing.T) { "wildcard": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.OperationAll}}, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "", "name", admission.Update), + a("g", "v", "r", "", "name", admission.Delete), + a("g", "v", "r", "", "name", admission.Connect), ), }, "create": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.Create}}, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Update), + a("g", "v", "r", "", "name", admission.Delete), + a("g", "v", "r", "", "name", admission.Connect), ), }, "update": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.Update}}, match: attrList( - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), + a("g", "v", "r", "", "name", admission.Update), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "", "name", admission.Delete), + a("g", "v", "r", "", "name", admission.Connect), ), }, "delete": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.Delete}}, match: attrList( - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), + a("g", "v", "r", "", "name", admission.Delete), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "", "name", admission.Update), + a("g", "v", "r", "", "name", admission.Connect), ), }, "connect": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.Connect}}, match: attrList( - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Connect), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "", "name", admission.Update), + a("g", "v", "r", "", "name", admission.Delete), ), }, "multiple": { rule: adreg.RuleWithOperations{Operations: []adreg.OperationType{adreg.Update, adreg.Delete}}, match: attrList( - a("g", "v", "r", "", "name", admission.Update, &metav1.UpdateOptions{}), - a("g", "v", "r", "", "name", admission.Delete, &metav1.DeleteOptions{}), + a("g", "v", "r", "", "name", admission.Update), + a("g", "v", "r", "", "name", admission.Delete), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "", "name", admission.Connect, nil), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "", "name", admission.Connect), ), }, } @@ -259,12 +228,12 @@ func TestResource(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), + a("2", "v", "r2", "", "name", admission.Create), ), noMatch: attrList( - a("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "proxy", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "exec", "name", admission.Create), + a("2", "v", "r2", "proxy", "name", admission.Create), ), }, "r & subresources": { @@ -274,12 +243,12 @@ func TestResource(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "exec", "name", admission.Create), ), noMatch: attrList( - a("2", "v", "r2", "", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "proxy", "name", admission.Create, &metav1.CreateOptions{}), + a("2", "v", "r2", "", "name", admission.Create), + a("2", "v", "r2", "proxy", "name", admission.Create), ), }, "r & subresources or r2": { @@ -289,12 +258,12 @@ func TestResource(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), + a("g", "v", "r", "exec", "name", admission.Create), + a("2", "v", "r2", "", "name", admission.Create), ), noMatch: attrList( - a("2", "v", "r2", "proxy", "name", admission.Create, &metav1.CreateOptions{}), + a("2", "v", "r2", "proxy", "name", admission.Create), ), }, "proxy or exec": { @@ -304,14 +273,14 @@ func TestResource(t *testing.T) { }, }, match: attrList( - a("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "proxy", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r3", "proxy", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "exec", "name", admission.Create), + a("2", "v", "r2", "proxy", "name", admission.Create), + a("2", "v", "r3", "proxy", "name", admission.Create), ), noMatch: attrList( - a("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r2", "", "name", admission.Create, &metav1.CreateOptions{}), - a("2", "v", "r4", "scale", "name", admission.Create, &metav1.CreateOptions{}), + a("g", "v", "r", "", "name", admission.Create), + a("2", "v", "r2", "", "name", admission.Create), + a("2", "v", "r4", "scale", "name", admission.Create), ), }, } @@ -330,93 +299,3 @@ func TestResource(t *testing.T) { } } } - -func TestScope(t *testing.T) { - cluster := adreg.ClusterScope - namespace := adreg.NamespacedScope - allscopes := adreg.AllScopes - table := tests{ - "cluster scope": { - rule: adreg.RuleWithOperations{ - Rule: adreg.Rule{ - Resources: []string{"*"}, - Scope: &cluster, - }, - }, - match: attrList( - clusterScopedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - ), - noMatch: attrList( - namespacedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - ), - }, - "namespace scope": { - rule: adreg.RuleWithOperations{ - Rule: adreg.Rule{ - Resources: []string{"*"}, - Scope: &namespace, - }, - }, - match: attrList( - namespacedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - ), - noMatch: attrList( - clusterScopedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - ), - }, - "all scopes": { - rule: adreg.RuleWithOperations{ - Rule: adreg.Rule{ - Resources: []string{"*"}, - Scope: &allscopes, - }, - }, - match: attrList( - namespacedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("g", "v", "r", "", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("g", "v", "r", "exec", "name", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - clusterScopedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "", "ns", admission.Create, &metav1.CreateOptions{}), - namespacedAttributes("", "v1", "namespaces", "finalize", "ns", admission.Create, &metav1.CreateOptions{}), - ), - noMatch: attrList(), - }, - } - keys := sets.NewString() - for name := range table { - keys.Insert(name) - } - for _, name := range keys.List() { - tt := table[name] - for i, m := range tt.match { - t.Run(fmt.Sprintf("%s_match_%d", name, i), func(t *testing.T) { - r := Matcher{tt.rule, m} - if !r.scope() { - t.Errorf("%v: expected match %#v", name, m) - } - }) - } - for i, m := range tt.noMatch { - t.Run(fmt.Sprintf("%s_nomatch_%d", name, i), func(t *testing.T) { - r := Matcher{tt.rule, m} - if r.scope() { - t.Errorf("%v: expected no match %#v", name, m) - } - }) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts/gencerts.sh b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts/gencerts.sh index 34493b966d5..98503f69f44 100755 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts/gencerts.sh +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts/gencerts.sh @@ -90,12 +90,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -// This file was generated using openssl by the gencerts.sh script -// and holds raw certificates for the webhook tests. - -package testcerts EOF +echo "// This file was generated using openssl by the gencerts.sh script" >> $outfile +echo "// and holds raw certificates for the webhook tests." >> $outfile +echo "" >> $outfile +echo "package testcerts" >> $outfile for file in CAKey CACert BadCAKey BadCACert ServerKey ServerCert ClientKey ClientCert; do data=$(cat ${file}.pem) echo "" >> $outfile @@ -103,7 +103,7 @@ for file in CAKey CACert BadCAKey BadCACert ServerKey ServerCert ClientKey Clien done # Clean up after we're done. -rm ./*.pem -rm ./*.csr -rm ./*.srl -rm ./*.conf +rm *.pem +rm *.csr +rm *.srl +rm *.conf diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/authentication_info_resolver.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/authentication_info_resolver.go index c06f6d826a8..eef54ee86ca 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/authentication_info_resolver.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/authentication_info_resolver.go @@ -52,12 +52,12 @@ type authenticationInfoResolver struct { cacheMisses *int32 } -func (a *authenticationInfoResolver) ClientConfigFor(hostPort string) (*rest.Config, error) { +func (a *authenticationInfoResolver) ClientConfigFor(server string) (*rest.Config, error) { atomic.AddInt32(a.cacheMisses, 1) return a.restConfig, nil } -func (a *authenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string, servicePort int) (*rest.Config, error) { +func (a *authenticationInfoResolver) ClientConfigForService(serviceName, serviceNamespace string) (*rest.Config, error) { atomic.AddInt32(a.cacheMisses, 1) return a.restConfig, nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/service_resolver.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/service_resolver.go index 97c2e9a521f..58d40287d21 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/service_resolver.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/service_resolver.go @@ -33,7 +33,7 @@ func NewServiceResolver(base url.URL) webhook.ServiceResolver { return &serviceResolver{base} } -func (f serviceResolver) ResolveEndpoint(namespace, name string, port int32) (*url.URL, error) { +func (f serviceResolver) ResolveEndpoint(namespace, name string) (*url.URL, error) { if namespace == "failResolve" { return nil, fmt.Errorf("couldn't resolve service location") } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go index 14cd8a9a119..ad3efee0e62 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/testcase.go @@ -17,14 +17,10 @@ limitations under the License. package testing import ( - "fmt" - "net/http" "net/url" - "reflect" - "strings" "sync" - registrationv1 "k8s.io/api/admissionregistration/v1" + registrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -32,32 +28,28 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/plugin/webhook/testcerts" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/authentication/user" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" fakeclientset "k8s.io/client-go/kubernetes/fake" ) -var matchEverythingRules = []registrationv1.RuleWithOperations{{ - Operations: []registrationv1.OperationType{registrationv1.OperationAll}, - Rule: registrationv1.Rule{ +var matchEverythingRules = []registrationv1beta1.RuleWithOperations{{ + Operations: []registrationv1beta1.OperationType{registrationv1beta1.OperationAll}, + Rule: registrationv1beta1.Rule{ APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}, }, }} -var sideEffectsUnknown = registrationv1.SideEffectClassUnknown -var sideEffectsNone = registrationv1.SideEffectClassNone -var sideEffectsSome = registrationv1.SideEffectClassSome -var sideEffectsNoneOnDryRun = registrationv1.SideEffectClassNoneOnDryRun +var sideEffectsUnknown = registrationv1beta1.SideEffectClassUnknown +var sideEffectsNone = registrationv1beta1.SideEffectClassNone +var sideEffectsSome = registrationv1beta1.SideEffectClassSome +var sideEffectsNoneOnDryRun = registrationv1beta1.SideEffectClassNoneOnDryRun -var reinvokeNever = registrationv1.NeverReinvocationPolicy -var reinvokeIfNeeded = registrationv1.IfNeededReinvocationPolicy - -// NewFakeValidatingDataSource returns a mock client and informer returning the given webhooks. -func NewFakeValidatingDataSource(name string, webhooks []registrationv1.ValidatingWebhook, stopCh <-chan struct{}) (clientset kubernetes.Interface, factory informers.SharedInformerFactory) { +// NewFakeDataSource returns a mock client and informer returning the given webhooks. +func NewFakeDataSource(name string, webhooks []registrationv1beta1.Webhook, mutating bool, stopCh <-chan struct{}) (clientset kubernetes.Interface, factory informers.SharedInformerFactory) { var objs = []runtime.Object{ &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -68,37 +60,21 @@ func NewFakeValidatingDataSource(name string, webhooks []registrationv1.Validati }, }, } - objs = append(objs, ®istrationv1.ValidatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-webhooks", - }, - Webhooks: webhooks, - }) - - client := fakeclientset.NewSimpleClientset(objs...) - informerFactory := informers.NewSharedInformerFactory(client, 0) - - return client, informerFactory -} - -// NewFakeMutatingDataSource returns a mock client and informer returning the given webhooks. -func NewFakeMutatingDataSource(name string, webhooks []registrationv1.MutatingWebhook, stopCh <-chan struct{}) (clientset kubernetes.Interface, factory informers.SharedInformerFactory) { - var objs = []runtime.Object{ - &corev1.Namespace{ + if mutating { + objs = append(objs, ®istrationv1beta1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ - Name: name, - Labels: map[string]string{ - "runlevel": "0", - }, + Name: "test-webhooks", }, - }, + Webhooks: webhooks, + }) + } else { + objs = append(objs, ®istrationv1beta1.ValidatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-webhooks", + }, + Webhooks: webhooks, + }) } - objs = append(objs, ®istrationv1.MutatingWebhookConfiguration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-webhooks", - }, - Webhooks: webhooks, - }) client := fakeclientset.NewSimpleClientset(objs...) informerFactory := informers.NewSharedInformerFactory(client, 0) @@ -124,10 +100,9 @@ func newAttributesRecord(object metav1.Object, oldObject metav1.Object, kind sch Name: "webhook-test", UID: "webhook-test", } - options := &metav1.UpdateOptions{} return &FakeAttributes{ - Attributes: admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, options, dryRun, &userInfo), + Attributes: admission.NewAttributesRecord(object.(runtime.Object), oldObject.(runtime.Object), kind, namespace, name, gvr, subResource, admission.Update, dryRun, &userInfo), } } @@ -140,11 +115,6 @@ type FakeAttributes struct { // AddAnnotation adds an annotation key value pair to FakeAttributes func (f *FakeAttributes) AddAnnotation(k, v string) error { - return f.AddAnnotationWithLevel(k, v, auditinternal.LevelMetadata) -} - -// AddAnnotationWithLevel adds an annotation key value pair to FakeAttributes -func (f *FakeAttributes) AddAnnotationWithLevel(k, v string, _ auditinternal.Level) error { f.mutex.Lock() defer f.mutex.Unlock() if err := f.Attributes.AddAnnotation(k, v); err != nil { @@ -158,7 +128,7 @@ func (f *FakeAttributes) AddAnnotationWithLevel(k, v string, _ auditinternal.Lev } // GetAnnotations reads annotations from FakeAttributes -func (f *FakeAttributes) GetAnnotations(level auditinternal.Level) map[string]string { +func (f *FakeAttributes) GetAnnotations() map[string]string { f.mutex.Lock() defer f.mutex.Unlock() return f.annotations @@ -199,151 +169,87 @@ type urlConfigGenerator struct { baseURL *url.URL } -func (c urlConfigGenerator) ccfgURL(urlPath string) registrationv1.WebhookClientConfig { +func (c urlConfigGenerator) ccfgURL(urlPath string) registrationv1beta1.WebhookClientConfig { u2 := *c.baseURL u2.Path = urlPath urlString := u2.String() - return registrationv1.WebhookClientConfig{ + return registrationv1beta1.WebhookClientConfig{ URL: &urlString, CABundle: testcerts.CACert, } } -// ValidatingTest is a validating webhook test case. -type ValidatingTest struct { - Name string - Webhooks []registrationv1.ValidatingWebhook - Path string - IsCRD bool - IsDryRun bool - AdditionalLabels map[string]string - SkipBenchmark bool - ExpectLabels map[string]string - ExpectAllow bool - ErrorContains string - ExpectAnnotations map[string]string - ExpectStatusCode int32 - ExpectReinvokeWebhooks map[string]bool -} - -// MutatingTest is a mutating webhook test case. -type MutatingTest struct { - Name string - Webhooks []registrationv1.MutatingWebhook - Path string - IsCRD bool - IsDryRun bool - AdditionalLabels map[string]string - SkipBenchmark bool - ExpectLabels map[string]string - ExpectAllow bool - ErrorContains string - ExpectAnnotations map[string]string - ExpectStatusCode int32 - ExpectReinvokeWebhooks map[string]bool -} - -// ConvertToMutatingTestCases converts a validating test case to a mutating one for test purposes. -func ConvertToMutatingTestCases(tests []ValidatingTest, configurationName string) []MutatingTest { - r := make([]MutatingTest, len(tests)) - for i, t := range tests { - for idx, hook := range t.Webhooks { - if t.ExpectAnnotations == nil { - t.ExpectAnnotations = map[string]string{} - } - // Add expected annotation if the converted webhook is intended to match - if reflect.DeepEqual(hook.NamespaceSelector, &metav1.LabelSelector{}) && - reflect.DeepEqual(hook.ObjectSelector, &metav1.LabelSelector{}) && - reflect.DeepEqual(hook.Rules, matchEverythingRules) { - key := fmt.Sprintf("mutation.webhook.admission.k8s.io/round_0_index_%d", idx) - value := mutationAnnotationValue(configurationName, hook.Name, false) - t.ExpectAnnotations[key] = value - } - // Break if the converted webhook is intended to fail close - if strings.Contains(hook.Name, "internalErr") && (hook.FailurePolicy == nil || *hook.FailurePolicy == registrationv1.Fail) { - break - } - } - r[i] = MutatingTest{t.Name, ConvertToMutatingWebhooks(t.Webhooks), t.Path, t.IsCRD, t.IsDryRun, t.AdditionalLabels, t.SkipBenchmark, t.ExpectLabels, t.ExpectAllow, t.ErrorContains, t.ExpectAnnotations, t.ExpectStatusCode, t.ExpectReinvokeWebhooks} - } - return r -} - -// ConvertToMutatingWebhooks converts a validating webhook to a mutating one for test purposes. -func ConvertToMutatingWebhooks(webhooks []registrationv1.ValidatingWebhook) []registrationv1.MutatingWebhook { - mutating := make([]registrationv1.MutatingWebhook, len(webhooks)) - for i, h := range webhooks { - mutating[i] = registrationv1.MutatingWebhook{h.Name, h.ClientConfig, h.Rules, h.FailurePolicy, h.MatchPolicy, h.NamespaceSelector, h.ObjectSelector, h.SideEffects, h.TimeoutSeconds, h.AdmissionReviewVersions, nil} - } - return mutating +// Test is a webhook test case. +type Test struct { + Name string + Webhooks []registrationv1beta1.Webhook + Path string + IsCRD bool + IsDryRun bool + AdditionalLabels map[string]string + ExpectLabels map[string]string + ExpectAllow bool + ErrorContains string + ExpectAnnotations map[string]string } // NewNonMutatingTestCases returns test cases with a given base url. // All test cases in NewNonMutatingTestCases have no Patch set in // AdmissionResponse. The test cases are used by both MutatingAdmissionWebhook // and ValidatingAdmissionWebhook. -func NewNonMutatingTestCases(url *url.URL) []ValidatingTest { - policyFail := registrationv1.Fail - policyIgnore := registrationv1.Ignore +func NewNonMutatingTestCases(url *url.URL) []Test { + policyFail := registrationv1beta1.Fail + policyIgnore := registrationv1beta1.Ignore ccfgURL := urlConfigGenerator{url}.ccfgURL - return []ValidatingTest{ + return []Test{ { Name: "no match", - Webhooks: []registrationv1.ValidatingWebhook{{ + Webhooks: []registrationv1beta1.Webhook{{ Name: "nomatch", ClientConfig: ccfgSVC("disallow"), - Rules: []registrationv1.RuleWithOperations{{ - Operations: []registrationv1.OperationType{registrationv1.Create}, + Rules: []registrationv1beta1.RuleWithOperations{{ + Operations: []registrationv1beta1.OperationType{registrationv1beta1.Create}, }}, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + NamespaceSelector: &metav1.LabelSelector{}, }}, ExpectAllow: true, }, { Name: "match & allow", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow.example.com", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow.example.com", + ClientConfig: ccfgSVC("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, ExpectAllow: true, ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"}, }, { Name: "match & disallow", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "disallow", - ClientConfig: ccfgSVC("disallow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "disallow", + ClientConfig: ccfgSVC("disallow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - ExpectStatusCode: http.StatusForbidden, - ErrorContains: "without explanation", + ErrorContains: "without explanation", }, { Name: "match & disallow ii", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "disallowReason", - ClientConfig: ccfgSVC("disallowReason"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "disallowReason", + ClientConfig: ccfgSVC("disallowReason"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - ExpectStatusCode: http.StatusForbidden, - ErrorContains: "you shall not pass", + + ErrorContains: "you shall not pass", }, { Name: "match & disallow & but allowed because namespaceSelector exempt the ns", - Webhooks: []registrationv1.ValidatingWebhook{{ + Webhooks: []registrationv1beta1.Webhook{{ Name: "disallow", ClientConfig: ccfgSVC("disallow"), Rules: newMatchEverythingRules(), @@ -354,15 +260,13 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest { Operator: metav1.LabelSelectorOpIn, }}, }, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, }}, ExpectAllow: true, }, { Name: "match & disallow & but allowed because namespaceSelector exempt the ns ii", - Webhooks: []registrationv1.ValidatingWebhook{{ + Webhooks: []registrationv1beta1.Webhook{{ Name: "disallow", ClientConfig: ccfgSVC("disallow"), Rules: newMatchEverythingRules(), @@ -373,193 +277,152 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest { Operator: metav1.LabelSelectorOpNotIn, }}, }, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, }}, ExpectAllow: true, }, { Name: "match & fail (but allow because fail open)", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "internalErr A", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "internalErr A", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }, { - Name: "internalErr B", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr B", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }, { - Name: "internalErr C", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr C", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, - SkipBenchmark: true, - ExpectAllow: true, + ExpectAllow: true, }, { Name: "match & fail (but disallow because fail close on nil FailurePolicy)", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "internalErr A", - ClientConfig: ccfgSVC("internalErr"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "internalErr A", + ClientConfig: ccfgSVC("internalErr"), + NamespaceSelector: &metav1.LabelSelector{}, + Rules: matchEverythingRules, }, { - Name: "internalErr B", - ClientConfig: ccfgSVC("internalErr"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr B", + ClientConfig: ccfgSVC("internalErr"), + NamespaceSelector: &metav1.LabelSelector{}, + Rules: matchEverythingRules, }, { - Name: "internalErr C", - ClientConfig: ccfgSVC("internalErr"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr C", + ClientConfig: ccfgSVC("internalErr"), + NamespaceSelector: &metav1.LabelSelector{}, + Rules: matchEverythingRules, }}, - ExpectStatusCode: http.StatusInternalServerError, - ExpectAllow: false, + ExpectAllow: false, }, { Name: "match & fail (but fail because fail closed)", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "internalErr A", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyFail, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "internalErr A", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyFail, }, { - Name: "internalErr B", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyFail, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr B", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyFail, }, { - Name: "internalErr C", - ClientConfig: ccfgSVC("internalErr"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyFail, - AdmissionReviewVersions: []string{"v1beta1"}, + Name: "internalErr C", + ClientConfig: ccfgSVC("internalErr"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyFail, }}, - ExpectStatusCode: http.StatusInternalServerError, - ExpectAllow: false, + ExpectAllow: false, }, { Name: "match & allow (url)", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow.example.com", - ClientConfig: ccfgURL("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow.example.com", + ClientConfig: ccfgURL("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, ExpectAllow: true, ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"}, }, { Name: "match & disallow (url)", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "disallow", - ClientConfig: ccfgURL("disallow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "disallow", + ClientConfig: ccfgURL("disallow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - ExpectStatusCode: http.StatusForbidden, - ErrorContains: "without explanation", + ErrorContains: "without explanation", }, { Name: "absent response and fail open", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "nilResponse", - ClientConfig: ccfgURL("nilResponse"), - FailurePolicy: &policyIgnore, - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "nilResponse", + ClientConfig: ccfgURL("nilResponse"), + FailurePolicy: &policyIgnore, + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - SkipBenchmark: true, - ExpectAllow: true, + ExpectAllow: true, }, { Name: "absent response and fail closed", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "nilResponse", - ClientConfig: ccfgURL("nilResponse"), - FailurePolicy: &policyFail, - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "nilResponse", + ClientConfig: ccfgURL("nilResponse"), + FailurePolicy: &policyFail, + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - ExpectStatusCode: http.StatusInternalServerError, - ErrorContains: "webhook response was absent", + ErrorContains: "Webhook response was absent", }, { Name: "no match dry run", - Webhooks: []registrationv1.ValidatingWebhook{{ + Webhooks: []registrationv1beta1.Webhook{{ Name: "nomatch", ClientConfig: ccfgSVC("allow"), - Rules: []registrationv1.RuleWithOperations{{ - Operations: []registrationv1.OperationType{registrationv1.Create}, + Rules: []registrationv1beta1.RuleWithOperations{{ + Operations: []registrationv1beta1.OperationType{registrationv1beta1.Create}, }}, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsSome, - AdmissionReviewVersions: []string{"v1beta1"}, + NamespaceSelector: &metav1.LabelSelector{}, + SideEffects: &sideEffectsSome, }}, IsDryRun: true, ExpectAllow: true, }, { Name: "match dry run side effects Unknown", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsUnknown, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow", + ClientConfig: ccfgSVC("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + SideEffects: &sideEffectsUnknown, }}, - IsDryRun: true, - ExpectStatusCode: http.StatusBadRequest, - ErrorContains: "does not support dry run", + IsDryRun: true, + ErrorContains: "does not support dry run", }, { Name: "match dry run side effects None", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsNone, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow", + ClientConfig: ccfgSVC("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + SideEffects: &sideEffectsNone, }}, IsDryRun: true, ExpectAllow: true, @@ -567,29 +430,24 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest { }, { Name: "match dry run side effects Some", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsSome, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow", + ClientConfig: ccfgSVC("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + SideEffects: &sideEffectsSome, }}, - IsDryRun: true, - ExpectStatusCode: http.StatusBadRequest, - ErrorContains: "does not support dry run", + IsDryRun: true, + ErrorContains: "does not support dry run", }, { Name: "match dry run side effects NoneOnDryRun", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsNoneOnDryRun, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "allow", + ClientConfig: ccfgSVC("allow"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, + SideEffects: &sideEffectsNoneOnDryRun, }}, IsDryRun: true, ExpectAllow: true, @@ -597,424 +455,171 @@ func NewNonMutatingTestCases(url *url.URL) []ValidatingTest { }, { Name: "illegal annotation format", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "invalidAnnotation", - ClientConfig: ccfgURL("invalidAnnotation"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - ExpectAllow: true, - }, - { - Name: "skip webhook whose objectSelector does not match", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow.example.com", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }, { - Name: "shouldNotBeCalled", - ClientConfig: ccfgSVC("shouldNotBeCalled"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label": "nonexistent", - }, - }, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - ExpectAllow: true, - ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"}, - }, - { - Name: "skip webhook whose objectSelector does not match CRD's labels", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "allow.example.com", - ClientConfig: ccfgSVC("allow"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }, { - Name: "shouldNotBeCalled", - ClientConfig: ccfgSVC("shouldNotBeCalled"), + Webhooks: []registrationv1beta1.Webhook{{ + Name: "invalidAnnotation", + ClientConfig: ccfgURL("invalidAnnotation"), + Rules: matchEverythingRules, NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label": "nonexistent", - }, - }, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, }}, - IsCRD: true, - ExpectAllow: true, - ExpectAnnotations: map[string]string{"allow.example.com/key1": "value1"}, + ExpectAllow: true, }, // No need to test everything with the url case, since only the // connection is different. } } -func mutationAnnotationValue(configuration, webhook string, mutated bool) string { - return fmt.Sprintf(`{"configuration":"%s","webhook":"%s","mutated":%t}`, configuration, webhook, mutated) -} - -func patchAnnotationValue(configuration, webhook string, patch string) string { - return strings.Replace(fmt.Sprintf(`{"configuration": "%s", "webhook": "%s", "patch": %s, "patchType": "JSONPatch"}`, configuration, webhook, patch), " ", "", -1) -} - // NewMutatingTestCases returns test cases with a given base url. // All test cases in NewMutatingTestCases have Patch set in // AdmissionResponse. The test cases are only used by both MutatingAdmissionWebhook. -func NewMutatingTestCases(url *url.URL, configurationName string) []MutatingTest { - return []MutatingTest{ +func NewMutatingTestCases(url *url.URL) []Test { + return []Test{ { Name: "match & remove label", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "removelabel.example.com", - ClientConfig: ccfgSVC("removeLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "removelabel.example.com", + ClientConfig: ccfgSVC("removeLabel"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - ExpectAllow: true, - AdditionalLabels: map[string]string{"remove": "me"}, - ExpectLabels: map[string]string{"pod.name": "my-pod"}, - ExpectAnnotations: map[string]string{ - "removelabel.example.com/key1": "value1", - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "removelabel.example.com", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "removelabel.example.com", `[{"op": "remove", "path": "/metadata/labels/remove"}]`), - }, + ExpectAllow: true, + AdditionalLabels: map[string]string{"remove": "me"}, + ExpectLabels: map[string]string{"pod.name": "my-pod"}, + ExpectAnnotations: map[string]string{"removelabel.example.com/key1": "value1"}, }, { Name: "match & add label", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "addLabel", - ClientConfig: ccfgSVC("addLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "addLabel", + ClientConfig: ccfgSVC("addLabel"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, ExpectAllow: true, ExpectLabels: map[string]string{"pod.name": "my-pod", "added": "test"}, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "addLabel", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "addLabel", `[{"op": "add", "path": "/metadata/labels/added", "value": "test"}]`), - }, }, { Name: "match CRD & add label", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "addLabel", - ClientConfig: ccfgSVC("addLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "addLabel", + ClientConfig: ccfgSVC("addLabel"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, IsCRD: true, ExpectAllow: true, ExpectLabels: map[string]string{"crd.name": "my-test-crd", "added": "test"}, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "addLabel", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "addLabel", `[{"op": "add", "path": "/metadata/labels/added", "value": "test"}]`), - }, }, { Name: "match CRD & remove label", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "removelabel.example.com", - ClientConfig: ccfgSVC("removeLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "removelabel.example.com", + ClientConfig: ccfgSVC("removeLabel"), + Rules: matchEverythingRules, + NamespaceSelector: &metav1.LabelSelector{}, }}, - IsCRD: true, - ExpectAllow: true, - AdditionalLabels: map[string]string{"remove": "me"}, - ExpectLabels: map[string]string{"crd.name": "my-test-crd"}, - ExpectAnnotations: map[string]string{ - "removelabel.example.com/key1": "value1", - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "removelabel.example.com", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "removelabel.example.com", `[{"op": "remove", "path": "/metadata/labels/remove"}]`), - }, + IsCRD: true, + ExpectAllow: true, + AdditionalLabels: map[string]string{"remove": "me"}, + ExpectLabels: map[string]string{"crd.name": "my-test-crd"}, + ExpectAnnotations: map[string]string{"removelabel.example.com/key1": "value1"}, }, { Name: "match & invalid mutation", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "invalidMutation", - ClientConfig: ccfgSVC("invalidMutation"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - ExpectStatusCode: http.StatusInternalServerError, - ErrorContains: "invalid character", - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "invalidMutation", false), - }, - }, - { - Name: "match & remove label dry run unsupported", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "removeLabel", - ClientConfig: ccfgSVC("removeLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - SideEffects: &sideEffectsUnknown, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - IsDryRun: true, - ExpectStatusCode: http.StatusBadRequest, - ErrorContains: "does not support dry run", - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "removeLabel", false), - }, - }, - { - Name: "first webhook remove labels, second webhook shouldn't be called", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "removelabel.example.com", - ClientConfig: ccfgSVC("removeLabel"), + Webhooks: []registrationv1beta1.Webhook{{ + Name: "invalidMutation", + ClientConfig: ccfgSVC("invalidMutation"), Rules: matchEverythingRules, NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "remove": "me", - }, - }, - AdmissionReviewVersions: []string{"v1beta1"}, - }, { - Name: "shouldNotBeCalled", - ClientConfig: ccfgSVC("shouldNotBeCalled"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "remove": "me", - }, - }, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, }}, - ExpectAllow: true, - AdditionalLabels: map[string]string{"remove": "me"}, - ExpectLabels: map[string]string{"pod.name": "my-pod"}, - ExpectAnnotations: map[string]string{ - "removelabel.example.com/key1": "value1", - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "removelabel.example.com", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "removelabel.example.com", `[{"op": "remove", "path": "/metadata/labels/remove"}]`), - }, + ErrorContains: "invalid character", }, { - Name: "first webhook remove labels from CRD, second webhook shouldn't be called", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "removelabel.example.com", + Name: "match & remove label dry run unsupported", + Webhooks: []registrationv1beta1.Webhook{{ + Name: "removeLabel", ClientConfig: ccfgSVC("removeLabel"), Rules: matchEverythingRules, NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "remove": "me", - }, - }, - AdmissionReviewVersions: []string{"v1beta1"}, - }, { - Name: "shouldNotBeCalled", - ClientConfig: ccfgSVC("shouldNotBeCalled"), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "remove": "me", - }, - }, - Rules: matchEverythingRules, - AdmissionReviewVersions: []string{"v1beta1"}, + SideEffects: &sideEffectsUnknown, }}, - IsCRD: true, - ExpectAllow: true, - AdditionalLabels: map[string]string{"remove": "me"}, - ExpectLabels: map[string]string{"crd.name": "my-test-crd"}, - ExpectAnnotations: map[string]string{ - "removelabel.example.com/key1": "value1", - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "removelabel.example.com", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "removelabel.example.com", `[{"op": "remove", "path": "/metadata/labels/remove"}]`), - }, + IsDryRun: true, + ErrorContains: "does not support dry run", }, // No need to test everything with the url case, since only the // connection is different. - { - Name: "match & reinvoke if needed policy", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "addLabel", - ClientConfig: ccfgSVC("addLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - ReinvocationPolicy: &reinvokeIfNeeded, - }, { - Name: "removeLabel", - ClientConfig: ccfgSVC("removeLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - ReinvocationPolicy: &reinvokeIfNeeded, - }}, - AdditionalLabels: map[string]string{"remove": "me"}, - ExpectAllow: true, - ExpectReinvokeWebhooks: map[string]bool{"addLabel": true}, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "addLabel", true), - "mutation.webhook.admission.k8s.io/round_0_index_1": mutationAnnotationValue(configurationName, "removeLabel", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "addLabel", `[{"op": "add", "path": "/metadata/labels/added", "value": "test"}]`), - "patch.webhook.admission.k8s.io/round_0_index_1": patchAnnotationValue(configurationName, "removeLabel", `[{"op": "remove", "path": "/metadata/labels/remove"}]`), - }, - }, - { - Name: "match & never reinvoke policy", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "addLabel", - ClientConfig: ccfgSVC("addLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - ReinvocationPolicy: &reinvokeNever, - }}, - ExpectAllow: true, - ExpectReinvokeWebhooks: map[string]bool{"addLabel": false}, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "addLabel", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "addLabel", `[{"op": "add", "path": "/metadata/labels/added", "value": "test"}]`), - }, - }, - { - Name: "match & never reinvoke policy (by default)", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "addLabel", - ClientConfig: ccfgSVC("addLabel"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - ExpectAllow: true, - ExpectReinvokeWebhooks: map[string]bool{"addLabel": false}, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "addLabel", true), - "patch.webhook.admission.k8s.io/round_0_index_0": patchAnnotationValue(configurationName, "addLabel", `[{"op": "add", "path": "/metadata/labels/added", "value": "test"}]`), - }, - }, - { - Name: "match & no reinvoke", - Webhooks: []registrationv1.MutatingWebhook{{ - Name: "noop", - ClientConfig: ccfgSVC("noop"), - Rules: matchEverythingRules, - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - AdmissionReviewVersions: []string{"v1beta1"}, - }}, - ExpectAllow: true, - ExpectAnnotations: map[string]string{ - "mutation.webhook.admission.k8s.io/round_0_index_0": mutationAnnotationValue(configurationName, "noop", false), - }, - }, } } // CachedTest is a test case for the client manager. type CachedTest struct { Name string - Webhooks []registrationv1.ValidatingWebhook + Webhooks []registrationv1beta1.Webhook ExpectAllow bool ExpectCacheMiss bool } // NewCachedClientTestcases returns a set of client manager test cases. func NewCachedClientTestcases(url *url.URL) []CachedTest { - policyIgnore := registrationv1.Ignore + policyIgnore := registrationv1beta1.Ignore ccfgURL := urlConfigGenerator{url}.ccfgURL return []CachedTest{ { Name: "uncached: service webhook, path 'allow'", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "cache1", - ClientConfig: ccfgSVC("allow"), - Rules: newMatchEverythingRules(), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "cache1", + ClientConfig: ccfgSVC("allow"), + Rules: newMatchEverythingRules(), + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, ExpectAllow: true, ExpectCacheMiss: true, }, { Name: "uncached: service webhook, path 'internalErr'", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "cache2", - ClientConfig: ccfgSVC("internalErr"), - Rules: newMatchEverythingRules(), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "cache2", + ClientConfig: ccfgSVC("internalErr"), + Rules: newMatchEverythingRules(), + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, ExpectAllow: true, ExpectCacheMiss: true, }, { Name: "cached: service webhook, path 'allow'", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "cache3", - ClientConfig: ccfgSVC("allow"), - Rules: newMatchEverythingRules(), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "cache3", + ClientConfig: ccfgSVC("allow"), + Rules: newMatchEverythingRules(), + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, ExpectAllow: true, ExpectCacheMiss: false, }, { Name: "uncached: url webhook, path 'allow'", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "cache4", - ClientConfig: ccfgURL("allow"), - Rules: newMatchEverythingRules(), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "cache4", + ClientConfig: ccfgURL("allow"), + Rules: newMatchEverythingRules(), + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, ExpectAllow: true, ExpectCacheMiss: true, }, { Name: "cached: service webhook, path 'allow'", - Webhooks: []registrationv1.ValidatingWebhook{{ - Name: "cache5", - ClientConfig: ccfgURL("allow"), - Rules: newMatchEverythingRules(), - NamespaceSelector: &metav1.LabelSelector{}, - ObjectSelector: &metav1.LabelSelector{}, - FailurePolicy: &policyIgnore, - AdmissionReviewVersions: []string{"v1beta1"}, + Webhooks: []registrationv1beta1.Webhook{{ + Name: "cache5", + ClientConfig: ccfgURL("allow"), + Rules: newMatchEverythingRules(), + NamespaceSelector: &metav1.LabelSelector{}, + FailurePolicy: &policyIgnore, }}, ExpectAllow: true, ExpectCacheMiss: false, @@ -1023,9 +628,9 @@ func NewCachedClientTestcases(url *url.URL) []CachedTest { } // ccfgSVC returns a client config using the service reference mechanism. -func ccfgSVC(urlPath string) registrationv1.WebhookClientConfig { - return registrationv1.WebhookClientConfig{ - Service: ®istrationv1.ServiceReference{ +func ccfgSVC(urlPath string) registrationv1beta1.WebhookClientConfig { + return registrationv1beta1.WebhookClientConfig{ + Service: ®istrationv1beta1.ServiceReference{ Name: "webhook-test", Namespace: "default", Path: &urlPath, @@ -1034,20 +639,13 @@ func ccfgSVC(urlPath string) registrationv1.WebhookClientConfig { } } -func newMatchEverythingRules() []registrationv1.RuleWithOperations { - return []registrationv1.RuleWithOperations{{ - Operations: []registrationv1.OperationType{registrationv1.OperationAll}, - Rule: registrationv1.Rule{ +func newMatchEverythingRules() []registrationv1beta1.RuleWithOperations { + return []registrationv1beta1.RuleWithOperations{{ + Operations: []registrationv1beta1.OperationType{registrationv1beta1.OperationAll}, + Rule: registrationv1beta1.Rule{ APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*/*"}, }, }} } - -// NewObjectInterfacesForTest returns an ObjectInterfaces appropriate for test cases in this file. -func NewObjectInterfacesForTest() admission.ObjectInterfaces { - scheme := runtime.NewScheme() - corev1.AddToScheme(scheme) - return admission.NewObjectInterfacesFromScheme(scheme) -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/webhook_server.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/webhook_server.go index b6d446005b0..0af53633532 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/webhook_server.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/webhook_server.go @@ -20,6 +20,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/json" + "fmt" "net/http" "net/http/httptest" "testing" @@ -30,12 +31,11 @@ import ( ) // NewTestServer returns a webhook test HTTPS server with fixed webhook test certs. -func NewTestServer(t testing.TB) *httptest.Server { +func NewTestServer(t *testing.T) *httptest.Server { // Create the test webhook server sCert, err := tls.X509KeyPair(testcerts.ServerCert, testcerts.ServerKey) if err != nil { - t.Error(err) - t.FailNow() + t.Fatal(err) } rootCAs := x509.NewCertPool() rootCAs.AppendCertsFromPEM(testcerts.CACert) @@ -49,7 +49,7 @@ func NewTestServer(t testing.TB) *httptest.Server { } func webhookHandler(w http.ResponseWriter, r *http.Request) { - // fmt.Printf("got req: %v\n", r.URL.Path) + fmt.Printf("got req: %v\n", r.URL.Path) switch r.URL.Path { case "/internalErr": http.Error(w, "webhook internal server error", http.StatusInternalServerError) @@ -66,9 +66,6 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{ Response: &v1beta1.AdmissionResponse{ Allowed: false, - Result: &metav1.Status{ - Code: http.StatusForbidden, - }, }, }) case "/disallowReason": @@ -78,18 +75,6 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { Allowed: false, Result: &metav1.Status{ Message: "you shall not pass", - Code: http.StatusForbidden, - }, - }, - }) - case "/shouldNotBeCalled": - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{ - Response: &v1beta1.AdmissionResponse{ - Allowed: false, - Result: &metav1.Status{ - Message: "doesn't expect labels to match object selector", - Code: http.StatusForbidden, }, }, }) @@ -149,13 +134,6 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) { }, }, }) - case "/noop": - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(&v1beta1.AdmissionReview{ - Response: &v1beta1.AdmissionResponse{ - Allowed: true, - }, - }) default: http.NotFound(w, r) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go index 2ed342321ea..49255eba06a 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/util/client_config.go @@ -17,15 +17,26 @@ limitations under the License. package util import ( - "k8s.io/apiserver/pkg/admission/plugin/webhook" + "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/apiserver/pkg/util/webhook" ) -// HasAdmissionReviewVersion check whether a version is accepted by a given webhook. -func HasAdmissionReviewVersion(a string, w webhook.WebhookAccessor) bool { - for _, b := range w.GetAdmissionReviewVersions() { - if b == a { - return true +// HookClientConfigForWebhook construct a webhook.ClientConfig using a v1beta1.Webhook API object. +// webhook.ClientConfig is used to create a HookClient and the purpose of the config struct is to +// share that with other packages that need to create a HookClient. +func HookClientConfigForWebhook(w *v1beta1.Webhook) webhook.ClientConfig { + ret := webhook.ClientConfig{Name: w.Name, CABundle: w.ClientConfig.CABundle} + if w.ClientConfig.URL != nil { + ret.URL = *w.ClientConfig.URL + } + if w.ClientConfig.Service != nil { + ret.Service = &webhook.ClientConfigService{ + Name: w.ClientConfig.Service.Name, + Namespace: w.ClientConfig.Service.Namespace, + } + if w.ClientConfig.Service.Path != nil { + ret.Service.Path = *w.ClientConfig.Service.Path } } - return false + return ret } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go index ab6b0392487..166e21adcdf 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/dispatcher.go @@ -22,108 +22,47 @@ import ( "sync" "time" - v1 "k8s.io/api/admissionregistration/v1" + "k8s.io/klog" + + admissionv1beta1 "k8s.io/api/admission/v1beta1" + "k8s.io/api/admissionregistration/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apiserver/pkg/admission" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" - "k8s.io/apiserver/pkg/admission/plugin/webhook" webhookerrors "k8s.io/apiserver/pkg/admission/plugin/webhook/errors" "k8s.io/apiserver/pkg/admission/plugin/webhook/generic" - webhookrequest "k8s.io/apiserver/pkg/admission/plugin/webhook/request" - webhookutil "k8s.io/apiserver/pkg/util/webhook" - "k8s.io/klog" - utiltrace "k8s.io/utils/trace" + "k8s.io/apiserver/pkg/admission/plugin/webhook/request" + "k8s.io/apiserver/pkg/admission/plugin/webhook/util" + "k8s.io/apiserver/pkg/util/webhook" ) type validatingDispatcher struct { - cm *webhookutil.ClientManager - plugin *Plugin + cm *webhook.ClientManager } -func newValidatingDispatcher(p *Plugin) func(cm *webhookutil.ClientManager) generic.Dispatcher { - return func(cm *webhookutil.ClientManager) generic.Dispatcher { - return &validatingDispatcher{cm, p} - } +func newValidatingDispatcher(cm *webhook.ClientManager) generic.Dispatcher { + return &validatingDispatcher{cm} } var _ generic.Dispatcher = &validatingDispatcher{} -func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces, hooks []webhook.WebhookAccessor) error { - var relevantHooks []*generic.WebhookInvocation - // Construct all the versions we need to call our webhooks - versionedAttrs := map[schema.GroupVersionKind]*generic.VersionedAttributes{} - for _, hook := range hooks { - invocation, statusError := d.plugin.ShouldCallHook(hook, attr, o) - if statusError != nil { - return statusError - } - if invocation == nil { - continue - } - relevantHooks = append(relevantHooks, invocation) - // If we already have this version, continue - if _, ok := versionedAttrs[invocation.Kind]; ok { - continue - } - versionedAttr, err := generic.NewVersionedAttributes(attr, invocation.Kind, o) - if err != nil { - return apierrors.NewInternalError(err) - } - versionedAttrs[invocation.Kind] = versionedAttr - } - - if len(relevantHooks) == 0 { - // no matching hooks - return nil - } - - // Check if the request has already timed out before spawning remote calls - select { - case <-ctx.Done(): - // parent context is canceled or timed out, no point in continuing - return apierrors.NewTimeoutError("request did not complete within requested timeout", 0) - default: - } - +func (d *validatingDispatcher) Dispatch(ctx context.Context, attr *generic.VersionedAttributes, relevantHooks []*v1beta1.Webhook) error { wg := sync.WaitGroup{} errCh := make(chan error, len(relevantHooks)) wg.Add(len(relevantHooks)) for i := range relevantHooks { - go func(invocation *generic.WebhookInvocation) { + go func(hook *v1beta1.Webhook) { defer wg.Done() - hook, ok := invocation.Webhook.GetValidatingWebhook() - if !ok { - utilruntime.HandleError(fmt.Errorf("validating webhook dispatch requires v1.ValidatingWebhook, but got %T", hook)) - return - } - versionedAttr := versionedAttrs[invocation.Kind] + t := time.Now() - err := d.callHook(ctx, hook, invocation, versionedAttr) - ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1.Ignore - rejected := false - if err != nil { - switch err := err.(type) { - case *webhookutil.ErrCallingWebhook: - if !ignoreClientCallFailures { - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionCallingWebhookError, 0) - } - case *webhookutil.ErrWebhookRejection: - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionNoError, int(err.Status.ErrStatus.Code)) - default: - rejected = true - admissionmetrics.Metrics.ObserveWebhookRejection(hook.Name, "validating", string(versionedAttr.Attributes.GetOperation()), admissionmetrics.WebhookRejectionAPIServerInternalError, 0) - } - } - admissionmetrics.Metrics.ObserveWebhook(time.Since(t), rejected, versionedAttr.Attributes, "validating", hook.Name) + err := d.callHook(ctx, hook, attr) + admissionmetrics.Metrics.ObserveWebhook(time.Since(t), err != nil, attr.Attributes, "validating", hook.Name) if err == nil { return } - if callErr, ok := err.(*webhookutil.ErrCallingWebhook); ok { + ignoreClientCallFailures := hook.FailurePolicy != nil && *hook.FailurePolicy == v1beta1.Ignore + if callErr, ok := err.(*webhook.ErrCallingWebhook); ok { if ignoreClientCallFailures { klog.Warningf("Failed calling webhook, failing open %v: %v", hook.Name, callErr) utilruntime.HandleError(callErr) @@ -135,9 +74,6 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr return } - if rejectionErr, ok := err.(*webhookutil.ErrWebhookRejection); ok { - err = rejectionErr.Status - } klog.Warningf("rejected by webhook %q: %#v", hook.Name, err) errCh <- err }(relevantHooks[i]) @@ -161,74 +97,38 @@ func (d *validatingDispatcher) Dispatch(ctx context.Context, attr admission.Attr return errs[0] } -func (d *validatingDispatcher) callHook(ctx context.Context, h *v1.ValidatingWebhook, invocation *generic.WebhookInvocation, attr *generic.VersionedAttributes) error { - if attr.Attributes.IsDryRun() { +func (d *validatingDispatcher) callHook(ctx context.Context, h *v1beta1.Webhook, attr *generic.VersionedAttributes) error { + if attr.IsDryRun() { if h.SideEffects == nil { - return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")} + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook SideEffects is nil")} } - if !(*h.SideEffects == v1.SideEffectClassNone || *h.SideEffects == v1.SideEffectClassNoneOnDryRun) { + if !(*h.SideEffects == v1beta1.SideEffectClassNone || *h.SideEffects == v1beta1.SideEffectClassNoneOnDryRun) { return webhookerrors.NewDryRunUnsupportedErr(h.Name) } } - uid, request, response, err := webhookrequest.CreateAdmissionObjects(attr, invocation) - if err != nil { - return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} - } // Make the webhook request - client, err := invocation.Webhook.GetRESTClient(d.cm) + request := request.CreateAdmissionReview(attr) + client, err := d.cm.HookClient(util.HookClientConfigForWebhook(h)) if err != nil { - return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} - } - trace := utiltrace.New("Call validating webhook", - utiltrace.Field{"configuration", invocation.Webhook.GetConfigurationName()}, - utiltrace.Field{"webhook", h.Name}, - utiltrace.Field{"resource", attr.GetResource()}, - utiltrace.Field{"subresource", attr.GetSubresource()}, - utiltrace.Field{"operation", attr.GetOperation()}, - utiltrace.Field{"UID", uid}) - defer trace.LogIfLong(500 * time.Millisecond) - - // if the webhook has a specific timeout, wrap the context to apply it - if h.TimeoutSeconds != nil { - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, time.Duration(*h.TimeoutSeconds)*time.Second) - defer cancel() + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err} } - - r := client.Post().Body(request) - - // if the context has a deadline, set it as a parameter to inform the backend - if deadline, hasDeadline := ctx.Deadline(); hasDeadline { - // compute the timeout - if timeout := time.Until(deadline); timeout > 0 { - // if it's not an even number of seconds, round up to the nearest second - if truncated := timeout.Truncate(time.Second); truncated != timeout { - timeout = truncated + time.Second - } - // set the timeout - r.Timeout(timeout) - } + response := &admissionv1beta1.AdmissionReview{} + if err := client.Post().Context(ctx).Body(&request).Do().Into(response); err != nil { + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: err} } - if err := r.Do(ctx).Into(response); err != nil { - return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} + if response.Response == nil { + return &webhook.ErrCallingWebhook{WebhookName: h.Name, Reason: fmt.Errorf("Webhook response was absent")} } - trace.Step("Request completed") - - result, err := webhookrequest.VerifyAdmissionResponse(uid, false, response) - if err != nil { - return &webhookutil.ErrCallingWebhook{WebhookName: h.Name, Reason: err} - } - - for k, v := range result.AuditAnnotations { + for k, v := range response.Response.AuditAnnotations { key := h.Name + "/" + k - if err := attr.Attributes.AddAnnotation(key, v); err != nil { + if err := attr.AddAnnotation(key, v); err != nil { klog.Warningf("Failed to set admission audit annotation %s to %s for validating webhook %s: %v", key, v, h.Name, err) } } - if result.Allowed { + if response.Response.Allowed { return nil } - return &webhookutil.ErrWebhookRejection{Status: webhookerrors.ToStatusErr(h.Name, result.Result)} + return webhookerrors.ToStatusErr(h.Name, response.Response.Result) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin.go index 6972877b185..7f79b9d7a08 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin.go @@ -17,7 +17,6 @@ limitations under the License. package validating import ( - "context" "io" "k8s.io/apiserver/pkg/admission" @@ -52,16 +51,14 @@ var _ admission.ValidationInterface = &Plugin{} // NewValidatingAdmissionWebhook returns a generic admission webhook plugin. func NewValidatingAdmissionWebhook(configFile io.Reader) (*Plugin, error) { handler := admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update) - p := &Plugin{} - var err error - p.Webhook, err = generic.NewWebhook(handler, configFile, configuration.NewValidatingWebhookConfigurationManager, newValidatingDispatcher(p)) + webhook, err := generic.NewWebhook(handler, configFile, configuration.NewValidatingWebhookConfigurationManager, newValidatingDispatcher) if err != nil { return nil, err } - return p, nil + return &Plugin{webhook}, nil } // Validate makes an admission decision based on the request attributes. -func (a *Plugin) Validate(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) error { - return a.Webhook.Dispatch(ctx, attr, o) +func (a *Plugin) Validate(attr admission.Attributes) error { + return a.Webhook.Dispatch(attr) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin_test.go b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin_test.go index a975962c679..3dff3864dbc 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin_test.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating/plugin_test.go @@ -17,91 +17,30 @@ limitations under the License. package validating import ( - "context" "net/url" - "os" "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/api/admission/v1beta1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" webhooktesting "k8s.io/apiserver/pkg/admission/plugin/webhook/testing" - auditinternal "k8s.io/apiserver/pkg/apis/audit" ) -// BenchmarkValidate tests that ValidatingWebhook#Validate works as expected -func BenchmarkValidate(b *testing.B) { - testServerURL := os.Getenv("WEBHOOK_TEST_SERVER_URL") - if len(testServerURL) == 0 { - b.Log("warning, WEBHOOK_TEST_SERVER_URL not set, starting in-process server, benchmarks will include webhook cost.") - b.Log("to run a standalone server, run:") - b.Log("go run ./vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/testing/main/main.go") - testServer := webhooktesting.NewTestServer(b) - testServer.StartTLS() - defer testServer.Close() - testServerURL = testServer.URL - } - - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - - serverURL, err := url.ParseRequestURI(testServerURL) - if err != nil { - b.Fatalf("this should never happen? %v", err) - } - - stopCh := make(chan struct{}) - defer close(stopCh) - - for _, tt := range webhooktesting.NewNonMutatingTestCases(serverURL) { - // For now, skip failure cases or tests that explicitly skip benchmarking - if !tt.ExpectAllow || tt.SkipBenchmark { - continue - } - - b.Run(tt.Name, func(b *testing.B) { - wh, err := NewValidatingAdmissionWebhook(nil) - if err != nil { - b.Errorf("%s: failed to create validating webhook: %v", tt.Name, err) - return - } - - ns := "webhook-test" - client, informer := webhooktesting.NewFakeValidatingDataSource(ns, tt.Webhooks, stopCh) - - wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32)))) - wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) - wh.SetExternalKubeClientSet(client) - wh.SetExternalKubeInformerFactory(informer) - - informer.Start(stopCh) - informer.WaitForCacheSync(stopCh) - - if err = wh.ValidateInitialization(); err != nil { - b.Errorf("%s: failed to validate initialization: %v", tt.Name, err) - return - } - - attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun) - - b.ResetTimer() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - wh.Validate(context.TODO(), attr, objectInterfaces) - } - }) - }) - } -} - // TestValidate tests that ValidatingWebhook#Validate works as expected func TestValidate(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, v1beta1.AddToScheme(scheme)) + require.NoError(t, corev1.AddToScheme(scheme)) + testServer := webhooktesting.NewTestServer(t) testServer.StartTLS() defer testServer.Close() - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - serverURL, err := url.ParseRequestURI(testServer.URL) if err != nil { t.Fatalf("this should never happen? %v", err) @@ -118,10 +57,11 @@ func TestValidate(t *testing.T) { } ns := "webhook-test" - client, informer := webhooktesting.NewFakeValidatingDataSource(ns, tt.Webhooks, stopCh) + client, informer := webhooktesting.NewFakeDataSource(ns, tt.Webhooks, false, stopCh) wh.SetAuthenticationInfoResolverWrapper(webhooktesting.Wrapper(webhooktesting.NewAuthenticationInfoResolver(new(int32)))) wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) + wh.SetScheme(scheme) wh.SetExternalKubeClientSet(client) wh.SetExternalKubeInformerFactory(informer) @@ -134,7 +74,7 @@ func TestValidate(t *testing.T) { } attr := webhooktesting.NewAttribute(ns, nil, tt.IsDryRun) - err = wh.Validate(context.TODO(), attr, objectInterfaces) + err = wh.Validate(attr) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } @@ -153,15 +93,19 @@ func TestValidate(t *testing.T) { continue } if len(tt.ExpectAnnotations) == 0 { - assert.Empty(t, fakeAttr.GetAnnotations(auditinternal.LevelMetadata), tt.Name+": annotations not set as expected.") + assert.Empty(t, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.") } else { - assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(auditinternal.LevelMetadata), tt.Name+": annotations not set as expected.") + assert.Equal(t, tt.ExpectAnnotations, fakeAttr.GetAnnotations(), tt.Name+": annotations not set as expected.") } } } // TestValidateCachedClient tests that ValidatingWebhook#Validate should cache restClient func TestValidateCachedClient(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, v1beta1.AddToScheme(scheme)) + require.NoError(t, corev1.AddToScheme(scheme)) + testServer := webhooktesting.NewTestServer(t) testServer.StartTLS() defer testServer.Close() @@ -170,8 +114,6 @@ func TestValidateCachedClient(t *testing.T) { t.Fatalf("this should never happen? %v", err) } - objectInterfaces := webhooktesting.NewObjectInterfacesForTest() - stopCh := make(chan struct{}) defer close(stopCh) @@ -180,10 +122,11 @@ func TestValidateCachedClient(t *testing.T) { t.Fatalf("Failed to create validating webhook: %v", err) } wh.SetServiceResolver(webhooktesting.NewServiceResolver(*serverURL)) + wh.SetScheme(scheme) for _, tt := range webhooktesting.NewCachedClientTestcases(serverURL) { ns := "webhook-test" - client, informer := webhooktesting.NewFakeValidatingDataSource(ns, tt.Webhooks, stopCh) + client, informer := webhooktesting.NewFakeDataSource(ns, tt.Webhooks, false, stopCh) // override the webhook source. The client cache will stay the same. cacheMisses := new(int32) @@ -199,7 +142,7 @@ func TestValidateCachedClient(t *testing.T) { continue } - err = wh.Validate(context.TODO(), webhooktesting.NewAttribute(ns, nil, false), objectInterfaces) + err = wh.Validate(webhooktesting.NewAttribute(ns, nil, false)) if tt.ExpectAllow != (err == nil) { t.Errorf("%s: expected allowed=%v, but got err=%v", tt.Name, tt.ExpectAllow, err) } diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugins.go b/vendor/k8s.io/apiserver/pkg/admission/plugins.go index d37af509c66..bdf087e564f 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugins.go +++ b/vendor/k8s.io/apiserver/pkg/admission/plugins.go @@ -160,7 +160,7 @@ func (ps *Plugins) NewFromPlugins(pluginNames []string, configProvider ConfigPro if len(validationPlugins) != 0 { klog.Infof("Loaded %d validating admission controller(s) successfully in the following order: %s.", len(validationPlugins), strings.Join(validationPlugins, ",")) } - return newReinvocationHandler(chainAdmissionHandler(handlers)), nil + return chainAdmissionHandler(handlers), nil } // InitPlugin creates an instance of the named interface. diff --git a/vendor/k8s.io/apiserver/pkg/admission/reinvocation.go b/vendor/k8s.io/apiserver/pkg/admission/reinvocation.go deleted file mode 100644 index f93c703a11c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/reinvocation.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2019 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 admission - -import "context" - -// newReinvocationHandler creates a handler that wraps the provided admission chain and reinvokes it -// if needed according to re-invocation policy of the webhooks. -func newReinvocationHandler(admissionChain Interface) Interface { - return &reinvoker{admissionChain} -} - -type reinvoker struct { - admissionChain Interface -} - -// Admit performs an admission control check using the wrapped admission chain, reinvoking the -// admission chain if needed according to the reinvocation policy. Plugins are expected to check -// the admission attributes' reinvocation context against their reinvocation policy to decide if -// they should re-run, and to update the reinvocation context if they perform any mutations. -func (r *reinvoker) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error { - if mutator, ok := r.admissionChain.(MutationInterface); ok { - err := mutator.Admit(ctx, a, o) - if err != nil { - return err - } - s := a.GetReinvocationContext() - if s.ShouldReinvoke() { - s.SetIsReinvoke() - // Calling admit a second time will reinvoke all in-tree plugins - // as well as any webhook plugins that need to be reinvoked based on the - // reinvocation policy. - return mutator.Admit(ctx, a, o) - } - } - return nil -} - -// Validate performs an admission control check using the wrapped admission chain, and returns immediately on first error. -func (r *reinvoker) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error { - if validator, ok := r.admissionChain.(ValidationInterface); ok { - return validator.Validate(ctx, a, o) - } - return nil -} - -// Handles will return true if any of the admission chain handlers handle the given operation. -func (r *reinvoker) Handles(operation Operation) bool { - return r.admissionChain.Handles(operation) -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/testing/helpers.go b/vendor/k8s.io/apiserver/pkg/admission/testing/helpers.go deleted file mode 100644 index 45e126dabf6..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/testing/helpers.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2019 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 testing - -import ( - "context" - "reflect" - "testing" - - apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/diff" - "k8s.io/apiserver/pkg/admission" -) - -// WithReinvocationTesting wraps a mutating admission handler and reinvokes it each time Admit is -// called. It checks the admission output object and reports a test error if the admission handler -// performs non-idempotent mutatations to the object. -func WithReinvocationTesting(t *testing.T, admission admission.MutationInterface) admission.MutationInterface { - return &reinvoker{t, admission} -} - -type reinvoker struct { - t *testing.T - admission admission.MutationInterface -} - -// Admit reinvokes the admission handler and reports a test error if the admission handler performs -// non-idempotent mutatations to the admission object. -func (r *reinvoker) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { - r.t.Helper() - outputs := []runtime.Object{} - for i := 0; i < 2; i++ { - err := r.admission.Admit(ctx, a, o) - if err != nil { - return err - } - if a.GetObject() != nil { - // keep a copy of the output for subsequent idempotency checking - outputs = append(outputs, a.GetObject().DeepCopyObject()) - // replace a.GetObject() with a copy of itself to make sure admission is safe to reinvoke with a round-tripped copy (no pointer comparisons are done) - if deepCopyInto, ok := reflect.TypeOf(a.GetObject()).MethodByName("DeepCopyInto"); ok { - deepCopyInto.Func.Call([]reflect.Value{ - reflect.ValueOf(a.GetObject().DeepCopyObject()), - reflect.ValueOf(a.GetObject()), - }) - } - } - } - for i := 1; i < len(outputs); i++ { - if !apiequality.Semantic.DeepEqual(outputs[0], outputs[i]) { - r.t.Errorf("expected mutating admission plugin to be idempontent, but got different results on reinvocation, diff:\n%s", diff.ObjectReflectDiff(outputs[0], outputs[i])) - } - } - return nil -} - -// Handles will return true if any of the admission andler handlers handle the given operation. -func (r *reinvoker) Handles(operation admission.Operation) bool { - r.t.Helper() - return r.admission.Handles(operation) -} diff --git a/vendor/k8s.io/apiserver/pkg/admission/util.go b/vendor/k8s.io/apiserver/pkg/admission/util.go deleted file mode 100644 index 842932f73e7..00000000000 --- a/vendor/k8s.io/apiserver/pkg/admission/util.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 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 admission - -import "k8s.io/apimachinery/pkg/runtime" - -type RuntimeObjectInterfaces struct { - runtime.ObjectCreater - runtime.ObjectTyper - runtime.ObjectDefaulter - runtime.ObjectConvertor - runtime.EquivalentResourceMapper -} - -func NewObjectInterfacesFromScheme(scheme *runtime.Scheme) ObjectInterfaces { - return &RuntimeObjectInterfaces{scheme, scheme, scheme, scheme, runtime.NewEquivalentResourceRegistry()} -} - -func (r *RuntimeObjectInterfaces) GetObjectCreater() runtime.ObjectCreater { - return r.ObjectCreater -} -func (r *RuntimeObjectInterfaces) GetObjectTyper() runtime.ObjectTyper { - return r.ObjectTyper -} -func (r *RuntimeObjectInterfaces) GetObjectDefaulter() runtime.ObjectDefaulter { - return r.ObjectDefaulter -} -func (r *RuntimeObjectInterfaces) GetObjectConvertor() runtime.ObjectConvertor { - return r.ObjectConvertor -} -func (r *RuntimeObjectInterfaces) GetEquivalentResourceMapper() runtime.EquivalentResourceMapper { - return r.EquivalentResourceMapper -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/OWNERS b/vendor/k8s.io/apiserver/pkg/apis/OWNERS index 38336c177f9..bae178f8175 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/apis/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - # Disable inheritance as this is an api owners file options: no_parent_owners: true diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/install/install.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/install/install.go index 8a8202cb5bf..4b58a9710be 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/install/install.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/install/install.go @@ -20,24 +20,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apiserver/pkg/apis/apiserver" - v1 "k8s.io/apiserver/pkg/apis/apiserver/v1" "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" - "k8s.io/apiserver/pkg/apis/apiserver/v1beta1" ) // Install registers the API group and adds types to a scheme func Install(scheme *runtime.Scheme) { utilruntime.Must(apiserver.AddToScheme(scheme)) - - // v1alpha is in the k8s.io-suffixed API group utilruntime.Must(v1alpha1.AddToScheme(scheme)) utilruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion)) - - // v1alpha is in the k8s.io-suffixed API group - utilruntime.Must(v1beta1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1beta1.SchemeGroupVersion)) - - // v1 is in the config.k8s.io-suffixed API group - utilruntime.Must(v1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) } diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/register.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/register.go index 7466f45460a..ffe9942a6cc 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/register.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/register.go @@ -21,15 +21,21 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -const LegacyGroupName = "apiserver.k8s.io" -const GroupName = "apiserver.config.k8s.io" - -// LegacySchemeGroupVersion is group version used to register these objects -var LegacySchemeGroupVersion = schema.GroupVersion{Group: LegacyGroupName, Version: runtime.APIVersionInternal} +const GroupName = "apiserver.k8s.io" // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns back a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + var ( SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) AddToScheme = SchemeBuilder.AddToScheme @@ -37,13 +43,8 @@ var ( // Adds the list of known types to the given scheme. func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(LegacySchemeGroupVersion, - &AdmissionConfiguration{}, - &EgressSelectorConfiguration{}, - ) scheme.AddKnownTypes(SchemeGroupVersion, &AdmissionConfiguration{}, - &EgressSelectorConfiguration{}, ) return nil } diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/types.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/types.go index 4e414944129..e55da95f95d 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/types.go @@ -48,101 +48,3 @@ type AdmissionPluginConfiguration struct { // +optional Configuration *runtime.Unknown } - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// EgressSelectorConfiguration provides versioned configuration for egress selector clients. -type EgressSelectorConfiguration struct { - metav1.TypeMeta - - // EgressSelections contains a list of egress selection client configurations - EgressSelections []EgressSelection -} - -// EgressSelection provides the configuration for a single egress selection client. -type EgressSelection struct { - // Name is the name of the egress selection. - // Currently supported values are "Master", "Etcd" and "Cluster" - Name string - - // Connection is the exact information used to configure the egress selection - Connection Connection -} - -// Connection provides the configuration for a single egress selection client. -type Connection struct { - // Protocol is the protocol used to connect from client to the konnectivity server. - ProxyProtocol ProtocolType - - // Transport defines the transport configurations we use to dial to the konnectivity server. - // This is required if ProxyProtocol is HTTPConnect or GRPC. - // +optional - Transport *Transport -} - -// ProtocolType is a set of valid values for Connection.ProtocolType -type ProtocolType string - -// Valid types for ProtocolType for konnectivity server -const ( - // Use HTTPConnect to connect to konnectivity server - ProtocolHTTPConnect ProtocolType = "HTTPConnect" - // Use grpc to connect to konnectivity server - ProtocolGRPC ProtocolType = "GRPC" - // Connect directly (skip konnectivity server) - ProtocolDirect ProtocolType = "Direct" -) - -// Transport defines the transport configurations we use to dial to the konnectivity server -type Transport struct { - // TCP is the TCP configuration for communicating with the konnectivity server via TCP - // ProxyProtocol of GRPC is not supported with TCP transport at the moment - // Requires at least one of TCP or UDS to be set - // +optional - TCP *TCPTransport - - // UDS is the UDS configuration for communicating with the konnectivity server via UDS - // Requires at least one of TCP or UDS to be set - // +optional - UDS *UDSTransport -} - -// TCPTransport provides the information to connect to konnectivity server via TCP -type TCPTransport struct { - // URL is the location of the konnectivity server to connect to. - // As an example it might be "https://127.0.0.1:8131" - URL string - - // TLSConfig is the config needed to use TLS when connecting to konnectivity server - // +optional - TLSConfig *TLSConfig -} - -// UDSTransport provides the information to connect to konnectivity server via UDS -type UDSTransport struct { - // UDSName is the name of the unix domain socket to connect to konnectivity server - // This does not use a unix:// prefix. (Eg: /etc/srv/kubernetes/konnectivity-server/konnectivity-server.socket) - UDSName string -} - -// TLSConfig provides the authentication information to connect to konnectivity server -// Only used with TCPTransport -type TLSConfig struct { - // caBundle is the file location of the CA to be used to determine trust with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // If absent while TCPTransport.URL is prefixed with https://, default to system trust roots. - // +optional - CABundle string - - // clientKey is the file location of the client key to authenticate with the konnectivity server - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientKey string - - // clientCert is the file location of the client certificate to authenticate with the konnectivity server - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientCert string -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/doc.go deleted file mode 100644 index 91458aee4e8..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2019 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. -*/ - -// +k8s:deepcopy-gen=package -// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/apiserver -// +k8s:defaulter-gen=TypeMeta -// +groupName=apiserver.config.k8s.io - -// Package v1 is the v1 version of the API. -package v1 // import "k8s.io/apiserver/pkg/apis/apiserver/v1" diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/register.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/register.go deleted file mode 100644 index 8d3bf987f9c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/register.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2019 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -const GroupName = "apiserver.config.k8s.io" - -// SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &AdmissionConfiguration{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/types.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/types.go deleted file mode 100644 index e139dceb9de..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/types.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2019 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" -) - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// AdmissionConfiguration provides versioned configuration for admission controllers. -type AdmissionConfiguration struct { - metav1.TypeMeta `json:",inline"` - - // Plugins allows specifying a configuration per admission control plugin. - // +optional - Plugins []AdmissionPluginConfiguration `json:"plugins"` -} - -// AdmissionPluginConfiguration provides the configuration for a single plug-in. -type AdmissionPluginConfiguration struct { - // Name is the name of the admission controller. - // It must match the registered admission plugin name. - Name string `json:"name"` - - // Path is the path to a configuration file that contains the plugin's - // configuration - // +optional - Path string `json:"path"` - - // Configuration is an embedded configuration object to be used as the plugin's - // configuration. If present, it will be used instead of the path to the configuration file. - // +optional - Configuration *runtime.Unknown `json:"configuration"` -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.conversion.go deleted file mode 100644 index 5116139ae98..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.conversion.go +++ /dev/null @@ -1,103 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1 - -import ( - unsafe "unsafe" - - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - apiserver "k8s.io/apiserver/pkg/apis/apiserver" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*AdmissionConfiguration)(nil), (*apiserver.AdmissionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_AdmissionConfiguration_To_apiserver_AdmissionConfiguration(a.(*AdmissionConfiguration), b.(*apiserver.AdmissionConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.AdmissionConfiguration)(nil), (*AdmissionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_AdmissionConfiguration_To_v1_AdmissionConfiguration(a.(*apiserver.AdmissionConfiguration), b.(*AdmissionConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*AdmissionPluginConfiguration)(nil), (*apiserver.AdmissionPluginConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_AdmissionPluginConfiguration_To_apiserver_AdmissionPluginConfiguration(a.(*AdmissionPluginConfiguration), b.(*apiserver.AdmissionPluginConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.AdmissionPluginConfiguration)(nil), (*AdmissionPluginConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_AdmissionPluginConfiguration_To_v1_AdmissionPluginConfiguration(a.(*apiserver.AdmissionPluginConfiguration), b.(*AdmissionPluginConfiguration), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1_AdmissionConfiguration_To_apiserver_AdmissionConfiguration(in *AdmissionConfiguration, out *apiserver.AdmissionConfiguration, s conversion.Scope) error { - out.Plugins = *(*[]apiserver.AdmissionPluginConfiguration)(unsafe.Pointer(&in.Plugins)) - return nil -} - -// Convert_v1_AdmissionConfiguration_To_apiserver_AdmissionConfiguration is an autogenerated conversion function. -func Convert_v1_AdmissionConfiguration_To_apiserver_AdmissionConfiguration(in *AdmissionConfiguration, out *apiserver.AdmissionConfiguration, s conversion.Scope) error { - return autoConvert_v1_AdmissionConfiguration_To_apiserver_AdmissionConfiguration(in, out, s) -} - -func autoConvert_apiserver_AdmissionConfiguration_To_v1_AdmissionConfiguration(in *apiserver.AdmissionConfiguration, out *AdmissionConfiguration, s conversion.Scope) error { - out.Plugins = *(*[]AdmissionPluginConfiguration)(unsafe.Pointer(&in.Plugins)) - return nil -} - -// Convert_apiserver_AdmissionConfiguration_To_v1_AdmissionConfiguration is an autogenerated conversion function. -func Convert_apiserver_AdmissionConfiguration_To_v1_AdmissionConfiguration(in *apiserver.AdmissionConfiguration, out *AdmissionConfiguration, s conversion.Scope) error { - return autoConvert_apiserver_AdmissionConfiguration_To_v1_AdmissionConfiguration(in, out, s) -} - -func autoConvert_v1_AdmissionPluginConfiguration_To_apiserver_AdmissionPluginConfiguration(in *AdmissionPluginConfiguration, out *apiserver.AdmissionPluginConfiguration, s conversion.Scope) error { - out.Name = in.Name - out.Path = in.Path - out.Configuration = (*runtime.Unknown)(unsafe.Pointer(in.Configuration)) - return nil -} - -// Convert_v1_AdmissionPluginConfiguration_To_apiserver_AdmissionPluginConfiguration is an autogenerated conversion function. -func Convert_v1_AdmissionPluginConfiguration_To_apiserver_AdmissionPluginConfiguration(in *AdmissionPluginConfiguration, out *apiserver.AdmissionPluginConfiguration, s conversion.Scope) error { - return autoConvert_v1_AdmissionPluginConfiguration_To_apiserver_AdmissionPluginConfiguration(in, out, s) -} - -func autoConvert_apiserver_AdmissionPluginConfiguration_To_v1_AdmissionPluginConfiguration(in *apiserver.AdmissionPluginConfiguration, out *AdmissionPluginConfiguration, s conversion.Scope) error { - out.Name = in.Name - out.Path = in.Path - out.Configuration = (*runtime.Unknown)(unsafe.Pointer(in.Configuration)) - return nil -} - -// Convert_apiserver_AdmissionPluginConfiguration_To_v1_AdmissionPluginConfiguration is an autogenerated conversion function. -func Convert_apiserver_AdmissionPluginConfiguration_To_v1_AdmissionPluginConfiguration(in *apiserver.AdmissionPluginConfiguration, out *AdmissionPluginConfiguration, s conversion.Scope) error { - return autoConvert_apiserver_AdmissionPluginConfiguration_To_v1_AdmissionPluginConfiguration(in, out, s) -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.defaults.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.defaults.go deleted file mode 100644 index cce2e603a69..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/register.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/register.go index 758be628a79..466b19ae5bb 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/register.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/register.go @@ -46,7 +46,6 @@ func init() { func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &AdmissionConfiguration{}, - &EgressSelectorConfiguration{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go index 7b9aacae86f..239b8e20e04 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go @@ -48,101 +48,3 @@ type AdmissionPluginConfiguration struct { // +optional Configuration *runtime.Unknown `json:"configuration"` } - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// EgressSelectorConfiguration provides versioned configuration for egress selector clients. -type EgressSelectorConfiguration struct { - metav1.TypeMeta `json:",inline"` - - // connectionServices contains a list of egress selection client configurations - EgressSelections []EgressSelection `json:"egressSelections"` -} - -// EgressSelection provides the configuration for a single egress selection client. -type EgressSelection struct { - // name is the name of the egress selection. - // Currently supported values are "Master", "Etcd" and "Cluster" - Name string `json:"name"` - - // connection is the exact information used to configure the egress selection - Connection Connection `json:"connection"` -} - -// Connection provides the configuration for a single egress selection client. -type Connection struct { - // Protocol is the protocol used to connect from client to the konnectivity server. - ProxyProtocol ProtocolType `json:"proxyProtocol,omitempty"` - - // Transport defines the transport configurations we use to dial to the konnectivity server. - // This is required if ProxyProtocol is HTTPConnect or GRPC. - // +optional - Transport *Transport `json:"transport,omitempty"` -} - -// ProtocolType is a set of valid values for Connection.ProtocolType -type ProtocolType string - -// Valid types for ProtocolType for konnectivity server -const ( - // Use HTTPConnect to connect to konnectivity server - ProtocolHTTPConnect ProtocolType = "HTTPConnect" - // Use grpc to connect to konnectivity server - ProtocolGRPC ProtocolType = "GRPC" - // Connect directly (skip konnectivity server) - ProtocolDirect ProtocolType = "Direct" -) - -// Transport defines the transport configurations we use to dial to the konnectivity server -type Transport struct { - // TCP is the TCP configuration for communicating with the konnectivity server via TCP - // ProxyProtocol of GRPC is not supported with TCP transport at the moment - // Requires at least one of TCP or UDS to be set - // +optional - TCP *TCPTransport `json:"tcp,omitempty"` - - // UDS is the UDS configuration for communicating with the konnectivity server via UDS - // Requires at least one of TCP or UDS to be set - // +optional - UDS *UDSTransport `json:"uds,omitempty"` -} - -// TCPTransport provides the information to connect to konnectivity server via TCP -type TCPTransport struct { - // URL is the location of the konnectivity server to connect to. - // As an example it might be "https://127.0.0.1:8131" - URL string `json:"url,omitempty"` - - // TLSConfig is the config needed to use TLS when connecting to konnectivity server - // +optional - TLSConfig *TLSConfig `json:"tlsConfig,omitempty"` -} - -// UDSTransport provides the information to connect to konnectivity server via UDS -type UDSTransport struct { - // UDSName is the name of the unix domain socket to connect to konnectivity server - // This does not use a unix:// prefix. (Eg: /etc/srv/kubernetes/konnectivity-server/konnectivity-server.socket) - UDSName string `json:"udsName,omitempty"` -} - -// TLSConfig provides the authentication information to connect to konnectivity server -// Only used with TCPTransport -type TLSConfig struct { - // caBundle is the file location of the CA to be used to determine trust with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // If absent while TCPTransport.URL is prefixed with https://, default to system trust roots. - // +optional - CABundle string `json:"caBundle,omitempty"` - - // clientKey is the file location of the client key to be used in mtls handshakes with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientKey string `json:"clientKey,omitempty"` - - // clientCert is the file location of the client certificate to be used in mtls handshakes with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientCert string `json:"clientCert,omitempty"` -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.conversion.go index 9174b16df70..64909b34a8f 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.conversion.go @@ -55,76 +55,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*Connection)(nil), (*apiserver.Connection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Connection_To_apiserver_Connection(a.(*Connection), b.(*apiserver.Connection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.Connection)(nil), (*Connection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_Connection_To_v1alpha1_Connection(a.(*apiserver.Connection), b.(*Connection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*EgressSelection)(nil), (*apiserver.EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(a.(*EgressSelection), b.(*apiserver.EgressSelection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelection)(nil), (*EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(a.(*apiserver.EgressSelection), b.(*EgressSelection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*EgressSelectorConfiguration)(nil), (*apiserver.EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(a.(*EgressSelectorConfiguration), b.(*apiserver.EgressSelectorConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelectorConfiguration)(nil), (*EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(a.(*apiserver.EgressSelectorConfiguration), b.(*EgressSelectorConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TCPTransport)(nil), (*apiserver.TCPTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_TCPTransport_To_apiserver_TCPTransport(a.(*TCPTransport), b.(*apiserver.TCPTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.TCPTransport)(nil), (*TCPTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_TCPTransport_To_v1alpha1_TCPTransport(a.(*apiserver.TCPTransport), b.(*TCPTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TLSConfig)(nil), (*apiserver.TLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_TLSConfig_To_apiserver_TLSConfig(a.(*TLSConfig), b.(*apiserver.TLSConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.TLSConfig)(nil), (*TLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(a.(*apiserver.TLSConfig), b.(*TLSConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Transport)(nil), (*apiserver.Transport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_Transport_To_apiserver_Transport(a.(*Transport), b.(*apiserver.Transport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.Transport)(nil), (*Transport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_Transport_To_v1alpha1_Transport(a.(*apiserver.Transport), b.(*Transport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*UDSTransport)(nil), (*apiserver.UDSTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_UDSTransport_To_apiserver_UDSTransport(a.(*UDSTransport), b.(*apiserver.UDSTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.UDSTransport)(nil), (*UDSTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(a.(*apiserver.UDSTransport), b.(*UDSTransport), scope) - }); err != nil { - return err - } return nil } @@ -171,159 +101,3 @@ func autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPlu func Convert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in *apiserver.AdmissionPluginConfiguration, out *AdmissionPluginConfiguration, s conversion.Scope) error { return autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in, out, s) } - -func autoConvert_v1alpha1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error { - out.ProxyProtocol = apiserver.ProtocolType(in.ProxyProtocol) - out.Transport = (*apiserver.Transport)(unsafe.Pointer(in.Transport)) - return nil -} - -// Convert_v1alpha1_Connection_To_apiserver_Connection is an autogenerated conversion function. -func Convert_v1alpha1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error { - return autoConvert_v1alpha1_Connection_To_apiserver_Connection(in, out, s) -} - -func autoConvert_apiserver_Connection_To_v1alpha1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error { - out.ProxyProtocol = ProtocolType(in.ProxyProtocol) - out.Transport = (*Transport)(unsafe.Pointer(in.Transport)) - return nil -} - -// Convert_apiserver_Connection_To_v1alpha1_Connection is an autogenerated conversion function. -func Convert_apiserver_Connection_To_v1alpha1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error { - return autoConvert_apiserver_Connection_To_v1alpha1_Connection(in, out, s) -} - -func autoConvert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error { - out.Name = in.Name - if err := Convert_v1alpha1_Connection_To_apiserver_Connection(&in.Connection, &out.Connection, s); err != nil { - return err - } - return nil -} - -// Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection is an autogenerated conversion function. -func Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error { - return autoConvert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in, out, s) -} - -func autoConvert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error { - out.Name = in.Name - if err := Convert_apiserver_Connection_To_v1alpha1_Connection(&in.Connection, &out.Connection, s); err != nil { - return err - } - return nil -} - -// Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection is an autogenerated conversion function. -func Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error { - return autoConvert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in, out, s) -} - -func autoConvert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error { - out.EgressSelections = *(*[]apiserver.EgressSelection)(unsafe.Pointer(&in.EgressSelections)) - return nil -} - -// Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration is an autogenerated conversion function. -func Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error { - return autoConvert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in, out, s) -} - -func autoConvert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error { - out.EgressSelections = *(*[]EgressSelection)(unsafe.Pointer(&in.EgressSelections)) - return nil -} - -// Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration is an autogenerated conversion function. -func Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error { - return autoConvert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in, out, s) -} - -func autoConvert_v1alpha1_TCPTransport_To_apiserver_TCPTransport(in *TCPTransport, out *apiserver.TCPTransport, s conversion.Scope) error { - out.URL = in.URL - out.TLSConfig = (*apiserver.TLSConfig)(unsafe.Pointer(in.TLSConfig)) - return nil -} - -// Convert_v1alpha1_TCPTransport_To_apiserver_TCPTransport is an autogenerated conversion function. -func Convert_v1alpha1_TCPTransport_To_apiserver_TCPTransport(in *TCPTransport, out *apiserver.TCPTransport, s conversion.Scope) error { - return autoConvert_v1alpha1_TCPTransport_To_apiserver_TCPTransport(in, out, s) -} - -func autoConvert_apiserver_TCPTransport_To_v1alpha1_TCPTransport(in *apiserver.TCPTransport, out *TCPTransport, s conversion.Scope) error { - out.URL = in.URL - out.TLSConfig = (*TLSConfig)(unsafe.Pointer(in.TLSConfig)) - return nil -} - -// Convert_apiserver_TCPTransport_To_v1alpha1_TCPTransport is an autogenerated conversion function. -func Convert_apiserver_TCPTransport_To_v1alpha1_TCPTransport(in *apiserver.TCPTransport, out *TCPTransport, s conversion.Scope) error { - return autoConvert_apiserver_TCPTransport_To_v1alpha1_TCPTransport(in, out, s) -} - -func autoConvert_v1alpha1_TLSConfig_To_apiserver_TLSConfig(in *TLSConfig, out *apiserver.TLSConfig, s conversion.Scope) error { - out.CABundle = in.CABundle - out.ClientKey = in.ClientKey - out.ClientCert = in.ClientCert - return nil -} - -// Convert_v1alpha1_TLSConfig_To_apiserver_TLSConfig is an autogenerated conversion function. -func Convert_v1alpha1_TLSConfig_To_apiserver_TLSConfig(in *TLSConfig, out *apiserver.TLSConfig, s conversion.Scope) error { - return autoConvert_v1alpha1_TLSConfig_To_apiserver_TLSConfig(in, out, s) -} - -func autoConvert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(in *apiserver.TLSConfig, out *TLSConfig, s conversion.Scope) error { - out.CABundle = in.CABundle - out.ClientKey = in.ClientKey - out.ClientCert = in.ClientCert - return nil -} - -// Convert_apiserver_TLSConfig_To_v1alpha1_TLSConfig is an autogenerated conversion function. -func Convert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(in *apiserver.TLSConfig, out *TLSConfig, s conversion.Scope) error { - return autoConvert_apiserver_TLSConfig_To_v1alpha1_TLSConfig(in, out, s) -} - -func autoConvert_v1alpha1_Transport_To_apiserver_Transport(in *Transport, out *apiserver.Transport, s conversion.Scope) error { - out.TCP = (*apiserver.TCPTransport)(unsafe.Pointer(in.TCP)) - out.UDS = (*apiserver.UDSTransport)(unsafe.Pointer(in.UDS)) - return nil -} - -// Convert_v1alpha1_Transport_To_apiserver_Transport is an autogenerated conversion function. -func Convert_v1alpha1_Transport_To_apiserver_Transport(in *Transport, out *apiserver.Transport, s conversion.Scope) error { - return autoConvert_v1alpha1_Transport_To_apiserver_Transport(in, out, s) -} - -func autoConvert_apiserver_Transport_To_v1alpha1_Transport(in *apiserver.Transport, out *Transport, s conversion.Scope) error { - out.TCP = (*TCPTransport)(unsafe.Pointer(in.TCP)) - out.UDS = (*UDSTransport)(unsafe.Pointer(in.UDS)) - return nil -} - -// Convert_apiserver_Transport_To_v1alpha1_Transport is an autogenerated conversion function. -func Convert_apiserver_Transport_To_v1alpha1_Transport(in *apiserver.Transport, out *Transport, s conversion.Scope) error { - return autoConvert_apiserver_Transport_To_v1alpha1_Transport(in, out, s) -} - -func autoConvert_v1alpha1_UDSTransport_To_apiserver_UDSTransport(in *UDSTransport, out *apiserver.UDSTransport, s conversion.Scope) error { - out.UDSName = in.UDSName - return nil -} - -// Convert_v1alpha1_UDSTransport_To_apiserver_UDSTransport is an autogenerated conversion function. -func Convert_v1alpha1_UDSTransport_To_apiserver_UDSTransport(in *UDSTransport, out *apiserver.UDSTransport, s conversion.Scope) error { - return autoConvert_v1alpha1_UDSTransport_To_apiserver_UDSTransport(in, out, s) -} - -func autoConvert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in *apiserver.UDSTransport, out *UDSTransport, s conversion.Scope) error { - out.UDSName = in.UDSName - return nil -} - -// Convert_apiserver_UDSTransport_To_v1alpha1_UDSTransport is an autogenerated conversion function. -func Convert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in *apiserver.UDSTransport, out *UDSTransport, s conversion.Scope) error { - return autoConvert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in, out, s) -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.deepcopy.go index 4498e408f0b..24151bbd22b 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/zz_generated.deepcopy.go @@ -76,152 +76,3 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Connection) DeepCopyInto(out *Connection) { - *out = *in - if in.Transport != nil { - in, out := &in.Transport, &out.Transport - *out = new(Transport) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection. -func (in *Connection) DeepCopy() *Connection { - if in == nil { - return nil - } - out := new(Connection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelection) DeepCopyInto(out *EgressSelection) { - *out = *in - in.Connection.DeepCopyInto(&out.Connection) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelection. -func (in *EgressSelection) DeepCopy() *EgressSelection { - if in == nil { - return nil - } - out := new(EgressSelection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelectorConfiguration) DeepCopyInto(out *EgressSelectorConfiguration) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.EgressSelections != nil { - in, out := &in.EgressSelections, &out.EgressSelections - *out = make([]EgressSelection, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelectorConfiguration. -func (in *EgressSelectorConfiguration) DeepCopy() *EgressSelectorConfiguration { - if in == nil { - return nil - } - out := new(EgressSelectorConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *EgressSelectorConfiguration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TCPTransport) DeepCopyInto(out *TCPTransport) { - *out = *in - if in.TLSConfig != nil { - in, out := &in.TLSConfig, &out.TLSConfig - *out = new(TLSConfig) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPTransport. -func (in *TCPTransport) DeepCopy() *TCPTransport { - if in == nil { - return nil - } - out := new(TCPTransport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. -func (in *TLSConfig) DeepCopy() *TLSConfig { - if in == nil { - return nil - } - out := new(TLSConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Transport) DeepCopyInto(out *Transport) { - *out = *in - if in.TCP != nil { - in, out := &in.TCP, &out.TCP - *out = new(TCPTransport) - (*in).DeepCopyInto(*out) - } - if in.UDS != nil { - in, out := &in.UDS, &out.UDS - *out = new(UDSTransport) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Transport. -func (in *Transport) DeepCopy() *Transport { - if in == nil { - return nil - } - out := new(Transport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UDSTransport) DeepCopyInto(out *UDSTransport) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UDSTransport. -func (in *UDSTransport) DeepCopy() *UDSTransport { - if in == nil { - return nil - } - out := new(UDSTransport) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/register.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/register.go deleted file mode 100644 index 9ea529472f3..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/register.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -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 v1beta1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -const GroupName = "apiserver.k8s.io" - -// SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &EgressSelectorConfiguration{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go deleted file mode 100644 index 0a6fd07321e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go +++ /dev/null @@ -1,119 +0,0 @@ -/* -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 v1beta1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// EgressSelectorConfiguration provides versioned configuration for egress selector clients. -type EgressSelectorConfiguration struct { - metav1.TypeMeta `json:",inline"` - - // connectionServices contains a list of egress selection client configurations - EgressSelections []EgressSelection `json:"egressSelections"` -} - -// EgressSelection provides the configuration for a single egress selection client. -type EgressSelection struct { - // name is the name of the egress selection. - // Currently supported values are "Master", "Etcd" and "Cluster" - Name string `json:"name"` - - // connection is the exact information used to configure the egress selection - Connection Connection `json:"connection"` -} - -// Connection provides the configuration for a single egress selection client. -type Connection struct { - // Protocol is the protocol used to connect from client to the konnectivity server. - ProxyProtocol ProtocolType `json:"proxyProtocol,omitempty"` - - // Transport defines the transport configurations we use to dial to the konnectivity server. - // This is required if ProxyProtocol is HTTPConnect or GRPC. - // +optional - Transport *Transport `json:"transport,omitempty"` -} - -// ProtocolType is a set of valid values for Connection.ProtocolType -type ProtocolType string - -// Valid types for ProtocolType for konnectivity server -const ( - // Use HTTPConnect to connect to konnectivity server - ProtocolHTTPConnect ProtocolType = "HTTPConnect" - // Use grpc to connect to konnectivity server - ProtocolGRPC ProtocolType = "GRPC" - // Connect directly (skip konnectivity server) - ProtocolDirect ProtocolType = "Direct" -) - -// Transport defines the transport configurations we use to dial to the konnectivity server -type Transport struct { - // TCP is the TCP configuration for communicating with the konnectivity server via TCP - // ProxyProtocol of GRPC is not supported with TCP transport at the moment - // Requires at least one of TCP or UDS to be set - // +optional - TCP *TCPTransport `json:"tcp,omitempty"` - - // UDS is the UDS configuration for communicating with the konnectivity server via UDS - // Requires at least one of TCP or UDS to be set - // +optional - UDS *UDSTransport `json:"uds,omitempty"` -} - -// TCPTransport provides the information to connect to konnectivity server via TCP -type TCPTransport struct { - // URL is the location of the konnectivity server to connect to. - // As an example it might be "https://127.0.0.1:8131" - URL string `json:"url,omitempty"` - - // TLSConfig is the config needed to use TLS when connecting to konnectivity server - // +optional - TLSConfig *TLSConfig `json:"tlsConfig,omitempty"` -} - -// UDSTransport provides the information to connect to konnectivity server via UDS -type UDSTransport struct { - // UDSName is the name of the unix domain socket to connect to konnectivity server - // This does not use a unix:// prefix. (Eg: /etc/srv/kubernetes/konnectivity-server/konnectivity-server.socket) - UDSName string `json:"udsName,omitempty"` -} - -// TLSConfig provides the authentication information to connect to konnectivity server -// Only used with TCPTransport -type TLSConfig struct { - // caBundle is the file location of the CA to be used to determine trust with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // If absent while TCPTransport.URL is prefixed with https://, default to system trust roots. - // +optional - CABundle string `json:"caBundle,omitempty"` - - // clientKey is the file location of the client key to be used in mtls handshakes with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientKey string `json:"clientKey,omitempty"` - - // clientCert is the file location of the client certificate to be used in mtls handshakes with the konnectivity server. - // Must be absent/empty if TCPTransport.URL is prefixed with http:// - // Must be configured if TCPTransport.URL is prefixed with https:// - // +optional - ClientCert string `json:"clientCert,omitempty"` -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.conversion.go deleted file mode 100644 index b0e44b7e16b..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.conversion.go +++ /dev/null @@ -1,265 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1beta1 - -import ( - unsafe "unsafe" - - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - apiserver "k8s.io/apiserver/pkg/apis/apiserver" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*Connection)(nil), (*apiserver.Connection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_Connection_To_apiserver_Connection(a.(*Connection), b.(*apiserver.Connection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.Connection)(nil), (*Connection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_Connection_To_v1beta1_Connection(a.(*apiserver.Connection), b.(*Connection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*EgressSelection)(nil), (*apiserver.EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_EgressSelection_To_apiserver_EgressSelection(a.(*EgressSelection), b.(*apiserver.EgressSelection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelection)(nil), (*EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_EgressSelection_To_v1beta1_EgressSelection(a.(*apiserver.EgressSelection), b.(*EgressSelection), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*EgressSelectorConfiguration)(nil), (*apiserver.EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(a.(*EgressSelectorConfiguration), b.(*apiserver.EgressSelectorConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelectorConfiguration)(nil), (*EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_EgressSelectorConfiguration_To_v1beta1_EgressSelectorConfiguration(a.(*apiserver.EgressSelectorConfiguration), b.(*EgressSelectorConfiguration), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TCPTransport)(nil), (*apiserver.TCPTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_TCPTransport_To_apiserver_TCPTransport(a.(*TCPTransport), b.(*apiserver.TCPTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.TCPTransport)(nil), (*TCPTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_TCPTransport_To_v1beta1_TCPTransport(a.(*apiserver.TCPTransport), b.(*TCPTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TLSConfig)(nil), (*apiserver.TLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_TLSConfig_To_apiserver_TLSConfig(a.(*TLSConfig), b.(*apiserver.TLSConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.TLSConfig)(nil), (*TLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_TLSConfig_To_v1beta1_TLSConfig(a.(*apiserver.TLSConfig), b.(*TLSConfig), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*Transport)(nil), (*apiserver.Transport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_Transport_To_apiserver_Transport(a.(*Transport), b.(*apiserver.Transport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.Transport)(nil), (*Transport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_Transport_To_v1beta1_Transport(a.(*apiserver.Transport), b.(*Transport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*UDSTransport)(nil), (*apiserver.UDSTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_UDSTransport_To_apiserver_UDSTransport(a.(*UDSTransport), b.(*apiserver.UDSTransport), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*apiserver.UDSTransport)(nil), (*UDSTransport)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_apiserver_UDSTransport_To_v1beta1_UDSTransport(a.(*apiserver.UDSTransport), b.(*UDSTransport), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1beta1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error { - out.ProxyProtocol = apiserver.ProtocolType(in.ProxyProtocol) - out.Transport = (*apiserver.Transport)(unsafe.Pointer(in.Transport)) - return nil -} - -// Convert_v1beta1_Connection_To_apiserver_Connection is an autogenerated conversion function. -func Convert_v1beta1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error { - return autoConvert_v1beta1_Connection_To_apiserver_Connection(in, out, s) -} - -func autoConvert_apiserver_Connection_To_v1beta1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error { - out.ProxyProtocol = ProtocolType(in.ProxyProtocol) - out.Transport = (*Transport)(unsafe.Pointer(in.Transport)) - return nil -} - -// Convert_apiserver_Connection_To_v1beta1_Connection is an autogenerated conversion function. -func Convert_apiserver_Connection_To_v1beta1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error { - return autoConvert_apiserver_Connection_To_v1beta1_Connection(in, out, s) -} - -func autoConvert_v1beta1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error { - out.Name = in.Name - if err := Convert_v1beta1_Connection_To_apiserver_Connection(&in.Connection, &out.Connection, s); err != nil { - return err - } - return nil -} - -// Convert_v1beta1_EgressSelection_To_apiserver_EgressSelection is an autogenerated conversion function. -func Convert_v1beta1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error { - return autoConvert_v1beta1_EgressSelection_To_apiserver_EgressSelection(in, out, s) -} - -func autoConvert_apiserver_EgressSelection_To_v1beta1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error { - out.Name = in.Name - if err := Convert_apiserver_Connection_To_v1beta1_Connection(&in.Connection, &out.Connection, s); err != nil { - return err - } - return nil -} - -// Convert_apiserver_EgressSelection_To_v1beta1_EgressSelection is an autogenerated conversion function. -func Convert_apiserver_EgressSelection_To_v1beta1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error { - return autoConvert_apiserver_EgressSelection_To_v1beta1_EgressSelection(in, out, s) -} - -func autoConvert_v1beta1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error { - out.EgressSelections = *(*[]apiserver.EgressSelection)(unsafe.Pointer(&in.EgressSelections)) - return nil -} - -// Convert_v1beta1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration is an autogenerated conversion function. -func Convert_v1beta1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error { - return autoConvert_v1beta1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in, out, s) -} - -func autoConvert_apiserver_EgressSelectorConfiguration_To_v1beta1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error { - out.EgressSelections = *(*[]EgressSelection)(unsafe.Pointer(&in.EgressSelections)) - return nil -} - -// Convert_apiserver_EgressSelectorConfiguration_To_v1beta1_EgressSelectorConfiguration is an autogenerated conversion function. -func Convert_apiserver_EgressSelectorConfiguration_To_v1beta1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error { - return autoConvert_apiserver_EgressSelectorConfiguration_To_v1beta1_EgressSelectorConfiguration(in, out, s) -} - -func autoConvert_v1beta1_TCPTransport_To_apiserver_TCPTransport(in *TCPTransport, out *apiserver.TCPTransport, s conversion.Scope) error { - out.URL = in.URL - out.TLSConfig = (*apiserver.TLSConfig)(unsafe.Pointer(in.TLSConfig)) - return nil -} - -// Convert_v1beta1_TCPTransport_To_apiserver_TCPTransport is an autogenerated conversion function. -func Convert_v1beta1_TCPTransport_To_apiserver_TCPTransport(in *TCPTransport, out *apiserver.TCPTransport, s conversion.Scope) error { - return autoConvert_v1beta1_TCPTransport_To_apiserver_TCPTransport(in, out, s) -} - -func autoConvert_apiserver_TCPTransport_To_v1beta1_TCPTransport(in *apiserver.TCPTransport, out *TCPTransport, s conversion.Scope) error { - out.URL = in.URL - out.TLSConfig = (*TLSConfig)(unsafe.Pointer(in.TLSConfig)) - return nil -} - -// Convert_apiserver_TCPTransport_To_v1beta1_TCPTransport is an autogenerated conversion function. -func Convert_apiserver_TCPTransport_To_v1beta1_TCPTransport(in *apiserver.TCPTransport, out *TCPTransport, s conversion.Scope) error { - return autoConvert_apiserver_TCPTransport_To_v1beta1_TCPTransport(in, out, s) -} - -func autoConvert_v1beta1_TLSConfig_To_apiserver_TLSConfig(in *TLSConfig, out *apiserver.TLSConfig, s conversion.Scope) error { - out.CABundle = in.CABundle - out.ClientKey = in.ClientKey - out.ClientCert = in.ClientCert - return nil -} - -// Convert_v1beta1_TLSConfig_To_apiserver_TLSConfig is an autogenerated conversion function. -func Convert_v1beta1_TLSConfig_To_apiserver_TLSConfig(in *TLSConfig, out *apiserver.TLSConfig, s conversion.Scope) error { - return autoConvert_v1beta1_TLSConfig_To_apiserver_TLSConfig(in, out, s) -} - -func autoConvert_apiserver_TLSConfig_To_v1beta1_TLSConfig(in *apiserver.TLSConfig, out *TLSConfig, s conversion.Scope) error { - out.CABundle = in.CABundle - out.ClientKey = in.ClientKey - out.ClientCert = in.ClientCert - return nil -} - -// Convert_apiserver_TLSConfig_To_v1beta1_TLSConfig is an autogenerated conversion function. -func Convert_apiserver_TLSConfig_To_v1beta1_TLSConfig(in *apiserver.TLSConfig, out *TLSConfig, s conversion.Scope) error { - return autoConvert_apiserver_TLSConfig_To_v1beta1_TLSConfig(in, out, s) -} - -func autoConvert_v1beta1_Transport_To_apiserver_Transport(in *Transport, out *apiserver.Transport, s conversion.Scope) error { - out.TCP = (*apiserver.TCPTransport)(unsafe.Pointer(in.TCP)) - out.UDS = (*apiserver.UDSTransport)(unsafe.Pointer(in.UDS)) - return nil -} - -// Convert_v1beta1_Transport_To_apiserver_Transport is an autogenerated conversion function. -func Convert_v1beta1_Transport_To_apiserver_Transport(in *Transport, out *apiserver.Transport, s conversion.Scope) error { - return autoConvert_v1beta1_Transport_To_apiserver_Transport(in, out, s) -} - -func autoConvert_apiserver_Transport_To_v1beta1_Transport(in *apiserver.Transport, out *Transport, s conversion.Scope) error { - out.TCP = (*TCPTransport)(unsafe.Pointer(in.TCP)) - out.UDS = (*UDSTransport)(unsafe.Pointer(in.UDS)) - return nil -} - -// Convert_apiserver_Transport_To_v1beta1_Transport is an autogenerated conversion function. -func Convert_apiserver_Transport_To_v1beta1_Transport(in *apiserver.Transport, out *Transport, s conversion.Scope) error { - return autoConvert_apiserver_Transport_To_v1beta1_Transport(in, out, s) -} - -func autoConvert_v1beta1_UDSTransport_To_apiserver_UDSTransport(in *UDSTransport, out *apiserver.UDSTransport, s conversion.Scope) error { - out.UDSName = in.UDSName - return nil -} - -// Convert_v1beta1_UDSTransport_To_apiserver_UDSTransport is an autogenerated conversion function. -func Convert_v1beta1_UDSTransport_To_apiserver_UDSTransport(in *UDSTransport, out *apiserver.UDSTransport, s conversion.Scope) error { - return autoConvert_v1beta1_UDSTransport_To_apiserver_UDSTransport(in, out, s) -} - -func autoConvert_apiserver_UDSTransport_To_v1beta1_UDSTransport(in *apiserver.UDSTransport, out *UDSTransport, s conversion.Scope) error { - out.UDSName = in.UDSName - return nil -} - -// Convert_apiserver_UDSTransport_To_v1beta1_UDSTransport is an autogenerated conversion function. -func Convert_apiserver_UDSTransport_To_v1beta1_UDSTransport(in *apiserver.UDSTransport, out *UDSTransport, s conversion.Scope) error { - return autoConvert_apiserver_UDSTransport_To_v1beta1_UDSTransport(in, out, s) -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.deepcopy.go deleted file mode 100644 index eda0eaffc4b..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.deepcopy.go +++ /dev/null @@ -1,174 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1beta1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Connection) DeepCopyInto(out *Connection) { - *out = *in - if in.Transport != nil { - in, out := &in.Transport, &out.Transport - *out = new(Transport) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection. -func (in *Connection) DeepCopy() *Connection { - if in == nil { - return nil - } - out := new(Connection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelection) DeepCopyInto(out *EgressSelection) { - *out = *in - in.Connection.DeepCopyInto(&out.Connection) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelection. -func (in *EgressSelection) DeepCopy() *EgressSelection { - if in == nil { - return nil - } - out := new(EgressSelection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelectorConfiguration) DeepCopyInto(out *EgressSelectorConfiguration) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.EgressSelections != nil { - in, out := &in.EgressSelections, &out.EgressSelections - *out = make([]EgressSelection, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelectorConfiguration. -func (in *EgressSelectorConfiguration) DeepCopy() *EgressSelectorConfiguration { - if in == nil { - return nil - } - out := new(EgressSelectorConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *EgressSelectorConfiguration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TCPTransport) DeepCopyInto(out *TCPTransport) { - *out = *in - if in.TLSConfig != nil { - in, out := &in.TLSConfig, &out.TLSConfig - *out = new(TLSConfig) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPTransport. -func (in *TCPTransport) DeepCopy() *TCPTransport { - if in == nil { - return nil - } - out := new(TCPTransport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. -func (in *TLSConfig) DeepCopy() *TLSConfig { - if in == nil { - return nil - } - out := new(TLSConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Transport) DeepCopyInto(out *Transport) { - *out = *in - if in.TCP != nil { - in, out := &in.TCP, &out.TCP - *out = new(TCPTransport) - (*in).DeepCopyInto(*out) - } - if in.UDS != nil { - in, out := &in.UDS, &out.UDS - *out = new(UDSTransport) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Transport. -func (in *Transport) DeepCopy() *Transport { - if in == nil { - return nil - } - out := new(Transport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UDSTransport) DeepCopyInto(out *UDSTransport) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UDSTransport. -func (in *UDSTransport) DeepCopy() *UDSTransport { - if in == nil { - return nil - } - out := new(UDSTransport) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.defaults.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.defaults.go deleted file mode 100644 index 73e63fc114d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1beta1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/apiserver/zz_generated.deepcopy.go index 622f1b5dc83..542ef977b6b 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/apiserver/zz_generated.deepcopy.go @@ -76,152 +76,3 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Connection) DeepCopyInto(out *Connection) { - *out = *in - if in.Transport != nil { - in, out := &in.Transport, &out.Transport - *out = new(Transport) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection. -func (in *Connection) DeepCopy() *Connection { - if in == nil { - return nil - } - out := new(Connection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelection) DeepCopyInto(out *EgressSelection) { - *out = *in - in.Connection.DeepCopyInto(&out.Connection) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelection. -func (in *EgressSelection) DeepCopy() *EgressSelection { - if in == nil { - return nil - } - out := new(EgressSelection) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EgressSelectorConfiguration) DeepCopyInto(out *EgressSelectorConfiguration) { - *out = *in - out.TypeMeta = in.TypeMeta - if in.EgressSelections != nil { - in, out := &in.EgressSelections, &out.EgressSelections - *out = make([]EgressSelection, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelectorConfiguration. -func (in *EgressSelectorConfiguration) DeepCopy() *EgressSelectorConfiguration { - if in == nil { - return nil - } - out := new(EgressSelectorConfiguration) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *EgressSelectorConfiguration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TCPTransport) DeepCopyInto(out *TCPTransport) { - *out = *in - if in.TLSConfig != nil { - in, out := &in.TLSConfig, &out.TLSConfig - *out = new(TLSConfig) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCPTransport. -func (in *TCPTransport) DeepCopy() *TCPTransport { - if in == nil { - return nil - } - out := new(TCPTransport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. -func (in *TLSConfig) DeepCopy() *TLSConfig { - if in == nil { - return nil - } - out := new(TLSConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Transport) DeepCopyInto(out *Transport) { - *out = *in - if in.TCP != nil { - in, out := &in.TCP, &out.TCP - *out = new(TCPTransport) - (*in).DeepCopyInto(*out) - } - if in.UDS != nil { - in, out := &in.UDS, &out.UDS - *out = new(UDSTransport) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Transport. -func (in *Transport) DeepCopy() *Transport { - if in == nil { - return nil - } - out := new(Transport) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UDSTransport) DeepCopyInto(out *UDSTransport) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UDSTransport. -func (in *UDSTransport) DeepCopy() *UDSTransport { - if in == nil { - return nil - } - out := new(UDSTransport) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/OWNERS b/vendor/k8s.io/apiserver/pkg/apis/audit/OWNERS index 7a21104f6df..8389778900f 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - # approval on api packages bubbles to api-approvers reviewers: - sig-auth-audit-approvers diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/install/roundtrip_test.go b/vendor/k8s.io/apiserver/pkg/apis/audit/install/roundtrip_test.go index 15146a22082..9497a364594 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/install/roundtrip_test.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/install/roundtrip_test.go @@ -25,5 +25,4 @@ import ( func TestRoundTrip(t *testing.T) { roundtrip.RoundTripTestForAPIGroup(t, Install, fuzzer.Funcs) - roundtrip.RoundTripProtobufTestForAPIGroup(t, Install, fuzzer.Funcs) } diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/types.go b/vendor/k8s.io/apiserver/pkg/apis/audit/types.go index b497be6df27..271274d44f5 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/types.go @@ -17,7 +17,6 @@ limitations under the License. package audit import ( - authnv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -93,10 +92,10 @@ type Event struct { // For non-resource requests, this is the lower-cased HTTP method. Verb string // Authenticated user information. - User authnv1.UserInfo + User UserInfo // Impersonated user information. // +optional - ImpersonatedUser *authnv1.UserInfo + ImpersonatedUser *UserInfo // Source IPs, from where the request originated and intermediate proxies. // +optional SourceIPs []string @@ -284,3 +283,21 @@ type ObjectReference struct { // +optional Subresource string } + +// UserInfo holds the information about the user needed to implement the +// user.Info interface. +type UserInfo struct { + // The name that uniquely identifies this user among all active users. + Username string + // A unique value that identifies this user across time. If this user is + // deleted and another user by the same name is added, they will have + // different UIDs. + UID string + // The names of groups this user is a part of. + Groups []string + // Any additional information provided by the authenticator. + Extra map[string]ExtraValue +} + +// ExtraValue masks the value so protobuf can generate +type ExtraValue []string diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/doc.go index d1f180c942a..b8f818ffdb2 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/doc.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/doc.go @@ -15,7 +15,6 @@ limitations under the License. */ // +k8s:deepcopy-gen=package -// +k8s:protobuf-gen=package // +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit // +k8s:openapi-gen=true // +k8s:defaulter-gen=TypeMeta diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.pb.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.pb.go index 3d2f444194b..7d4ce7573df 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.pb.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.pb.go @@ -17,26 +17,39 @@ limitations under the License. // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.proto +/* + Package v1 is a generated protocol buffer package. + + It is generated from these files: + k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.proto + + It has these top-level messages: + Event + EventList + GroupResources + ObjectReference + Policy + PolicyList + PolicyRule +*/ package v1 -import ( - fmt "fmt" +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" - io "io" +import k8s_io_api_authentication_v1 "k8s.io/api/authentication/v1" +import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import k8s_io_apimachinery_pkg_runtime "k8s.io/apimachinery/pkg/runtime" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - v1 "k8s.io/api/authentication/v1" - v11 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" +import k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" - math "math" - math_bits "math/bits" - reflect "reflect" - strings "strings" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" -) +import strings "strings" +import reflect "reflect" + +import io "io" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -47,207 +60,38 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -func (m *Event) Reset() { *m = Event{} } -func (*Event) ProtoMessage() {} -func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{0} -} -func (m *Event) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Event) XXX_Merge(src proto.Message) { - xxx_messageInfo_Event.Merge(m, src) -} -func (m *Event) XXX_Size() int { - return m.Size() -} -func (m *Event) XXX_DiscardUnknown() { - xxx_messageInfo_Event.DiscardUnknown(m) -} - -var xxx_messageInfo_Event proto.InternalMessageInfo - -func (m *EventList) Reset() { *m = EventList{} } -func (*EventList) ProtoMessage() {} -func (*EventList) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{1} -} -func (m *EventList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *EventList) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventList.Merge(m, src) -} -func (m *EventList) XXX_Size() int { - return m.Size() -} -func (m *EventList) XXX_DiscardUnknown() { - xxx_messageInfo_EventList.DiscardUnknown(m) -} - -var xxx_messageInfo_EventList proto.InternalMessageInfo - -func (m *GroupResources) Reset() { *m = GroupResources{} } -func (*GroupResources) ProtoMessage() {} -func (*GroupResources) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{2} -} -func (m *GroupResources) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GroupResources) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *GroupResources) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupResources.Merge(m, src) -} -func (m *GroupResources) XXX_Size() int { - return m.Size() -} -func (m *GroupResources) XXX_DiscardUnknown() { - xxx_messageInfo_GroupResources.DiscardUnknown(m) -} - -var xxx_messageInfo_GroupResources proto.InternalMessageInfo - -func (m *ObjectReference) Reset() { *m = ObjectReference{} } -func (*ObjectReference) ProtoMessage() {} -func (*ObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{3} -} -func (m *ObjectReference) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ObjectReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *ObjectReference) XXX_Merge(src proto.Message) { - xxx_messageInfo_ObjectReference.Merge(m, src) -} -func (m *ObjectReference) XXX_Size() int { - return m.Size() -} -func (m *ObjectReference) XXX_DiscardUnknown() { - xxx_messageInfo_ObjectReference.DiscardUnknown(m) -} +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package -var xxx_messageInfo_ObjectReference proto.InternalMessageInfo +func (m *Event) Reset() { *m = Event{} } +func (*Event) ProtoMessage() {} +func (*Event) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } -func (m *Policy) Reset() { *m = Policy{} } -func (*Policy) ProtoMessage() {} -func (*Policy) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{4} -} -func (m *Policy) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Policy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Policy) XXX_Merge(src proto.Message) { - xxx_messageInfo_Policy.Merge(m, src) -} -func (m *Policy) XXX_Size() int { - return m.Size() -} -func (m *Policy) XXX_DiscardUnknown() { - xxx_messageInfo_Policy.DiscardUnknown(m) -} +func (m *EventList) Reset() { *m = EventList{} } +func (*EventList) ProtoMessage() {} +func (*EventList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } -var xxx_messageInfo_Policy proto.InternalMessageInfo +func (m *GroupResources) Reset() { *m = GroupResources{} } +func (*GroupResources) ProtoMessage() {} +func (*GroupResources) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } -func (m *PolicyList) Reset() { *m = PolicyList{} } -func (*PolicyList) ProtoMessage() {} -func (*PolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{5} -} -func (m *PolicyList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyList) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyList.Merge(m, src) -} -func (m *PolicyList) XXX_Size() int { - return m.Size() -} -func (m *PolicyList) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyList.DiscardUnknown(m) -} +func (m *ObjectReference) Reset() { *m = ObjectReference{} } +func (*ObjectReference) ProtoMessage() {} +func (*ObjectReference) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } -var xxx_messageInfo_PolicyList proto.InternalMessageInfo +func (m *Policy) Reset() { *m = Policy{} } +func (*Policy) ProtoMessage() {} +func (*Policy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } -func (m *PolicyRule) Reset() { *m = PolicyRule{} } -func (*PolicyRule) ProtoMessage() {} -func (*PolicyRule) Descriptor() ([]byte, []int) { - return fileDescriptor_4982ac40a460d730, []int{6} -} -func (m *PolicyRule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyRule) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyRule.Merge(m, src) -} -func (m *PolicyRule) XXX_Size() int { - return m.Size() -} -func (m *PolicyRule) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyRule.DiscardUnknown(m) -} +func (m *PolicyList) Reset() { *m = PolicyList{} } +func (*PolicyList) ProtoMessage() {} +func (*PolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} } -var xxx_messageInfo_PolicyRule proto.InternalMessageInfo +func (m *PolicyRule) Reset() { *m = PolicyRule{} } +func (*PolicyRule) ProtoMessage() {} +func (*PolicyRule) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} } func init() { proto.RegisterType((*Event)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.Event") - proto.RegisterMapType((map[string]string)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.Event.AnnotationsEntry") proto.RegisterType((*EventList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.EventList") proto.RegisterType((*GroupResources)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.GroupResources") proto.RegisterType((*ObjectReference)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.ObjectReference") @@ -255,97 +99,10 @@ func init() { proto.RegisterType((*PolicyList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.PolicyList") proto.RegisterType((*PolicyRule)(nil), "k8s.io.apiserver.pkg.apis.audit.v1.PolicyRule") } - -func init() { - proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.proto", fileDescriptor_4982ac40a460d730) -} - -var fileDescriptor_4982ac40a460d730 = []byte{ - // 1243 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcd, 0x8e, 0x1b, 0x45, - 0x10, 0xde, 0x59, 0xaf, 0xb3, 0x76, 0x3b, 0xeb, 0x75, 0x3a, 0x11, 0x19, 0xed, 0xc1, 0x36, 0x46, - 0x42, 0x06, 0x96, 0x99, 0xec, 0x12, 0x48, 0x14, 0x09, 0x24, 0x5b, 0x89, 0xc0, 0x22, 0xd9, 0xac, - 0xda, 0x38, 0x07, 0xc4, 0x21, 0xe3, 0x71, 0xc5, 0x1e, 0x6c, 0xcf, 0x4c, 0xba, 0x7b, 0x8c, 0xf6, - 0xc6, 0x0b, 0x20, 0x71, 0xe7, 0x2d, 0xb8, 0x45, 0xbc, 0x40, 0x8e, 0x39, 0xe6, 0x64, 0x11, 0xc3, - 0x43, 0xa0, 0x9c, 0x50, 0xff, 0xcc, 0x8f, 0xbd, 0x6b, 0xc5, 0xcb, 0x81, 0xdb, 0x74, 0xd5, 0xf7, - 0x7d, 0x55, 0x5d, 0xd3, 0x55, 0xdd, 0xe8, 0xdb, 0xf1, 0x5d, 0x66, 0x79, 0x81, 0x3d, 0x8e, 0xfa, - 0x40, 0x7d, 0xe0, 0xc0, 0xec, 0x19, 0xf8, 0x83, 0x80, 0xda, 0xda, 0xe1, 0x84, 0x1e, 0x03, 0x3a, - 0x03, 0x6a, 0x87, 0xe3, 0xa1, 0x5c, 0xd9, 0x4e, 0x34, 0xf0, 0xb8, 0x3d, 0x3b, 0xb2, 0x87, 0xe0, - 0x03, 0x75, 0x38, 0x0c, 0xac, 0x90, 0x06, 0x3c, 0xc0, 0x0d, 0xc5, 0xb1, 0x12, 0x8e, 0x15, 0x8e, - 0x87, 0x72, 0x65, 0x49, 0x8e, 0x35, 0x3b, 0x3a, 0xf8, 0x74, 0xe8, 0xf1, 0x51, 0xd4, 0xb7, 0xdc, - 0x60, 0x6a, 0x0f, 0x83, 0x61, 0x60, 0x4b, 0x6a, 0x3f, 0x7a, 0x26, 0x57, 0x72, 0x21, 0xbf, 0x94, - 0xe4, 0xc1, 0x61, 0x9a, 0x86, 0xed, 0x44, 0x7c, 0x04, 0x3e, 0xf7, 0x5c, 0x87, 0x7b, 0x81, 0x7f, - 0x41, 0x02, 0x07, 0xb7, 0x53, 0xf4, 0xd4, 0x71, 0x47, 0x9e, 0x0f, 0xf4, 0x2c, 0xcd, 0x7b, 0x0a, - 0xdc, 0xb9, 0x88, 0x65, 0xaf, 0x63, 0xd1, 0xc8, 0xe7, 0xde, 0x14, 0xce, 0x11, 0xbe, 0x78, 0x17, - 0x81, 0xb9, 0x23, 0x98, 0x3a, 0xab, 0xbc, 0xc6, 0xdf, 0x08, 0xe5, 0x1f, 0xcc, 0xc0, 0xe7, 0xf8, - 0x10, 0xe5, 0x27, 0x30, 0x83, 0x89, 0x69, 0xd4, 0x8d, 0x66, 0xb1, 0xfd, 0xde, 0xcb, 0x79, 0x6d, - 0x6b, 0x31, 0xaf, 0xe5, 0x1f, 0x0a, 0xe3, 0xdb, 0xf8, 0x83, 0x28, 0x10, 0x3e, 0x41, 0xbb, 0xb2, - 0x7e, 0x9d, 0xfb, 0xe6, 0xb6, 0xc4, 0xdf, 0xd6, 0xf8, 0xdd, 0x96, 0x32, 0xbf, 0x9d, 0xd7, 0xde, - 0x5f, 0x97, 0x13, 0x3f, 0x0b, 0x81, 0x59, 0xbd, 0xce, 0x7d, 0x12, 0x8b, 0x88, 0xe8, 0x8c, 0x3b, - 0x43, 0x30, 0x73, 0xcb, 0xd1, 0xbb, 0xc2, 0xf8, 0x36, 0xfe, 0x20, 0x0a, 0x84, 0x8f, 0x11, 0xa2, - 0xf0, 0x3c, 0x02, 0xc6, 0x7b, 0xa4, 0x63, 0xee, 0x48, 0x0a, 0xd6, 0x14, 0x44, 0x12, 0x0f, 0xc9, - 0xa0, 0x70, 0x1d, 0xed, 0xcc, 0x80, 0xf6, 0xcd, 0xbc, 0x44, 0x5f, 0xd5, 0xe8, 0x9d, 0x27, 0x40, - 0xfb, 0x44, 0x7a, 0xf0, 0x37, 0x68, 0x27, 0x62, 0x40, 0xcd, 0x2b, 0x75, 0xa3, 0x59, 0x3a, 0xfe, - 0xd0, 0x4a, 0x8f, 0x8e, 0xb5, 0xfc, 0x9f, 0xad, 0xd9, 0x91, 0xd5, 0x63, 0x40, 0x3b, 0xfe, 0xb3, - 0x20, 0x55, 0x12, 0x16, 0x22, 0x15, 0xf0, 0x08, 0x55, 0xbc, 0x69, 0x08, 0x94, 0x05, 0xbe, 0xa8, - 0xb5, 0xf0, 0x98, 0xbb, 0x97, 0x52, 0xbd, 0xb1, 0x98, 0xd7, 0x2a, 0x9d, 0x15, 0x0d, 0x72, 0x4e, - 0x15, 0x7f, 0x82, 0x8a, 0x2c, 0x88, 0xa8, 0x0b, 0x9d, 0x53, 0x66, 0x16, 0xea, 0xb9, 0x66, 0xb1, - 0xbd, 0xb7, 0x98, 0xd7, 0x8a, 0xdd, 0xd8, 0x48, 0x52, 0x3f, 0xb6, 0x51, 0x51, 0xa4, 0xd7, 0x1a, - 0x82, 0xcf, 0xcd, 0x8a, 0xac, 0xc3, 0x35, 0x9d, 0x7d, 0xb1, 0x17, 0x3b, 0x48, 0x8a, 0xc1, 0x4f, - 0x51, 0x31, 0xe8, 0xff, 0x08, 0x2e, 0x27, 0xf0, 0xcc, 0x2c, 0xca, 0x0d, 0x7c, 0x66, 0xbd, 0xbb, - 0xa3, 0xac, 0xc7, 0x31, 0x09, 0x28, 0xf8, 0x2e, 0xa8, 0x94, 0x12, 0x23, 0x49, 0x45, 0xf1, 0x08, - 0x95, 0x29, 0xb0, 0x30, 0xf0, 0x19, 0x74, 0xb9, 0xc3, 0x23, 0x66, 0x22, 0x19, 0xe6, 0x30, 0x13, - 0x26, 0x39, 0x3c, 0x69, 0x24, 0xd1, 0x37, 0x22, 0x90, 0xe2, 0xb4, 0xf1, 0x62, 0x5e, 0x2b, 0x93, - 0x25, 0x1d, 0xb2, 0xa2, 0x8b, 0x1d, 0xb4, 0xa7, 0x4f, 0x83, 0x4a, 0xc4, 0x2c, 0xc9, 0x40, 0xcd, - 0xb5, 0x81, 0x74, 0xe7, 0x58, 0x3d, 0x7f, 0xec, 0x07, 0x3f, 0xf9, 0xed, 0x6b, 0x8b, 0x79, 0x6d, - 0x8f, 0x64, 0x25, 0xc8, 0xb2, 0x22, 0x1e, 0xa4, 0x9b, 0xd1, 0x31, 0xae, 0x5e, 0x32, 0xc6, 0xd2, - 0x46, 0x74, 0x90, 0x15, 0x4d, 0xfc, 0x8b, 0x81, 0x4c, 0x1d, 0x97, 0x80, 0x0b, 0xde, 0x0c, 0x06, - 0xdf, 0x79, 0x53, 0x60, 0xdc, 0x99, 0x86, 0xe6, 0x9e, 0x0c, 0x68, 0x6f, 0x56, 0xbd, 0x47, 0x9e, - 0x4b, 0x03, 0xc1, 0x6d, 0xd7, 0xf5, 0x31, 0x30, 0xc9, 0x1a, 0x61, 0xb2, 0x36, 0x24, 0x0e, 0x50, - 0x59, 0x76, 0x65, 0x9a, 0x44, 0xf9, 0xbf, 0x25, 0x11, 0x37, 0x7d, 0xb9, 0xbb, 0x24, 0x47, 0x56, - 0xe4, 0xf1, 0x73, 0x54, 0x72, 0x7c, 0x3f, 0xe0, 0xb2, 0x6b, 0x98, 0xb9, 0x5f, 0xcf, 0x35, 0x4b, - 0xc7, 0xf7, 0x36, 0x39, 0x97, 0x72, 0xd2, 0x59, 0xad, 0x94, 0xfc, 0xc0, 0xe7, 0xf4, 0xac, 0x7d, - 0x5d, 0x07, 0x2e, 0x65, 0x3c, 0x24, 0x1b, 0xe3, 0xe0, 0x2b, 0x54, 0x59, 0x65, 0xe1, 0x0a, 0xca, - 0x8d, 0xe1, 0x4c, 0x8d, 0x4b, 0x22, 0x3e, 0xf1, 0x0d, 0x94, 0x9f, 0x39, 0x93, 0x08, 0xd4, 0x48, - 0x24, 0x6a, 0x71, 0x6f, 0xfb, 0xae, 0xd1, 0x78, 0x61, 0xa0, 0xa2, 0x0c, 0xfe, 0xd0, 0x63, 0x1c, - 0xff, 0x80, 0x0a, 0x62, 0xf7, 0x03, 0x87, 0x3b, 0x92, 0x5e, 0x3a, 0xb6, 0x36, 0xab, 0x95, 0x60, - 0x3f, 0x02, 0xee, 0xb4, 0x2b, 0x3a, 0xe3, 0x42, 0x6c, 0x21, 0x89, 0x22, 0x3e, 0x41, 0x79, 0x8f, - 0xc3, 0x94, 0x99, 0xdb, 0xb2, 0x30, 0x1f, 0x6d, 0x5c, 0x98, 0xf6, 0x5e, 0x3c, 0x75, 0x3b, 0x82, - 0x4f, 0x94, 0x4c, 0xe3, 0x37, 0x03, 0x95, 0xbf, 0xa6, 0x41, 0x14, 0x12, 0x50, 0xa3, 0x84, 0xe1, - 0x0f, 0x50, 0x7e, 0x28, 0x2c, 0xfa, 0xae, 0x48, 0x78, 0x0a, 0xa6, 0x7c, 0x62, 0x34, 0xd1, 0x98, - 0x21, 0x73, 0xd1, 0xa3, 0x29, 0x91, 0x21, 0xa9, 0x1f, 0xdf, 0x11, 0xdd, 0xa9, 0x16, 0x27, 0xce, - 0x14, 0x98, 0x99, 0x93, 0x04, 0xdd, 0x73, 0x19, 0x07, 0x59, 0xc6, 0x35, 0x7e, 0xcf, 0xa1, 0xfd, - 0x95, 0x71, 0x83, 0x0f, 0x51, 0x21, 0x06, 0xe9, 0x0c, 0x93, 0x7a, 0xc5, 0x5a, 0x24, 0x41, 0x88, - 0xa9, 0xe8, 0x0b, 0xa9, 0xd0, 0x71, 0xf5, 0x9f, 0x4b, 0xa7, 0xe2, 0x49, 0xec, 0x20, 0x29, 0x46, - 0xdc, 0x24, 0x62, 0xa1, 0xaf, 0xaa, 0x64, 0xfe, 0x0b, 0x2c, 0x91, 0x1e, 0xdc, 0x46, 0xb9, 0xc8, - 0x1b, 0xe8, 0x8b, 0xe9, 0x96, 0x06, 0xe4, 0x7a, 0x9b, 0xde, 0x8a, 0x82, 0x2c, 0x36, 0xe1, 0x84, - 0x9e, 0xac, 0xa8, 0xbe, 0xb3, 0x92, 0x4d, 0xb4, 0x4e, 0x3b, 0xaa, 0xd2, 0x09, 0x42, 0xdc, 0x88, - 0x4e, 0xe8, 0x3d, 0x01, 0xca, 0xbc, 0xc0, 0x97, 0x37, 0x58, 0xe6, 0x46, 0x6c, 0x9d, 0x76, 0xb4, - 0x87, 0x64, 0x50, 0xb8, 0x85, 0xf6, 0xe3, 0x22, 0xc4, 0xc4, 0x5d, 0x49, 0xbc, 0xa9, 0x89, 0xfb, - 0x64, 0xd9, 0x4d, 0x56, 0xf1, 0xf8, 0x73, 0x54, 0x62, 0x51, 0x3f, 0x29, 0x76, 0x41, 0xd2, 0x93, - 0x76, 0xea, 0xa6, 0x2e, 0x92, 0xc5, 0x35, 0xfe, 0x31, 0xd0, 0x95, 0xd3, 0x60, 0xe2, 0xb9, 0x67, - 0xf8, 0xe9, 0xb9, 0x5e, 0xb8, 0xb5, 0x59, 0x2f, 0xa8, 0x9f, 0x2e, 0xbb, 0x21, 0xd9, 0x68, 0x6a, - 0xcb, 0xf4, 0x43, 0x17, 0xe5, 0x69, 0x34, 0x81, 0xb8, 0x1f, 0xac, 0x4d, 0xfa, 0x41, 0x25, 0x47, - 0xa2, 0x09, 0xa4, 0x87, 0x5b, 0xac, 0x18, 0x51, 0x5a, 0xf8, 0x0e, 0x42, 0xc1, 0xd4, 0xe3, 0x72, - 0x52, 0xc5, 0x87, 0xf5, 0xa6, 0x4c, 0x21, 0xb1, 0xa6, 0xaf, 0x96, 0x0c, 0xb4, 0xf1, 0x87, 0x81, - 0x90, 0x52, 0xff, 0x1f, 0x46, 0xc1, 0xe3, 0xe5, 0x51, 0xf0, 0xf1, 0xe6, 0x5b, 0x5f, 0x33, 0x0b, - 0x5e, 0xe4, 0xe2, 0xec, 0x45, 0x35, 0x2e, 0xf9, 0x66, 0xac, 0xa1, 0xbc, 0x78, 0x5a, 0xc4, 0xc3, - 0xa0, 0x28, 0x90, 0xe2, 0xd9, 0xc1, 0x88, 0xb2, 0x63, 0x0b, 0x21, 0xf1, 0x21, 0x4f, 0x74, 0x5c, - 0xd4, 0xb2, 0x28, 0x6a, 0x2f, 0xb1, 0x92, 0x0c, 0x42, 0x08, 0x8a, 0x87, 0x1b, 0x33, 0x77, 0x52, - 0x41, 0xf1, 0x9e, 0x63, 0x44, 0xd9, 0xb1, 0x9b, 0x1d, 0x41, 0x79, 0x59, 0x83, 0xe3, 0x4d, 0x6a, - 0xb0, 0x3c, 0xee, 0xd2, 0x71, 0x70, 0xe1, 0xe8, 0xb2, 0x10, 0x4a, 0x66, 0x03, 0x33, 0xaf, 0xa4, - 0x59, 0x27, 0xc3, 0x83, 0x91, 0x0c, 0x02, 0x7f, 0x89, 0xf6, 0xfd, 0xc0, 0x8f, 0xa5, 0x7a, 0xe4, - 0x21, 0x33, 0x77, 0x25, 0xe9, 0xba, 0x68, 0xb9, 0x93, 0x65, 0x17, 0x59, 0xc5, 0xae, 0x9c, 0xbc, - 0xc2, 0xc6, 0x27, 0xaf, 0xdd, 0x7c, 0xf9, 0xa6, 0xba, 0xf5, 0xea, 0x4d, 0x75, 0xeb, 0xf5, 0x9b, - 0xea, 0xd6, 0xcf, 0x8b, 0xaa, 0xf1, 0x72, 0x51, 0x35, 0x5e, 0x2d, 0xaa, 0xc6, 0xeb, 0x45, 0xd5, - 0xf8, 0x73, 0x51, 0x35, 0x7e, 0xfd, 0xab, 0xba, 0xf5, 0xfd, 0xf6, 0xec, 0xe8, 0xdf, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x33, 0x6e, 0xcf, 0xc7, 0x82, 0x0d, 0x00, 0x00, -} - func (m *Event) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -353,177 +110,154 @@ func (m *Event) Marshal() (dAtA []byte, err error) { } func (m *Event) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Event) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.UserAgent) - copy(dAtA[i:], m.UserAgent) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x82 - if len(m.Annotations) > 0 { - keysForAnnotations := make([]string, 0, len(m.Annotations)) - for k := range m.Annotations { - keysForAnnotations = append(keysForAnnotations, string(k)) - } - github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) - for iNdEx := len(keysForAnnotations) - 1; iNdEx >= 0; iNdEx-- { - v := m.Annotations[string(keysForAnnotations[iNdEx])] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintGenerated(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(keysForAnnotations[iNdEx]) - copy(dAtA[i:], keysForAnnotations[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(keysForAnnotations[iNdEx]))) - i-- - dAtA[i] = 0xa - i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x7a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) + i += copy(dAtA[i:], m.AuditID) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) + i += copy(dAtA[i:], m.Stage) + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) + i += copy(dAtA[i:], m.RequestURI) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) + i += copy(dAtA[i:], m.Verb) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.User.Size())) + n1, err := m.User.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - { - size, err := m.StageTimestamp.MarshalToSizedBuffer(dAtA[:i]) + i += n1 + if m.ImpersonatedUser != nil { + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ImpersonatedUser.Size())) + n2, err := m.ImpersonatedUser.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n2 } - i-- - dAtA[i] = 0x72 - { - size, err := m.RequestReceivedTimestamp.MarshalToSizedBuffer(dAtA[:i]) + if len(m.SourceIPs) > 0 { + for _, s := range m.SourceIPs { + dAtA[i] = 0x42 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + if m.ObjectRef != nil { + dAtA[i] = 0x4a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectRef.Size())) + n3, err := m.ObjectRef.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n3 } - i-- - dAtA[i] = 0x6a - if m.ResponseObject != nil { - { - size, err := m.ResponseObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + if m.ResponseStatus != nil { + dAtA[i] = 0x52 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseStatus.Size())) + n4, err := m.ResponseStatus.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x62 + i += n4 } if m.RequestObject != nil { - { - size, err := m.RequestObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- dAtA[i] = 0x5a - } - if m.ResponseStatus != nil { - { - size, err := m.ResponseStatus.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestObject.Size())) + n5, err := m.RequestObject.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x52 + i += n5 } - if m.ObjectRef != nil { - { - size, err := m.ObjectRef.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + if m.ResponseObject != nil { + dAtA[i] = 0x62 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseObject.Size())) + n6, err := m.ResponseObject.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x4a + i += n6 } - if len(m.SourceIPs) > 0 { - for iNdEx := len(m.SourceIPs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.SourceIPs[iNdEx]) - copy(dAtA[i:], m.SourceIPs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.SourceIPs[iNdEx]))) - i-- - dAtA[i] = 0x42 - } + dAtA[i] = 0x6a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestReceivedTimestamp.Size())) + n7, err := m.RequestReceivedTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - if m.ImpersonatedUser != nil { - { - size, err := m.ImpersonatedUser.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a + i += n7 + dAtA[i] = 0x72 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.StageTimestamp.Size())) + n8, err := m.StageTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - { - size, err := m.User.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + i += n8 + if len(m.Annotations) > 0 { + keysForAnnotations := make([]string, 0, len(m.Annotations)) + for k := range m.Annotations { + keysForAnnotations = append(keysForAnnotations, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + for _, k := range keysForAnnotations { + dAtA[i] = 0x7a + i++ + v := m.Annotations[string(k)] + mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + i = encodeVarintGenerated(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x32 - i -= len(m.Verb) - copy(dAtA[i:], m.Verb) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) - i-- - dAtA[i] = 0x2a - i -= len(m.RequestURI) - copy(dAtA[i:], m.RequestURI) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) - i-- - dAtA[i] = 0x22 - i -= len(m.Stage) - copy(dAtA[i:], m.Stage) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) - i-- - dAtA[i] = 0x1a - i -= len(m.AuditID) - copy(dAtA[i:], m.AuditID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) - i-- - dAtA[i] = 0x12 - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + dAtA[i] = 0x82 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) + i += copy(dAtA[i:], m.UserAgent) + return i, nil } func (m *EventList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -531,46 +265,37 @@ func (m *EventList) Marshal() (dAtA []byte, err error) { } func (m *EventList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n9, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n9 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *GroupResources) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -578,45 +303,51 @@ func (m *GroupResources) Marshal() (dAtA []byte, err error) { } func (m *GroupResources) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GroupResources) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.ResourceNames) > 0 { - for iNdEx := len(m.ResourceNames) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ResourceNames[iNdEx]) - copy(dAtA[i:], m.ResourceNames[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceNames[iNdEx]))) - i-- - dAtA[i] = 0x1a - } - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i += copy(dAtA[i:], m.Group) if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Resources[iNdEx]) - copy(dAtA[i:], m.Resources[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resources[iNdEx]))) - i-- + for _, s := range m.Resources { dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Group) - copy(dAtA[i:], m.Group) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + if len(m.ResourceNames) > 0 { + for _, s := range m.ResourceNames { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil } func (m *ObjectReference) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -624,62 +355,49 @@ func (m *ObjectReference) Marshal() (dAtA []byte, err error) { } func (m *ObjectReference) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ObjectReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.Subresource) - copy(dAtA[i:], m.Subresource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) - i-- - dAtA[i] = 0x42 - i -= len(m.ResourceVersion) - copy(dAtA[i:], m.ResourceVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) - i-- - dAtA[i] = 0x3a - i -= len(m.APIVersion) - copy(dAtA[i:], m.APIVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) - i-- - dAtA[i] = 0x32 - i -= len(m.APIGroup) - copy(dAtA[i:], m.APIGroup) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIGroup))) - i-- - dAtA[i] = 0x2a - i -= len(m.UID) - copy(dAtA[i:], m.UID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) - i-- - dAtA[i] = 0x22 - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x1a - i -= len(m.Namespace) - copy(dAtA[i:], m.Namespace) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) - i-- - dAtA[i] = 0x12 - i -= len(m.Resource) - copy(dAtA[i:], m.Resource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) - i-- dAtA[i] = 0xa - return len(dAtA) - i, nil + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) + i += copy(dAtA[i:], m.Resource) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i += copy(dAtA[i:], m.Namespace) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i += copy(dAtA[i:], m.UID) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIGroup))) + i += copy(dAtA[i:], m.APIGroup) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) + i += copy(dAtA[i:], m.APIVersion) + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) + i += copy(dAtA[i:], m.ResourceVersion) + dAtA[i] = 0x42 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) + i += copy(dAtA[i:], m.Subresource) + return i, nil } func (m *Policy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -687,55 +405,52 @@ func (m *Policy) Marshal() (dAtA []byte, err error) { } func (m *Policy) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Policy) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x1a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n10, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } + i += n10 if len(m.Rules) > 0 { - for iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Rules[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Rules { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -743,46 +458,37 @@ func (m *PolicyList) Marshal() (dAtA []byte, err error) { } func (m *PolicyList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n11, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n11 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyRule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -790,106 +496,129 @@ func (m *PolicyRule) Marshal() (dAtA []byte, err error) { } func (m *PolicyRule) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyRule) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x42 + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + if len(m.Users) > 0 { + for _, s := range m.Users { + dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.NonResourceURLs) > 0 { - for iNdEx := len(m.NonResourceURLs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.NonResourceURLs[iNdEx]) - copy(dAtA[i:], m.NonResourceURLs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.NonResourceURLs[iNdEx]))) - i-- - dAtA[i] = 0x3a + if len(m.UserGroups) > 0 { + for _, s := range m.UserGroups { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Namespaces) > 0 { - for iNdEx := len(m.Namespaces) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Namespaces[iNdEx]) - copy(dAtA[i:], m.Namespaces[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespaces[iNdEx]))) - i-- - dAtA[i] = 0x32 + if len(m.Verbs) > 0 { + for _, s := range m.Verbs { + dAtA[i] = 0x22 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Resources[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Resources { dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - if len(m.Verbs) > 0 { - for iNdEx := len(m.Verbs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Verbs[iNdEx]) - copy(dAtA[i:], m.Verbs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verbs[iNdEx]))) - i-- - dAtA[i] = 0x22 + if len(m.Namespaces) > 0 { + for _, s := range m.Namespaces { + dAtA[i] = 0x32 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.UserGroups) > 0 { - for iNdEx := len(m.UserGroups) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.UserGroups[iNdEx]) - copy(dAtA[i:], m.UserGroups[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserGroups[iNdEx]))) - i-- - dAtA[i] = 0x1a + if len(m.NonResourceURLs) > 0 { + for _, s := range m.NonResourceURLs { + dAtA[i] = 0x3a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Users) > 0 { - for iNdEx := len(m.Users) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Users[iNdEx]) - copy(dAtA[i:], m.Users[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Users[iNdEx]))) - i-- - dAtA[i] = 0x12 + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x42 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { - offset -= sovGenerated(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *Event) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Level) @@ -948,9 +677,6 @@ func (m *Event) Size() (n int) { } func (m *EventList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -965,9 +691,6 @@ func (m *EventList) Size() (n int) { } func (m *GroupResources) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Group) @@ -988,9 +711,6 @@ func (m *GroupResources) Size() (n int) { } func (m *ObjectReference) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Resource) @@ -1013,9 +733,6 @@ func (m *ObjectReference) Size() (n int) { } func (m *Policy) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -1036,9 +753,6 @@ func (m *Policy) Size() (n int) { } func (m *PolicyList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -1053,9 +767,6 @@ func (m *PolicyList) Size() (n int) { } func (m *PolicyRule) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Level) @@ -1106,7 +817,14 @@ func (m *PolicyRule) Size() (n int) { } func sovGenerated(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1131,15 +849,15 @@ func (this *Event) String() string { `Stage:` + fmt.Sprintf("%v", this.Stage) + `,`, `RequestURI:` + fmt.Sprintf("%v", this.RequestURI) + `,`, `Verb:` + fmt.Sprintf("%v", this.Verb) + `,`, - `User:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.User), "UserInfo", "v1.UserInfo", 1), `&`, ``, 1) + `,`, - `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "v1.UserInfo", 1) + `,`, + `User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1), `&`, ``, 1) + `,`, + `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1) + `,`, `SourceIPs:` + fmt.Sprintf("%v", this.SourceIPs) + `,`, - `ObjectRef:` + strings.Replace(this.ObjectRef.String(), "ObjectReference", "ObjectReference", 1) + `,`, - `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "v11.Status", 1) + `,`, - `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "runtime.Unknown", 1) + `,`, - `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "runtime.Unknown", 1) + `,`, - `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.RequestReceivedTimestamp), "MicroTime", "v11.MicroTime", 1), `&`, ``, 1) + `,`, - `StageTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StageTimestamp), "MicroTime", "v11.MicroTime", 1), `&`, ``, 1) + `,`, + `ObjectRef:` + strings.Replace(fmt.Sprintf("%v", this.ObjectRef), "ObjectReference", "ObjectReference", 1) + `,`, + `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "k8s_io_apimachinery_pkg_apis_meta_v1.Status", 1) + `,`, + `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(this.RequestReceivedTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, + `StageTimestamp:` + strings.Replace(strings.Replace(this.StageTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, `Annotations:` + mapStringForAnnotations + `,`, `UserAgent:` + fmt.Sprintf("%v", this.UserAgent) + `,`, `}`, @@ -1150,14 +868,9 @@ func (this *EventList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Event{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Event", "Event", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&EventList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v11.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Event", "Event", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1195,14 +908,9 @@ func (this *Policy) String() string { if this == nil { return "nil" } - repeatedStringForRules := "[]PolicyRule{" - for _, f := range this.Rules { - repeatedStringForRules += strings.Replace(strings.Replace(f.String(), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + "," - } - repeatedStringForRules += "}" s := strings.Join([]string{`&Policy{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v11.ObjectMeta", 1), `&`, ``, 1) + `,`, - `Rules:` + repeatedStringForRules + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Rules:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Rules), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, `}`, }, "") @@ -1212,14 +920,9 @@ func (this *PolicyList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Policy{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Policy", "Policy", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&PolicyList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v11.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Policy", "Policy", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1228,17 +931,12 @@ func (this *PolicyRule) String() string { if this == nil { return "nil" } - repeatedStringForResources := "[]GroupResources{" - for _, f := range this.Resources { - repeatedStringForResources += strings.Replace(strings.Replace(f.String(), "GroupResources", "GroupResources", 1), `&`, ``, 1) + "," - } - repeatedStringForResources += "}" s := strings.Join([]string{`&PolicyRule{`, `Level:` + fmt.Sprintf("%v", this.Level) + `,`, `Users:` + fmt.Sprintf("%v", this.Users) + `,`, `UserGroups:` + fmt.Sprintf("%v", this.UserGroups) + `,`, `Verbs:` + fmt.Sprintf("%v", this.Verbs) + `,`, - `Resources:` + repeatedStringForResources + `,`, + `Resources:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Resources), "GroupResources", "GroupResources", 1), `&`, ``, 1) + `,`, `Namespaces:` + fmt.Sprintf("%v", this.Namespaces) + `,`, `NonResourceURLs:` + fmt.Sprintf("%v", this.NonResourceURLs) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, @@ -1269,7 +967,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1297,7 +995,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1307,9 +1005,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1329,7 +1024,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1339,9 +1034,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1361,7 +1053,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1371,9 +1063,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1393,7 +1082,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1403,9 +1092,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1425,7 +1111,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1435,9 +1121,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1457,7 +1140,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1466,9 +1149,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1490,7 +1170,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1499,14 +1179,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ImpersonatedUser == nil { - m.ImpersonatedUser = &v1.UserInfo{} + m.ImpersonatedUser = &k8s_io_api_authentication_v1.UserInfo{} } if err := m.ImpersonatedUser.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1526,7 +1203,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1536,9 +1213,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1558,7 +1232,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1567,9 +1241,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1594,7 +1265,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1603,14 +1274,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseStatus == nil { - m.ResponseStatus = &v11.Status{} + m.ResponseStatus = &k8s_io_apimachinery_pkg_apis_meta_v1.Status{} } if err := m.ResponseStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1630,7 +1298,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1639,14 +1307,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.RequestObject == nil { - m.RequestObject = &runtime.Unknown{} + m.RequestObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.RequestObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1666,7 +1331,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1675,14 +1340,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseObject == nil { - m.ResponseObject = &runtime.Unknown{} + m.ResponseObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.ResponseObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1702,7 +1364,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1711,9 +1373,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1735,7 +1394,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1744,9 +1403,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1768,7 +1424,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1777,9 +1433,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1800,7 +1453,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1817,7 +1470,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift + stringLenmapkey |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1827,9 +1480,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1846,7 +1496,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift + stringLenmapvalue |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1856,9 +1506,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1895,7 +1542,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1905,9 +1552,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1922,9 +1566,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -1952,7 +1593,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1980,7 +1621,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1989,9 +1630,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2013,7 +1651,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2022,9 +1660,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2042,9 +1677,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2072,7 +1704,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2100,7 +1732,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2110,9 +1742,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2132,7 +1761,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2142,9 +1771,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2164,7 +1790,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2174,9 +1800,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2191,9 +1814,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2221,7 +1841,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2249,7 +1869,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2259,9 +1879,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2281,7 +1898,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2291,9 +1908,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2313,7 +1927,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2323,9 +1937,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2345,7 +1956,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2355,9 +1966,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2377,7 +1985,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2387,9 +1995,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2409,7 +2014,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2419,9 +2024,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2441,7 +2043,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2451,9 +2053,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2473,7 +2072,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2483,9 +2082,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2500,9 +2096,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2530,7 +2123,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2558,7 +2151,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2567,9 +2160,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2591,7 +2181,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2600,9 +2190,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2625,7 +2212,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2635,9 +2222,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2652,9 +2236,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2682,7 +2263,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2710,7 +2291,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2719,9 +2300,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2743,7 +2321,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2752,9 +2330,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2772,9 +2347,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2802,7 +2374,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2830,7 +2402,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2840,9 +2412,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2862,7 +2431,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2872,9 +2441,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2894,7 +2460,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2904,9 +2470,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2926,7 +2489,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2936,9 +2499,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2958,7 +2518,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2967,9 +2527,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2992,7 +2549,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3002,9 +2559,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3024,7 +2578,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3034,9 +2588,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3056,7 +2607,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3066,9 +2617,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3083,9 +2631,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -3101,7 +2646,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -3133,8 +2677,10 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -3151,34 +2697,139 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + iNdEx += length if length < 0 { return 0, ErrInvalidLengthGenerated } - iNdEx += length + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenerated + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipGenerated(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next } - depth-- + return iNdEx, nil + case 4: + return iNdEx, nil case 5: iNdEx += 4 + return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") ) + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1/generated.proto", fileDescriptorGenerated) +} + +var fileDescriptorGenerated = []byte{ + // 1242 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcd, 0x8e, 0x1b, 0x45, + 0x10, 0xde, 0x59, 0xaf, 0xb3, 0x76, 0x3b, 0xeb, 0x75, 0x3a, 0x11, 0x19, 0xed, 0xc1, 0x36, 0x46, + 0x42, 0x06, 0x96, 0x99, 0xec, 0x12, 0x48, 0x14, 0x09, 0x24, 0x5b, 0x89, 0xc0, 0x22, 0xd9, 0xac, + 0xda, 0x38, 0x07, 0xc4, 0x21, 0xe3, 0x71, 0xc5, 0x1e, 0x6c, 0xcf, 0x4c, 0xba, 0x7b, 0x8c, 0xf6, + 0xc6, 0x0b, 0x20, 0x71, 0xe7, 0x2d, 0xb8, 0x45, 0xbc, 0x40, 0x8e, 0x39, 0xe6, 0x64, 0x11, 0xc3, + 0x43, 0xa0, 0x9c, 0x50, 0xff, 0xcc, 0x8f, 0xbd, 0x6b, 0xc5, 0xcb, 0x81, 0xdb, 0x74, 0xd5, 0xf7, + 0x7d, 0x55, 0x53, 0x53, 0x55, 0x3d, 0xe8, 0xdb, 0xf1, 0x5d, 0x66, 0x79, 0x81, 0x3d, 0x8e, 0xfa, + 0x40, 0x7d, 0xe0, 0xc0, 0xec, 0x19, 0xf8, 0x83, 0x80, 0xda, 0xda, 0xe1, 0x84, 0x1e, 0x03, 0x3a, + 0x03, 0x6a, 0x87, 0xe3, 0xa1, 0x3c, 0xd9, 0x4e, 0x34, 0xf0, 0xb8, 0x3d, 0x3b, 0xb2, 0x87, 0xe0, + 0x03, 0x75, 0x38, 0x0c, 0xac, 0x90, 0x06, 0x3c, 0xc0, 0x0d, 0xc5, 0xb1, 0x12, 0x8e, 0x15, 0x8e, + 0x87, 0xf2, 0x64, 0x49, 0x8e, 0x35, 0x3b, 0x3a, 0xf8, 0x74, 0xe8, 0xf1, 0x51, 0xd4, 0xb7, 0xdc, + 0x60, 0x6a, 0x0f, 0x83, 0x61, 0x60, 0x4b, 0x6a, 0x3f, 0x7a, 0x26, 0x4f, 0xf2, 0x20, 0x9f, 0x94, + 0xe4, 0xc1, 0x61, 0x9a, 0x86, 0xed, 0x44, 0x7c, 0x04, 0x3e, 0xf7, 0x5c, 0x87, 0x7b, 0x81, 0x7f, + 0x41, 0x02, 0x07, 0xb7, 0x53, 0xf4, 0xd4, 0x71, 0x47, 0x9e, 0x0f, 0xf4, 0x2c, 0xcd, 0x7b, 0x0a, + 0xdc, 0xb9, 0x88, 0x65, 0xaf, 0x63, 0xd1, 0xc8, 0xe7, 0xde, 0x14, 0xce, 0x11, 0xbe, 0x78, 0x17, + 0x81, 0xb9, 0x23, 0x98, 0x3a, 0xab, 0xbc, 0xc6, 0xdf, 0x08, 0xe5, 0x1f, 0xcc, 0xc0, 0xe7, 0xf8, + 0x10, 0xe5, 0x27, 0x30, 0x83, 0x89, 0x69, 0xd4, 0x8d, 0x66, 0xb1, 0xfd, 0xde, 0xcb, 0x79, 0x6d, + 0x6b, 0x31, 0xaf, 0xe5, 0x1f, 0x0a, 0xe3, 0xdb, 0xf8, 0x81, 0x28, 0x10, 0x3e, 0x41, 0xbb, 0xb2, + 0x7e, 0x9d, 0xfb, 0xe6, 0xb6, 0xc4, 0xdf, 0xd6, 0xf8, 0xdd, 0x96, 0x32, 0xbf, 0x9d, 0xd7, 0xde, + 0x5f, 0x97, 0x13, 0x3f, 0x0b, 0x81, 0x59, 0xbd, 0xce, 0x7d, 0x12, 0x8b, 0x88, 0xe8, 0x8c, 0x3b, + 0x43, 0x30, 0x73, 0xcb, 0xd1, 0xbb, 0xc2, 0xf8, 0x36, 0x7e, 0x20, 0x0a, 0x84, 0x8f, 0x11, 0xa2, + 0xf0, 0x3c, 0x02, 0xc6, 0x7b, 0xa4, 0x63, 0xee, 0x48, 0x0a, 0xd6, 0x14, 0x44, 0x12, 0x0f, 0xc9, + 0xa0, 0x70, 0x1d, 0xed, 0xcc, 0x80, 0xf6, 0xcd, 0xbc, 0x44, 0x5f, 0xd5, 0xe8, 0x9d, 0x27, 0x40, + 0xfb, 0x44, 0x7a, 0xf0, 0x37, 0x68, 0x27, 0x62, 0x40, 0xcd, 0x2b, 0x75, 0xa3, 0x59, 0x3a, 0xfe, + 0xd0, 0x4a, 0x5b, 0xc7, 0x5a, 0xfe, 0xce, 0xd6, 0xec, 0xc8, 0xea, 0x31, 0xa0, 0x1d, 0xff, 0x59, + 0x90, 0x2a, 0x09, 0x0b, 0x91, 0x0a, 0x78, 0x84, 0x2a, 0xde, 0x34, 0x04, 0xca, 0x02, 0x5f, 0xd4, + 0x5a, 0x78, 0xcc, 0xdd, 0x4b, 0xa9, 0xde, 0x58, 0xcc, 0x6b, 0x95, 0xce, 0x8a, 0x06, 0x39, 0xa7, + 0x8a, 0x3f, 0x41, 0x45, 0x16, 0x44, 0xd4, 0x85, 0xce, 0x29, 0x33, 0x0b, 0xf5, 0x5c, 0xb3, 0xd8, + 0xde, 0x5b, 0xcc, 0x6b, 0xc5, 0x6e, 0x6c, 0x24, 0xa9, 0x1f, 0x3f, 0x45, 0xc5, 0xa0, 0xff, 0x23, + 0xb8, 0x9c, 0xc0, 0x33, 0xb3, 0x28, 0xf3, 0xf9, 0xcc, 0x7a, 0xf7, 0x80, 0x58, 0x8f, 0x63, 0x12, + 0x50, 0xf0, 0x5d, 0x50, 0x11, 0x12, 0x23, 0x49, 0x45, 0xf1, 0x08, 0x95, 0x29, 0xb0, 0x30, 0xf0, + 0x19, 0x74, 0xb9, 0xc3, 0x23, 0x66, 0x22, 0x19, 0xe6, 0x30, 0x13, 0x26, 0xe9, 0x85, 0x34, 0x92, + 0x18, 0x03, 0x11, 0x48, 0x71, 0xda, 0x78, 0x31, 0xaf, 0x95, 0xc9, 0x92, 0x0e, 0x59, 0xd1, 0xc5, + 0x0e, 0xda, 0xd3, 0x1f, 0x57, 0x25, 0x62, 0x96, 0x64, 0xa0, 0xe6, 0xda, 0x40, 0x7a, 0x10, 0xac, + 0x9e, 0x3f, 0xf6, 0x83, 0x9f, 0xfc, 0xf6, 0xb5, 0xc5, 0xbc, 0xb6, 0x47, 0xb2, 0x12, 0x64, 0x59, + 0x11, 0x0f, 0xd2, 0x97, 0xd1, 0x31, 0xae, 0x5e, 0x32, 0xc6, 0xd2, 0x8b, 0xe8, 0x20, 0x2b, 0x9a, + 0xf8, 0x17, 0x03, 0x99, 0x3a, 0x2e, 0x01, 0x17, 0xbc, 0x19, 0x0c, 0xbe, 0xf3, 0xa6, 0xc0, 0xb8, + 0x33, 0x0d, 0xcd, 0x3d, 0x19, 0xd0, 0xde, 0xac, 0x7a, 0x8f, 0x3c, 0x97, 0x06, 0x82, 0xdb, 0xae, + 0xeb, 0x9e, 0x34, 0xc9, 0x1a, 0x61, 0xb2, 0x36, 0x24, 0x0e, 0x50, 0x59, 0x0e, 0x59, 0x9a, 0x44, + 0xf9, 0xbf, 0x25, 0x11, 0xcf, 0x70, 0xb9, 0xbb, 0x24, 0x47, 0x56, 0xe4, 0xf1, 0x73, 0x54, 0x72, + 0x7c, 0x3f, 0xe0, 0x72, 0x08, 0x98, 0xb9, 0x5f, 0xcf, 0x35, 0x4b, 0xc7, 0xf7, 0x36, 0xe9, 0x4b, + 0xb9, 0xb8, 0xac, 0x56, 0x4a, 0x7e, 0xe0, 0x73, 0x7a, 0xd6, 0xbe, 0xae, 0x03, 0x97, 0x32, 0x1e, + 0x92, 0x8d, 0x81, 0x6d, 0x54, 0x14, 0x73, 0xda, 0x1a, 0x82, 0xcf, 0xcd, 0x8a, 0x5c, 0x08, 0xd7, + 0x34, 0xa9, 0xd8, 0x8b, 0x1d, 0x24, 0xc5, 0x1c, 0x7c, 0x85, 0x2a, 0xab, 0x61, 0x70, 0x05, 0xe5, + 0xc6, 0x70, 0xa6, 0xd6, 0x25, 0x11, 0x8f, 0xf8, 0x06, 0xca, 0xcf, 0x9c, 0x49, 0x04, 0x6a, 0x25, + 0x12, 0x75, 0xb8, 0xb7, 0x7d, 0xd7, 0x68, 0xbc, 0x30, 0x50, 0x51, 0x66, 0xfb, 0xd0, 0x63, 0x1c, + 0xff, 0x80, 0x0a, 0xa2, 0x5c, 0x03, 0x87, 0x3b, 0x92, 0x5e, 0x3a, 0xb6, 0x36, 0x2b, 0xae, 0x60, + 0x3f, 0x02, 0xee, 0xb4, 0x2b, 0x3a, 0xdb, 0x42, 0x6c, 0x21, 0x89, 0x22, 0x3e, 0x41, 0x79, 0x8f, + 0xc3, 0x94, 0x99, 0xdb, 0xb2, 0x92, 0x1f, 0x6d, 0x5c, 0xc9, 0xf6, 0x5e, 0xbc, 0x75, 0x3b, 0x82, + 0x4f, 0x94, 0x4c, 0xe3, 0x37, 0x03, 0x95, 0xbf, 0xa6, 0x41, 0x14, 0x12, 0x50, 0xab, 0x84, 0xe1, + 0x0f, 0x50, 0x7e, 0x28, 0x2c, 0xfa, 0xae, 0x48, 0x78, 0x0a, 0xa6, 0x7c, 0x62, 0x35, 0xd1, 0x98, + 0x21, 0x73, 0xd1, 0xab, 0x29, 0x91, 0x21, 0xa9, 0x1f, 0xdf, 0x11, 0xe3, 0xac, 0x0e, 0x27, 0xce, + 0x14, 0x98, 0x99, 0x93, 0x04, 0x3d, 0xa4, 0x19, 0x07, 0x59, 0xc6, 0x35, 0x7e, 0xcf, 0xa1, 0xfd, + 0x95, 0xfd, 0x84, 0x0f, 0x51, 0x21, 0x06, 0xe9, 0x0c, 0x93, 0x7a, 0xc5, 0x5a, 0x24, 0x41, 0x88, + 0x66, 0xf0, 0x85, 0x54, 0xe8, 0xb8, 0xfa, 0xcb, 0xa5, 0xcd, 0x70, 0x12, 0x3b, 0x48, 0x8a, 0x11, + 0x37, 0x89, 0x38, 0xe8, 0xab, 0x2a, 0xd9, 0xff, 0x02, 0x4b, 0xa4, 0x07, 0xb7, 0x51, 0x2e, 0xf2, + 0x06, 0xfa, 0x62, 0xba, 0xa5, 0x01, 0xb9, 0xde, 0xa6, 0xb7, 0xa2, 0x20, 0x8b, 0x97, 0x70, 0x42, + 0x4f, 0x56, 0x54, 0xdf, 0x59, 0xc9, 0x4b, 0xb4, 0x4e, 0x3b, 0xaa, 0xd2, 0x09, 0x42, 0xdc, 0x88, + 0x4e, 0xe8, 0x3d, 0x01, 0xca, 0xbc, 0xc0, 0x97, 0x37, 0x58, 0xe6, 0x46, 0x6c, 0x9d, 0x76, 0xb4, + 0x87, 0x64, 0x50, 0xb8, 0x85, 0xf6, 0xe3, 0x22, 0xc4, 0xc4, 0x5d, 0x49, 0xbc, 0xa9, 0x89, 0xfb, + 0x64, 0xd9, 0x4d, 0x56, 0xf1, 0xf8, 0x73, 0x54, 0x62, 0x51, 0x3f, 0x29, 0x76, 0x41, 0xd2, 0x93, + 0xf9, 0xeb, 0xa6, 0x2e, 0x92, 0xc5, 0x35, 0xfe, 0x31, 0xd0, 0x95, 0xd3, 0x60, 0xe2, 0xb9, 0x67, + 0xf8, 0xe9, 0xb9, 0x59, 0xb8, 0xb5, 0xd9, 0x2c, 0xa8, 0x8f, 0x2e, 0xa7, 0x21, 0x79, 0xd1, 0xd4, + 0x96, 0x99, 0x87, 0x2e, 0xca, 0xd3, 0x68, 0x02, 0xf1, 0x3c, 0x58, 0x9b, 0xcc, 0x83, 0x4a, 0x8e, + 0x44, 0x13, 0x48, 0x9b, 0x5b, 0x9c, 0x18, 0x51, 0x5a, 0xf8, 0x0e, 0x42, 0xc1, 0xd4, 0xe3, 0x72, + 0xb5, 0xc5, 0xcd, 0x7a, 0x53, 0xa6, 0x90, 0x58, 0xd3, 0xbf, 0x96, 0x0c, 0xb4, 0xf1, 0x87, 0x81, + 0x90, 0x52, 0xff, 0x1f, 0x56, 0xc1, 0xe3, 0xe5, 0x55, 0xf0, 0xf1, 0xe6, 0xaf, 0xbe, 0x66, 0x17, + 0xbc, 0xc8, 0xc5, 0xd9, 0x8b, 0x6a, 0x5c, 0xf2, 0x9f, 0xb1, 0x86, 0xf2, 0x62, 0xa3, 0xc6, 0xcb, + 0xa0, 0x28, 0x90, 0x62, 0xdb, 0x32, 0xa2, 0xec, 0xd8, 0x42, 0x48, 0x3c, 0xc8, 0x8e, 0x8e, 0x8b, + 0x5a, 0x16, 0x45, 0xed, 0x25, 0x56, 0x92, 0x41, 0x08, 0x41, 0xf1, 0xe3, 0xc6, 0xcc, 0x9d, 0x54, + 0x50, 0xfc, 0xcf, 0x31, 0xa2, 0xec, 0xd8, 0xcd, 0xae, 0xa0, 0xbc, 0xac, 0xc1, 0xf1, 0x26, 0x35, + 0x58, 0x5e, 0x77, 0xe9, 0x3a, 0xb8, 0x70, 0x75, 0x59, 0x08, 0x25, 0xbb, 0x81, 0x99, 0x57, 0xd2, + 0xac, 0x93, 0xe5, 0xc1, 0x48, 0x06, 0x81, 0xbf, 0x44, 0xfb, 0x7e, 0xe0, 0xc7, 0x52, 0x3d, 0xf2, + 0x90, 0x99, 0xbb, 0x92, 0x74, 0x5d, 0x8c, 0xdc, 0xc9, 0xb2, 0x8b, 0xac, 0x62, 0x57, 0x3a, 0xaf, + 0xb0, 0x71, 0xe7, 0xb5, 0x9b, 0x2f, 0xdf, 0x54, 0xb7, 0x5e, 0xbd, 0xa9, 0x6e, 0xbd, 0x7e, 0x53, + 0xdd, 0xfa, 0x79, 0x51, 0x35, 0x5e, 0x2e, 0xaa, 0xc6, 0xab, 0x45, 0xd5, 0x78, 0xbd, 0xa8, 0x1a, + 0x7f, 0x2e, 0xaa, 0xc6, 0xaf, 0x7f, 0x55, 0xb7, 0xbe, 0xdf, 0x9e, 0x1d, 0xfd, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0x2b, 0xa9, 0x3a, 0xe6, 0x82, 0x0d, 0x00, 0x00, +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.conversion.go index 4500bfe3142..0e99ab45300 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.conversion.go @@ -117,8 +117,11 @@ func autoConvert_v1_Event_To_audit_Event(in *Event, out *audit.Event, s conversi out.Stage = audit.Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User - out.ImpersonatedUser = (*authenticationv1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } + out.ImpersonatedUser = (*audit.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent out.ObjectRef = (*audit.ObjectReference)(unsafe.Pointer(in.ObjectRef)) @@ -142,7 +145,10 @@ func autoConvert_audit_Event_To_v1_Event(in *audit.Event, out *Event, s conversi out.Stage = Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } out.ImpersonatedUser = (*authenticationv1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.deepcopy.go index 81d126d4e02..ec2eb26ad66 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1/zz_generated.deepcopy.go @@ -95,7 +95,7 @@ func (in *Event) DeepCopyObject() runtime.Object { func (in *EventList) DeepCopyInto(out *EventList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Event, len(*in)) @@ -208,7 +208,7 @@ func (in *Policy) DeepCopyObject() runtime.Object { func (in *PolicyList) DeepCopyInto(out *PolicyList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Policy, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/doc.go index 54a8440eb7e..d2cbdd9919b 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/doc.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/doc.go @@ -15,7 +15,6 @@ limitations under the License. */ // +k8s:deepcopy-gen=package -// +k8s:protobuf-gen=package // +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit // +k8s:openapi-gen=true // +k8s:defaulter-gen=TypeMeta diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go index 0b381d42427..6ef668a9d96 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.pb.go @@ -17,26 +17,39 @@ limitations under the License. // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto +/* + Package v1alpha1 is a generated protocol buffer package. + + It is generated from these files: + k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto + + It has these top-level messages: + Event + EventList + GroupResources + ObjectReference + Policy + PolicyList + PolicyRule +*/ package v1alpha1 -import ( - fmt "fmt" +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" - io "io" +import k8s_io_api_authentication_v1 "k8s.io/api/authentication/v1" +import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import k8s_io_apimachinery_pkg_runtime "k8s.io/apimachinery/pkg/runtime" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - v11 "k8s.io/api/authentication/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" +import k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" - math "math" - math_bits "math/bits" - reflect "reflect" - strings "strings" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" -) +import strings "strings" +import reflect "reflect" + +import io "io" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -47,207 +60,38 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package -func (m *Event) Reset() { *m = Event{} } -func (*Event) ProtoMessage() {} -func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{0} -} -func (m *Event) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Event) XXX_Merge(src proto.Message) { - xxx_messageInfo_Event.Merge(m, src) -} -func (m *Event) XXX_Size() int { - return m.Size() -} -func (m *Event) XXX_DiscardUnknown() { - xxx_messageInfo_Event.DiscardUnknown(m) -} +func (m *Event) Reset() { *m = Event{} } +func (*Event) ProtoMessage() {} +func (*Event) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } -var xxx_messageInfo_Event proto.InternalMessageInfo +func (m *EventList) Reset() { *m = EventList{} } +func (*EventList) ProtoMessage() {} +func (*EventList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } -func (m *EventList) Reset() { *m = EventList{} } -func (*EventList) ProtoMessage() {} -func (*EventList) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{1} -} -func (m *EventList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *EventList) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventList.Merge(m, src) -} -func (m *EventList) XXX_Size() int { - return m.Size() -} -func (m *EventList) XXX_DiscardUnknown() { - xxx_messageInfo_EventList.DiscardUnknown(m) -} +func (m *GroupResources) Reset() { *m = GroupResources{} } +func (*GroupResources) ProtoMessage() {} +func (*GroupResources) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } -var xxx_messageInfo_EventList proto.InternalMessageInfo +func (m *ObjectReference) Reset() { *m = ObjectReference{} } +func (*ObjectReference) ProtoMessage() {} +func (*ObjectReference) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } -func (m *GroupResources) Reset() { *m = GroupResources{} } -func (*GroupResources) ProtoMessage() {} -func (*GroupResources) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{2} -} -func (m *GroupResources) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GroupResources) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *GroupResources) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupResources.Merge(m, src) -} -func (m *GroupResources) XXX_Size() int { - return m.Size() -} -func (m *GroupResources) XXX_DiscardUnknown() { - xxx_messageInfo_GroupResources.DiscardUnknown(m) -} +func (m *Policy) Reset() { *m = Policy{} } +func (*Policy) ProtoMessage() {} +func (*Policy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } -var xxx_messageInfo_GroupResources proto.InternalMessageInfo +func (m *PolicyList) Reset() { *m = PolicyList{} } +func (*PolicyList) ProtoMessage() {} +func (*PolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} } -func (m *ObjectReference) Reset() { *m = ObjectReference{} } -func (*ObjectReference) ProtoMessage() {} -func (*ObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{3} -} -func (m *ObjectReference) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ObjectReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *ObjectReference) XXX_Merge(src proto.Message) { - xxx_messageInfo_ObjectReference.Merge(m, src) -} -func (m *ObjectReference) XXX_Size() int { - return m.Size() -} -func (m *ObjectReference) XXX_DiscardUnknown() { - xxx_messageInfo_ObjectReference.DiscardUnknown(m) -} - -var xxx_messageInfo_ObjectReference proto.InternalMessageInfo - -func (m *Policy) Reset() { *m = Policy{} } -func (*Policy) ProtoMessage() {} -func (*Policy) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{4} -} -func (m *Policy) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Policy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Policy) XXX_Merge(src proto.Message) { - xxx_messageInfo_Policy.Merge(m, src) -} -func (m *Policy) XXX_Size() int { - return m.Size() -} -func (m *Policy) XXX_DiscardUnknown() { - xxx_messageInfo_Policy.DiscardUnknown(m) -} - -var xxx_messageInfo_Policy proto.InternalMessageInfo - -func (m *PolicyList) Reset() { *m = PolicyList{} } -func (*PolicyList) ProtoMessage() {} -func (*PolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{5} -} -func (m *PolicyList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyList) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyList.Merge(m, src) -} -func (m *PolicyList) XXX_Size() int { - return m.Size() -} -func (m *PolicyList) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyList.DiscardUnknown(m) -} - -var xxx_messageInfo_PolicyList proto.InternalMessageInfo - -func (m *PolicyRule) Reset() { *m = PolicyRule{} } -func (*PolicyRule) ProtoMessage() {} -func (*PolicyRule) Descriptor() ([]byte, []int) { - return fileDescriptor_46c0b2c8ea67b187, []int{6} -} -func (m *PolicyRule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyRule) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyRule.Merge(m, src) -} -func (m *PolicyRule) XXX_Size() int { - return m.Size() -} -func (m *PolicyRule) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyRule.DiscardUnknown(m) -} - -var xxx_messageInfo_PolicyRule proto.InternalMessageInfo +func (m *PolicyRule) Reset() { *m = PolicyRule{} } +func (*PolicyRule) ProtoMessage() {} +func (*PolicyRule) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} } func init() { proto.RegisterType((*Event)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.Event") - proto.RegisterMapType((map[string]string)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.Event.AnnotationsEntry") proto.RegisterType((*EventList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.EventList") proto.RegisterType((*GroupResources)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.GroupResources") proto.RegisterType((*ObjectReference)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.ObjectReference") @@ -255,98 +99,10 @@ func init() { proto.RegisterType((*PolicyList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.PolicyList") proto.RegisterType((*PolicyRule)(nil), "k8s.io.apiserver.pkg.apis.audit.v1alpha1.PolicyRule") } - -func init() { - proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto", fileDescriptor_46c0b2c8ea67b187) -} - -var fileDescriptor_46c0b2c8ea67b187 = []byte{ - // 1263 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xd6, 0x71, 0x63, 0x8f, 0x1b, 0xc7, 0x99, 0x56, 0x74, 0x95, 0x83, 0x6d, 0x8c, 0x84, - 0x2c, 0x08, 0xbb, 0x49, 0x14, 0x68, 0x40, 0x02, 0x11, 0xab, 0x15, 0x58, 0x4a, 0x43, 0x78, 0x89, - 0x2b, 0xf1, 0xe7, 0xc0, 0xda, 0x7e, 0xb1, 0x17, 0xdb, 0xbb, 0xcb, 0xce, 0xac, 0xab, 0xdc, 0x38, - 0x70, 0x45, 0xe2, 0xce, 0x87, 0xe0, 0x23, 0x54, 0xdc, 0x72, 0xec, 0xb1, 0x27, 0x8b, 0x98, 0x6f, - 0x91, 0x03, 0x42, 0x33, 0xfb, 0x67, 0xd6, 0x4e, 0x2d, 0x1c, 0x0e, 0xbd, 0xed, 0xbc, 0xf7, 0x7b, - 0xbf, 0xf7, 0xe6, 0xed, 0xfb, 0x33, 0xe4, 0xeb, 0xc1, 0x01, 0x33, 0x6c, 0xd7, 0x1c, 0x04, 0x6d, - 0xf4, 0x1d, 0xe4, 0xc8, 0xcc, 0x31, 0x3a, 0x5d, 0xd7, 0x37, 0x23, 0x85, 0xe5, 0xd9, 0x0c, 0xfd, - 0x31, 0xfa, 0xa6, 0x37, 0xe8, 0xc9, 0x93, 0x69, 0x05, 0x5d, 0x9b, 0x9b, 0xe3, 0x5d, 0x6b, 0xe8, - 0xf5, 0xad, 0x5d, 0xb3, 0x87, 0x0e, 0xfa, 0x16, 0xc7, 0xae, 0xe1, 0xf9, 0x2e, 0x77, 0x69, 0x3d, - 0xb4, 0x34, 0x12, 0x4b, 0xc3, 0x1b, 0xf4, 0xe4, 0xc9, 0x90, 0x96, 0x46, 0x6c, 0xb9, 0xf5, 0x41, - 0xcf, 0xe6, 0xfd, 0xa0, 0x6d, 0x74, 0xdc, 0x91, 0xd9, 0x73, 0x7b, 0xae, 0x29, 0x09, 0xda, 0xc1, - 0xb9, 0x3c, 0xc9, 0x83, 0xfc, 0x0a, 0x89, 0xb7, 0xb6, 0x55, 0x48, 0xa6, 0x15, 0xf0, 0x3e, 0x3a, - 0xdc, 0xee, 0x58, 0xdc, 0x76, 0x1d, 0x73, 0x7c, 0x23, 0x8c, 0xad, 0x7d, 0x85, 0x1e, 0x59, 0x9d, - 0xbe, 0xed, 0xa0, 0x7f, 0xa1, 0xee, 0x30, 0x42, 0x6e, 0xbd, 0xce, 0xca, 0x5c, 0x64, 0xe5, 0x07, - 0x0e, 0xb7, 0x47, 0x78, 0xc3, 0xe0, 0xa3, 0xff, 0x32, 0x60, 0x9d, 0x3e, 0x8e, 0xac, 0x79, 0xbb, - 0xda, 0x1f, 0xf7, 0x48, 0xf6, 0xc9, 0x18, 0x1d, 0x4e, 0x7f, 0x20, 0x39, 0x11, 0x4d, 0xd7, 0xe2, - 0x96, 0xae, 0x55, 0xb5, 0x7a, 0x61, 0x6f, 0xc7, 0x50, 0x29, 0x4c, 0x48, 0x55, 0x16, 0x05, 0xda, - 0x18, 0xef, 0x1a, 0x5f, 0xb5, 0x7f, 0xc4, 0x0e, 0x7f, 0x8a, 0xdc, 0x6a, 0xd0, 0xcb, 0x49, 0x65, - 0x65, 0x3a, 0xa9, 0x10, 0x25, 0x83, 0x84, 0x95, 0x6e, 0x93, 0xec, 0x10, 0xc7, 0x38, 0xd4, 0xef, - 0x54, 0xb5, 0x7a, 0xbe, 0xf1, 0x56, 0x04, 0xce, 0x1e, 0x09, 0xe1, 0x75, 0xfc, 0x01, 0x21, 0x88, - 0x7e, 0x47, 0xf2, 0x22, 0x70, 0xc6, 0xad, 0x91, 0xa7, 0x67, 0x64, 0x40, 0xef, 0x2d, 0x17, 0xd0, - 0x99, 0x3d, 0xc2, 0xc6, 0x66, 0xc4, 0x9e, 0x3f, 0x8b, 0x49, 0x40, 0xf1, 0xd1, 0x63, 0xb2, 0x26, - 0x8b, 0xa0, 0xf9, 0x58, 0x5f, 0x95, 0xc1, 0xec, 0x47, 0xf0, 0xb5, 0xc3, 0x50, 0x7c, 0x3d, 0xa9, - 0xbc, 0xbd, 0x28, 0xa5, 0xfc, 0xc2, 0x43, 0x66, 0xb4, 0x9a, 0x8f, 0x21, 0x26, 0x11, 0x57, 0x63, - 0xdc, 0xea, 0xa1, 0x9e, 0x9d, 0xbd, 0xda, 0xa9, 0x10, 0x5e, 0xc7, 0x1f, 0x10, 0x82, 0xe8, 0x1e, - 0x21, 0x3e, 0xfe, 0x14, 0x20, 0xe3, 0x2d, 0x68, 0xea, 0x77, 0xa5, 0x49, 0x92, 0x3a, 0x48, 0x34, - 0x90, 0x42, 0xd1, 0x2a, 0x59, 0x1d, 0xa3, 0xdf, 0xd6, 0xd7, 0x24, 0xfa, 0x5e, 0x84, 0x5e, 0x7d, - 0x86, 0x7e, 0x1b, 0xa4, 0x86, 0x7e, 0x49, 0x56, 0x03, 0x86, 0xbe, 0x9e, 0x93, 0xb9, 0x7a, 0x37, - 0x95, 0x2b, 0x63, 0xb6, 0x4c, 0x45, 0x8e, 0x5a, 0x0c, 0xfd, 0xa6, 0x73, 0xee, 0x2a, 0x26, 0x21, - 0x01, 0xc9, 0x40, 0xfb, 0xa4, 0x64, 0x8f, 0x3c, 0xf4, 0x99, 0xeb, 0x88, 0x52, 0x11, 0x1a, 0x3d, - 0x7f, 0x2b, 0xd6, 0x07, 0xd3, 0x49, 0xa5, 0xd4, 0x9c, 0xe3, 0x80, 0x1b, 0xac, 0xf4, 0x7d, 0x92, - 0x67, 0x6e, 0xe0, 0x77, 0xb0, 0x79, 0xc2, 0x74, 0x52, 0xcd, 0xd4, 0xf3, 0x8d, 0x75, 0xf1, 0xd3, - 0x4e, 0x63, 0x21, 0x28, 0x3d, 0x35, 0x49, 0x5e, 0x84, 0x77, 0xd8, 0x43, 0x87, 0xeb, 0x54, 0xe6, - 0x21, 0xf9, 0xcb, 0xad, 0x58, 0x01, 0x0a, 0x43, 0xcf, 0x49, 0xde, 0x95, 0x85, 0x08, 0x78, 0xae, - 0x17, 0xe4, 0x05, 0x3e, 0x36, 0x96, 0x1d, 0x0b, 0x51, 0x5d, 0x03, 0x9e, 0xa3, 0x8f, 0x4e, 0x07, - 0xc3, 0xc0, 0x12, 0x21, 0x28, 0x6a, 0xda, 0x27, 0x45, 0x1f, 0x99, 0xe7, 0x3a, 0x0c, 0x4f, 0xb9, - 0xc5, 0x03, 0xa6, 0xdf, 0x93, 0xce, 0xb6, 0x97, 0xab, 0xd7, 0xd0, 0xa6, 0x41, 0xa7, 0x93, 0x4a, - 0x11, 0x66, 0x78, 0x60, 0x8e, 0x97, 0x5a, 0x64, 0x3d, 0xaa, 0x89, 0x30, 0x10, 0x7d, 0x5d, 0x3a, - 0xaa, 0x2f, 0x74, 0x14, 0xb5, 0xbf, 0xd1, 0x72, 0x06, 0x8e, 0xfb, 0xdc, 0x69, 0x6c, 0x4e, 0x27, - 0x95, 0x75, 0x48, 0x53, 0xc0, 0x2c, 0x23, 0xed, 0xaa, 0xcb, 0x44, 0x3e, 0x8a, 0xb7, 0xf4, 0x31, - 0x73, 0x91, 0xc8, 0xc9, 0x1c, 0x27, 0xfd, 0x55, 0x23, 0x7a, 0xe4, 0x17, 0xb0, 0x83, 0xf6, 0x18, - 0xbb, 0x49, 0xa3, 0xea, 0x1b, 0xd2, 0xa1, 0xb9, 0x5c, 0xf6, 0x9e, 0xda, 0x1d, 0xdf, 0x95, 0x2d, - 0x5f, 0x8d, 0x8a, 0x41, 0x87, 0x05, 0xc4, 0xb0, 0xd0, 0x25, 0x75, 0x49, 0x51, 0xf6, 0xa6, 0x0a, - 0xa2, 0xf4, 0xff, 0x82, 0x88, 0x5b, 0xbf, 0x78, 0x3a, 0x43, 0x07, 0x73, 0xf4, 0xf4, 0x39, 0x29, - 0x58, 0x8e, 0xe3, 0x72, 0xd9, 0x3b, 0x4c, 0xdf, 0xac, 0x66, 0xea, 0x85, 0xbd, 0xcf, 0x97, 0xaf, - 0x4e, 0x39, 0xb4, 0x8d, 0x43, 0x45, 0xf1, 0xc4, 0xe1, 0xfe, 0x45, 0xe3, 0x7e, 0xe4, 0xbe, 0x90, - 0xd2, 0x40, 0xda, 0xd3, 0xd6, 0x67, 0xa4, 0x34, 0x6f, 0x45, 0x4b, 0x24, 0x33, 0xc0, 0x0b, 0x39, - 0xf6, 0xf3, 0x20, 0x3e, 0xe9, 0x03, 0x92, 0x1d, 0x5b, 0xc3, 0x00, 0xc3, 0x59, 0x0d, 0xe1, 0xe1, - 0x93, 0x3b, 0x07, 0x5a, 0xed, 0x85, 0x46, 0xf2, 0xd2, 0xf9, 0x91, 0xcd, 0x38, 0xfd, 0xfe, 0xc6, - 0xd6, 0x30, 0x96, 0xcb, 0x98, 0xb0, 0x96, 0x3b, 0xa3, 0x14, 0x45, 0x9c, 0x8b, 0x25, 0xa9, 0x8d, - 0x71, 0x46, 0xb2, 0x36, 0xc7, 0x11, 0xd3, 0xef, 0xc8, 0xf4, 0x98, 0xb7, 0x4c, 0x4f, 0x63, 0x3d, - 0x9e, 0xc3, 0x4d, 0xc1, 0x02, 0x21, 0x59, 0xed, 0x77, 0x8d, 0x14, 0xbf, 0xf0, 0xdd, 0xc0, 0x03, - 0x0c, 0x87, 0x0b, 0xa3, 0xef, 0x90, 0x6c, 0x4f, 0x48, 0xc2, 0x14, 0x28, 0xbb, 0x10, 0x16, 0xea, - 0xc4, 0xb0, 0xf2, 0x63, 0x0b, 0x19, 0x51, 0x34, 0xac, 0x12, 0x1a, 0x50, 0x7a, 0xfa, 0x48, 0x74, - 0x6a, 0x78, 0x38, 0xb6, 0x46, 0xc8, 0xf4, 0x8c, 0x34, 0x88, 0xfa, 0x2f, 0xa5, 0x80, 0x59, 0x5c, - 0xed, 0x97, 0x0c, 0xd9, 0x98, 0x1b, 0x3d, 0x74, 0x9b, 0xe4, 0x62, 0x50, 0x14, 0x61, 0x92, 0xb5, - 0x98, 0x0b, 0x12, 0x84, 0x98, 0x93, 0x8e, 0xa0, 0xf2, 0xac, 0x4e, 0xf4, 0xff, 0xd4, 0x9c, 0x3c, - 0x8e, 0x15, 0xa0, 0x30, 0x62, 0xb7, 0x88, 0x83, 0xdc, 0xb2, 0xa9, 0xdd, 0x22, 0xb0, 0x20, 0x35, - 0xb4, 0x41, 0x32, 0x81, 0xdd, 0x8d, 0x76, 0xe5, 0x4e, 0x04, 0xc8, 0xb4, 0x96, 0xdd, 0x93, 0xc2, - 0x58, 0x6c, 0x3d, 0xcb, 0xb3, 0x9f, 0xa1, 0xcf, 0x6c, 0xd7, 0x89, 0x16, 0x65, 0xb2, 0xf5, 0x0e, - 0x4f, 0x9a, 0x91, 0x06, 0x52, 0x28, 0x7a, 0x48, 0x36, 0xe2, 0x6b, 0xc5, 0x86, 0xe1, 0xba, 0x7c, - 0x18, 0x19, 0x6e, 0xc0, 0xac, 0x1a, 0xe6, 0xf1, 0xf4, 0x43, 0x52, 0x60, 0x41, 0x3b, 0x49, 0x5f, - 0xb8, 0x3f, 0x93, 0x36, 0x39, 0x55, 0x2a, 0x48, 0xe3, 0x6a, 0xff, 0x68, 0xe4, 0xee, 0x89, 0x3b, - 0xb4, 0x3b, 0x17, 0x6f, 0xe0, 0x65, 0xf4, 0x0d, 0xc9, 0xfa, 0xc1, 0x10, 0xe3, 0x3a, 0xdf, 0x5f, - 0xbe, 0xce, 0xc3, 0x10, 0x21, 0x18, 0xa2, 0x2a, 0x5a, 0x71, 0x62, 0x10, 0x32, 0xd2, 0x47, 0x84, - 0xb8, 0x23, 0x9b, 0xcb, 0x69, 0x14, 0x17, 0xe1, 0x43, 0x19, 0x48, 0x22, 0x55, 0xef, 0x93, 0x14, - 0xb4, 0xf6, 0xa7, 0x46, 0x48, 0xc8, 0xfe, 0x06, 0x1a, 0xbd, 0x35, 0xdb, 0xe8, 0x3b, 0xb7, 0x4d, - 0xc0, 0x82, 0x4e, 0x7f, 0x91, 0x89, 0xef, 0x20, 0x72, 0xa2, 0x1e, 0xa0, 0xda, 0x32, 0x0f, 0xd0, - 0x0a, 0xc9, 0x8a, 0xa7, 0x44, 0xdc, 0xea, 0x79, 0x81, 0x14, 0xcf, 0x0c, 0x06, 0xa1, 0x9c, 0x1a, - 0x84, 0x88, 0x0f, 0x39, 0x23, 0xe2, 0xd4, 0x16, 0x45, 0x6a, 0x5b, 0x89, 0x14, 0x52, 0x08, 0x41, - 0x28, 0x1e, 0x6a, 0x4c, 0x5f, 0x55, 0x84, 0xe2, 0xfd, 0xc6, 0x20, 0x94, 0x53, 0x3b, 0x3d, 0x60, - 0xb2, 0x32, 0x13, 0x07, 0xcb, 0x67, 0x62, 0x76, 0xa4, 0xa9, 0x96, 0x7f, 0xed, 0x78, 0x32, 0x08, - 0x49, 0xfa, 0x9f, 0xe9, 0x77, 0x55, 0xec, 0xc9, 0x80, 0x60, 0x90, 0x42, 0xd0, 0x4f, 0xc9, 0x86, - 0xe3, 0x3a, 0x31, 0x55, 0x0b, 0x8e, 0x98, 0xbe, 0x26, 0x8d, 0xee, 0x8b, 0x26, 0x3c, 0x9e, 0x55, - 0xc1, 0x3c, 0x76, 0xae, 0x0a, 0x73, 0x4b, 0x57, 0x61, 0xc3, 0xb8, 0xbc, 0x2a, 0xaf, 0xbc, 0xbc, - 0x2a, 0xaf, 0xbc, 0xba, 0x2a, 0xaf, 0xfc, 0x3c, 0x2d, 0x6b, 0x97, 0xd3, 0xb2, 0xf6, 0x72, 0x5a, - 0xd6, 0x5e, 0x4d, 0xcb, 0xda, 0x5f, 0xd3, 0xb2, 0xf6, 0xdb, 0xdf, 0xe5, 0x95, 0x6f, 0x73, 0x71, - 0x12, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x19, 0xf8, 0xf6, 0xd0, 0x49, 0x0e, 0x00, 0x00, -} - func (m *Event) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -354,201 +110,174 @@ func (m *Event) Marshal() (dAtA []byte, err error) { } func (m *Event) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Event) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.UserAgent) - copy(dAtA[i:], m.UserAgent) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x92 - if len(m.Annotations) > 0 { - keysForAnnotations := make([]string, 0, len(m.Annotations)) - for k := range m.Annotations { - keysForAnnotations = append(keysForAnnotations, string(k)) - } - github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) - for iNdEx := len(keysForAnnotations) - 1; iNdEx >= 0; iNdEx-- { - v := m.Annotations[string(keysForAnnotations[iNdEx])] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintGenerated(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(keysForAnnotations[iNdEx]) - copy(dAtA[i:], keysForAnnotations[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(keysForAnnotations[iNdEx]))) - i-- - dAtA[i] = 0xa - i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x8a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n1, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - { - size, err := m.StageTimestamp.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n1 + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Timestamp.Size())) + n2, err := m.Timestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x82 - { - size, err := m.RequestReceivedTimestamp.MarshalToSizedBuffer(dAtA[:i]) + i += n2 + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) + i += copy(dAtA[i:], m.AuditID) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) + i += copy(dAtA[i:], m.Stage) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) + i += copy(dAtA[i:], m.RequestURI) + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) + i += copy(dAtA[i:], m.Verb) + dAtA[i] = 0x42 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.User.Size())) + n3, err := m.User.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + if m.ImpersonatedUser != nil { + dAtA[i] = 0x4a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ImpersonatedUser.Size())) + n4, err := m.ImpersonatedUser.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n4 } - i-- - dAtA[i] = 0x7a - if m.ResponseObject != nil { - { - size, err := m.ResponseObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x72 - } - if m.RequestObject != nil { - { - size, err := m.RequestObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x6a - } - if m.ResponseStatus != nil { - { - size, err := m.ResponseStatus.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.SourceIPs) > 0 { + for _, s := range m.SourceIPs { + dAtA[i] = 0x52 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } - i-- - dAtA[i] = 0x62 } if m.ObjectRef != nil { - { - size, err := m.ObjectRef.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- dAtA[i] = 0x5a - } - if len(m.SourceIPs) > 0 { - for iNdEx := len(m.SourceIPs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.SourceIPs[iNdEx]) - copy(dAtA[i:], m.SourceIPs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.SourceIPs[iNdEx]))) - i-- - dAtA[i] = 0x52 - } - } - if m.ImpersonatedUser != nil { - { - size, err := m.ImpersonatedUser.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectRef.Size())) + n5, err := m.ObjectRef.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x4a + i += n5 } - { - size, err := m.User.MarshalToSizedBuffer(dAtA[:i]) + if m.ResponseStatus != nil { + dAtA[i] = 0x62 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseStatus.Size())) + n6, err := m.ResponseStatus.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n6 } - i-- - dAtA[i] = 0x42 - i -= len(m.Verb) - copy(dAtA[i:], m.Verb) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) - i-- - dAtA[i] = 0x3a - i -= len(m.RequestURI) - copy(dAtA[i:], m.RequestURI) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) - i-- - dAtA[i] = 0x32 - i -= len(m.Stage) - copy(dAtA[i:], m.Stage) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) - i-- - dAtA[i] = 0x2a - i -= len(m.AuditID) - copy(dAtA[i:], m.AuditID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) - i-- - dAtA[i] = 0x22 - { - size, err := m.Timestamp.MarshalToSizedBuffer(dAtA[:i]) + if m.RequestObject != nil { + dAtA[i] = 0x6a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestObject.Size())) + n7, err := m.RequestObject.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n7 } - i-- - dAtA[i] = 0x1a - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0x12 - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if m.ResponseObject != nil { + dAtA[i] = 0x72 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseObject.Size())) + n8, err := m.ResponseObject.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n8 } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + dAtA[i] = 0x7a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestReceivedTimestamp.Size())) + n9, err := m.RequestReceivedTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n9 + dAtA[i] = 0x82 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.StageTimestamp.Size())) + n10, err := m.StageTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n10 + if len(m.Annotations) > 0 { + keysForAnnotations := make([]string, 0, len(m.Annotations)) + for k := range m.Annotations { + keysForAnnotations = append(keysForAnnotations, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + for _, k := range keysForAnnotations { + dAtA[i] = 0x8a + i++ + dAtA[i] = 0x1 + i++ + v := m.Annotations[string(k)] + mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + i = encodeVarintGenerated(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } + dAtA[i] = 0x92 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) + i += copy(dAtA[i:], m.UserAgent) + return i, nil } func (m *EventList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -556,46 +285,37 @@ func (m *EventList) Marshal() (dAtA []byte, err error) { } func (m *EventList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n11, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n11 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *GroupResources) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -603,45 +323,51 @@ func (m *GroupResources) Marshal() (dAtA []byte, err error) { } func (m *GroupResources) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GroupResources) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.ResourceNames) > 0 { - for iNdEx := len(m.ResourceNames) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ResourceNames[iNdEx]) - copy(dAtA[i:], m.ResourceNames[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceNames[iNdEx]))) - i-- - dAtA[i] = 0x1a - } - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i += copy(dAtA[i:], m.Group) if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Resources[iNdEx]) - copy(dAtA[i:], m.Resources[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resources[iNdEx]))) - i-- + for _, s := range m.Resources { dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Group) - copy(dAtA[i:], m.Group) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + if len(m.ResourceNames) > 0 { + for _, s := range m.ResourceNames { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil } func (m *ObjectReference) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -649,57 +375,45 @@ func (m *ObjectReference) Marshal() (dAtA []byte, err error) { } func (m *ObjectReference) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ObjectReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.Subresource) - copy(dAtA[i:], m.Subresource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) - i-- - dAtA[i] = 0x3a - i -= len(m.ResourceVersion) - copy(dAtA[i:], m.ResourceVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) - i-- - dAtA[i] = 0x32 - i -= len(m.APIVersion) - copy(dAtA[i:], m.APIVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) - i-- - dAtA[i] = 0x2a - i -= len(m.UID) - copy(dAtA[i:], m.UID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) - i-- - dAtA[i] = 0x22 - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x1a - i -= len(m.Namespace) - copy(dAtA[i:], m.Namespace) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) - i-- - dAtA[i] = 0x12 - i -= len(m.Resource) - copy(dAtA[i:], m.Resource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) - i-- dAtA[i] = 0xa - return len(dAtA) - i, nil + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) + i += copy(dAtA[i:], m.Resource) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i += copy(dAtA[i:], m.Namespace) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i += copy(dAtA[i:], m.UID) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) + i += copy(dAtA[i:], m.APIVersion) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) + i += copy(dAtA[i:], m.ResourceVersion) + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) + i += copy(dAtA[i:], m.Subresource) + return i, nil } func (m *Policy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -707,55 +421,52 @@ func (m *Policy) Marshal() (dAtA []byte, err error) { } func (m *Policy) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Policy) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x1a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n12, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } + i += n12 if len(m.Rules) > 0 { - for iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Rules[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Rules { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -763,46 +474,37 @@ func (m *PolicyList) Marshal() (dAtA []byte, err error) { } func (m *PolicyList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n13, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n13 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + for _, msg := range m.Items { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + i += n } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyRule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -810,106 +512,129 @@ func (m *PolicyRule) Marshal() (dAtA []byte, err error) { } func (m *PolicyRule) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyRule) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x42 + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + if len(m.Users) > 0 { + for _, s := range m.Users { + dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.NonResourceURLs) > 0 { - for iNdEx := len(m.NonResourceURLs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.NonResourceURLs[iNdEx]) - copy(dAtA[i:], m.NonResourceURLs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.NonResourceURLs[iNdEx]))) - i-- - dAtA[i] = 0x3a + if len(m.UserGroups) > 0 { + for _, s := range m.UserGroups { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Namespaces) > 0 { - for iNdEx := len(m.Namespaces) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Namespaces[iNdEx]) - copy(dAtA[i:], m.Namespaces[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespaces[iNdEx]))) - i-- - dAtA[i] = 0x32 + if len(m.Verbs) > 0 { + for _, s := range m.Verbs { + dAtA[i] = 0x22 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Resources[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Resources { dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - if len(m.Verbs) > 0 { - for iNdEx := len(m.Verbs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Verbs[iNdEx]) - copy(dAtA[i:], m.Verbs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verbs[iNdEx]))) - i-- - dAtA[i] = 0x22 + if len(m.Namespaces) > 0 { + for _, s := range m.Namespaces { + dAtA[i] = 0x32 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.UserGroups) > 0 { - for iNdEx := len(m.UserGroups) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.UserGroups[iNdEx]) - copy(dAtA[i:], m.UserGroups[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserGroups[iNdEx]))) - i-- - dAtA[i] = 0x1a + if len(m.NonResourceURLs) > 0 { + for _, s := range m.NonResourceURLs { + dAtA[i] = 0x3a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Users) > 0 { - for iNdEx := len(m.Users) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Users[iNdEx]) - copy(dAtA[i:], m.Users[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Users[iNdEx]))) - i-- - dAtA[i] = 0x12 + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x42 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { - offset -= sovGenerated(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *Event) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -972,9 +697,6 @@ func (m *Event) Size() (n int) { } func (m *EventList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -989,9 +711,6 @@ func (m *EventList) Size() (n int) { } func (m *GroupResources) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Group) @@ -1012,9 +731,6 @@ func (m *GroupResources) Size() (n int) { } func (m *ObjectReference) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Resource) @@ -1035,9 +751,6 @@ func (m *ObjectReference) Size() (n int) { } func (m *Policy) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -1058,9 +771,6 @@ func (m *Policy) Size() (n int) { } func (m *PolicyList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -1075,9 +785,6 @@ func (m *PolicyList) Size() (n int) { } func (m *PolicyRule) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Level) @@ -1128,7 +835,14 @@ func (m *PolicyRule) Size() (n int) { } func sovGenerated(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1148,22 +862,22 @@ func (this *Event) String() string { } mapStringForAnnotations += "}" s := strings.Join([]string{`&Event{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, `Level:` + fmt.Sprintf("%v", this.Level) + `,`, - `Timestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Timestamp), "Time", "v1.Time", 1), `&`, ``, 1) + `,`, + `Timestamp:` + strings.Replace(strings.Replace(this.Timestamp.String(), "Time", "k8s_io_apimachinery_pkg_apis_meta_v1.Time", 1), `&`, ``, 1) + `,`, `AuditID:` + fmt.Sprintf("%v", this.AuditID) + `,`, `Stage:` + fmt.Sprintf("%v", this.Stage) + `,`, `RequestURI:` + fmt.Sprintf("%v", this.RequestURI) + `,`, `Verb:` + fmt.Sprintf("%v", this.Verb) + `,`, - `User:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.User), "UserInfo", "v11.UserInfo", 1), `&`, ``, 1) + `,`, - `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "v11.UserInfo", 1) + `,`, + `User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1), `&`, ``, 1) + `,`, + `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1) + `,`, `SourceIPs:` + fmt.Sprintf("%v", this.SourceIPs) + `,`, - `ObjectRef:` + strings.Replace(this.ObjectRef.String(), "ObjectReference", "ObjectReference", 1) + `,`, - `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "v1.Status", 1) + `,`, - `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "runtime.Unknown", 1) + `,`, - `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "runtime.Unknown", 1) + `,`, - `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.RequestReceivedTimestamp), "MicroTime", "v1.MicroTime", 1), `&`, ``, 1) + `,`, - `StageTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StageTimestamp), "MicroTime", "v1.MicroTime", 1), `&`, ``, 1) + `,`, + `ObjectRef:` + strings.Replace(fmt.Sprintf("%v", this.ObjectRef), "ObjectReference", "ObjectReference", 1) + `,`, + `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "k8s_io_apimachinery_pkg_apis_meta_v1.Status", 1) + `,`, + `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(this.RequestReceivedTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, + `StageTimestamp:` + strings.Replace(strings.Replace(this.StageTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, `Annotations:` + mapStringForAnnotations + `,`, `UserAgent:` + fmt.Sprintf("%v", this.UserAgent) + `,`, `}`, @@ -1174,14 +888,9 @@ func (this *EventList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Event{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Event", "Event", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&EventList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Event", "Event", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1218,14 +927,9 @@ func (this *Policy) String() string { if this == nil { return "nil" } - repeatedStringForRules := "[]PolicyRule{" - for _, f := range this.Rules { - repeatedStringForRules += strings.Replace(strings.Replace(f.String(), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + "," - } - repeatedStringForRules += "}" s := strings.Join([]string{`&Policy{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, - `Rules:` + repeatedStringForRules + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Rules:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Rules), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, `}`, }, "") @@ -1235,14 +939,9 @@ func (this *PolicyList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Policy{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Policy", "Policy", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&PolicyList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Policy", "Policy", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1251,17 +950,12 @@ func (this *PolicyRule) String() string { if this == nil { return "nil" } - repeatedStringForResources := "[]GroupResources{" - for _, f := range this.Resources { - repeatedStringForResources += strings.Replace(strings.Replace(f.String(), "GroupResources", "GroupResources", 1), `&`, ``, 1) + "," - } - repeatedStringForResources += "}" s := strings.Join([]string{`&PolicyRule{`, `Level:` + fmt.Sprintf("%v", this.Level) + `,`, `Users:` + fmt.Sprintf("%v", this.Users) + `,`, `UserGroups:` + fmt.Sprintf("%v", this.UserGroups) + `,`, `Verbs:` + fmt.Sprintf("%v", this.Verbs) + `,`, - `Resources:` + repeatedStringForResources + `,`, + `Resources:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Resources), "GroupResources", "GroupResources", 1), `&`, ``, 1) + `,`, `Namespaces:` + fmt.Sprintf("%v", this.Namespaces) + `,`, `NonResourceURLs:` + fmt.Sprintf("%v", this.NonResourceURLs) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, @@ -1292,7 +986,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1320,7 +1014,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1329,9 +1023,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1353,7 +1044,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1363,9 +1054,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1385,7 +1073,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1394,9 +1082,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1418,7 +1103,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1428,9 +1113,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1450,7 +1132,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1460,9 +1142,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1482,7 +1161,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1492,9 +1171,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1514,7 +1190,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1524,9 +1200,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1546,7 +1219,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1555,9 +1228,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1579,7 +1249,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1588,14 +1258,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ImpersonatedUser == nil { - m.ImpersonatedUser = &v11.UserInfo{} + m.ImpersonatedUser = &k8s_io_api_authentication_v1.UserInfo{} } if err := m.ImpersonatedUser.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1615,7 +1282,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1625,9 +1292,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1647,7 +1311,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1656,9 +1320,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1683,7 +1344,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1692,14 +1353,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseStatus == nil { - m.ResponseStatus = &v1.Status{} + m.ResponseStatus = &k8s_io_apimachinery_pkg_apis_meta_v1.Status{} } if err := m.ResponseStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1719,7 +1377,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1728,14 +1386,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.RequestObject == nil { - m.RequestObject = &runtime.Unknown{} + m.RequestObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.RequestObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1755,7 +1410,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1764,14 +1419,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseObject == nil { - m.ResponseObject = &runtime.Unknown{} + m.ResponseObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.ResponseObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1791,7 +1443,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1800,9 +1452,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1824,7 +1473,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1833,9 +1482,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1857,7 +1503,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1866,9 +1512,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1889,7 +1532,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1906,7 +1549,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift + stringLenmapkey |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1916,9 +1559,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1935,7 +1575,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift + stringLenmapvalue |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1945,9 +1585,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1984,7 +1621,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1994,9 +1631,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2011,9 +1645,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2041,7 +1672,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2069,7 +1700,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2078,9 +1709,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2102,7 +1730,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2111,9 +1739,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2131,9 +1756,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2161,7 +1783,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2189,7 +1811,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2199,9 +1821,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2221,7 +1840,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2231,9 +1850,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2253,7 +1869,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2263,9 +1879,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2280,9 +1893,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2310,7 +1920,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2338,7 +1948,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2348,9 +1958,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2370,7 +1977,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2380,9 +1987,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2402,7 +2006,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2412,9 +2016,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2434,7 +2035,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2444,9 +2045,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2466,7 +2064,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2476,9 +2074,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2498,7 +2093,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2508,9 +2103,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2530,7 +2122,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2540,9 +2132,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2557,9 +2146,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2587,7 +2173,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2615,7 +2201,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2624,9 +2210,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2648,7 +2231,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2657,9 +2240,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2682,7 +2262,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2692,9 +2272,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2709,9 +2286,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2739,7 +2313,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2767,7 +2341,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2776,9 +2350,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2800,7 +2371,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2809,9 +2380,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2829,9 +2397,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2859,7 +2424,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2887,7 +2452,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2897,9 +2462,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2919,7 +2481,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2929,9 +2491,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2951,7 +2510,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2961,9 +2520,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2983,7 +2539,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2993,9 +2549,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3015,7 +2568,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -3024,9 +2577,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3049,7 +2599,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3059,9 +2609,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3081,7 +2628,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3091,9 +2638,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3113,7 +2657,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3123,9 +2667,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3140,9 +2681,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -3158,7 +2696,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -3190,8 +2727,10 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -3208,34 +2747,140 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + iNdEx += length if length < 0 { return 0, ErrInvalidLengthGenerated } - iNdEx += length + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenerated + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipGenerated(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next } - depth-- + return iNdEx, nil + case 4: + return iNdEx, nil case 5: iNdEx += 4 + return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") ) + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/generated.proto", fileDescriptorGenerated) +} + +var fileDescriptorGenerated = []byte{ + // 1263 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xd6, 0x71, 0x63, 0x8f, 0x1b, 0xc7, 0x99, 0x56, 0x74, 0x95, 0x83, 0x6d, 0x8c, 0x84, + 0x2c, 0x08, 0xbb, 0x49, 0x14, 0x68, 0x40, 0x02, 0x11, 0xab, 0x15, 0x58, 0x4a, 0x43, 0x78, 0x89, + 0x2b, 0xf1, 0xe7, 0xc0, 0xda, 0x7e, 0xb1, 0x17, 0xdb, 0xbb, 0xcb, 0xce, 0xac, 0xab, 0xdc, 0x38, + 0x70, 0x45, 0xe2, 0xce, 0x87, 0xe0, 0x23, 0x54, 0xdc, 0x72, 0xec, 0xb1, 0x27, 0x8b, 0x98, 0x6f, + 0x91, 0x03, 0x42, 0x33, 0xfb, 0x67, 0xd6, 0x4e, 0x2d, 0x1c, 0x0e, 0xbd, 0xed, 0xbc, 0xf7, 0x7b, + 0xbf, 0xf7, 0xe6, 0xed, 0xfb, 0x33, 0xe4, 0xeb, 0xc1, 0x01, 0x33, 0x6c, 0xd7, 0x1c, 0x04, 0x6d, + 0xf4, 0x1d, 0xe4, 0xc8, 0xcc, 0x31, 0x3a, 0x5d, 0xd7, 0x37, 0x23, 0x85, 0xe5, 0xd9, 0x0c, 0xfd, + 0x31, 0xfa, 0xa6, 0x37, 0xe8, 0xc9, 0x93, 0x69, 0x05, 0x5d, 0x9b, 0x9b, 0xe3, 0x5d, 0x6b, 0xe8, + 0xf5, 0xad, 0x5d, 0xb3, 0x87, 0x0e, 0xfa, 0x16, 0xc7, 0xae, 0xe1, 0xf9, 0x2e, 0x77, 0x69, 0x3d, + 0xb4, 0x34, 0x12, 0x4b, 0xc3, 0x1b, 0xf4, 0xe4, 0xc9, 0x90, 0x96, 0x46, 0x6c, 0xb9, 0xf5, 0x41, + 0xcf, 0xe6, 0xfd, 0xa0, 0x6d, 0x74, 0xdc, 0x91, 0xd9, 0x73, 0x7b, 0xae, 0x29, 0x09, 0xda, 0xc1, + 0xb9, 0x3c, 0xc9, 0x83, 0xfc, 0x0a, 0x89, 0xb7, 0xb6, 0x55, 0x48, 0xa6, 0x15, 0xf0, 0x3e, 0x3a, + 0xdc, 0xee, 0x58, 0xdc, 0x76, 0x1d, 0x73, 0x7c, 0x23, 0x8c, 0xad, 0x7d, 0x85, 0x1e, 0x59, 0x9d, + 0xbe, 0xed, 0xa0, 0x7f, 0xa1, 0xee, 0x30, 0x42, 0x6e, 0xbd, 0xce, 0xca, 0x5c, 0x64, 0xe5, 0x07, + 0x0e, 0xb7, 0x47, 0x78, 0xc3, 0xe0, 0xa3, 0xff, 0x32, 0x60, 0x9d, 0x3e, 0x8e, 0xac, 0x79, 0xbb, + 0xda, 0x1f, 0xf7, 0x48, 0xf6, 0xc9, 0x18, 0x1d, 0x4e, 0x7f, 0x20, 0x39, 0x11, 0x4d, 0xd7, 0xe2, + 0x96, 0xae, 0x55, 0xb5, 0x7a, 0x61, 0x6f, 0xc7, 0x50, 0x29, 0x4c, 0x48, 0x55, 0x16, 0x05, 0xda, + 0x18, 0xef, 0x1a, 0x5f, 0xb5, 0x7f, 0xc4, 0x0e, 0x7f, 0x8a, 0xdc, 0x6a, 0xd0, 0xcb, 0x49, 0x65, + 0x65, 0x3a, 0xa9, 0x10, 0x25, 0x83, 0x84, 0x95, 0x6e, 0x93, 0xec, 0x10, 0xc7, 0x38, 0xd4, 0xef, + 0x54, 0xb5, 0x7a, 0xbe, 0xf1, 0x56, 0x04, 0xce, 0x1e, 0x09, 0xe1, 0x75, 0xfc, 0x01, 0x21, 0x88, + 0x7e, 0x47, 0xf2, 0x22, 0x70, 0xc6, 0xad, 0x91, 0xa7, 0x67, 0x64, 0x40, 0xef, 0x2d, 0x17, 0xd0, + 0x99, 0x3d, 0xc2, 0xc6, 0x66, 0xc4, 0x9e, 0x3f, 0x8b, 0x49, 0x40, 0xf1, 0xd1, 0x63, 0xb2, 0x26, + 0x8b, 0xa0, 0xf9, 0x58, 0x5f, 0x95, 0xc1, 0xec, 0x47, 0xf0, 0xb5, 0xc3, 0x50, 0x7c, 0x3d, 0xa9, + 0xbc, 0xbd, 0x28, 0xa5, 0xfc, 0xc2, 0x43, 0x66, 0xb4, 0x9a, 0x8f, 0x21, 0x26, 0x11, 0x57, 0x63, + 0xdc, 0xea, 0xa1, 0x9e, 0x9d, 0xbd, 0xda, 0xa9, 0x10, 0x5e, 0xc7, 0x1f, 0x10, 0x82, 0xe8, 0x1e, + 0x21, 0x3e, 0xfe, 0x14, 0x20, 0xe3, 0x2d, 0x68, 0xea, 0x77, 0xa5, 0x49, 0x92, 0x3a, 0x48, 0x34, + 0x90, 0x42, 0xd1, 0x2a, 0x59, 0x1d, 0xa3, 0xdf, 0xd6, 0xd7, 0x24, 0xfa, 0x5e, 0x84, 0x5e, 0x7d, + 0x86, 0x7e, 0x1b, 0xa4, 0x86, 0x7e, 0x49, 0x56, 0x03, 0x86, 0xbe, 0x9e, 0x93, 0xb9, 0x7a, 0x37, + 0x95, 0x2b, 0x63, 0xb6, 0x4c, 0x45, 0x8e, 0x5a, 0x0c, 0xfd, 0xa6, 0x73, 0xee, 0x2a, 0x26, 0x21, + 0x01, 0xc9, 0x40, 0xfb, 0xa4, 0x64, 0x8f, 0x3c, 0xf4, 0x99, 0xeb, 0x88, 0x52, 0x11, 0x1a, 0x3d, + 0x7f, 0x2b, 0xd6, 0x07, 0xd3, 0x49, 0xa5, 0xd4, 0x9c, 0xe3, 0x80, 0x1b, 0xac, 0xf4, 0x7d, 0x92, + 0x67, 0x6e, 0xe0, 0x77, 0xb0, 0x79, 0xc2, 0x74, 0x52, 0xcd, 0xd4, 0xf3, 0x8d, 0x75, 0xf1, 0xd3, + 0x4e, 0x63, 0x21, 0x28, 0x3d, 0x3d, 0x27, 0x79, 0x57, 0xd6, 0x15, 0xe0, 0xb9, 0x5e, 0x90, 0xf1, + 0x7c, 0x6c, 0x2c, 0xdb, 0xe5, 0x51, 0x99, 0x02, 0x9e, 0xa3, 0x8f, 0x4e, 0x07, 0x43, 0x3f, 0x89, + 0x10, 0x14, 0x35, 0xed, 0x93, 0xa2, 0x8f, 0xcc, 0x73, 0x1d, 0x86, 0xa7, 0xdc, 0xe2, 0x01, 0xd3, + 0xef, 0x49, 0x67, 0xdb, 0xcb, 0x95, 0x5f, 0x68, 0xd3, 0xa0, 0xd3, 0x49, 0xa5, 0x08, 0x33, 0x3c, + 0x30, 0xc7, 0x4b, 0x2d, 0xb2, 0x1e, 0xfd, 0xe2, 0x30, 0x10, 0x7d, 0x5d, 0x3a, 0xaa, 0x2f, 0x74, + 0x14, 0x75, 0xb3, 0xd1, 0x72, 0x06, 0x8e, 0xfb, 0xdc, 0x69, 0x6c, 0x4e, 0x27, 0x95, 0x75, 0x48, + 0x53, 0xc0, 0x2c, 0x23, 0xed, 0xaa, 0xcb, 0x44, 0x3e, 0x8a, 0xb7, 0xf4, 0x31, 0x73, 0x91, 0xc8, + 0xc9, 0x1c, 0x27, 0xfd, 0x55, 0x23, 0x7a, 0xe4, 0x17, 0xb0, 0x83, 0xf6, 0x18, 0xbb, 0x49, 0xdf, + 0xe9, 0x1b, 0xd2, 0xa1, 0xb9, 0x5c, 0xf6, 0x9e, 0xda, 0x1d, 0xdf, 0x95, 0x1d, 0x5c, 0x8d, 0x2a, + 0x53, 0x87, 0x05, 0xc4, 0xb0, 0xd0, 0x25, 0x75, 0x49, 0x51, 0xb6, 0x9a, 0x0a, 0xa2, 0xf4, 0xff, + 0x82, 0x88, 0x3b, 0xb9, 0x78, 0x3a, 0x43, 0x07, 0x73, 0xf4, 0xf4, 0x39, 0x29, 0x58, 0x8e, 0xe3, + 0x72, 0xd9, 0x0a, 0x4c, 0xdf, 0xac, 0x66, 0xea, 0x85, 0xbd, 0xcf, 0x97, 0xaf, 0x4e, 0x39, 0x83, + 0x8d, 0x43, 0x45, 0xf1, 0xc4, 0xe1, 0xfe, 0x45, 0xe3, 0x7e, 0xe4, 0xbe, 0x90, 0xd2, 0x40, 0xda, + 0x13, 0x35, 0x49, 0x5e, 0xf4, 0xec, 0x61, 0x0f, 0x1d, 0xae, 0x53, 0x39, 0x1c, 0x92, 0xd1, 0xd7, + 0x8a, 0x15, 0xa0, 0x30, 0x5b, 0x9f, 0x91, 0xd2, 0xbc, 0x1b, 0x5a, 0x22, 0x99, 0x01, 0x5e, 0xc8, + 0xb1, 0x9f, 0x07, 0xf1, 0x49, 0x1f, 0x90, 0xec, 0xd8, 0x1a, 0x06, 0x18, 0xce, 0x6a, 0x08, 0x0f, + 0x9f, 0xdc, 0x39, 0xd0, 0x6a, 0x2f, 0x34, 0x92, 0x97, 0xd1, 0x1e, 0xd9, 0x8c, 0xd3, 0xef, 0x6f, + 0x6c, 0x0d, 0x63, 0xb9, 0x14, 0x0b, 0x6b, 0xb9, 0x33, 0x4a, 0x51, 0xb4, 0xb9, 0x58, 0x92, 0xda, + 0x18, 0x67, 0x24, 0x6b, 0x73, 0x1c, 0x31, 0xfd, 0x8e, 0xcc, 0xa7, 0x79, 0xcb, 0x7c, 0x36, 0xd6, + 0xe3, 0x39, 0xdc, 0x14, 0x2c, 0x10, 0x92, 0xd5, 0x7e, 0xd7, 0x48, 0xf1, 0x0b, 0xdf, 0x0d, 0x3c, + 0xc0, 0x70, 0xb8, 0x30, 0xfa, 0x0e, 0xc9, 0xf6, 0x84, 0x24, 0x4c, 0x81, 0xb2, 0x0b, 0x61, 0xa1, + 0x4e, 0x0c, 0x2b, 0x3f, 0xb6, 0x90, 0x11, 0x45, 0xc3, 0x2a, 0xa1, 0x01, 0xa5, 0xa7, 0x8f, 0x44, + 0x6b, 0x87, 0x87, 0x63, 0x6b, 0x84, 0x4c, 0xcf, 0x48, 0x83, 0xa8, 0x61, 0x53, 0x0a, 0x98, 0xc5, + 0xd5, 0x7e, 0xc9, 0x90, 0x8d, 0xb9, 0x59, 0x45, 0xb7, 0x49, 0x2e, 0x06, 0x45, 0x11, 0x26, 0x59, + 0x8b, 0xb9, 0x20, 0x41, 0x88, 0x92, 0x70, 0x04, 0x95, 0x67, 0x75, 0xa2, 0xff, 0xa7, 0x4a, 0xe2, + 0x38, 0x56, 0x80, 0xc2, 0x88, 0xdd, 0x22, 0x0e, 0x72, 0xcb, 0xa6, 0x76, 0x8b, 0xc0, 0x82, 0xd4, + 0xd0, 0x06, 0xc9, 0x04, 0x76, 0x37, 0xda, 0x95, 0x3b, 0x11, 0x20, 0xd3, 0x5a, 0x76, 0x4f, 0x0a, + 0x63, 0xb1, 0xf5, 0x2c, 0xcf, 0x7e, 0x86, 0x3e, 0xb3, 0x5d, 0x27, 0x5a, 0x94, 0xc9, 0xd6, 0x3b, + 0x3c, 0x69, 0x46, 0x1a, 0x48, 0xa1, 0xe8, 0x21, 0xd9, 0x88, 0xaf, 0x15, 0x1b, 0x86, 0xeb, 0xf2, + 0x61, 0x64, 0xb8, 0x01, 0xb3, 0x6a, 0x98, 0xc7, 0xd3, 0x0f, 0x49, 0x81, 0x05, 0xed, 0x24, 0x7d, + 0xe1, 0xfe, 0x4c, 0xfa, 0xea, 0x54, 0xa9, 0x20, 0x8d, 0xab, 0xfd, 0xa3, 0x91, 0xbb, 0x27, 0xee, + 0xd0, 0xee, 0x5c, 0xbc, 0x81, 0x97, 0xd1, 0x37, 0x24, 0xeb, 0x07, 0x43, 0x8c, 0xeb, 0x7c, 0x7f, + 0xf9, 0x3a, 0x0f, 0x43, 0x84, 0x60, 0x88, 0xaa, 0x68, 0xc5, 0x89, 0x41, 0xc8, 0x48, 0x1f, 0x11, + 0xe2, 0x8e, 0x6c, 0x2e, 0xc7, 0x57, 0x5c, 0x84, 0x0f, 0x65, 0x20, 0x89, 0x54, 0xbd, 0x4f, 0x52, + 0xd0, 0xda, 0x9f, 0x1a, 0x21, 0x21, 0xfb, 0x1b, 0x68, 0xf4, 0xd6, 0x6c, 0xa3, 0xef, 0xdc, 0x36, + 0x01, 0x0b, 0x3a, 0xfd, 0x45, 0x26, 0xbe, 0x83, 0xc8, 0x89, 0x7a, 0x80, 0x6a, 0xcb, 0x3c, 0x40, + 0x2b, 0x24, 0x2b, 0xa6, 0x66, 0xdc, 0xea, 0x79, 0x81, 0x14, 0x13, 0x95, 0x41, 0x28, 0xa7, 0x06, + 0x21, 0xe2, 0x43, 0xce, 0x88, 0x38, 0xb5, 0x45, 0x91, 0xda, 0x56, 0x22, 0x85, 0x14, 0x42, 0x10, + 0x8a, 0x87, 0x1a, 0xd3, 0x57, 0x15, 0xa1, 0x78, 0xbf, 0x31, 0x08, 0xe5, 0xd4, 0x4e, 0x0f, 0x98, + 0xac, 0xcc, 0xc4, 0xc1, 0xf2, 0x99, 0x98, 0x1d, 0x69, 0xaa, 0xe5, 0x5f, 0x3b, 0x9e, 0x0c, 0x42, + 0x92, 0xfe, 0x67, 0xfa, 0x5d, 0x15, 0x7b, 0x32, 0x20, 0x18, 0xa4, 0x10, 0xf4, 0x53, 0xb2, 0xe1, + 0xb8, 0x4e, 0x4c, 0xd5, 0x82, 0x23, 0xa6, 0xaf, 0x49, 0xa3, 0xfb, 0xa2, 0x09, 0x8f, 0x67, 0x55, + 0x30, 0x8f, 0x9d, 0xab, 0xc2, 0xdc, 0xd2, 0x55, 0xd8, 0x30, 0x2e, 0xaf, 0xca, 0x2b, 0x2f, 0xaf, + 0xca, 0x2b, 0xaf, 0xae, 0xca, 0x2b, 0x3f, 0x4f, 0xcb, 0xda, 0xe5, 0xb4, 0xac, 0xbd, 0x9c, 0x96, + 0xb5, 0x57, 0xd3, 0xb2, 0xf6, 0xd7, 0xb4, 0xac, 0xfd, 0xf6, 0x77, 0x79, 0xe5, 0xdb, 0x5c, 0x9c, + 0x84, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xfc, 0xbf, 0xfd, 0x49, 0x0e, 0x00, 0x00, +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go index 74a18420536..ac56459ae83 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.conversion.go @@ -23,8 +23,8 @@ package v1alpha1 import ( unsafe "unsafe" - v1 "k8s.io/api/authentication/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + authenticationv1 "k8s.io/api/authentication/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" types "k8s.io/apimachinery/pkg/types" @@ -38,6 +38,16 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*Event)(nil), (*audit.Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_Event_To_audit_Event(a.(*Event), b.(*audit.Event), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*audit.Event)(nil), (*Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_audit_Event_To_v1alpha1_Event(a.(*audit.Event), b.(*Event), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*EventList)(nil), (*audit.EventList)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_EventList_To_audit_EventList(a.(*EventList), b.(*audit.EventList), scope) }); err != nil { @@ -58,6 +68,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*ObjectReference)(nil), (*audit.ObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ObjectReference_To_audit_ObjectReference(a.(*ObjectReference), b.(*audit.ObjectReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*audit.ObjectReference)(nil), (*ObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_audit_ObjectReference_To_v1alpha1_ObjectReference(a.(*audit.ObjectReference), b.(*ObjectReference), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*Policy)(nil), (*audit.Policy)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_Policy_To_audit_Policy(a.(*Policy), b.(*audit.Policy), scope) }); err != nil { @@ -119,8 +139,11 @@ func autoConvert_v1alpha1_Event_To_audit_Event(in *Event, out *audit.Event, s co out.Stage = audit.Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User - out.ImpersonatedUser = (*v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } + out.ImpersonatedUser = (*audit.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent if in.ObjectRef != nil { @@ -132,7 +155,7 @@ func autoConvert_v1alpha1_Event_To_audit_Event(in *Event, out *audit.Event, s co } else { out.ObjectRef = nil } - out.ResponseStatus = (*metav1.Status)(unsafe.Pointer(in.ResponseStatus)) + out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) out.RequestReceivedTimestamp = in.RequestReceivedTimestamp @@ -147,8 +170,11 @@ func autoConvert_audit_Event_To_v1alpha1_Event(in *audit.Event, out *Event, s co out.Stage = Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User - out.ImpersonatedUser = (*v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } + out.ImpersonatedUser = (*authenticationv1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent if in.ObjectRef != nil { @@ -160,7 +186,7 @@ func autoConvert_audit_Event_To_v1alpha1_Event(in *audit.Event, out *Event, s co } else { out.ObjectRef = nil } - out.ResponseStatus = (*metav1.Status)(unsafe.Pointer(in.ResponseStatus)) + out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) out.RequestReceivedTimestamp = in.RequestReceivedTimestamp diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go index efb6cd87de4..1926b620526 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1alpha1/zz_generated.deepcopy.go @@ -97,7 +97,7 @@ func (in *Event) DeepCopyObject() runtime.Object { func (in *EventList) DeepCopyInto(out *EventList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Event, len(*in)) @@ -210,7 +210,7 @@ func (in *Policy) DeepCopyObject() runtime.Object { func (in *PolicyList) DeepCopyInto(out *PolicyList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Policy, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go index f3fe61683d8..d43a807c3de 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/doc.go @@ -15,7 +15,6 @@ limitations under the License. */ // +k8s:deepcopy-gen=package -// +k8s:protobuf-gen=package // +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/audit // +k8s:openapi-gen=true // +k8s:defaulter-gen=TypeMeta diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.pb.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.pb.go index 14870e42944..ecc26c2e735 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.pb.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.pb.go @@ -17,26 +17,39 @@ limitations under the License. // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.proto +/* + Package v1beta1 is a generated protocol buffer package. + + It is generated from these files: + k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.proto + + It has these top-level messages: + Event + EventList + GroupResources + ObjectReference + Policy + PolicyList + PolicyRule +*/ package v1beta1 -import ( - fmt "fmt" +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" - io "io" +import k8s_io_api_authentication_v1 "k8s.io/api/authentication/v1" +import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import k8s_io_apimachinery_pkg_runtime "k8s.io/apimachinery/pkg/runtime" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - v11 "k8s.io/api/authentication/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" +import k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" - math "math" - math_bits "math/bits" - reflect "reflect" - strings "strings" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - k8s_io_apimachinery_pkg_types "k8s.io/apimachinery/pkg/types" -) +import strings "strings" +import reflect "reflect" + +import io "io" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -47,207 +60,38 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package -func (m *Event) Reset() { *m = Event{} } -func (*Event) ProtoMessage() {} -func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{0} -} -func (m *Event) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Event) XXX_Merge(src proto.Message) { - xxx_messageInfo_Event.Merge(m, src) -} -func (m *Event) XXX_Size() int { - return m.Size() -} -func (m *Event) XXX_DiscardUnknown() { - xxx_messageInfo_Event.DiscardUnknown(m) -} +func (m *Event) Reset() { *m = Event{} } +func (*Event) ProtoMessage() {} +func (*Event) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } -var xxx_messageInfo_Event proto.InternalMessageInfo +func (m *EventList) Reset() { *m = EventList{} } +func (*EventList) ProtoMessage() {} +func (*EventList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } -func (m *EventList) Reset() { *m = EventList{} } -func (*EventList) ProtoMessage() {} -func (*EventList) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{1} -} -func (m *EventList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *EventList) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventList.Merge(m, src) -} -func (m *EventList) XXX_Size() int { - return m.Size() -} -func (m *EventList) XXX_DiscardUnknown() { - xxx_messageInfo_EventList.DiscardUnknown(m) -} +func (m *GroupResources) Reset() { *m = GroupResources{} } +func (*GroupResources) ProtoMessage() {} +func (*GroupResources) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } -var xxx_messageInfo_EventList proto.InternalMessageInfo +func (m *ObjectReference) Reset() { *m = ObjectReference{} } +func (*ObjectReference) ProtoMessage() {} +func (*ObjectReference) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } -func (m *GroupResources) Reset() { *m = GroupResources{} } -func (*GroupResources) ProtoMessage() {} -func (*GroupResources) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{2} -} -func (m *GroupResources) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GroupResources) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *GroupResources) XXX_Merge(src proto.Message) { - xxx_messageInfo_GroupResources.Merge(m, src) -} -func (m *GroupResources) XXX_Size() int { - return m.Size() -} -func (m *GroupResources) XXX_DiscardUnknown() { - xxx_messageInfo_GroupResources.DiscardUnknown(m) -} +func (m *Policy) Reset() { *m = Policy{} } +func (*Policy) ProtoMessage() {} +func (*Policy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } -var xxx_messageInfo_GroupResources proto.InternalMessageInfo +func (m *PolicyList) Reset() { *m = PolicyList{} } +func (*PolicyList) ProtoMessage() {} +func (*PolicyList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} } -func (m *ObjectReference) Reset() { *m = ObjectReference{} } -func (*ObjectReference) ProtoMessage() {} -func (*ObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{3} -} -func (m *ObjectReference) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ObjectReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *ObjectReference) XXX_Merge(src proto.Message) { - xxx_messageInfo_ObjectReference.Merge(m, src) -} -func (m *ObjectReference) XXX_Size() int { - return m.Size() -} -func (m *ObjectReference) XXX_DiscardUnknown() { - xxx_messageInfo_ObjectReference.DiscardUnknown(m) -} - -var xxx_messageInfo_ObjectReference proto.InternalMessageInfo - -func (m *Policy) Reset() { *m = Policy{} } -func (*Policy) ProtoMessage() {} -func (*Policy) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{4} -} -func (m *Policy) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Policy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Policy) XXX_Merge(src proto.Message) { - xxx_messageInfo_Policy.Merge(m, src) -} -func (m *Policy) XXX_Size() int { - return m.Size() -} -func (m *Policy) XXX_DiscardUnknown() { - xxx_messageInfo_Policy.DiscardUnknown(m) -} - -var xxx_messageInfo_Policy proto.InternalMessageInfo - -func (m *PolicyList) Reset() { *m = PolicyList{} } -func (*PolicyList) ProtoMessage() {} -func (*PolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{5} -} -func (m *PolicyList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyList) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyList.Merge(m, src) -} -func (m *PolicyList) XXX_Size() int { - return m.Size() -} -func (m *PolicyList) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyList.DiscardUnknown(m) -} - -var xxx_messageInfo_PolicyList proto.InternalMessageInfo - -func (m *PolicyRule) Reset() { *m = PolicyRule{} } -func (*PolicyRule) ProtoMessage() {} -func (*PolicyRule) Descriptor() ([]byte, []int) { - return fileDescriptor_c7e4d52063960930, []int{6} -} -func (m *PolicyRule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PolicyRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PolicyRule) XXX_Merge(src proto.Message) { - xxx_messageInfo_PolicyRule.Merge(m, src) -} -func (m *PolicyRule) XXX_Size() int { - return m.Size() -} -func (m *PolicyRule) XXX_DiscardUnknown() { - xxx_messageInfo_PolicyRule.DiscardUnknown(m) -} - -var xxx_messageInfo_PolicyRule proto.InternalMessageInfo +func (m *PolicyRule) Reset() { *m = PolicyRule{} } +func (*PolicyRule) ProtoMessage() {} +func (*PolicyRule) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} } func init() { proto.RegisterType((*Event)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.Event") - proto.RegisterMapType((map[string]string)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.Event.AnnotationsEntry") proto.RegisterType((*EventList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.EventList") proto.RegisterType((*GroupResources)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.GroupResources") proto.RegisterType((*ObjectReference)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.ObjectReference") @@ -255,99 +99,10 @@ func init() { proto.RegisterType((*PolicyList)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.PolicyList") proto.RegisterType((*PolicyRule)(nil), "k8s.io.apiserver.pkg.apis.audit.v1beta1.PolicyRule") } - -func init() { - proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.proto", fileDescriptor_c7e4d52063960930) -} - -var fileDescriptor_c7e4d52063960930 = []byte{ - // 1279 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xd6, 0x71, 0x63, 0x8f, 0x1b, 0xc7, 0x9d, 0x56, 0x74, 0x95, 0x83, 0x6d, 0x8c, 0x04, - 0x11, 0xa4, 0xbb, 0x4d, 0x28, 0x24, 0x42, 0x02, 0x64, 0xab, 0x15, 0x58, 0x4a, 0x43, 0x34, 0x8e, - 0x2b, 0x04, 0x1c, 0x58, 0xdb, 0x2f, 0xf6, 0x62, 0x7b, 0x77, 0xd9, 0x99, 0x35, 0xca, 0x8d, 0x2f, - 0x80, 0xc4, 0x9d, 0xcf, 0xc0, 0x85, 0x0f, 0x50, 0x71, 0xcc, 0xb1, 0xc7, 0x9e, 0x2c, 0x62, 0xbe, - 0x45, 0x24, 0x24, 0x34, 0x7f, 0x76, 0x67, 0xed, 0xd4, 0xc2, 0xe1, 0xd0, 0xdb, 0xce, 0x7b, 0xbf, - 0xf7, 0x9b, 0x37, 0xbf, 0x7d, 0xf3, 0xde, 0xa0, 0x93, 0xe1, 0x21, 0xb5, 0x5c, 0xdf, 0x1e, 0x46, - 0x1d, 0x08, 0x3d, 0x60, 0x40, 0xed, 0x09, 0x78, 0x3d, 0x3f, 0xb4, 0x95, 0xc3, 0x09, 0x5c, 0x0a, - 0xe1, 0x04, 0x42, 0x3b, 0x18, 0xf6, 0xc5, 0xca, 0x76, 0xa2, 0x9e, 0xcb, 0xec, 0xc9, 0x5e, 0x07, - 0x98, 0xb3, 0x67, 0xf7, 0xc1, 0x83, 0xd0, 0x61, 0xd0, 0xb3, 0x82, 0xd0, 0x67, 0x3e, 0x7e, 0x4f, - 0x06, 0x5a, 0x49, 0xa0, 0x15, 0x0c, 0xfb, 0x62, 0x65, 0x89, 0x40, 0x4b, 0x05, 0x6e, 0x3f, 0xec, - 0xbb, 0x6c, 0x10, 0x75, 0xac, 0xae, 0x3f, 0xb6, 0xfb, 0x7e, 0xdf, 0xb7, 0x45, 0x7c, 0x27, 0x3a, - 0x13, 0x2b, 0xb1, 0x10, 0x5f, 0x92, 0x77, 0x7b, 0x57, 0x27, 0x64, 0x3b, 0x11, 0x1b, 0x80, 0xc7, - 0xdc, 0xae, 0xc3, 0x5c, 0xdf, 0xb3, 0x27, 0xd7, 0xb2, 0xd8, 0x7e, 0xac, 0xd1, 0x63, 0xa7, 0x3b, - 0x70, 0x3d, 0x08, 0xcf, 0xf5, 0x09, 0xc6, 0xc0, 0x9c, 0xd7, 0x45, 0xd9, 0xcb, 0xa2, 0xc2, 0xc8, - 0x63, 0xee, 0x18, 0xae, 0x05, 0x7c, 0xfc, 0x5f, 0x01, 0xb4, 0x3b, 0x80, 0xb1, 0xb3, 0x18, 0x57, - 0xfb, 0xfd, 0x0e, 0xca, 0x3e, 0x9d, 0x80, 0xc7, 0xf0, 0xf7, 0x28, 0xc7, 0xb3, 0xe9, 0x39, 0xcc, - 0x31, 0x8d, 0xaa, 0xb1, 0x53, 0xd8, 0x7f, 0x64, 0x69, 0x05, 0x13, 0x52, 0x2d, 0x22, 0x47, 0x5b, - 0x93, 0x3d, 0xeb, 0xab, 0xce, 0x0f, 0xd0, 0x65, 0xcf, 0x80, 0x39, 0x0d, 0x7c, 0x31, 0xad, 0xac, - 0xcd, 0xa6, 0x15, 0xa4, 0x6d, 0x24, 0x61, 0xc5, 0xbb, 0x28, 0x3b, 0x82, 0x09, 0x8c, 0xcc, 0x5b, - 0x55, 0x63, 0x27, 0xdf, 0x78, 0x4b, 0x81, 0xb3, 0x47, 0xdc, 0x78, 0x15, 0x7f, 0x10, 0x09, 0xc2, - 0xdf, 0xa2, 0x3c, 0x4f, 0x9c, 0x32, 0x67, 0x1c, 0x98, 0x19, 0x91, 0xd0, 0xfb, 0xab, 0x25, 0x74, - 0xea, 0x8e, 0xa1, 0x71, 0x57, 0xb1, 0xe7, 0x4f, 0x63, 0x12, 0xa2, 0xf9, 0xf0, 0x31, 0xda, 0x10, - 0x35, 0xd0, 0x7c, 0x62, 0xae, 0x8b, 0x64, 0x1e, 0x2b, 0xf8, 0x46, 0x5d, 0x9a, 0xaf, 0xa6, 0x95, - 0xb7, 0x97, 0x49, 0xca, 0xce, 0x03, 0xa0, 0x56, 0xbb, 0xf9, 0x84, 0xc4, 0x24, 0xfc, 0x68, 0x94, - 0x39, 0x7d, 0x30, 0xb3, 0xf3, 0x47, 0x6b, 0x71, 0xe3, 0x55, 0xfc, 0x41, 0x24, 0x08, 0xef, 0x23, - 0x14, 0xc2, 0x8f, 0x11, 0x50, 0xd6, 0x26, 0x4d, 0xf3, 0xb6, 0x08, 0x49, 0xa4, 0x23, 0x89, 0x87, - 0xa4, 0x50, 0xb8, 0x8a, 0xd6, 0x27, 0x10, 0x76, 0xcc, 0x0d, 0x81, 0xbe, 0xa3, 0xd0, 0xeb, 0xcf, - 0x21, 0xec, 0x10, 0xe1, 0xc1, 0x5f, 0xa2, 0xf5, 0x88, 0x42, 0x68, 0xe6, 0x84, 0x56, 0xef, 0xa6, - 0xb4, 0xb2, 0xe6, 0xcb, 0x94, 0x6b, 0xd4, 0xa6, 0x10, 0x36, 0xbd, 0x33, 0x5f, 0x33, 0x71, 0x0b, - 0x11, 0x0c, 0x78, 0x80, 0x4a, 0xee, 0x38, 0x80, 0x90, 0xfa, 0x1e, 0x2f, 0x15, 0xee, 0x31, 0xf3, - 0x37, 0x62, 0xbd, 0x3f, 0x9b, 0x56, 0x4a, 0xcd, 0x05, 0x0e, 0x72, 0x8d, 0x15, 0x7f, 0x80, 0xf2, - 0xd4, 0x8f, 0xc2, 0x2e, 0x34, 0x4f, 0xa8, 0x89, 0xaa, 0x99, 0x9d, 0x7c, 0x63, 0x93, 0xff, 0xb4, - 0x56, 0x6c, 0x24, 0xda, 0x8f, 0x6d, 0x94, 0xe7, 0xe9, 0xd5, 0xfb, 0xe0, 0x31, 0x13, 0x0b, 0x1d, - 0x92, 0xbf, 0xdc, 0x8e, 0x1d, 0x44, 0x63, 0x30, 0xa0, 0xbc, 0x2f, 0x0a, 0x91, 0xc0, 0x99, 0x59, - 0x10, 0x07, 0x38, 0xb4, 0x56, 0xec, 0x0a, 0xaa, 0xac, 0x09, 0x9c, 0x41, 0x08, 0x5e, 0x17, 0x64, - 0x5e, 0x89, 0x91, 0x68, 0x66, 0x3c, 0x40, 0xc5, 0x10, 0x68, 0xe0, 0x7b, 0x14, 0x5a, 0xcc, 0x61, - 0x11, 0x35, 0xef, 0x88, 0xbd, 0x76, 0x57, 0x2b, 0x57, 0x19, 0xd3, 0xc0, 0xb3, 0x69, 0xa5, 0x48, - 0xe6, 0x78, 0xc8, 0x02, 0x2f, 0x76, 0xd0, 0xa6, 0x2a, 0x09, 0x99, 0x88, 0xb9, 0x29, 0x36, 0xda, - 0x59, 0xba, 0x91, 0xba, 0xfd, 0x56, 0xdb, 0x1b, 0x7a, 0xfe, 0x4f, 0x5e, 0xe3, 0xee, 0x6c, 0x5a, - 0xd9, 0x24, 0x69, 0x0a, 0x32, 0xcf, 0x88, 0x7b, 0xfa, 0x30, 0x6a, 0x8f, 0xe2, 0x0d, 0xf7, 0x98, - 0x3b, 0x88, 0xda, 0x64, 0x81, 0x13, 0xff, 0x62, 0x20, 0x53, 0xed, 0x4b, 0xa0, 0x0b, 0xee, 0x04, - 0x7a, 0xc9, 0x3d, 0x35, 0xb7, 0xc4, 0x86, 0xf6, 0x6a, 0xea, 0x3d, 0x73, 0xbb, 0xa1, 0x2f, 0x6e, - 0x7c, 0x55, 0xd5, 0x82, 0x49, 0x96, 0x10, 0x93, 0xa5, 0x5b, 0x62, 0x1f, 0x15, 0xc5, 0xd5, 0xd4, - 0x49, 0x94, 0xfe, 0x5f, 0x12, 0xf1, 0xcd, 0x2f, 0xb6, 0xe6, 0xe8, 0xc8, 0x02, 0x3d, 0x9e, 0xa0, - 0x82, 0xe3, 0x79, 0x3e, 0x13, 0x57, 0x87, 0x9a, 0x77, 0xab, 0x99, 0x9d, 0xc2, 0xfe, 0xe7, 0x2b, - 0x17, 0xa7, 0x68, 0xd9, 0x56, 0x5d, 0x33, 0x3c, 0xf5, 0x58, 0x78, 0xde, 0xb8, 0xa7, 0x76, 0x2f, - 0xa4, 0x3c, 0x24, 0xbd, 0xd1, 0xf6, 0x67, 0xa8, 0xb4, 0x18, 0x85, 0x4b, 0x28, 0x33, 0x84, 0x73, - 0xd1, 0xf4, 0xf3, 0x84, 0x7f, 0xe2, 0xfb, 0x28, 0x3b, 0x71, 0x46, 0x11, 0xc8, 0x4e, 0x4d, 0xe4, - 0xe2, 0x93, 0x5b, 0x87, 0x46, 0xed, 0x85, 0x81, 0xf2, 0x62, 0xf3, 0x23, 0x97, 0x32, 0xfc, 0xdd, - 0xb5, 0x99, 0x61, 0xad, 0x26, 0x18, 0x8f, 0x16, 0x13, 0xa3, 0xa4, 0x32, 0xce, 0xc5, 0x96, 0xd4, - 0xbc, 0x68, 0xa1, 0xac, 0xcb, 0x60, 0x4c, 0xcd, 0x5b, 0x42, 0x1d, 0xeb, 0x66, 0xea, 0x34, 0x36, - 0xe3, 0x26, 0xdc, 0xe4, 0x24, 0x44, 0x72, 0xd5, 0x7e, 0x33, 0x50, 0xf1, 0x8b, 0xd0, 0x8f, 0x02, - 0x02, 0xb2, 0xb3, 0x50, 0xfc, 0x0e, 0xca, 0xf6, 0xb9, 0x45, 0x2a, 0xa0, 0xe3, 0x24, 0x4c, 0xfa, - 0x78, 0xa7, 0x0a, 0xe3, 0x08, 0x91, 0x90, 0xea, 0x54, 0x09, 0x0d, 0xd1, 0x7e, 0x7c, 0xc0, 0xef, - 0xa9, 0x5c, 0x1c, 0x3b, 0x63, 0xa0, 0x66, 0x46, 0x04, 0xa8, 0xdb, 0x97, 0x72, 0x90, 0x79, 0x5c, - 0xed, 0x8f, 0x0c, 0xda, 0x5a, 0x68, 0x3c, 0x78, 0x17, 0xe5, 0x62, 0x90, 0xca, 0x30, 0x11, 0x2d, - 0xe6, 0x22, 0x09, 0x82, 0x37, 0x49, 0x8f, 0x53, 0x05, 0x4e, 0x57, 0xfd, 0x3e, 0xdd, 0x24, 0x8f, - 0x63, 0x07, 0xd1, 0x18, 0x3e, 0x58, 0xf8, 0x42, 0x8c, 0xd8, 0xd4, 0x60, 0xe1, 0x58, 0x22, 0x3c, - 0xb8, 0x81, 0x32, 0x91, 0xdb, 0x53, 0x83, 0xf2, 0x91, 0x02, 0x64, 0xda, 0xab, 0x0e, 0x49, 0x1e, - 0xcc, 0x0f, 0xe1, 0x04, 0xae, 0x50, 0x54, 0xcd, 0xc8, 0xe4, 0x10, 0xf5, 0x93, 0xa6, 0x54, 0x3a, - 0x41, 0xf0, 0x01, 0xe9, 0x04, 0xee, 0x73, 0x08, 0xa9, 0xeb, 0x7b, 0x8b, 0x03, 0xb2, 0x7e, 0xd2, - 0x54, 0x1e, 0x92, 0x42, 0xe1, 0x3a, 0xda, 0x8a, 0x45, 0x88, 0x03, 0xe5, 0xac, 0x7c, 0xa0, 0x02, - 0xb7, 0xc8, 0xbc, 0x9b, 0x2c, 0xe2, 0xf1, 0x47, 0xa8, 0x40, 0xa3, 0x4e, 0x22, 0x76, 0x4e, 0x84, - 0x27, 0x77, 0xaa, 0xa5, 0x5d, 0x24, 0x8d, 0xab, 0xfd, 0x63, 0xa0, 0xdb, 0x27, 0xfe, 0xc8, 0xed, - 0x9e, 0xbf, 0x81, 0x47, 0xd4, 0xd7, 0x28, 0x1b, 0x46, 0x23, 0x88, 0x2f, 0xc5, 0x87, 0x2b, 0x5f, - 0x0a, 0x99, 0x21, 0x89, 0x46, 0xa0, 0x2b, 0x9c, 0xaf, 0x28, 0x91, 0x84, 0xf8, 0x00, 0x21, 0x7f, - 0xec, 0x32, 0xd1, 0xb8, 0xe2, 0x8a, 0x7d, 0x20, 0xf2, 0x48, 0xac, 0xfa, 0x25, 0x93, 0x82, 0xd6, - 0xfe, 0x34, 0x10, 0x92, 0xec, 0x6f, 0xa0, 0x29, 0x9c, 0xce, 0x37, 0x05, 0xfb, 0x86, 0xe7, 0x5f, - 0xd2, 0x15, 0x5e, 0x64, 0xe2, 0x23, 0x70, 0x49, 0xf4, 0x4b, 0xd5, 0x58, 0xe5, 0xa5, 0x5a, 0x41, - 0x59, 0xfe, 0xe6, 0x88, 0xdb, 0x42, 0x9e, 0x23, 0xf9, 0x7b, 0x84, 0x12, 0x69, 0xc7, 0x16, 0x42, - 0xfc, 0x43, 0xd4, 0x76, 0xac, 0x6c, 0x91, 0x2b, 0xdb, 0x4e, 0xac, 0x24, 0x85, 0xe0, 0x84, 0xfc, - 0x45, 0x47, 0xcd, 0x75, 0x4d, 0xc8, 0x1f, 0x7a, 0x94, 0x48, 0x3b, 0x1e, 0xa4, 0x9b, 0x51, 0x56, - 0x08, 0x71, 0xb0, 0xb2, 0x10, 0xf3, 0xdd, 0x4f, 0x77, 0x87, 0xd7, 0x76, 0x32, 0x0b, 0xa1, 0xa4, - 0x55, 0x50, 0xf3, 0xb6, 0x4e, 0x3d, 0xe9, 0x25, 0x94, 0xa4, 0x10, 0xf8, 0x53, 0xb4, 0xe5, 0xf9, - 0x5e, 0x4c, 0xd5, 0x26, 0x47, 0xd4, 0xdc, 0x10, 0x41, 0xf7, 0xf8, 0x0d, 0x3c, 0x9e, 0x77, 0x91, - 0x45, 0xec, 0x42, 0x0d, 0xe6, 0x56, 0xae, 0xc1, 0xc6, 0xc3, 0x8b, 0xcb, 0xf2, 0xda, 0xcb, 0xcb, - 0xf2, 0xda, 0xab, 0xcb, 0xf2, 0xda, 0xcf, 0xb3, 0xb2, 0x71, 0x31, 0x2b, 0x1b, 0x2f, 0x67, 0x65, - 0xe3, 0xd5, 0xac, 0x6c, 0xfc, 0x35, 0x2b, 0x1b, 0xbf, 0xfe, 0x5d, 0x5e, 0xfb, 0x66, 0x43, 0x69, - 0xf0, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4f, 0xae, 0x4a, 0x9d, 0x6e, 0x0e, 0x00, 0x00, -} - func (m *Event) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -355,201 +110,174 @@ func (m *Event) Marshal() (dAtA []byte, err error) { } func (m *Event) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Event) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.UserAgent) - copy(dAtA[i:], m.UserAgent) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x92 - if len(m.Annotations) > 0 { - keysForAnnotations := make([]string, 0, len(m.Annotations)) - for k := range m.Annotations { - keysForAnnotations = append(keysForAnnotations, string(k)) - } - github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) - for iNdEx := len(keysForAnnotations) - 1; iNdEx >= 0; iNdEx-- { - v := m.Annotations[string(keysForAnnotations[iNdEx])] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintGenerated(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(keysForAnnotations[iNdEx]) - copy(dAtA[i:], keysForAnnotations[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(keysForAnnotations[iNdEx]))) - i-- - dAtA[i] = 0xa - i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x8a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n1, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - { - size, err := m.StageTimestamp.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n1 + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Timestamp.Size())) + n2, err := m.Timestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x82 - { - size, err := m.RequestReceivedTimestamp.MarshalToSizedBuffer(dAtA[:i]) + i += n2 + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) + i += copy(dAtA[i:], m.AuditID) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) + i += copy(dAtA[i:], m.Stage) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) + i += copy(dAtA[i:], m.RequestURI) + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) + i += copy(dAtA[i:], m.Verb) + dAtA[i] = 0x42 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.User.Size())) + n3, err := m.User.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + if m.ImpersonatedUser != nil { + dAtA[i] = 0x4a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ImpersonatedUser.Size())) + n4, err := m.ImpersonatedUser.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x7a - if m.ResponseObject != nil { - { - size, err := m.ResponseObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x72 - } - if m.RequestObject != nil { - { - size, err := m.RequestObject.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x6a + i += n4 } - if m.ResponseStatus != nil { - { - size, err := m.ResponseStatus.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.SourceIPs) > 0 { + for _, s := range m.SourceIPs { + dAtA[i] = 0x52 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } - i-- - dAtA[i] = 0x62 } if m.ObjectRef != nil { - { - size, err := m.ObjectRef.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- dAtA[i] = 0x5a - } - if len(m.SourceIPs) > 0 { - for iNdEx := len(m.SourceIPs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.SourceIPs[iNdEx]) - copy(dAtA[i:], m.SourceIPs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.SourceIPs[iNdEx]))) - i-- - dAtA[i] = 0x52 - } - } - if m.ImpersonatedUser != nil { - { - size, err := m.ImpersonatedUser.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectRef.Size())) + n5, err := m.ObjectRef.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x4a + i += n5 } - { - size, err := m.User.MarshalToSizedBuffer(dAtA[:i]) + if m.ResponseStatus != nil { + dAtA[i] = 0x62 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseStatus.Size())) + n6, err := m.ResponseStatus.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n6 } - i-- - dAtA[i] = 0x42 - i -= len(m.Verb) - copy(dAtA[i:], m.Verb) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verb))) - i-- - dAtA[i] = 0x3a - i -= len(m.RequestURI) - copy(dAtA[i:], m.RequestURI) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.RequestURI))) - i-- - dAtA[i] = 0x32 - i -= len(m.Stage) - copy(dAtA[i:], m.Stage) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Stage))) - i-- - dAtA[i] = 0x2a - i -= len(m.AuditID) - copy(dAtA[i:], m.AuditID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.AuditID))) - i-- - dAtA[i] = 0x22 - { - size, err := m.Timestamp.MarshalToSizedBuffer(dAtA[:i]) + if m.RequestObject != nil { + dAtA[i] = 0x6a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestObject.Size())) + n7, err := m.RequestObject.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n7 } - i-- - dAtA[i] = 0x1a - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0x12 - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) + if m.ResponseObject != nil { + dAtA[i] = 0x72 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ResponseObject.Size())) + n8, err := m.ResponseObject.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n8 } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + dAtA[i] = 0x7a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.RequestReceivedTimestamp.Size())) + n9, err := m.RequestReceivedTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n9 + dAtA[i] = 0x82 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.StageTimestamp.Size())) + n10, err := m.StageTimestamp.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n10 + if len(m.Annotations) > 0 { + keysForAnnotations := make([]string, 0, len(m.Annotations)) + for k := range m.Annotations { + keysForAnnotations = append(keysForAnnotations, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + for _, k := range keysForAnnotations { + dAtA[i] = 0x8a + i++ + dAtA[i] = 0x1 + i++ + v := m.Annotations[string(k)] + mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + i = encodeVarintGenerated(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } + dAtA[i] = 0x92 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserAgent))) + i += copy(dAtA[i:], m.UserAgent) + return i, nil } func (m *EventList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -557,46 +285,37 @@ func (m *EventList) Marshal() (dAtA []byte, err error) { } func (m *EventList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n11, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n11 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *GroupResources) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -604,45 +323,51 @@ func (m *GroupResources) Marshal() (dAtA []byte, err error) { } func (m *GroupResources) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GroupResources) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.ResourceNames) > 0 { - for iNdEx := len(m.ResourceNames) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ResourceNames[iNdEx]) - copy(dAtA[i:], m.ResourceNames[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceNames[iNdEx]))) - i-- - dAtA[i] = 0x1a - } - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i += copy(dAtA[i:], m.Group) if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Resources[iNdEx]) - copy(dAtA[i:], m.Resources[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resources[iNdEx]))) - i-- + for _, s := range m.Resources { dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Group) - copy(dAtA[i:], m.Group) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + if len(m.ResourceNames) > 0 { + for _, s := range m.ResourceNames { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil } func (m *ObjectReference) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -650,62 +375,49 @@ func (m *ObjectReference) Marshal() (dAtA []byte, err error) { } func (m *ObjectReference) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ObjectReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.Subresource) - copy(dAtA[i:], m.Subresource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) - i-- - dAtA[i] = 0x42 - i -= len(m.ResourceVersion) - copy(dAtA[i:], m.ResourceVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) - i-- - dAtA[i] = 0x3a - i -= len(m.APIVersion) - copy(dAtA[i:], m.APIVersion) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) - i-- - dAtA[i] = 0x32 - i -= len(m.APIGroup) - copy(dAtA[i:], m.APIGroup) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIGroup))) - i-- - dAtA[i] = 0x2a - i -= len(m.UID) - copy(dAtA[i:], m.UID) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) - i-- - dAtA[i] = 0x22 - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x1a - i -= len(m.Namespace) - copy(dAtA[i:], m.Namespace) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) - i-- - dAtA[i] = 0x12 - i -= len(m.Resource) - copy(dAtA[i:], m.Resource) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) - i-- dAtA[i] = 0xa - return len(dAtA) - i, nil + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) + i += copy(dAtA[i:], m.Resource) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i += copy(dAtA[i:], m.Namespace) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.UID))) + i += copy(dAtA[i:], m.UID) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIGroup))) + i += copy(dAtA[i:], m.APIGroup) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.APIVersion))) + i += copy(dAtA[i:], m.APIVersion) + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ResourceVersion))) + i += copy(dAtA[i:], m.ResourceVersion) + dAtA[i] = 0x42 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subresource))) + i += copy(dAtA[i:], m.Subresource) + return i, nil } func (m *Policy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -713,55 +425,52 @@ func (m *Policy) Marshal() (dAtA []byte, err error) { } func (m *Policy) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Policy) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x1a - } + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n12, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } + i += n12 if len(m.Rules) > 0 { - for iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Rules[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Rules { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -769,46 +478,37 @@ func (m *PolicyList) Marshal() (dAtA []byte, err error) { } func (m *PolicyList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n13, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n13 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PolicyRule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -816,106 +516,129 @@ func (m *PolicyRule) Marshal() (dAtA []byte, err error) { } func (m *PolicyRule) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PolicyRule) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if len(m.OmitStages) > 0 { - for iNdEx := len(m.OmitStages) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.OmitStages[iNdEx]) - copy(dAtA[i:], m.OmitStages[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.OmitStages[iNdEx]))) - i-- - dAtA[i] = 0x42 + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) + i += copy(dAtA[i:], m.Level) + if len(m.Users) > 0 { + for _, s := range m.Users { + dAtA[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.NonResourceURLs) > 0 { - for iNdEx := len(m.NonResourceURLs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.NonResourceURLs[iNdEx]) - copy(dAtA[i:], m.NonResourceURLs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.NonResourceURLs[iNdEx]))) - i-- - dAtA[i] = 0x3a + if len(m.UserGroups) > 0 { + for _, s := range m.UserGroups { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Namespaces) > 0 { - for iNdEx := len(m.Namespaces) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Namespaces[iNdEx]) - copy(dAtA[i:], m.Namespaces[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespaces[iNdEx]))) - i-- - dAtA[i] = 0x32 + if len(m.Verbs) > 0 { + for _, s := range m.Verbs { + dAtA[i] = 0x22 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } if len(m.Resources) > 0 { - for iNdEx := len(m.Resources) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Resources[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Resources { dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - if len(m.Verbs) > 0 { - for iNdEx := len(m.Verbs) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Verbs[iNdEx]) - copy(dAtA[i:], m.Verbs[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Verbs[iNdEx]))) - i-- - dAtA[i] = 0x22 + if len(m.Namespaces) > 0 { + for _, s := range m.Namespaces { + dAtA[i] = 0x32 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.UserGroups) > 0 { - for iNdEx := len(m.UserGroups) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.UserGroups[iNdEx]) - copy(dAtA[i:], m.UserGroups[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.UserGroups[iNdEx]))) - i-- - dAtA[i] = 0x1a + if len(m.NonResourceURLs) > 0 { + for _, s := range m.NonResourceURLs { + dAtA[i] = 0x3a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - if len(m.Users) > 0 { - for iNdEx := len(m.Users) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Users[iNdEx]) - copy(dAtA[i:], m.Users[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Users[iNdEx]))) - i-- - dAtA[i] = 0x12 + if len(m.OmitStages) > 0 { + for _, s := range m.OmitStages { + dAtA[i] = 0x42 + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) } } - i -= len(m.Level) - copy(dAtA[i:], m.Level) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Level))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { - offset -= sovGenerated(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *Event) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -978,9 +701,6 @@ func (m *Event) Size() (n int) { } func (m *EventList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -995,9 +715,6 @@ func (m *EventList) Size() (n int) { } func (m *GroupResources) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Group) @@ -1018,9 +735,6 @@ func (m *GroupResources) Size() (n int) { } func (m *ObjectReference) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Resource) @@ -1043,9 +757,6 @@ func (m *ObjectReference) Size() (n int) { } func (m *Policy) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -1066,9 +777,6 @@ func (m *Policy) Size() (n int) { } func (m *PolicyList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -1083,9 +791,6 @@ func (m *PolicyList) Size() (n int) { } func (m *PolicyRule) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Level) @@ -1136,7 +841,14 @@ func (m *PolicyRule) Size() (n int) { } func sovGenerated(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -1156,22 +868,22 @@ func (this *Event) String() string { } mapStringForAnnotations += "}" s := strings.Join([]string{`&Event{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, `Level:` + fmt.Sprintf("%v", this.Level) + `,`, - `Timestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Timestamp), "Time", "v1.Time", 1), `&`, ``, 1) + `,`, + `Timestamp:` + strings.Replace(strings.Replace(this.Timestamp.String(), "Time", "k8s_io_apimachinery_pkg_apis_meta_v1.Time", 1), `&`, ``, 1) + `,`, `AuditID:` + fmt.Sprintf("%v", this.AuditID) + `,`, `Stage:` + fmt.Sprintf("%v", this.Stage) + `,`, `RequestURI:` + fmt.Sprintf("%v", this.RequestURI) + `,`, `Verb:` + fmt.Sprintf("%v", this.Verb) + `,`, - `User:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.User), "UserInfo", "v11.UserInfo", 1), `&`, ``, 1) + `,`, - `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "v11.UserInfo", 1) + `,`, + `User:` + strings.Replace(strings.Replace(this.User.String(), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1), `&`, ``, 1) + `,`, + `ImpersonatedUser:` + strings.Replace(fmt.Sprintf("%v", this.ImpersonatedUser), "UserInfo", "k8s_io_api_authentication_v1.UserInfo", 1) + `,`, `SourceIPs:` + fmt.Sprintf("%v", this.SourceIPs) + `,`, - `ObjectRef:` + strings.Replace(this.ObjectRef.String(), "ObjectReference", "ObjectReference", 1) + `,`, - `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "v1.Status", 1) + `,`, - `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "runtime.Unknown", 1) + `,`, - `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "runtime.Unknown", 1) + `,`, - `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.RequestReceivedTimestamp), "MicroTime", "v1.MicroTime", 1), `&`, ``, 1) + `,`, - `StageTimestamp:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.StageTimestamp), "MicroTime", "v1.MicroTime", 1), `&`, ``, 1) + `,`, + `ObjectRef:` + strings.Replace(fmt.Sprintf("%v", this.ObjectRef), "ObjectReference", "ObjectReference", 1) + `,`, + `ResponseStatus:` + strings.Replace(fmt.Sprintf("%v", this.ResponseStatus), "Status", "k8s_io_apimachinery_pkg_apis_meta_v1.Status", 1) + `,`, + `RequestObject:` + strings.Replace(fmt.Sprintf("%v", this.RequestObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `ResponseObject:` + strings.Replace(fmt.Sprintf("%v", this.ResponseObject), "Unknown", "k8s_io_apimachinery_pkg_runtime.Unknown", 1) + `,`, + `RequestReceivedTimestamp:` + strings.Replace(strings.Replace(this.RequestReceivedTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, + `StageTimestamp:` + strings.Replace(strings.Replace(this.StageTimestamp.String(), "MicroTime", "k8s_io_apimachinery_pkg_apis_meta_v1.MicroTime", 1), `&`, ``, 1) + `,`, `Annotations:` + mapStringForAnnotations + `,`, `UserAgent:` + fmt.Sprintf("%v", this.UserAgent) + `,`, `}`, @@ -1182,14 +894,9 @@ func (this *EventList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Event{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Event", "Event", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&EventList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Event", "Event", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1227,14 +934,9 @@ func (this *Policy) String() string { if this == nil { return "nil" } - repeatedStringForRules := "[]PolicyRule{" - for _, f := range this.Rules { - repeatedStringForRules += strings.Replace(strings.Replace(f.String(), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + "," - } - repeatedStringForRules += "}" s := strings.Join([]string{`&Policy{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, - `Rules:` + repeatedStringForRules + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Rules:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Rules), "PolicyRule", "PolicyRule", 1), `&`, ``, 1) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, `}`, }, "") @@ -1244,14 +946,9 @@ func (this *PolicyList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Policy{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Policy", "Policy", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&PolicyList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Policy", "Policy", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1260,17 +957,12 @@ func (this *PolicyRule) String() string { if this == nil { return "nil" } - repeatedStringForResources := "[]GroupResources{" - for _, f := range this.Resources { - repeatedStringForResources += strings.Replace(strings.Replace(f.String(), "GroupResources", "GroupResources", 1), `&`, ``, 1) + "," - } - repeatedStringForResources += "}" s := strings.Join([]string{`&PolicyRule{`, `Level:` + fmt.Sprintf("%v", this.Level) + `,`, `Users:` + fmt.Sprintf("%v", this.Users) + `,`, `UserGroups:` + fmt.Sprintf("%v", this.UserGroups) + `,`, `Verbs:` + fmt.Sprintf("%v", this.Verbs) + `,`, - `Resources:` + repeatedStringForResources + `,`, + `Resources:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Resources), "GroupResources", "GroupResources", 1), `&`, ``, 1) + `,`, `Namespaces:` + fmt.Sprintf("%v", this.Namespaces) + `,`, `NonResourceURLs:` + fmt.Sprintf("%v", this.NonResourceURLs) + `,`, `OmitStages:` + fmt.Sprintf("%v", this.OmitStages) + `,`, @@ -1301,7 +993,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1329,7 +1021,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1338,9 +1030,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1362,7 +1051,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1372,9 +1061,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1394,7 +1080,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1403,9 +1089,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1427,7 +1110,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1437,9 +1120,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1459,7 +1139,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1469,9 +1149,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1491,7 +1168,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1501,9 +1178,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1523,7 +1197,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1533,9 +1207,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1555,7 +1226,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1564,9 +1235,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1588,7 +1256,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1597,14 +1265,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ImpersonatedUser == nil { - m.ImpersonatedUser = &v11.UserInfo{} + m.ImpersonatedUser = &k8s_io_api_authentication_v1.UserInfo{} } if err := m.ImpersonatedUser.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1624,7 +1289,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1634,9 +1299,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1656,7 +1318,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1665,9 +1327,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1692,7 +1351,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1701,14 +1360,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseStatus == nil { - m.ResponseStatus = &v1.Status{} + m.ResponseStatus = &k8s_io_apimachinery_pkg_apis_meta_v1.Status{} } if err := m.ResponseStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1728,7 +1384,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1737,14 +1393,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.RequestObject == nil { - m.RequestObject = &runtime.Unknown{} + m.RequestObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.RequestObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1764,7 +1417,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1773,14 +1426,11 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.ResponseObject == nil { - m.ResponseObject = &runtime.Unknown{} + m.ResponseObject = &k8s_io_apimachinery_pkg_runtime.Unknown{} } if err := m.ResponseObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -1800,7 +1450,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1809,9 +1459,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1833,7 +1480,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1842,9 +1489,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1866,7 +1510,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1875,9 +1519,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1898,7 +1539,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1915,7 +1556,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift + stringLenmapkey |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1925,9 +1566,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1944,7 +1582,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift + stringLenmapvalue |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1954,9 +1592,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1993,7 +1628,7 @@ func (m *Event) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2003,9 +1638,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2020,9 +1652,6 @@ func (m *Event) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2050,7 +1679,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2078,7 +1707,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2087,9 +1716,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2111,7 +1737,7 @@ func (m *EventList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2120,9 +1746,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2140,9 +1763,6 @@ func (m *EventList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2170,7 +1790,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2198,7 +1818,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2208,9 +1828,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2230,7 +1847,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2240,9 +1857,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2262,7 +1876,7 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2272,9 +1886,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2289,9 +1900,6 @@ func (m *GroupResources) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2319,7 +1927,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2347,7 +1955,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2357,9 +1965,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2379,7 +1984,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2389,9 +1994,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2411,7 +2013,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2421,9 +2023,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2443,7 +2042,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2453,9 +2052,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2475,7 +2071,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2485,9 +2081,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2507,7 +2100,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2517,9 +2110,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2539,7 +2129,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2549,9 +2139,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2571,7 +2158,7 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2581,9 +2168,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2598,9 +2182,6 @@ func (m *ObjectReference) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2628,7 +2209,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2656,7 +2237,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2665,9 +2246,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2689,7 +2267,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2698,9 +2276,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2723,7 +2298,7 @@ func (m *Policy) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2733,9 +2308,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2750,9 +2322,6 @@ func (m *Policy) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2780,7 +2349,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2808,7 +2377,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2817,9 +2386,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2841,7 +2407,7 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2850,9 +2416,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2870,9 +2433,6 @@ func (m *PolicyList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2900,7 +2460,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2928,7 +2488,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2938,9 +2498,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2960,7 +2517,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2970,9 +2527,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2992,7 +2546,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3002,9 +2556,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3024,7 +2575,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3034,9 +2585,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3056,7 +2604,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -3065,9 +2613,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3090,7 +2635,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3100,9 +2645,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3122,7 +2664,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3132,9 +2674,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3154,7 +2693,7 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -3164,9 +2703,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -3181,9 +2717,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -3199,7 +2732,6 @@ func (m *PolicyRule) Unmarshal(dAtA []byte) error { func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -3231,8 +2763,10 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -3249,34 +2783,141 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + iNdEx += length if length < 0 { return 0, ErrInvalidLengthGenerated } - iNdEx += length + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenerated + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipGenerated(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next } - depth-- + return iNdEx, nil + case 4: + return iNdEx, nil case 5: iNdEx += 4 + return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") ) + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/generated.proto", fileDescriptorGenerated) +} + +var fileDescriptorGenerated = []byte{ + // 1278 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xd6, 0x71, 0x63, 0x8f, 0x1b, 0xc7, 0x9d, 0x56, 0x74, 0x95, 0x83, 0x6d, 0x8c, 0x04, + 0x11, 0xa4, 0xbb, 0x4d, 0x28, 0x24, 0x42, 0x02, 0x64, 0xab, 0x15, 0x58, 0x4a, 0x43, 0x34, 0x8e, + 0x2b, 0x04, 0x1c, 0x58, 0xdb, 0x2f, 0xf6, 0x62, 0x7b, 0x77, 0xd9, 0x99, 0x35, 0xca, 0x8d, 0x2f, + 0x80, 0xc4, 0x9d, 0xcf, 0xc0, 0x85, 0x0f, 0x50, 0x71, 0xcc, 0xb1, 0xc7, 0x9e, 0x2c, 0x62, 0xbe, + 0x45, 0x24, 0x24, 0x34, 0x7f, 0x76, 0x67, 0xed, 0xd4, 0xc2, 0xe1, 0xd0, 0xdb, 0xce, 0x7b, 0xbf, + 0xf7, 0x7b, 0x6f, 0xde, 0xbe, 0x3f, 0x83, 0x4e, 0x86, 0x87, 0xd4, 0x72, 0x7d, 0x7b, 0x18, 0x75, + 0x20, 0xf4, 0x80, 0x01, 0xb5, 0x27, 0xe0, 0xf5, 0xfc, 0xd0, 0x56, 0x0a, 0x27, 0x70, 0x29, 0x84, + 0x13, 0x08, 0xed, 0x60, 0xd8, 0x17, 0x27, 0xdb, 0x89, 0x7a, 0x2e, 0xb3, 0x27, 0x7b, 0x1d, 0x60, + 0xce, 0x9e, 0xdd, 0x07, 0x0f, 0x42, 0x87, 0x41, 0xcf, 0x0a, 0x42, 0x9f, 0xf9, 0xf8, 0x3d, 0x69, + 0x68, 0x25, 0x86, 0x56, 0x30, 0xec, 0x8b, 0x93, 0x25, 0x0c, 0x2d, 0x65, 0xb8, 0xfd, 0xb0, 0xef, + 0xb2, 0x41, 0xd4, 0xb1, 0xba, 0xfe, 0xd8, 0xee, 0xfb, 0x7d, 0xdf, 0x16, 0xf6, 0x9d, 0xe8, 0x4c, + 0x9c, 0xc4, 0x41, 0x7c, 0x49, 0xde, 0xed, 0x5d, 0x1d, 0x90, 0xed, 0x44, 0x6c, 0x00, 0x1e, 0x73, + 0xbb, 0x0e, 0x73, 0x7d, 0xcf, 0x9e, 0x5c, 0x8b, 0x62, 0xfb, 0xb1, 0x46, 0x8f, 0x9d, 0xee, 0xc0, + 0xf5, 0x20, 0x3c, 0xd7, 0x37, 0x18, 0x03, 0x73, 0x5e, 0x67, 0x65, 0x2f, 0xb3, 0x0a, 0x23, 0x8f, + 0xb9, 0x63, 0xb8, 0x66, 0xf0, 0xf1, 0x7f, 0x19, 0xd0, 0xee, 0x00, 0xc6, 0xce, 0xa2, 0x5d, 0xed, + 0xf7, 0x3b, 0x28, 0xfb, 0x74, 0x02, 0x1e, 0xc3, 0xdf, 0xa3, 0x1c, 0x8f, 0xa6, 0xe7, 0x30, 0xc7, + 0x34, 0xaa, 0xc6, 0x4e, 0x61, 0xff, 0x91, 0xa5, 0x33, 0x98, 0x90, 0xea, 0x24, 0x72, 0xb4, 0x35, + 0xd9, 0xb3, 0xbe, 0xea, 0xfc, 0x00, 0x5d, 0xf6, 0x0c, 0x98, 0xd3, 0xc0, 0x17, 0xd3, 0xca, 0xda, + 0x6c, 0x5a, 0x41, 0x5a, 0x46, 0x12, 0x56, 0xbc, 0x8b, 0xb2, 0x23, 0x98, 0xc0, 0xc8, 0xbc, 0x55, + 0x35, 0x76, 0xf2, 0x8d, 0xb7, 0x14, 0x38, 0x7b, 0xc4, 0x85, 0x57, 0xf1, 0x07, 0x91, 0x20, 0xfc, + 0x2d, 0xca, 0xf3, 0xc0, 0x29, 0x73, 0xc6, 0x81, 0x99, 0x11, 0x01, 0xbd, 0xbf, 0x5a, 0x40, 0xa7, + 0xee, 0x18, 0x1a, 0x77, 0x15, 0x7b, 0xfe, 0x34, 0x26, 0x21, 0x9a, 0x0f, 0x1f, 0xa3, 0x0d, 0x51, + 0x03, 0xcd, 0x27, 0xe6, 0xba, 0x08, 0xe6, 0xb1, 0x82, 0x6f, 0xd4, 0xa5, 0xf8, 0x6a, 0x5a, 0x79, + 0x7b, 0x59, 0x4a, 0xd9, 0x79, 0x00, 0xd4, 0x6a, 0x37, 0x9f, 0x90, 0x98, 0x84, 0x5f, 0x8d, 0x32, + 0xa7, 0x0f, 0x66, 0x76, 0xfe, 0x6a, 0x2d, 0x2e, 0xbc, 0x8a, 0x3f, 0x88, 0x04, 0xe1, 0x7d, 0x84, + 0x42, 0xf8, 0x31, 0x02, 0xca, 0xda, 0xa4, 0x69, 0xde, 0x16, 0x26, 0x49, 0xea, 0x48, 0xa2, 0x21, + 0x29, 0x14, 0xae, 0xa2, 0xf5, 0x09, 0x84, 0x1d, 0x73, 0x43, 0xa0, 0xef, 0x28, 0xf4, 0xfa, 0x73, + 0x08, 0x3b, 0x44, 0x68, 0xf0, 0x97, 0x68, 0x3d, 0xa2, 0x10, 0x9a, 0x39, 0x91, 0xab, 0x77, 0x53, + 0xb9, 0xb2, 0xe6, 0xcb, 0x94, 0xe7, 0xa8, 0x4d, 0x21, 0x6c, 0x7a, 0x67, 0xbe, 0x66, 0xe2, 0x12, + 0x22, 0x18, 0xf0, 0x00, 0x95, 0xdc, 0x71, 0x00, 0x21, 0xf5, 0x3d, 0x5e, 0x2a, 0x5c, 0x63, 0xe6, + 0x6f, 0xc4, 0x7a, 0x7f, 0x36, 0xad, 0x94, 0x9a, 0x0b, 0x1c, 0xe4, 0x1a, 0x2b, 0xfe, 0x00, 0xe5, + 0xa9, 0x1f, 0x85, 0x5d, 0x68, 0x9e, 0x50, 0x13, 0x55, 0x33, 0x3b, 0xf9, 0xc6, 0x26, 0xff, 0x69, + 0xad, 0x58, 0x48, 0xb4, 0x1e, 0x03, 0xca, 0xfb, 0xa2, 0xae, 0x08, 0x9c, 0x99, 0x05, 0x11, 0xcf, + 0xa1, 0xb5, 0x62, 0x93, 0xab, 0x2a, 0x25, 0x70, 0x06, 0x21, 0x78, 0x5d, 0x90, 0x6e, 0x12, 0x21, + 0xd1, 0xcc, 0x78, 0x80, 0x8a, 0x21, 0xd0, 0xc0, 0xf7, 0x28, 0xb4, 0x98, 0xc3, 0x22, 0x6a, 0xde, + 0x11, 0xbe, 0x76, 0x57, 0xab, 0x3e, 0x69, 0xd3, 0xc0, 0xb3, 0x69, 0xa5, 0x48, 0xe6, 0x78, 0xc8, + 0x02, 0x2f, 0x76, 0xd0, 0xa6, 0xfa, 0xc3, 0x32, 0x10, 0x73, 0x53, 0x38, 0xda, 0x59, 0xea, 0x48, + 0x35, 0xb3, 0xd5, 0xf6, 0x86, 0x9e, 0xff, 0x93, 0xd7, 0xb8, 0x3b, 0x9b, 0x56, 0x36, 0x49, 0x9a, + 0x82, 0xcc, 0x33, 0xe2, 0x9e, 0xbe, 0x8c, 0xf2, 0x51, 0xbc, 0xa1, 0x8f, 0xb9, 0x8b, 0x28, 0x27, + 0x0b, 0x9c, 0xf8, 0x17, 0x03, 0x99, 0xca, 0x2f, 0x81, 0x2e, 0xb8, 0x13, 0xe8, 0x25, 0x6d, 0x67, + 0x6e, 0x09, 0x87, 0xf6, 0x6a, 0xd9, 0x7b, 0xe6, 0x76, 0x43, 0x5f, 0x34, 0x70, 0x55, 0x15, 0xa6, + 0x49, 0x96, 0x10, 0x93, 0xa5, 0x2e, 0xb1, 0x8f, 0x8a, 0xa2, 0xd3, 0x74, 0x10, 0xa5, 0xff, 0x17, + 0x44, 0xdc, 0xc8, 0xc5, 0xd6, 0x1c, 0x1d, 0x59, 0xa0, 0xc7, 0x13, 0x54, 0x70, 0x3c, 0xcf, 0x67, + 0xa2, 0x13, 0xa8, 0x79, 0xb7, 0x9a, 0xd9, 0x29, 0xec, 0x7f, 0xbe, 0x72, 0x71, 0x8a, 0x09, 0x6c, + 0xd5, 0x35, 0xc3, 0x53, 0x8f, 0x85, 0xe7, 0x8d, 0x7b, 0xca, 0x7b, 0x21, 0xa5, 0x21, 0x69, 0x47, + 0xd8, 0x46, 0x79, 0xde, 0xb1, 0xf5, 0x3e, 0x78, 0xcc, 0xc4, 0x62, 0x34, 0x24, 0x83, 0xaf, 0x1d, + 0x2b, 0x88, 0xc6, 0x6c, 0x7f, 0x86, 0x4a, 0x8b, 0x6e, 0x70, 0x09, 0x65, 0x86, 0x70, 0x2e, 0x86, + 0x7e, 0x9e, 0xf0, 0x4f, 0x7c, 0x1f, 0x65, 0x27, 0xce, 0x28, 0x02, 0x39, 0xa9, 0x89, 0x3c, 0x7c, + 0x72, 0xeb, 0xd0, 0xa8, 0xbd, 0x30, 0x50, 0x5e, 0x44, 0x7b, 0xe4, 0x52, 0x86, 0xbf, 0xbb, 0xb6, + 0x33, 0xac, 0xd5, 0x32, 0xcc, 0xad, 0xc5, 0xc6, 0x28, 0xa9, 0x68, 0x73, 0xb1, 0x24, 0xb5, 0x2f, + 0x5a, 0x28, 0xeb, 0x32, 0x18, 0x53, 0xf3, 0x96, 0x48, 0xa7, 0x75, 0xb3, 0x74, 0x36, 0x36, 0xe3, + 0x21, 0xdc, 0xe4, 0x24, 0x44, 0x72, 0xd5, 0x7e, 0x33, 0x50, 0xf1, 0x8b, 0xd0, 0x8f, 0x02, 0x02, + 0x72, 0xb2, 0x50, 0xfc, 0x0e, 0xca, 0xf6, 0xb9, 0x44, 0x66, 0x40, 0xdb, 0x49, 0x98, 0xd4, 0xf1, + 0x49, 0x15, 0xc6, 0x16, 0x22, 0x20, 0x35, 0xa9, 0x12, 0x1a, 0xa2, 0xf5, 0xf8, 0x80, 0x37, 0xb6, + 0x3c, 0x1c, 0x3b, 0x63, 0xa0, 0x66, 0x46, 0x18, 0xa8, 0x76, 0x4d, 0x29, 0xc8, 0x3c, 0xae, 0xf6, + 0x47, 0x06, 0x6d, 0x2d, 0x4c, 0x2a, 0xbc, 0x8b, 0x72, 0x31, 0x48, 0x45, 0x98, 0x24, 0x2d, 0xe6, + 0x22, 0x09, 0x82, 0x57, 0x84, 0xc7, 0xa9, 0x02, 0xa7, 0xab, 0x7e, 0x9f, 0xae, 0x88, 0xe3, 0x58, + 0x41, 0x34, 0x86, 0x2f, 0x16, 0x7e, 0x10, 0x2b, 0x36, 0xb5, 0x58, 0x38, 0x96, 0x08, 0x0d, 0x6e, + 0xa0, 0x4c, 0xe4, 0xf6, 0xd4, 0xa2, 0x7c, 0xa4, 0x00, 0x99, 0xf6, 0xaa, 0x4b, 0x92, 0x1b, 0xf3, + 0x4b, 0x38, 0x81, 0x2b, 0x32, 0xaa, 0x76, 0x64, 0x72, 0x89, 0xfa, 0x49, 0x53, 0x66, 0x3a, 0x41, + 0xf0, 0x05, 0xe9, 0x04, 0xee, 0x73, 0x08, 0xa9, 0xeb, 0x7b, 0x8b, 0x0b, 0xb2, 0x7e, 0xd2, 0x54, + 0x1a, 0x92, 0x42, 0xe1, 0x3a, 0xda, 0x8a, 0x93, 0x10, 0x1b, 0xca, 0x5d, 0xf9, 0x40, 0x19, 0x6e, + 0x91, 0x79, 0x35, 0x59, 0xc4, 0xe3, 0x8f, 0x50, 0x81, 0x46, 0x9d, 0x24, 0xd9, 0x39, 0x61, 0x9e, + 0x34, 0x61, 0x4b, 0xab, 0x48, 0x1a, 0x57, 0xfb, 0xc7, 0x40, 0xb7, 0x4f, 0xfc, 0x91, 0xdb, 0x3d, + 0x7f, 0x03, 0x8f, 0xa8, 0xaf, 0x51, 0x36, 0x8c, 0x46, 0x10, 0x37, 0xc5, 0x87, 0x2b, 0x37, 0x85, + 0x8c, 0x90, 0x44, 0x23, 0xd0, 0x15, 0xce, 0x4f, 0x94, 0x48, 0x42, 0x7c, 0x80, 0x90, 0x3f, 0x76, + 0x99, 0x98, 0x74, 0x71, 0xc5, 0x3e, 0x10, 0x71, 0x24, 0x52, 0xfd, 0x92, 0x49, 0x41, 0x6b, 0x7f, + 0x1a, 0x08, 0x49, 0xf6, 0x37, 0x30, 0x14, 0x4e, 0xe7, 0x87, 0x82, 0x7d, 0xc3, 0xfb, 0x2f, 0x99, + 0x0a, 0x2f, 0x32, 0xf1, 0x15, 0x78, 0x4a, 0xf4, 0x4b, 0xd5, 0x58, 0xe5, 0xa5, 0x5a, 0x41, 0x59, + 0x3e, 0x60, 0xe3, 0xb1, 0x90, 0xe7, 0x48, 0x3e, 0x7c, 0x29, 0x91, 0x72, 0x6c, 0x21, 0xc4, 0x3f, + 0x44, 0x6d, 0xc7, 0x99, 0x2d, 0xf2, 0xcc, 0xb6, 0x13, 0x29, 0x49, 0x21, 0x38, 0x21, 0x7f, 0xd1, + 0x51, 0x73, 0x5d, 0x13, 0xf2, 0x87, 0x1e, 0x25, 0x52, 0x8e, 0x07, 0xe9, 0x61, 0x94, 0x15, 0x89, + 0x38, 0x58, 0x39, 0x11, 0xf3, 0xd3, 0x4f, 0x4f, 0x87, 0xd7, 0x4e, 0x32, 0x0b, 0xa1, 0x64, 0x54, + 0x50, 0xf3, 0xb6, 0x0e, 0x3d, 0x99, 0x25, 0x94, 0xa4, 0x10, 0xf8, 0x53, 0xb4, 0xe5, 0xf9, 0x5e, + 0x4c, 0xd5, 0x26, 0x47, 0xd4, 0xdc, 0x10, 0x46, 0xf7, 0x78, 0x07, 0x1e, 0xcf, 0xab, 0xc8, 0x22, + 0x76, 0xa1, 0x06, 0x73, 0x2b, 0xd7, 0x60, 0xe3, 0xe1, 0xc5, 0x65, 0x79, 0xed, 0xe5, 0x65, 0x79, + 0xed, 0xd5, 0x65, 0x79, 0xed, 0xe7, 0x59, 0xd9, 0xb8, 0x98, 0x95, 0x8d, 0x97, 0xb3, 0xb2, 0xf1, + 0x6a, 0x56, 0x36, 0xfe, 0x9a, 0x95, 0x8d, 0x5f, 0xff, 0x2e, 0xaf, 0x7d, 0xb3, 0xa1, 0x72, 0xf0, + 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0xe5, 0x7c, 0x52, 0x6e, 0x0e, 0x00, 0x00, +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go index 0aac32119e2..ca16088cfea 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.conversion.go @@ -23,8 +23,8 @@ package v1beta1 import ( unsafe "unsafe" - v1 "k8s.io/api/authentication/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + authenticationv1 "k8s.io/api/authentication/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" types "k8s.io/apimachinery/pkg/types" @@ -38,6 +38,16 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*Event)(nil), (*audit.Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_Event_To_audit_Event(a.(*Event), b.(*audit.Event), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*audit.Event)(nil), (*Event)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_audit_Event_To_v1beta1_Event(a.(*audit.Event), b.(*Event), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*EventList)(nil), (*audit.EventList)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_EventList_To_audit_EventList(a.(*EventList), b.(*audit.EventList), scope) }); err != nil { @@ -119,12 +129,15 @@ func autoConvert_v1beta1_Event_To_audit_Event(in *Event, out *audit.Event, s con out.Stage = audit.Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User - out.ImpersonatedUser = (*v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } + out.ImpersonatedUser = (*audit.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent out.ObjectRef = (*audit.ObjectReference)(unsafe.Pointer(in.ObjectRef)) - out.ResponseStatus = (*metav1.Status)(unsafe.Pointer(in.ResponseStatus)) + out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) out.RequestReceivedTimestamp = in.RequestReceivedTimestamp @@ -139,12 +152,15 @@ func autoConvert_audit_Event_To_v1beta1_Event(in *audit.Event, out *Event, s con out.Stage = Stage(in.Stage) out.RequestURI = in.RequestURI out.Verb = in.Verb - out.User = in.User - out.ImpersonatedUser = (*v1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) + // TODO: Inefficient conversion - can we improve it? + if err := s.Convert(&in.User, &out.User, 0); err != nil { + return err + } + out.ImpersonatedUser = (*authenticationv1.UserInfo)(unsafe.Pointer(in.ImpersonatedUser)) out.SourceIPs = *(*[]string)(unsafe.Pointer(&in.SourceIPs)) out.UserAgent = in.UserAgent out.ObjectRef = (*ObjectReference)(unsafe.Pointer(in.ObjectRef)) - out.ResponseStatus = (*metav1.Status)(unsafe.Pointer(in.ResponseStatus)) + out.ResponseStatus = (*v1.Status)(unsafe.Pointer(in.ResponseStatus)) out.RequestObject = (*runtime.Unknown)(unsafe.Pointer(in.RequestObject)) out.ResponseObject = (*runtime.Unknown)(unsafe.Pointer(in.ResponseObject)) out.RequestReceivedTimestamp = in.RequestReceivedTimestamp diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go index 5adbd5a78c0..e8f7adffd87 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/v1beta1/zz_generated.deepcopy.go @@ -97,7 +97,7 @@ func (in *Event) DeepCopyObject() runtime.Object { func (in *EventList) DeepCopyInto(out *EventList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Event, len(*in)) @@ -210,7 +210,7 @@ func (in *Policy) DeepCopyObject() runtime.Object { func (in *PolicyList) DeepCopyInto(out *PolicyList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Policy, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go b/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go index 0611c1ae5f1..397317f23b2 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go @@ -100,7 +100,7 @@ func validateResources(groupResources []audit.GroupResources, fldPath *field.Pat // The empty string represents the core API group. if len(groupResource.Group) != 0 { // Group names must be lower case and be valid DNS subdomains. - // reference: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md + // reference: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md // an error is returned for group name like rbac.authorization.k8s.io/v1beta1 // rbac.authorization.k8s.io is the valid one if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 { diff --git a/vendor/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go index a210f631b2d..70093df22fc 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go @@ -21,8 +21,7 @@ limitations under the License. package audit import ( - v1 "k8s.io/api/authentication/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -33,7 +32,7 @@ func (in *Event) DeepCopyInto(out *Event) { in.User.DeepCopyInto(&out.User) if in.ImpersonatedUser != nil { in, out := &in.ImpersonatedUser, &out.ImpersonatedUser - *out = new(v1.UserInfo) + *out = new(UserInfo) (*in).DeepCopyInto(*out) } if in.SourceIPs != nil { @@ -48,7 +47,7 @@ func (in *Event) DeepCopyInto(out *Event) { } if in.ResponseStatus != nil { in, out := &in.ResponseStatus, &out.ResponseStatus - *out = new(metav1.Status) + *out = new(v1.Status) (*in).DeepCopyInto(*out) } if in.RequestObject != nil { @@ -95,7 +94,7 @@ func (in *Event) DeepCopyObject() runtime.Object { func (in *EventList) DeepCopyInto(out *EventList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Event, len(*in)) @@ -124,6 +123,26 @@ func (in *EventList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ExtraValue) DeepCopyInto(out *ExtraValue) { + { + in := &in + *out = make(ExtraValue, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraValue. +func (in ExtraValue) DeepCopy() ExtraValue { + if in == nil { + return nil + } + out := new(ExtraValue) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupResources) DeepCopyInto(out *GroupResources) { *out = *in @@ -208,7 +227,7 @@ func (in *Policy) DeepCopyObject() runtime.Object { func (in *PolicyList) DeepCopyInto(out *PolicyList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Policy, len(*in)) @@ -289,3 +308,39 @@ func (in *PolicyRule) DeepCopy() *PolicyRule { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UserInfo) DeepCopyInto(out *UserInfo) { + *out = *in + if in.Groups != nil { + in, out := &in.Groups, &out.Groups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Extra != nil { + in, out := &in.Extra, &out.Extra + *out = make(map[string]ExtraValue, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(ExtraValue, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserInfo. +func (in *UserInfo) DeepCopy() *UserInfo { + if in == nil { + return nil + } + out := new(UserInfo) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/types.go b/vendor/k8s.io/apiserver/pkg/apis/config/types.go index 5dddc97f964..822806d7e5d 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/types.go @@ -17,11 +17,46 @@ limitations under the License. package config import ( - "fmt" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// LeaderElectionConfiguration defines the configuration of leader election +// clients for components that can run with leader election enabled. +type LeaderElectionConfiguration struct { + // leaderElect enables a leader election client to gain leadership + // before executing the main loop. Enable this when running replicated + // components for high availability. + LeaderElect bool + // leaseDuration is the duration that non-leader candidates will wait + // after observing a leadership renewal until attempting to acquire + // leadership of a led but unrenewed leader slot. This is effectively the + // maximum duration that a leader can be stopped before it is replaced + // by another candidate. This is only applicable if leader election is + // enabled. + LeaseDuration metav1.Duration + // renewDeadline is the interval between attempts by the acting master to + // renew a leadership slot before it stops leading. This must be less + // than or equal to the lease duration. This is only applicable if leader + // election is enabled. + RenewDeadline metav1.Duration + // retryPeriod is the duration the clients should wait between attempting + // acquisition and renewal of a leadership. This is only applicable if + // leader election is enabled. + RetryPeriod metav1.Duration + // resourceLock indicates the resource object type that will be used to lock + // during leader election cycles. + ResourceLock string +} + +// DebuggingConfiguration holds configuration for Debugging related features. +type DebuggingConfiguration struct { + // enableProfiling enables profiling via web interface host:port/debug/pprof/ + EnableProfiling bool + // enableContentionProfiling enables lock contention profiling, if + // enableProfiling is true. + EnableContentionProfiling bool +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // EncryptionConfiguration stores the complete configuration for encryption providers. @@ -76,11 +111,6 @@ type Key struct { Secret string } -// String implements Stringer interface in a log safe way. -func (k Key) String() string { - return fmt.Sprintf("Name: %s, Secret: [REDACTED]", k.Name) -} - // IdentityConfiguration is an empty struct to allow identity transformer in provider configuration. type IdentityConfiguration struct{} @@ -88,13 +118,9 @@ type IdentityConfiguration struct{} type KMSConfiguration struct { // name is the name of the KMS plugin to be used. Name string - // cachesize is the maximum number of secrets which are cached in memory. The default value is 1000. - // Set to a negative value to disable caching. + // cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000. // +optional - CacheSize *int32 + CacheSize int32 // endpoint is the gRPC server listening address, for example "unix:///var/run/kms-provider.sock". Endpoint string - // timeout for gRPC calls to kms-plugin (ex. 5s). The default is 3 seconds. - // +optional - Timeout *metav1.Duration } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults_test.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults_test.go deleted file mode 100644 index 0b1909fe57e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults_test.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2019 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 v1 - -import ( - "testing" - "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/google/go-cmp/cmp" -) - -func TestKMSProviderTimeoutDefaults(t *testing.T) { - testCases := []struct { - desc string - in *KMSConfiguration - want *KMSConfiguration - }{ - { - desc: "timeout not supplied", - in: &KMSConfiguration{}, - want: &KMSConfiguration{Timeout: defaultTimeout, CacheSize: &defaultCacheSize}, - }, - { - desc: "timeout supplied", - in: &KMSConfiguration{Timeout: &v1.Duration{Duration: 1 * time.Minute}}, - want: &KMSConfiguration{Timeout: &v1.Duration{Duration: 1 * time.Minute}, CacheSize: &defaultCacheSize}, - }, - } - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - SetDefaults_KMSConfiguration(tt.in) - if d := cmp.Diff(tt.want, tt.in); d != "" { - t.Fatalf("KMS Provider mismatch (-want +got):\n%s", d) - } - }) - } -} - -func TestKMSProviderCacheDefaults(t *testing.T) { - var ( - zero int32 = 0 - ten int32 = 10 - ) - - testCases := []struct { - desc string - in *KMSConfiguration - want *KMSConfiguration - }{ - { - desc: "cache size not supplied", - in: &KMSConfiguration{}, - want: &KMSConfiguration{Timeout: defaultTimeout, CacheSize: &defaultCacheSize}, - }, - { - desc: "cache of zero size supplied", - in: &KMSConfiguration{CacheSize: &zero}, - want: &KMSConfiguration{Timeout: defaultTimeout, CacheSize: &zero}, - }, - { - desc: "positive cache size supplied", - in: &KMSConfiguration{CacheSize: &ten}, - want: &KMSConfiguration{Timeout: defaultTimeout, CacheSize: &ten}, - }, - } - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - SetDefaults_KMSConfiguration(tt.in) - if d := cmp.Diff(tt.want, tt.in); d != "" { - t.Fatalf("KMS Provider mismatch (-want +got):\n%s", d) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/register.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/register.go index 32b5634c44e..2e3ecfff2ea 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/register.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1/register.go @@ -40,7 +40,6 @@ func init() { // generated functions takes place in the generated files. The separation // makes the code compile even when the generated files are missing. localSchemeBuilder.Register(addKnownTypes) - localSchemeBuilder.Register(addDefaultingFuncs) } func addKnownTypes(scheme *runtime.Scheme) error { diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/types.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/types.go index d7d68d2584d..e2c123d1dc2 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1/types.go @@ -16,11 +16,7 @@ limitations under the License. package v1 -import ( - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -76,11 +72,6 @@ type Key struct { Secret string `json:"secret"` } -// String implements Stringer interface in a log safe way. -func (k Key) String() string { - return fmt.Sprintf("Name: %s, Secret: [REDACTED]", k.Name) -} - // IdentityConfiguration is an empty struct to allow identity transformer in provider configuration. type IdentityConfiguration struct{} @@ -88,13 +79,9 @@ type IdentityConfiguration struct{} type KMSConfiguration struct { // name is the name of the KMS plugin to be used. Name string `json:"name"` - // cachesize is the maximum number of secrets which are cached in memory. The default value is 1000. - // Set to a negative value to disable caching. + // cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000. // +optional - CacheSize *int32 `json:"cachesize,omitempty"` + CacheSize int32 `json:"cachesize,omitempty"` // endpoint is the gRPC server listening address, for example "unix:///var/run/kms-provider.sock". Endpoint string `json:"endpoint"` - // timeout for gRPC calls to kms-plugin (ex. 5s). The default is 3 seconds. - // +optional - Timeout *metav1.Duration `json:"timeout,omitempty"` } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.conversion.go index c7de6539d85..27fb16d3183 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.conversion.go @@ -23,7 +23,6 @@ package v1 import ( unsafe "unsafe" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" config "k8s.io/apiserver/pkg/apis/config" @@ -179,9 +178,8 @@ func Convert_config_IdentityConfiguration_To_v1_IdentityConfiguration(in *config func autoConvert_v1_KMSConfiguration_To_config_KMSConfiguration(in *KMSConfiguration, out *config.KMSConfiguration, s conversion.Scope) error { out.Name = in.Name - out.CacheSize = (*int32)(unsafe.Pointer(in.CacheSize)) + out.CacheSize = in.CacheSize out.Endpoint = in.Endpoint - out.Timeout = (*metav1.Duration)(unsafe.Pointer(in.Timeout)) return nil } @@ -192,9 +190,8 @@ func Convert_v1_KMSConfiguration_To_config_KMSConfiguration(in *KMSConfiguration func autoConvert_config_KMSConfiguration_To_v1_KMSConfiguration(in *config.KMSConfiguration, out *KMSConfiguration, s conversion.Scope) error { out.Name = in.Name - out.CacheSize = (*int32)(unsafe.Pointer(in.CacheSize)) + out.CacheSize = in.CacheSize out.Endpoint = in.Endpoint - out.Timeout = (*metav1.Duration)(unsafe.Pointer(in.Timeout)) return nil } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.deepcopy.go index dcb4e855297..e5f28d46a3d 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.deepcopy.go @@ -21,7 +21,6 @@ limitations under the License. package v1 import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -97,16 +96,6 @@ func (in *IdentityConfiguration) DeepCopy() *IdentityConfiguration { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KMSConfiguration) DeepCopyInto(out *KMSConfiguration) { *out = *in - if in.CacheSize != nil { - in, out := &in.CacheSize, &out.CacheSize - *out = new(int32) - **out = **in - } - if in.Timeout != nil { - in, out := &in.Timeout, &out.Timeout - *out = new(metav1.Duration) - **out = **in - } return } @@ -162,7 +151,7 @@ func (in *ProviderConfiguration) DeepCopyInto(out *ProviderConfiguration) { if in.KMS != nil { in, out := &in.KMS, &out.KMS *out = new(KMSConfiguration) - (*in).DeepCopyInto(*out) + **out = **in } return } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.defaults.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.defaults.go index 1c8db8d04f6..cce2e603a69 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.defaults.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1/zz_generated.defaults.go @@ -28,18 +28,5 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { - scheme.AddTypeDefaultingFunc(&EncryptionConfiguration{}, func(obj interface{}) { SetObjectDefaults_EncryptionConfiguration(obj.(*EncryptionConfiguration)) }) return nil } - -func SetObjectDefaults_EncryptionConfiguration(in *EncryptionConfiguration) { - for i := range in.Resources { - a := &in.Resources[i] - for j := range a.Providers { - b := &a.Providers[j] - if b.KMS != nil { - SetDefaults_KMSConfiguration(b.KMS) - } - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/conversion.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/conversion.go new file mode 100644 index 00000000000..75190ad161c --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/conversion.go @@ -0,0 +1,45 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apiserver/pkg/apis/config" +) + +// Important! The public back-and-forth conversion functions for the types in this generic +// package with ComponentConfig types need to be manually exposed like this in order for +// other packages that reference this package to be able to call these conversion functions +// in an autogenerated manner. +// TODO: Fix the bug in conversion-gen so it automatically discovers these Convert_* functions +// in autogenerated code as well. + +func Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in, out, s) +} + +func Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error { + return autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in, out, s) +} + +func Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error { + return autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in, out, s) +} + +func Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error { + return autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in, out, s) +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/defaults.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/defaults.go new file mode 100644 index 00000000000..caee3d8e491 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/defaults.go @@ -0,0 +1,52 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilpointer "k8s.io/utils/pointer" +) + +// RecommendedDefaultLeaderElectionConfiguration defaults a pointer to a +// LeaderElectionConfiguration struct. This will set the recommended default +// values, but they may be subject to change between API versions. This function +// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo` +// function to allow consumers of this type to set whatever defaults for their +// embedded configs. Forcing consumers to use these defaults would be problematic +// as defaulting in the scheme is done as part of the conversion, and there would +// be no easy way to opt-out. Instead, if you want to use this defaulting method +// run it in your wrapper struct of this type in its `SetDefaults_` method. +func RecommendedDefaultLeaderElectionConfiguration(obj *LeaderElectionConfiguration) { + zero := metav1.Duration{} + if obj.LeaseDuration == zero { + obj.LeaseDuration = metav1.Duration{Duration: 15 * time.Second} + } + if obj.RenewDeadline == zero { + obj.RenewDeadline = metav1.Duration{Duration: 10 * time.Second} + } + if obj.RetryPeriod == zero { + obj.RetryPeriod = metav1.Duration{Duration: 2 * time.Second} + } + if obj.ResourceLock == "" { + obj.ResourceLock = EndpointsResourceLock + } + if obj.LeaderElect == nil { + obj.LeaderElect = utilpointer.BoolPtr(true) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/doc.go similarity index 68% rename from vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/doc.go rename to vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/doc.go index 92cfed10744..a7492964ef2 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission/v1/doc.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,9 +15,6 @@ limitations under the License. */ // +k8s:deepcopy-gen=package -// +k8s:conversion-gen=k8s.io/apiserver/pkg/admission/plugin/webhook/config/apis/webhookadmission -// +k8s:defaulter-gen=TypeMeta -// +groupName=apiserver.config.k8s.io +// +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/config -// Package v1 is the v1 version of the API. -package v1 +package v1alpha1 // import "k8s.io/apiserver/pkg/apis/config/v1alpha1" diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/register.go similarity index 51% rename from vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults.go rename to vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/register.go index 2d529651a9f..ddc186c9aa4 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/v1/defaults.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/register.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,31 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1 +package v1alpha1 import ( - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) var ( - defaultTimeout = &metav1.Duration{Duration: 3 * time.Second} - defaultCacheSize int32 = 1000 + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder runtime.SchemeBuilder + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme ) - -func addDefaultingFuncs(scheme *runtime.Scheme) error { - return RegisterDefaults(scheme) -} - -// SetDefaults_KMSConfiguration applies defaults to KMSConfiguration. -func SetDefaults_KMSConfiguration(obj *KMSConfiguration) { - if obj.Timeout == nil { - obj.Timeout = defaultTimeout - } - - if obj.CacheSize == nil { - obj.CacheSize = &defaultCacheSize - } -} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/types.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/types.go new file mode 100644 index 00000000000..f5ca97151a2 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/types.go @@ -0,0 +1,60 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const EndpointsResourceLock = "endpoints" + +// LeaderElectionConfiguration defines the configuration of leader election +// clients for components that can run with leader election enabled. +type LeaderElectionConfiguration struct { + // leaderElect enables a leader election client to gain leadership + // before executing the main loop. Enable this when running replicated + // components for high availability. + LeaderElect *bool `json:"leaderElect"` + // leaseDuration is the duration that non-leader candidates will wait + // after observing a leadership renewal until attempting to acquire + // leadership of a led but unrenewed leader slot. This is effectively the + // maximum duration that a leader can be stopped before it is replaced + // by another candidate. This is only applicable if leader election is + // enabled. + LeaseDuration metav1.Duration `json:"leaseDuration"` + // renewDeadline is the interval between attempts by the acting master to + // renew a leadership slot before it stops leading. This must be less + // than or equal to the lease duration. This is only applicable if leader + // election is enabled. + RenewDeadline metav1.Duration `json:"renewDeadline"` + // retryPeriod is the duration the clients should wait between attempting + // acquisition and renewal of a leadership. This is only applicable if + // leader election is enabled. + RetryPeriod metav1.Duration `json:"retryPeriod"` + // resourceLock indicates the resource object type that will be used to lock + // during leader election cycles. + ResourceLock string `json:"resourceLock"` +} + +// DebuggingConfiguration holds configuration for Debugging related features. +type DebuggingConfiguration struct { + // enableProfiling enables profiling via web interface host:port/debug/pprof/ + EnableProfiling bool `json:"enableProfiling"` + // enableContentionProfiling enables lock contention profiling, if + // enableProfiling is true. + EnableContentionProfiling bool `json:"enableContentionProfiling"` +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.conversion.go new file mode 100644 index 00000000000..eaf2076ac4b --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,112 @@ +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + config "k8s.io/apiserver/pkg/apis/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*DebuggingConfiguration)(nil), (*config.DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(a.(*DebuggingConfiguration), b.(*config.DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DebuggingConfiguration)(nil), (*DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(a.(*config.DebuggingConfiguration), b.(*DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*LeaderElectionConfiguration)(nil), (*config.LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(a.(*LeaderElectionConfiguration), b.(*config.LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.LeaderElectionConfiguration)(nil), (*LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(a.(*config.LeaderElectionConfiguration), b.(*LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.DebuggingConfiguration)(nil), (*DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(a.(*config.DebuggingConfiguration), b.(*DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.LeaderElectionConfiguration)(nil), (*LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(a.(*config.LeaderElectionConfiguration), b.(*LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*DebuggingConfiguration)(nil), (*config.DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(a.(*DebuggingConfiguration), b.(*config.DebuggingConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*LeaderElectionConfiguration)(nil), (*config.LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(a.(*LeaderElectionConfiguration), b.(*config.LeaderElectionConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error { + out.EnableProfiling = in.EnableProfiling + out.EnableContentionProfiling = in.EnableContentionProfiling + return nil +} + +func autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error { + out.EnableProfiling = in.EnableProfiling + out.EnableContentionProfiling = in.EnableContentionProfiling + return nil +} + +func autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error { + if err := v1.Convert_Pointer_bool_To_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil { + return err + } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + out.ResourceLock = in.ResourceLock + return nil +} + +func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error { + if err := v1.Convert_bool_To_Pointer_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil { + return err + } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + out.ResourceLock = in.ResourceLock + return nil +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go similarity index 51% rename from vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.deepcopy.go rename to vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go index a0e039de0d7..f40bbe19af0 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/apiserver/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go @@ -18,61 +18,44 @@ limitations under the License. // Code generated by deepcopy-gen. DO NOT EDIT. -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) +package v1alpha1 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AdmissionConfiguration) DeepCopyInto(out *AdmissionConfiguration) { +func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) { *out = *in - out.TypeMeta = in.TypeMeta - if in.Plugins != nil { - in, out := &in.Plugins, &out.Plugins - *out = make([]AdmissionPluginConfiguration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionConfiguration. -func (in *AdmissionConfiguration) DeepCopy() *AdmissionConfiguration { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration. +func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration { if in == nil { return nil } - out := new(AdmissionConfiguration) + out := new(DebuggingConfiguration) in.DeepCopyInto(out) return out } -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *AdmissionConfiguration) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AdmissionPluginConfiguration) DeepCopyInto(out *AdmissionPluginConfiguration) { +func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { *out = *in - if in.Configuration != nil { - in, out := &in.Configuration, &out.Configuration - *out = new(runtime.Unknown) - (*in).DeepCopyInto(*out) + if in.LeaderElect != nil { + in, out := &in.LeaderElect, &out.LeaderElect + *out = new(bool) + **out = **in } + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionPluginConfiguration. -func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration. +func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration { if in == nil { return nil } - out := new(AdmissionPluginConfiguration) + out := new(LeaderElectionConfiguration) in.DeepCopyInto(out) return out } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation.go b/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation.go index d911d05972c..00cadf10133 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,206 +14,33 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package validation validates EncryptionConfiguration. package validation import ( - "encoding/base64" - "fmt" - "net/url" - "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/apis/config" ) -const ( - moreThanOneElementErr = "more than one provider specified in a single element, should split into different list elements" - keyLenErrFmt = "secret is not of the expected length, got %d, expected one of %v" - unsupportedSchemeErrFmt = "unsupported scheme %q for KMS provider, only unix is supported" - atLeastOneRequiredErrFmt = "at least one %s is required" - mandatoryFieldErrFmt = "%s is a mandatory field for a %s" - base64EncodingErr = "secrets must be base64 encoded" - zeroOrNegativeErrFmt = "%s should be a positive value" - nonZeroErrFmt = "%s should be a positive value, or negative to disable" - encryptionConfigNilErr = "EncryptionConfiguration can't be nil" -) - -var ( - aesKeySizes = []int{16, 24, 32} - // See https://golang.org/pkg/crypto/aes/#NewCipher for details on supported key sizes for AES. - secretBoxKeySizes = []int{32} - // See https://godoc.org/golang.org/x/crypto/nacl/secretbox#Open for details on the supported key sizes for Secretbox. - root = field.NewPath("resources") -) - -// ValidateEncryptionConfiguration validates a v1.EncryptionConfiguration. -func ValidateEncryptionConfiguration(c *config.EncryptionConfiguration) field.ErrorList { - allErrs := field.ErrorList{} - - if c == nil { - allErrs = append(allErrs, field.Required(root, "EncryptionConfiguration can't be nil")) - return allErrs - } - - if len(c.Resources) == 0 { - allErrs = append(allErrs, field.Required(root, fmt.Sprintf(atLeastOneRequiredErrFmt, root))) - return allErrs - } - - for i, conf := range c.Resources { - r := root.Index(i).Child("resources") - p := root.Index(i).Child("providers") - - if len(conf.Resources) == 0 { - allErrs = append(allErrs, field.Required(r, fmt.Sprintf(atLeastOneRequiredErrFmt, r))) - } - - if len(conf.Providers) == 0 { - allErrs = append(allErrs, field.Required(p, fmt.Sprintf(atLeastOneRequiredErrFmt, p))) - } - - for j, provider := range conf.Providers { - path := p.Index(j) - allErrs = append(allErrs, validateSingleProvider(provider, path)...) - - switch { - case provider.KMS != nil: - allErrs = append(allErrs, validateKMSConfiguration(provider.KMS, path.Child("kms"))...) - case provider.AESGCM != nil: - allErrs = append(allErrs, validateKeys(provider.AESGCM.Keys, path.Child("aesgcm").Child("keys"), aesKeySizes)...) - case provider.AESCBC != nil: - allErrs = append(allErrs, validateKeys(provider.AESCBC.Keys, path.Child("aescbc").Child("keys"), aesKeySizes)...) - case provider.Secretbox != nil: - allErrs = append(allErrs, validateKeys(provider.Secretbox.Keys, path.Child("secretbox").Child("keys"), secretBoxKeySizes)...) - } - } - } - - return allErrs -} - -func validateSingleProvider(provider config.ProviderConfiguration, filedPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - found := 0 - - if provider.KMS != nil { - found++ - } - if provider.AESGCM != nil { - found++ - } - if provider.AESCBC != nil { - found++ - } - if provider.Secretbox != nil { - found++ - } - if provider.Identity != nil { - found++ - } - - if found == 0 { - return append(allErrs, field.Invalid(filedPath, provider, "provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity")) - } - - if found > 1 { - return append(allErrs, field.Invalid(filedPath, provider, moreThanOneElementErr)) - } - - return allErrs -} - -func validateKeys(keys []config.Key, fieldPath *field.Path, expectedLen []int) field.ErrorList { - allErrs := field.ErrorList{} - - if len(keys) == 0 { - allErrs = append(allErrs, field.Required(fieldPath, fmt.Sprintf(atLeastOneRequiredErrFmt, "keys"))) - return allErrs - } - - for i, key := range keys { - allErrs = append(allErrs, validateKey(key, fieldPath.Index(i), expectedLen)...) - } - - return allErrs -} - -func validateKey(key config.Key, fieldPath *field.Path, expectedLen []int) field.ErrorList { +// ValidateLeaderElectionConfiguration ensures validation of the LeaderElectionConfiguration struct +func ValidateLeaderElectionConfiguration(cc *config.LeaderElectionConfiguration, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - - if key.Name == "" { - allErrs = append(allErrs, field.Required(fieldPath.Child("name"), fmt.Sprintf(mandatoryFieldErrFmt, "name", "key"))) - } - - if key.Secret == "" { - allErrs = append(allErrs, field.Required(fieldPath.Child("secret"), fmt.Sprintf(mandatoryFieldErrFmt, "secret", "key"))) + if !cc.LeaderElect { return allErrs } - - secret, err := base64.StdEncoding.DecodeString(key.Secret) - if err != nil { - allErrs = append(allErrs, field.Invalid(fieldPath.Child("secret"), "REDACTED", base64EncodingErr)) - return allErrs - } - - lenMatched := false - for _, l := range expectedLen { - if len(secret) == l { - lenMatched = true - break - } - } - - if !lenMatched { - allErrs = append(allErrs, field.Invalid(fieldPath.Child("secret"), "REDACTED", fmt.Sprintf(keyLenErrFmt, len(secret), expectedLen))) - } - - return allErrs -} - -func validateKMSConfiguration(c *config.KMSConfiguration, fieldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if c.Name == "" { - allErrs = append(allErrs, field.Required(fieldPath.Child("name"), fmt.Sprintf(mandatoryFieldErrFmt, "name", "provider"))) - } - allErrs = append(allErrs, validateKMSTimeout(c, fieldPath.Child("timeout"))...) - allErrs = append(allErrs, validateKMSEndpoint(c, fieldPath.Child("endpoint"))...) - allErrs = append(allErrs, validateKMSCacheSize(c, fieldPath.Child("cachesize"))...) - return allErrs -} - -func validateKMSCacheSize(c *config.KMSConfiguration, fieldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if *c.CacheSize == 0 { - allErrs = append(allErrs, field.Invalid(fieldPath, *c.CacheSize, fmt.Sprintf(nonZeroErrFmt, "cachesize"))) + if cc.LeaseDuration.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("leaseDuration"), cc.LeaseDuration, "must be greater than zero")) } - - return allErrs -} - -func validateKMSTimeout(c *config.KMSConfiguration, fieldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if c.Timeout.Duration <= 0 { - allErrs = append(allErrs, field.Invalid(fieldPath, c.Timeout, fmt.Sprintf(zeroOrNegativeErrFmt, "timeout"))) + if cc.RenewDeadline.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("renewDeadline"), cc.LeaseDuration, "must be greater than zero")) } - - return allErrs -} - -func validateKMSEndpoint(c *config.KMSConfiguration, fieldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if len(c.Endpoint) == 0 { - return append(allErrs, field.Invalid(fieldPath, "", fmt.Sprintf(mandatoryFieldErrFmt, "endpoint", "kms"))) + if cc.RetryPeriod.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("retryPeriod"), cc.RetryPeriod, "must be greater than zero")) } - - u, err := url.Parse(c.Endpoint) - if err != nil { - return append(allErrs, field.Invalid(fieldPath, c.Endpoint, fmt.Sprintf("invalid endpoint for kms provider, error: %v", err))) + if cc.LeaseDuration.Duration < cc.RenewDeadline.Duration { + allErrs = append(allErrs, field.Invalid(fldPath.Child("leaseDuration"), cc.RenewDeadline, "LeaseDuration must be greater than RenewDeadline")) } - - if u.Scheme != "unix" { - return append(allErrs, field.Invalid(fieldPath, c.Endpoint, fmt.Sprintf(unsupportedSchemeErrFmt, u.Scheme))) + if len(cc.ResourceLock) == 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceLock"), cc.RenewDeadline, "resourceLock is required")) } - return allErrs } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation_test.go b/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation_test.go index 03192c83731..b55c9fb1ba7 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation_test.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/validation/validation_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,336 +17,96 @@ limitations under the License. package validation import ( - "fmt" - "testing" - "time" - - "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/apis/config" + "testing" + "time" ) -func TestStructure(t *testing.T) { - firstResourcePath := root.Index(0) - testCases := []struct { - desc string - in *config.EncryptionConfiguration - want field.ErrorList - }{ - { - desc: "nil encryption config", - in: nil, - want: field.ErrorList{ - field.Required(root, encryptionConfigNilErr), - }, - }, - { - desc: "empty encryption config", - in: &config.EncryptionConfiguration{}, - want: field.ErrorList{ - field.Required(root, fmt.Sprintf(atLeastOneRequiredErrFmt, root)), - }, - }, - { - desc: "no k8s resources", - in: &config.EncryptionConfiguration{ - Resources: []config.ResourceConfiguration{ - { - Providers: []config.ProviderConfiguration{ - { - AESCBC: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - }, - }, - }, - }, - }, - want: field.ErrorList{ - field.Required(firstResourcePath.Child("resources"), fmt.Sprintf(atLeastOneRequiredErrFmt, root.Index(0).Child("resources"))), - }, - }, - { - desc: "no providers", - in: &config.EncryptionConfiguration{ - Resources: []config.ResourceConfiguration{ - { - Resources: []string{"secrets"}, - }, - }, - }, - want: field.ErrorList{ - field.Required(firstResourcePath.Child("providers"), fmt.Sprintf(atLeastOneRequiredErrFmt, root.Index(0).Child("providers"))), - }, - }, - { - desc: "multiple providers", - in: &config.EncryptionConfiguration{ - Resources: []config.ResourceConfiguration{ - { - Resources: []string{"secrets"}, - Providers: []config.ProviderConfiguration{ - { - AESGCM: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - AESCBC: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - }, - }, - }, - }, - }, - want: field.ErrorList{ - field.Invalid( - firstResourcePath.Child("providers").Index(0), - config.ProviderConfiguration{ - AESGCM: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - AESCBC: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - }, - moreThanOneElementErr), - }, - }, - { - desc: "valid config", - in: &config.EncryptionConfiguration{ - Resources: []config.ResourceConfiguration{ - { - Resources: []string{"secrets"}, - Providers: []config.ProviderConfiguration{ - { - AESGCM: &config.AESConfiguration{ - Keys: []config.Key{ - { - Name: "foo", - Secret: "A/j5CnrWGB83ylcPkuUhm/6TSyrQtsNJtDPwPHNOj4Q=", - }, - }, - }, - }, - }, - }, - }, - }, - want: field.ErrorList{}, - }, +func TestValidateLeaderElectionConfiguration(t *testing.T) { + validConfig := &config.LeaderElectionConfiguration{ + ResourceLock: "configmap", + LeaderElect: true, + LeaseDuration: metav1.Duration{Duration: 30 * time.Second}, + RenewDeadline: metav1.Duration{Duration: 15 * time.Second}, + RetryPeriod: metav1.Duration{Duration: 5 * time.Second}, } - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got := ValidateEncryptionConfiguration(tt.in) - if d := cmp.Diff(tt.want, got); d != "" { - t.Fatalf("EncryptionConfiguratoin validation results mismatch (-want +got):\n%s", d) - } - }) - } -} + renewDeadlineExceedsLeaseDuration := validConfig.DeepCopy() + renewDeadlineExceedsLeaseDuration.RenewDeadline = metav1.Duration{Duration: 45 * time.Second} -func TestKey(t *testing.T) { - path := root.Index(0).Child("provider").Index(0).Child("key").Index(0) - testCases := []struct { - desc string - in config.Key - want field.ErrorList - }{ - { - desc: "valid key", - in: config.Key{Name: "foo", Secret: "c2VjcmV0IGlzIHNlY3VyZQ=="}, - want: field.ErrorList{}, - }, - { - desc: "key without name", - in: config.Key{Secret: "c2VjcmV0IGlzIHNlY3VyZQ=="}, - want: field.ErrorList{ - field.Required(path.Child("name"), fmt.Sprintf(mandatoryFieldErrFmt, "name", "key")), - }, - }, - { - desc: "key without secret", - in: config.Key{Name: "foo"}, - want: field.ErrorList{ - field.Required(path.Child("secret"), fmt.Sprintf(mandatoryFieldErrFmt, "secret", "key")), - }, - }, - { - desc: "key is not base64 encoded", - in: config.Key{Name: "foo", Secret: "P@ssword"}, - want: field.ErrorList{ - field.Invalid(path.Child("secret"), "REDACTED", base64EncodingErr), - }, - }, - { - desc: "key is not of expected length", - in: config.Key{Name: "foo", Secret: "cGFzc3dvcmQK"}, - want: field.ErrorList{ - field.Invalid(path.Child("secret"), "REDACTED", fmt.Sprintf(keyLenErrFmt, 9, aesKeySizes)), - }, - }, - } + renewDeadlineZero := validConfig.DeepCopy() + renewDeadlineZero.RenewDeadline = metav1.Duration{Duration: 0 * time.Second} - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got := validateKey(tt.in, path, aesKeySizes) - if d := cmp.Diff(tt.want, got); d != "" { - t.Fatalf("Key validation results mismatch (-want +got):\n%s", d) - } - }) - } -} + leaseDurationZero := validConfig.DeepCopy() + leaseDurationZero.LeaseDuration = metav1.Duration{Duration: 0 * time.Second} -func TestKMSProviderTimeout(t *testing.T) { - timeoutField := field.NewPath("Resource").Index(0).Child("Provider").Index(0).Child("KMS").Child("Timeout") - negativeTimeout := &metav1.Duration{Duration: -1 * time.Minute} - zeroTimeout := &metav1.Duration{Duration: 0 * time.Minute} + negativeValForRetryPeriod := validConfig.DeepCopy() + negativeValForRetryPeriod.RetryPeriod = metav1.Duration{Duration: -45 * time.Second} - testCases := []struct { - desc string - in *config.KMSConfiguration - want field.ErrorList - }{ - { - desc: "valid timeout", - in: &config.KMSConfiguration{Timeout: &metav1.Duration{Duration: 1 * time.Minute}}, - want: field.ErrorList{}, - }, - { - desc: "negative timeout", - in: &config.KMSConfiguration{Timeout: negativeTimeout}, - want: field.ErrorList{ - field.Invalid(timeoutField, negativeTimeout, fmt.Sprintf(zeroOrNegativeErrFmt, "timeout")), - }, - }, - { - desc: "zero timeout", - in: &config.KMSConfiguration{Timeout: zeroTimeout}, - want: field.ErrorList{ - field.Invalid(timeoutField, zeroTimeout, fmt.Sprintf(zeroOrNegativeErrFmt, "timeout")), - }, - }, - } + negativeValForLeaseDuration := validConfig.DeepCopy() + negativeValForLeaseDuration.LeaseDuration = metav1.Duration{Duration: -45 * time.Second} - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got := validateKMSTimeout(tt.in, timeoutField) - if d := cmp.Diff(tt.want, got); d != "" { - t.Fatalf("KMS Provider validation mismatch (-want +got):\n%s", d) - } - }) - } -} + negativeValForRenewDeadline := validConfig.DeepCopy() + negativeValForRenewDeadline.RenewDeadline = metav1.Duration{Duration: -45 * time.Second} + + LeaderElectButLeaderElectNotEnabled := validConfig.DeepCopy() + LeaderElectButLeaderElectNotEnabled.LeaderElect = false + LeaderElectButLeaderElectNotEnabled.LeaseDuration = metav1.Duration{Duration: -45 * time.Second} -func TestKMSEndpoint(t *testing.T) { - endpointField := field.NewPath("Resource").Index(0).Child("Provider").Index(0).Child("kms").Child("endpoint") - testCases := []struct { - desc string - in *config.KMSConfiguration - want field.ErrorList + resourceLockNotDefined := validConfig.DeepCopy() + resourceLockNotDefined.ResourceLock = "" + + scenarios := map[string]struct { + expectedToFail bool + config *config.LeaderElectionConfiguration }{ - { - desc: "valid endpoint", - in: &config.KMSConfiguration{Endpoint: "unix:///socket.sock"}, - want: field.ErrorList{}, + "good": { + expectedToFail: false, + config: validConfig, }, - { - desc: "empty endpoint", - in: &config.KMSConfiguration{}, - want: field.ErrorList{ - field.Invalid(endpointField, "", fmt.Sprintf(mandatoryFieldErrFmt, "endpoint", "kms")), - }, + "good-dont-check-leader-config-if-not-enabled": { + expectedToFail: false, + config: LeaderElectButLeaderElectNotEnabled, }, - { - desc: "non unix endpoint", - in: &config.KMSConfiguration{Endpoint: "https://www.foo.com"}, - want: field.ErrorList{ - field.Invalid(endpointField, "https://www.foo.com", fmt.Sprintf(unsupportedSchemeErrFmt, "https")), - }, + "bad-renew-deadline-exceeds-lease-duration": { + expectedToFail: true, + config: renewDeadlineExceedsLeaseDuration, }, - { - desc: "invalid url", - in: &config.KMSConfiguration{Endpoint: "unix:///foo\n.socket"}, - want: field.ErrorList{ - field.Invalid(endpointField, "unix:///foo\n.socket", "invalid endpoint for kms provider, error: parse unix:///foo\n.socket: net/url: invalid control character in URL"), - }, + "bad-negative-value-for-retry-period": { + expectedToFail: true, + config: negativeValForRetryPeriod, }, - } - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got := validateKMSEndpoint(tt.in, endpointField) - if d := cmp.Diff(tt.want, got); d != "" { - t.Fatalf("KMS Provider validation mismatch (-want +got):\n%s", d) - } - }) - } -} - -func TestKMSProviderCacheSize(t *testing.T) { - cacheField := root.Index(0).Child("kms").Child("cachesize") - negativeCacheSize := int32(-1) - positiveCacheSize := int32(10) - zeroCacheSize := int32(0) - - testCases := []struct { - desc string - in *config.KMSConfiguration - want field.ErrorList - }{ - { - desc: "valid positive cache size", - in: &config.KMSConfiguration{CacheSize: &positiveCacheSize}, - want: field.ErrorList{}, + "bad-negative-value-for-lease-duration": { + expectedToFail: true, + config: negativeValForLeaseDuration, + }, + "bad-negative-value-for-renew-deadline": { + expectedToFail: true, + config: negativeValForRenewDeadline, + }, + "bad-renew-deadline-zero": { + expectedToFail: true, + config: renewDeadlineZero, }, - { - desc: "invalid zero cache size", - in: &config.KMSConfiguration{CacheSize: &zeroCacheSize}, - want: field.ErrorList{ - field.Invalid(cacheField, int32(0), fmt.Sprintf(nonZeroErrFmt, "cachesize")), - }, + "bad-lease-duration-zero": { + expectedToFail: true, + config: leaseDurationZero, }, - { - desc: "valid negative caches size", - in: &config.KMSConfiguration{CacheSize: &negativeCacheSize}, - want: field.ErrorList{}, + "bad-resource-lock-not-defined": { + expectedToFail: true, + config: resourceLockNotDefined, }, } - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got := validateKMSCacheSize(tt.in, cacheField) - if d := cmp.Diff(tt.want, got); d != "" { - t.Fatalf("KMS Provider validation mismatch (-want +got):\n%s", d) - } - }) + for name, scenario := range scenarios { + errs := ValidateLeaderElectionConfiguration(scenario.config, field.NewPath("leaderElectionConfiguration")) + if len(errs) == 0 && scenario.expectedToFail { + t.Errorf("Unexpected success for scenario: %s", name) + } + if len(errs) > 0 && !scenario.expectedToFail { + t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs) + } } } diff --git a/vendor/k8s.io/apiserver/pkg/apis/config/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/config/zz_generated.deepcopy.go index dd66315ee71..438dff997d5 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/config/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/config/zz_generated.deepcopy.go @@ -21,7 +21,6 @@ limitations under the License. package config import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -46,6 +45,22 @@ func (in *AESConfiguration) DeepCopy() *AESConfiguration { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration. +func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration { + if in == nil { + return nil + } + out := new(DebuggingConfiguration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EncryptionConfiguration) DeepCopyInto(out *EncryptionConfiguration) { *out = *in @@ -97,16 +112,6 @@ func (in *IdentityConfiguration) DeepCopy() *IdentityConfiguration { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KMSConfiguration) DeepCopyInto(out *KMSConfiguration) { *out = *in - if in.CacheSize != nil { - in, out := &in.CacheSize, &out.CacheSize - *out = new(int32) - **out = **in - } - if in.Timeout != nil { - in, out := &in.Timeout, &out.Timeout - *out = new(v1.Duration) - **out = **in - } return } @@ -136,6 +141,25 @@ func (in *Key) DeepCopy() *Key { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { + *out = *in + out.LeaseDuration = in.LeaseDuration + out.RenewDeadline = in.RenewDeadline + out.RetryPeriod = in.RetryPeriod + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration. +func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration { + if in == nil { + return nil + } + out := new(LeaderElectionConfiguration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProviderConfiguration) DeepCopyInto(out *ProviderConfiguration) { *out = *in @@ -162,7 +186,7 @@ func (in *ProviderConfiguration) DeepCopyInto(out *ProviderConfiguration) { if in.KMS != nil { in, out := &in.KMS, &out.KMS *out = new(KMSConfiguration) - (*in).DeepCopyInto(*out) + **out = **in } return } diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/install/roundtrip_test.go b/vendor/k8s.io/apiserver/pkg/apis/example/install/roundtrip_test.go index 6cb530b1b86..7f67418d245 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/install/roundtrip_test.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/install/roundtrip_test.go @@ -25,5 +25,4 @@ import ( func TestRoundTrip(t *testing.T) { roundtrip.RoundTripTestForAPIGroup(t, Install, examplefuzzer.Funcs) - roundtrip.RoundTripProtobufTestForAPIGroup(t, Install, examplefuzzer.Funcs) } diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/types.go b/vendor/k8s.io/apiserver/pkg/apis/example/types.go index 2a2861cdb7f..243c1c03306 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/types.go @@ -55,7 +55,7 @@ type PodStatus struct { // A human readable message indicating details about why the pod is in this state. // +optional Message string - // A brief CamelCase message indicating details about why the pod is in this state. e.g. 'DiskPressure' + // A brief CamelCase message indicating details about why the pod is in this state. e.g. 'OutOfDisk' // +optional Reason string diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/v1/doc.go b/vendor/k8s.io/apiserver/pkg/apis/example/v1/doc.go index ab15774a384..33a3ef04b33 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/v1/doc.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/v1/doc.go @@ -15,7 +15,6 @@ limitations under the License. */ // +k8s:deepcopy-gen=package -// +k8s:protobuf-gen=package // +k8s:conversion-gen=k8s.io/apiserver/pkg/apis/example // +k8s:openapi-gen=false // +k8s:defaulter-gen=TypeMeta diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.pb.go b/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.pb.go index 996deca8101..24cacbde69e 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.pb.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.pb.go @@ -17,22 +17,33 @@ limitations under the License. // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto +/* + Package v1 is a generated protocol buffer package. + + It is generated from these files: + k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto + + It has these top-level messages: + Pod + PodCondition + PodList + PodSpec + PodStatus +*/ package v1 -import ( - fmt "fmt" +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" - io "io" +import k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - proto "github.com/gogo/protobuf/proto" - github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" - math "math" - math_bits "math/bits" - reflect "reflect" - strings "strings" -) +import strings "strings" +import reflect "reflect" + +import io "io" // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal @@ -43,235 +54,39 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package -func (m *Pod) Reset() { *m = Pod{} } -func (*Pod) ProtoMessage() {} -func (*Pod) Descriptor() ([]byte, []int) { - return fileDescriptor_e51f083472f439e3, []int{0} -} -func (m *Pod) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Pod) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *Pod) XXX_Merge(src proto.Message) { - xxx_messageInfo_Pod.Merge(m, src) -} -func (m *Pod) XXX_Size() int { - return m.Size() -} -func (m *Pod) XXX_DiscardUnknown() { - xxx_messageInfo_Pod.DiscardUnknown(m) -} +func (m *Pod) Reset() { *m = Pod{} } +func (*Pod) ProtoMessage() {} +func (*Pod) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } -var xxx_messageInfo_Pod proto.InternalMessageInfo +func (m *PodCondition) Reset() { *m = PodCondition{} } +func (*PodCondition) ProtoMessage() {} +func (*PodCondition) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } -func (m *PodCondition) Reset() { *m = PodCondition{} } -func (*PodCondition) ProtoMessage() {} -func (*PodCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_e51f083472f439e3, []int{1} -} -func (m *PodCondition) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PodCondition) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PodCondition) XXX_Merge(src proto.Message) { - xxx_messageInfo_PodCondition.Merge(m, src) -} -func (m *PodCondition) XXX_Size() int { - return m.Size() -} -func (m *PodCondition) XXX_DiscardUnknown() { - xxx_messageInfo_PodCondition.DiscardUnknown(m) -} +func (m *PodList) Reset() { *m = PodList{} } +func (*PodList) ProtoMessage() {} +func (*PodList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } -var xxx_messageInfo_PodCondition proto.InternalMessageInfo +func (m *PodSpec) Reset() { *m = PodSpec{} } +func (*PodSpec) ProtoMessage() {} +func (*PodSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } -func (m *PodList) Reset() { *m = PodList{} } -func (*PodList) ProtoMessage() {} -func (*PodList) Descriptor() ([]byte, []int) { - return fileDescriptor_e51f083472f439e3, []int{2} -} -func (m *PodList) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PodList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PodList) XXX_Merge(src proto.Message) { - xxx_messageInfo_PodList.Merge(m, src) -} -func (m *PodList) XXX_Size() int { - return m.Size() -} -func (m *PodList) XXX_DiscardUnknown() { - xxx_messageInfo_PodList.DiscardUnknown(m) -} - -var xxx_messageInfo_PodList proto.InternalMessageInfo - -func (m *PodSpec) Reset() { *m = PodSpec{} } -func (*PodSpec) ProtoMessage() {} -func (*PodSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e51f083472f439e3, []int{3} -} -func (m *PodSpec) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PodSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PodSpec) XXX_Merge(src proto.Message) { - xxx_messageInfo_PodSpec.Merge(m, src) -} -func (m *PodSpec) XXX_Size() int { - return m.Size() -} -func (m *PodSpec) XXX_DiscardUnknown() { - xxx_messageInfo_PodSpec.DiscardUnknown(m) -} - -var xxx_messageInfo_PodSpec proto.InternalMessageInfo - -func (m *PodStatus) Reset() { *m = PodStatus{} } -func (*PodStatus) ProtoMessage() {} -func (*PodStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e51f083472f439e3, []int{4} -} -func (m *PodStatus) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PodStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PodStatus) XXX_Merge(src proto.Message) { - xxx_messageInfo_PodStatus.Merge(m, src) -} -func (m *PodStatus) XXX_Size() int { - return m.Size() -} -func (m *PodStatus) XXX_DiscardUnknown() { - xxx_messageInfo_PodStatus.DiscardUnknown(m) -} - -var xxx_messageInfo_PodStatus proto.InternalMessageInfo +func (m *PodStatus) Reset() { *m = PodStatus{} } +func (*PodStatus) ProtoMessage() {} +func (*PodStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } func init() { proto.RegisterType((*Pod)(nil), "k8s.io.apiserver.pkg.apis.example.v1.Pod") proto.RegisterType((*PodCondition)(nil), "k8s.io.apiserver.pkg.apis.example.v1.PodCondition") proto.RegisterType((*PodList)(nil), "k8s.io.apiserver.pkg.apis.example.v1.PodList") proto.RegisterType((*PodSpec)(nil), "k8s.io.apiserver.pkg.apis.example.v1.PodSpec") - proto.RegisterMapType((map[string]string)(nil), "k8s.io.apiserver.pkg.apis.example.v1.PodSpec.NodeSelectorEntry") proto.RegisterType((*PodStatus)(nil), "k8s.io.apiserver.pkg.apis.example.v1.PodStatus") } - -func init() { - proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto", fileDescriptor_e51f083472f439e3) -} - -var fileDescriptor_e51f083472f439e3 = []byte{ - // 1052 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6e, 0xdb, 0xc6, - 0x13, 0x36, 0x2d, 0xcb, 0x92, 0xd6, 0x56, 0x62, 0x6f, 0x62, 0x80, 0x31, 0x10, 0xc9, 0xf1, 0xef, - 0x07, 0xc3, 0x29, 0x1a, 0xb2, 0x36, 0xd2, 0x22, 0x6d, 0x0f, 0x41, 0x68, 0x17, 0xb5, 0x0b, 0xff, - 0x21, 0x56, 0x06, 0x02, 0x14, 0x3d, 0x74, 0x45, 0x4e, 0x64, 0x56, 0x22, 0x97, 0x58, 0xae, 0xd4, - 0xea, 0xd6, 0x47, 0x68, 0x1f, 0xa0, 0x4f, 0xd1, 0x43, 0x81, 0x3e, 0x81, 0x8f, 0x39, 0xe6, 0x24, - 0xd4, 0xea, 0x5b, 0xf8, 0x54, 0xec, 0xf2, 0x8f, 0x48, 0x4b, 0x75, 0xe5, 0xdb, 0xee, 0xcc, 0xf7, - 0x7d, 0x33, 0x9c, 0x1d, 0xce, 0xa0, 0xd3, 0xee, 0xab, 0xc8, 0xf0, 0x98, 0xd9, 0xed, 0xb7, 0x81, - 0x07, 0x20, 0x20, 0x32, 0x07, 0x10, 0xb8, 0x8c, 0x9b, 0x89, 0x83, 0x86, 0x5e, 0x04, 0x7c, 0x00, - 0xdc, 0x0c, 0xbb, 0x1d, 0x75, 0x33, 0xe1, 0x27, 0xea, 0x87, 0x3d, 0x30, 0x07, 0x7b, 0x66, 0x07, - 0x02, 0xe0, 0x54, 0x80, 0x6b, 0x84, 0x9c, 0x09, 0x86, 0xff, 0x1f, 0xb3, 0x8c, 0x8c, 0x65, 0x84, - 0xdd, 0x8e, 0xba, 0x19, 0x09, 0xcb, 0x18, 0xec, 0x6d, 0xbe, 0xe8, 0x78, 0xe2, 0xb2, 0xdf, 0x36, - 0x1c, 0xe6, 0x9b, 0x1d, 0xd6, 0x61, 0xa6, 0x22, 0xb7, 0xfb, 0xef, 0xd4, 0x4d, 0x5d, 0xd4, 0x29, - 0x16, 0xdd, 0x7c, 0x39, 0x49, 0xc5, 0xa7, 0xce, 0xa5, 0x17, 0x00, 0x1f, 0x4e, 0xb2, 0xf1, 0x41, - 0xd0, 0x19, 0xa9, 0x6c, 0x9a, 0xff, 0xc6, 0xe2, 0xfd, 0x40, 0x78, 0x3e, 0x4c, 0x11, 0x3e, 0xfb, - 0x2f, 0x42, 0xe4, 0x5c, 0x82, 0x4f, 0x6f, 0xf3, 0xb6, 0x7f, 0x5d, 0x44, 0x25, 0x9b, 0xb9, 0xf8, - 0x7b, 0x54, 0x95, 0xb9, 0xb8, 0x54, 0x50, 0x5d, 0xdb, 0xd2, 0x76, 0x57, 0xf6, 0x3f, 0x31, 0x26, - 0xe5, 0xc8, 0x24, 0x27, 0x15, 0x91, 0x68, 0x63, 0xb0, 0x67, 0x9c, 0xb7, 0x7f, 0x00, 0x47, 0x9c, - 0x82, 0xa0, 0x16, 0xbe, 0x1a, 0x35, 0x17, 0xc6, 0xa3, 0x26, 0x9a, 0xd8, 0x48, 0xa6, 0x8a, 0xcf, - 0xd1, 0x52, 0x14, 0x82, 0xa3, 0x2f, 0x2a, 0xf5, 0x17, 0xc6, 0x3c, 0xc5, 0x36, 0x6c, 0xe6, 0xb6, - 0x42, 0x70, 0xac, 0xd5, 0x44, 0x7a, 0x49, 0xde, 0x88, 0x12, 0xc2, 0x6f, 0xd1, 0x72, 0x24, 0xa8, - 0xe8, 0x47, 0x7a, 0x49, 0x49, 0x9a, 0xf3, 0x4b, 0x2a, 0x9a, 0xf5, 0x20, 0x11, 0x5d, 0x8e, 0xef, - 0x24, 0x91, 0xdb, 0xfe, 0xbd, 0x84, 0x56, 0x6d, 0xe6, 0x1e, 0xb0, 0xc0, 0xf5, 0x84, 0xc7, 0x02, - 0xfc, 0x12, 0x2d, 0x89, 0x61, 0x08, 0xaa, 0x30, 0x35, 0x6b, 0x2b, 0xcd, 0xe5, 0x62, 0x18, 0xc2, - 0xcd, 0xa8, 0xb9, 0x96, 0xc7, 0x4a, 0x1b, 0x51, 0x68, 0xfc, 0x79, 0x96, 0xdf, 0xa2, 0xe2, 0x3d, - 0x2b, 0x86, 0xbb, 0x19, 0x35, 0x1f, 0x66, 0xb4, 0x62, 0x06, 0xb8, 0x83, 0xea, 0x3d, 0x1a, 0x09, - 0x9b, 0xb3, 0x36, 0x5c, 0x78, 0x3e, 0x24, 0x5f, 0xf8, 0xd1, 0x7c, 0x4f, 0x22, 0x19, 0xd6, 0x46, - 0x12, 0xad, 0x7e, 0x92, 0x17, 0x22, 0x45, 0x5d, 0x3c, 0x40, 0x58, 0x1a, 0x2e, 0x38, 0x0d, 0xa2, - 0x38, 0x7f, 0x19, 0x6d, 0xe9, 0xde, 0xd1, 0x36, 0x93, 0x68, 0xf8, 0x64, 0x4a, 0x8d, 0xcc, 0x88, - 0x80, 0x77, 0xd0, 0x32, 0x07, 0x1a, 0xb1, 0x40, 0x2f, 0xab, 0xda, 0x64, 0x4f, 0x41, 0x94, 0x95, - 0x24, 0x5e, 0xfc, 0x1c, 0x55, 0x7c, 0x88, 0x22, 0xda, 0x01, 0x7d, 0x59, 0x01, 0x1f, 0x26, 0xc0, - 0xca, 0x69, 0x6c, 0x26, 0xa9, 0x7f, 0xfb, 0x0f, 0x0d, 0x55, 0x6c, 0xe6, 0x9e, 0x78, 0x91, 0xc0, - 0xdf, 0x4d, 0x75, 0xb3, 0x31, 0xdf, 0xc7, 0x48, 0xb6, 0xea, 0xe5, 0xb5, 0x24, 0x4e, 0x35, 0xb5, - 0xe4, 0x3a, 0xf9, 0x0c, 0x95, 0x3d, 0x01, 0xbe, 0x7c, 0xd7, 0xd2, 0xee, 0xca, 0xfe, 0xf3, 0xb9, - 0xfb, 0xce, 0xaa, 0x27, 0xaa, 0xe5, 0x63, 0xc9, 0x27, 0xb1, 0xcc, 0xf6, 0x9f, 0x15, 0x95, 0xb9, - 0x6c, 0x6d, 0x7c, 0x82, 0xea, 0x1c, 0x22, 0x41, 0xb9, 0xb0, 0x59, 0xcf, 0x73, 0x86, 0xea, 0xe5, - 0x6b, 0xd6, 0x4e, 0xfa, 0x9a, 0x24, 0xef, 0xbc, 0xb9, 0x6d, 0x20, 0x45, 0x32, 0xee, 0xa0, 0xa7, - 0x02, 0xb8, 0xef, 0x05, 0x54, 0x56, 0xfe, 0x6b, 0x4e, 0x1d, 0xb0, 0x81, 0x7b, 0xcc, 0x6d, 0x81, - 0xc3, 0x02, 0x37, 0x52, 0x2f, 0x5d, 0xb2, 0x9e, 0x8d, 0x47, 0xcd, 0xa7, 0x17, 0x77, 0x01, 0xc9, - 0xdd, 0x3a, 0xf8, 0x1c, 0x6d, 0x50, 0x47, 0x78, 0x03, 0x38, 0x04, 0xea, 0xf6, 0xbc, 0x00, 0xd2, - 0x00, 0x65, 0x15, 0xe0, 0xc9, 0x78, 0xd4, 0xdc, 0x78, 0x33, 0x0b, 0x40, 0x66, 0xf3, 0xf0, 0x10, - 0xad, 0x06, 0xcc, 0x85, 0x16, 0xf4, 0xc0, 0x11, 0x8c, 0xeb, 0x15, 0x55, 0xea, 0xd7, 0xf7, 0x9a, - 0x1a, 0xc6, 0x59, 0x4e, 0xe1, 0xab, 0x40, 0xf0, 0xa1, 0xf5, 0x38, 0xa9, 0xe3, 0x6a, 0xde, 0x45, - 0x0a, 0xa1, 0xf0, 0x37, 0x08, 0x4b, 0x6d, 0xcf, 0x81, 0x37, 0x8e, 0xc3, 0xfa, 0x81, 0x38, 0xa3, - 0x3e, 0xe8, 0x55, 0xf5, 0x0e, 0x59, 0x9f, 0xb7, 0xa6, 0x10, 0x64, 0x06, 0x0b, 0x1f, 0xa1, 0x07, - 0x45, 0xab, 0x5e, 0x2b, 0xcc, 0x10, 0xfd, 0x10, 0x42, 0x0e, 0x8e, 0x1c, 0xc8, 0x45, 0x45, 0x72, - 0x8b, 0x87, 0x3f, 0x46, 0x55, 0x99, 0xa5, 0xca, 0x05, 0x29, 0x8d, 0xac, 0x45, 0xcf, 0x12, 0x3b, - 0xc9, 0x10, 0xf8, 0x53, 0xb4, 0x72, 0xc9, 0x22, 0x71, 0x06, 0xe2, 0x47, 0xc6, 0xbb, 0xfa, 0xca, - 0x96, 0xb6, 0x5b, 0xb5, 0x1e, 0x25, 0x84, 0x95, 0xa3, 0x89, 0x8b, 0xe4, 0x71, 0xf2, 0x77, 0x93, - 0x57, 0xfb, 0xf8, 0x50, 0x5f, 0x55, 0x94, 0xec, 0x77, 0x3b, 0x8a, 0xcd, 0x24, 0xf5, 0xa7, 0xd0, - 0x63, 0xfb, 0x40, 0xaf, 0x4f, 0x43, 0x8f, 0xed, 0x03, 0x92, 0xfa, 0x65, 0xea, 0xf2, 0x18, 0xc8, - 0xd4, 0xd7, 0x8a, 0xa9, 0x1f, 0x25, 0x76, 0x92, 0x21, 0xb0, 0x89, 0x6a, 0x51, 0xbf, 0xed, 0x32, - 0x9f, 0x7a, 0x81, 0xbe, 0xae, 0xe0, 0xeb, 0x09, 0xbc, 0xd6, 0x4a, 0x1d, 0x64, 0x82, 0xc1, 0x5f, - 0xa2, 0xba, 0x5c, 0x6e, 0x6e, 0xbf, 0x07, 0x5c, 0xc5, 0x78, 0xa4, 0x48, 0xd9, 0x00, 0x6c, 0xa5, - 0x4e, 0x55, 0xa3, 0x22, 0x76, 0xf3, 0x35, 0x5a, 0x9f, 0xea, 0x12, 0xbc, 0x86, 0x4a, 0x5d, 0x18, - 0xc6, 0xe3, 0x9e, 0xc8, 0x23, 0x7e, 0x8c, 0xca, 0x03, 0xda, 0xeb, 0x43, 0x3c, 0xca, 0x49, 0x7c, - 0xf9, 0x62, 0xf1, 0x95, 0xb6, 0xfd, 0x5b, 0x09, 0xd5, 0xb2, 0x95, 0x82, 0x4d, 0x54, 0x0e, 0x2f, - 0x69, 0x94, 0xae, 0x8a, 0x27, 0xe9, 0xff, 0x6e, 0x4b, 0xe3, 0xcd, 0xa8, 0x59, 0xb5, 0x99, 0xab, - 0xce, 0x24, 0xc6, 0xe1, 0x77, 0x08, 0x39, 0xe9, 0x12, 0x48, 0x07, 0xca, 0xfe, 0xdc, 0x5d, 0x9e, - 0xed, 0x8f, 0xc9, 0xee, 0xcd, 0x4c, 0x11, 0xc9, 0x29, 0xe7, 0x07, 0x69, 0xe9, 0xee, 0x41, 0x9a, - 0x9b, 0xcd, 0x4b, 0x77, 0xce, 0xe6, 0x1d, 0xb4, 0x1c, 0xbf, 0xf0, 0xed, 0x19, 0x1e, 0x37, 0x00, - 0x49, 0xbc, 0xf8, 0x7f, 0xa8, 0x1c, 0x32, 0xf7, 0xd8, 0x4e, 0x26, 0x78, 0x36, 0x03, 0x6d, 0x69, - 0x24, 0xb1, 0x0f, 0xbf, 0x45, 0x35, 0x35, 0xb8, 0xd4, 0xfe, 0xa9, 0xdc, 0x7b, 0xff, 0xd4, 0x55, - 0x77, 0xa4, 0x02, 0x64, 0xa2, 0x65, 0xed, 0x5e, 0x5d, 0x37, 0x16, 0xde, 0x5f, 0x37, 0x16, 0x3e, - 0x5c, 0x37, 0x16, 0x7e, 0x1e, 0x37, 0xb4, 0xab, 0x71, 0x43, 0x7b, 0x3f, 0x6e, 0x68, 0x1f, 0xc6, - 0x0d, 0xed, 0xaf, 0x71, 0x43, 0xfb, 0xe5, 0xef, 0xc6, 0xc2, 0xb7, 0x8b, 0x83, 0xbd, 0x7f, 0x02, - 0x00, 0x00, 0xff, 0xff, 0xdf, 0x7a, 0x1b, 0x54, 0x4e, 0x0a, 0x00, 0x00, -} - func (m *Pod) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -279,52 +94,41 @@ func (m *Pod) Marshal() (dAtA []byte, err error) { } func (m *Pod) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Pod) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - { - size, err := m.Status.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - { - size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n1, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- + i += n1 dAtA[i] = 0x12 - { - size, err := m.ObjectMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Spec.Size())) + n2, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + i += n2 + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Status.Size())) + n3, err := m.Status.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + return i, nil } func (m *PodCondition) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -332,62 +136,49 @@ func (m *PodCondition) Marshal() (dAtA []byte, err error) { } func (m *PodCondition) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PodCondition) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.Message) - copy(dAtA[i:], m.Message) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) - i-- - dAtA[i] = 0x32 - i -= len(m.Reason) - copy(dAtA[i:], m.Reason) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) - i-- - dAtA[i] = 0x2a - { - size, err := m.LastTransitionTime.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Type))) + i += copy(dAtA[i:], m.Type) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Status))) + i += copy(dAtA[i:], m.Status) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.LastProbeTime.Size())) + n4, err := m.LastProbeTime.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- + i += n4 dAtA[i] = 0x22 - { - size, err := m.LastProbeTime.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.LastTransitionTime.Size())) + n5, err := m.LastTransitionTime.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x1a - i -= len(m.Status) - copy(dAtA[i:], m.Status) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Status))) - i-- - dAtA[i] = 0x12 - i -= len(m.Type) - copy(dAtA[i:], m.Type) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Type))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + i += n5 + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) + i += copy(dAtA[i:], m.Reason) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) + i += copy(dAtA[i:], m.Message) + return i, nil } func (m *PodList) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -395,46 +186,37 @@ func (m *PodList) Marshal() (dAtA []byte, err error) { } func (m *PodList) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PodList) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n6, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 if len(m.Items) > 0 { - for iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Items[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- + for _, msg := range m.Items { dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n } } - { - size, err := m.ListMeta.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func (m *PodSpec) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -442,121 +224,107 @@ func (m *PodSpec) Marshal() (dAtA []byte, err error) { } func (m *PodSpec) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PodSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - i -= len(m.SchedulerName) - copy(dAtA[i:], m.SchedulerName) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.SchedulerName))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x9a - i -= len(m.Subdomain) - copy(dAtA[i:], m.Subdomain) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subdomain))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x8a - i -= len(m.Hostname) - copy(dAtA[i:], m.Hostname) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Hostname))) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0x82 - i-- - if m.HostIPC { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x68 - i-- - if m.HostPID { - dAtA[i] = 1 - } else { - dAtA[i] = 0 + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.RestartPolicy))) + i += copy(dAtA[i:], m.RestartPolicy) + if m.TerminationGracePeriodSeconds != nil { + dAtA[i] = 0x20 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(*m.TerminationGracePeriodSeconds)) } - i-- - dAtA[i] = 0x60 - i-- - if m.HostNetwork { - dAtA[i] = 1 - } else { - dAtA[i] = 0 + if m.ActiveDeadlineSeconds != nil { + dAtA[i] = 0x28 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(*m.ActiveDeadlineSeconds)) } - i-- - dAtA[i] = 0x58 - i -= len(m.NodeName) - copy(dAtA[i:], m.NodeName) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.NodeName))) - i-- - dAtA[i] = 0x52 - i -= len(m.DeprecatedServiceAccount) - copy(dAtA[i:], m.DeprecatedServiceAccount) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.DeprecatedServiceAccount))) - i-- - dAtA[i] = 0x4a - i -= len(m.ServiceAccountName) - copy(dAtA[i:], m.ServiceAccountName) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.ServiceAccountName))) - i-- - dAtA[i] = 0x42 if len(m.NodeSelector) > 0 { keysForNodeSelector := make([]string, 0, len(m.NodeSelector)) for k := range m.NodeSelector { keysForNodeSelector = append(keysForNodeSelector, string(k)) } github_com_gogo_protobuf_sortkeys.Strings(keysForNodeSelector) - for iNdEx := len(keysForNodeSelector) - 1; iNdEx >= 0; iNdEx-- { - v := m.NodeSelector[string(keysForNodeSelector[iNdEx])] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintGenerated(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(keysForNodeSelector[iNdEx]) - copy(dAtA[i:], keysForNodeSelector[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(keysForNodeSelector[iNdEx]))) - i-- - dAtA[i] = 0xa - i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) - i-- + for _, k := range keysForNodeSelector { dAtA[i] = 0x3a + i++ + v := m.NodeSelector[string(k)] + mapSize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + i = encodeVarintGenerated(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) } } - if m.ActiveDeadlineSeconds != nil { - i = encodeVarintGenerated(dAtA, i, uint64(*m.ActiveDeadlineSeconds)) - i-- - dAtA[i] = 0x28 + dAtA[i] = 0x42 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ServiceAccountName))) + i += copy(dAtA[i:], m.ServiceAccountName) + dAtA[i] = 0x4a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.DeprecatedServiceAccount))) + i += copy(dAtA[i:], m.DeprecatedServiceAccount) + dAtA[i] = 0x52 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.NodeName))) + i += copy(dAtA[i:], m.NodeName) + dAtA[i] = 0x58 + i++ + if m.HostNetwork { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } - if m.TerminationGracePeriodSeconds != nil { - i = encodeVarintGenerated(dAtA, i, uint64(*m.TerminationGracePeriodSeconds)) - i-- - dAtA[i] = 0x20 + i++ + dAtA[i] = 0x60 + i++ + if m.HostPID { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } - i -= len(m.RestartPolicy) - copy(dAtA[i:], m.RestartPolicy) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.RestartPolicy))) - i-- - dAtA[i] = 0x1a - return len(dAtA) - i, nil + i++ + dAtA[i] = 0x68 + i++ + if m.HostIPC { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + dAtA[i] = 0x82 + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Hostname))) + i += copy(dAtA[i:], m.Hostname) + dAtA[i] = 0x8a + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Subdomain))) + i += copy(dAtA[i:], m.Subdomain) + dAtA[i] = 0x9a + i++ + dAtA[i] = 0x1 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.SchedulerName))) + i += copy(dAtA[i:], m.SchedulerName) + return i, nil } func (m *PodStatus) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } @@ -564,84 +332,65 @@ func (m *PodStatus) Marshal() (dAtA []byte, err error) { } func (m *PodStatus) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PodStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) + var i int _ = i var l int _ = l - if m.StartTime != nil { - { - size, err := m.StartTime.MarshalToSizedBuffer(dAtA[:i]) + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Phase))) + i += copy(dAtA[i:], m.Phase) + if len(m.Conditions) > 0 { + for _, msg := range m.Conditions { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) + i += n } - i-- - dAtA[i] = 0x3a } - i -= len(m.PodIP) - copy(dAtA[i:], m.PodIP) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.PodIP))) - i-- - dAtA[i] = 0x32 - i -= len(m.HostIP) - copy(dAtA[i:], m.HostIP) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.HostIP))) - i-- - dAtA[i] = 0x2a - i -= len(m.Reason) - copy(dAtA[i:], m.Reason) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) - i-- - dAtA[i] = 0x22 - i -= len(m.Message) - copy(dAtA[i:], m.Message) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) - i-- dAtA[i] = 0x1a - if len(m.Conditions) > 0 { - for iNdEx := len(m.Conditions) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Conditions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenerated(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) + i += copy(dAtA[i:], m.Message) + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Reason))) + i += copy(dAtA[i:], m.Reason) + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.HostIP))) + i += copy(dAtA[i:], m.HostIP) + dAtA[i] = 0x32 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.PodIP))) + i += copy(dAtA[i:], m.PodIP) + if m.StartTime != nil { + dAtA[i] = 0x3a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.StartTime.Size())) + n7, err := m.StartTime.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err } + i += n7 } - i -= len(m.Phase) - copy(dAtA[i:], m.Phase) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Phase))) - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil + return i, nil } func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { - offset -= sovGenerated(v) - base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } dAtA[offset] = uint8(v) - return base + return offset + 1 } func (m *Pod) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ObjectMeta.Size() @@ -654,9 +403,6 @@ func (m *Pod) Size() (n int) { } func (m *PodCondition) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Type) @@ -675,9 +421,6 @@ func (m *PodCondition) Size() (n int) { } func (m *PodList) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = m.ListMeta.Size() @@ -692,9 +435,6 @@ func (m *PodList) Size() (n int) { } func (m *PodSpec) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.RestartPolicy) @@ -732,9 +472,6 @@ func (m *PodSpec) Size() (n int) { } func (m *PodStatus) Size() (n int) { - if m == nil { - return 0 - } var l int _ = l l = len(m.Phase) @@ -761,7 +498,14 @@ func (m *PodStatus) Size() (n int) { } func sovGenerated(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n } func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) @@ -771,7 +515,7 @@ func (this *Pod) String() string { return "nil" } s := strings.Join([]string{`&Pod{`, - `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, `Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "PodSpec", "PodSpec", 1), `&`, ``, 1) + `,`, `Status:` + strings.Replace(strings.Replace(this.Status.String(), "PodStatus", "PodStatus", 1), `&`, ``, 1) + `,`, `}`, @@ -785,8 +529,8 @@ func (this *PodCondition) String() string { s := strings.Join([]string{`&PodCondition{`, `Type:` + fmt.Sprintf("%v", this.Type) + `,`, `Status:` + fmt.Sprintf("%v", this.Status) + `,`, - `LastProbeTime:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.LastProbeTime), "Time", "v1.Time", 1), `&`, ``, 1) + `,`, - `LastTransitionTime:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.LastTransitionTime), "Time", "v1.Time", 1), `&`, ``, 1) + `,`, + `LastProbeTime:` + strings.Replace(strings.Replace(this.LastProbeTime.String(), "Time", "k8s_io_apimachinery_pkg_apis_meta_v1.Time", 1), `&`, ``, 1) + `,`, + `LastTransitionTime:` + strings.Replace(strings.Replace(this.LastTransitionTime.String(), "Time", "k8s_io_apimachinery_pkg_apis_meta_v1.Time", 1), `&`, ``, 1) + `,`, `Reason:` + fmt.Sprintf("%v", this.Reason) + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `}`, @@ -797,14 +541,9 @@ func (this *PodList) String() string { if this == nil { return "nil" } - repeatedStringForItems := "[]Pod{" - for _, f := range this.Items { - repeatedStringForItems += strings.Replace(strings.Replace(f.String(), "Pod", "Pod", 1), `&`, ``, 1) + "," - } - repeatedStringForItems += "}" s := strings.Join([]string{`&PodList{`, - `ListMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ListMeta), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, - `Items:` + repeatedStringForItems + `,`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "Pod", "Pod", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -845,19 +584,14 @@ func (this *PodStatus) String() string { if this == nil { return "nil" } - repeatedStringForConditions := "[]PodCondition{" - for _, f := range this.Conditions { - repeatedStringForConditions += strings.Replace(strings.Replace(f.String(), "PodCondition", "PodCondition", 1), `&`, ``, 1) + "," - } - repeatedStringForConditions += "}" s := strings.Join([]string{`&PodStatus{`, `Phase:` + fmt.Sprintf("%v", this.Phase) + `,`, - `Conditions:` + repeatedStringForConditions + `,`, + `Conditions:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Conditions), "PodCondition", "PodCondition", 1), `&`, ``, 1) + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `Reason:` + fmt.Sprintf("%v", this.Reason) + `,`, `HostIP:` + fmt.Sprintf("%v", this.HostIP) + `,`, `PodIP:` + fmt.Sprintf("%v", this.PodIP) + `,`, - `StartTime:` + strings.Replace(fmt.Sprintf("%v", this.StartTime), "Time", "v1.Time", 1) + `,`, + `StartTime:` + strings.Replace(fmt.Sprintf("%v", this.StartTime), "Time", "k8s_io_apimachinery_pkg_apis_meta_v1.Time", 1) + `,`, `}`, }, "") return s @@ -885,7 +619,7 @@ func (m *Pod) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -913,7 +647,7 @@ func (m *Pod) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -922,9 +656,6 @@ func (m *Pod) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -946,7 +677,7 @@ func (m *Pod) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -955,9 +686,6 @@ func (m *Pod) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -979,7 +707,7 @@ func (m *Pod) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -988,9 +716,6 @@ func (m *Pod) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1007,9 +732,6 @@ func (m *Pod) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -1037,7 +759,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1065,7 +787,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1075,9 +797,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1097,7 +816,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1107,9 +826,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1129,7 +845,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1138,9 +854,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1162,7 +875,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1171,9 +884,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1195,7 +905,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1205,9 +915,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1227,7 +934,7 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1237,9 +944,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1254,9 +958,6 @@ func (m *PodCondition) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -1284,7 +985,7 @@ func (m *PodList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1312,7 +1013,7 @@ func (m *PodList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1321,9 +1022,6 @@ func (m *PodList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1345,7 +1043,7 @@ func (m *PodList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1354,9 +1052,6 @@ func (m *PodList) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1374,9 +1069,6 @@ func (m *PodList) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -1404,7 +1096,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1432,7 +1124,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1442,9 +1134,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1464,7 +1153,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int64(b&0x7F) << shift + v |= (int64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1484,7 +1173,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int64(b&0x7F) << shift + v |= (int64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1504,7 +1193,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1513,9 +1202,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1536,7 +1222,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1553,7 +1239,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift + stringLenmapkey |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1563,9 +1249,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapkey > l { return io.ErrUnexpectedEOF } @@ -1582,7 +1265,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift + stringLenmapvalue |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1592,9 +1275,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } if postStringIndexmapvalue > l { return io.ErrUnexpectedEOF } @@ -1631,7 +1311,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1641,9 +1321,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1663,7 +1340,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1673,9 +1350,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1695,7 +1369,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1705,9 +1379,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1727,7 +1398,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + v |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1747,7 +1418,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + v |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1767,7 +1438,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + v |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1787,7 +1458,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1797,9 +1468,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1819,7 +1487,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1829,9 +1497,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1851,7 +1516,7 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1861,9 +1526,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1878,9 +1540,6 @@ func (m *PodSpec) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -1908,7 +1567,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - wire |= uint64(b&0x7F) << shift + wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1936,7 +1595,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -1946,9 +1605,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -1968,7 +1624,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -1977,9 +1633,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2002,7 +1655,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2012,9 +1665,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2034,7 +1684,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2044,9 +1694,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2066,7 +1713,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2076,9 +1723,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2098,7 +1742,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { break } @@ -2108,9 +1752,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } @@ -2130,7 +1771,7 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + msglen |= (int(b) & 0x7F) << shift if b < 0x80 { break } @@ -2139,14 +1780,11 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { return ErrInvalidLengthGenerated } postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenerated - } if postIndex > l { return io.ErrUnexpectedEOF } if m.StartTime == nil { - m.StartTime = &v1.Time{} + m.StartTime = &k8s_io_apimachinery_pkg_apis_meta_v1.Time{} } if err := m.StartTime.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2161,9 +1799,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { if skippy < 0 { return ErrInvalidLengthGenerated } - if (iNdEx + skippy) < 0 { - return ErrInvalidLengthGenerated - } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } @@ -2179,7 +1814,6 @@ func (m *PodStatus) Unmarshal(dAtA []byte) error { func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 - depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -2211,8 +1845,10 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + return iNdEx, nil case 1: iNdEx += 8 + return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -2229,34 +1865,127 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } + iNdEx += length if length < 0 { return 0, ErrInvalidLengthGenerated } - iNdEx += length + return iNdEx, nil case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupGenerated + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenerated + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipGenerated(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next } - depth-- + return iNdEx, nil + case 4: + return iNdEx, nil case 5: iNdEx += 4 + return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - if depth == 0 { - return iNdEx, nil - } } - return 0, io.ErrUnexpectedEOF + panic("unreachable") } var ( - ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") ) + +func init() { + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto", fileDescriptorGenerated) +} + +var fileDescriptorGenerated = []byte{ + // 1052 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcf, 0x6e, 0xdb, 0xc6, + 0x13, 0x36, 0x2d, 0xcb, 0x92, 0xd6, 0x56, 0x62, 0x6f, 0x62, 0x80, 0x31, 0x10, 0xc9, 0xf1, 0xef, + 0x07, 0xc3, 0x29, 0x1a, 0xb2, 0x36, 0xd2, 0x22, 0x6d, 0x0f, 0x41, 0x68, 0x17, 0xb5, 0x0b, 0xff, + 0x21, 0x56, 0x06, 0x02, 0x14, 0x3d, 0x74, 0x45, 0x4e, 0x64, 0x56, 0x22, 0x97, 0x58, 0xae, 0xd4, + 0xea, 0xd6, 0x47, 0x68, 0x1f, 0xa0, 0x4f, 0xd1, 0x43, 0x81, 0x3e, 0x81, 0x8f, 0x39, 0xe6, 0x24, + 0xd4, 0xea, 0x5b, 0xf8, 0x54, 0xec, 0xf2, 0x8f, 0x48, 0x4b, 0x75, 0xe5, 0xdb, 0xee, 0xcc, 0xf7, + 0x7d, 0x33, 0x9c, 0x1d, 0xce, 0xa0, 0xd3, 0xee, 0xab, 0xc8, 0xf0, 0x98, 0xd9, 0xed, 0xb7, 0x81, + 0x07, 0x20, 0x20, 0x32, 0x07, 0x10, 0xb8, 0x8c, 0x9b, 0x89, 0x83, 0x86, 0x5e, 0x04, 0x7c, 0x00, + 0xdc, 0x0c, 0xbb, 0x1d, 0x75, 0x33, 0xe1, 0x27, 0xea, 0x87, 0x3d, 0x30, 0x07, 0x7b, 0x66, 0x07, + 0x02, 0xe0, 0x54, 0x80, 0x6b, 0x84, 0x9c, 0x09, 0x86, 0xff, 0x1f, 0xb3, 0x8c, 0x8c, 0x65, 0x84, + 0xdd, 0x8e, 0xba, 0x19, 0x09, 0xcb, 0x18, 0xec, 0x6d, 0xbe, 0xe8, 0x78, 0xe2, 0xb2, 0xdf, 0x36, + 0x1c, 0xe6, 0x9b, 0x1d, 0xd6, 0x61, 0xa6, 0x22, 0xb7, 0xfb, 0xef, 0xd4, 0x4d, 0x5d, 0xd4, 0x29, + 0x16, 0xdd, 0x7c, 0x39, 0x49, 0xc5, 0xa7, 0xce, 0xa5, 0x17, 0x00, 0x1f, 0x4e, 0xb2, 0xf1, 0x41, + 0xd0, 0x19, 0xa9, 0x6c, 0x9a, 0xff, 0xc6, 0xe2, 0xfd, 0x40, 0x78, 0x3e, 0x4c, 0x11, 0x3e, 0xfb, + 0x2f, 0x42, 0xe4, 0x5c, 0x82, 0x4f, 0x6f, 0xf3, 0xb6, 0x7f, 0x5d, 0x44, 0x25, 0x9b, 0xb9, 0xf8, + 0x7b, 0x54, 0x95, 0xb9, 0xb8, 0x54, 0x50, 0x5d, 0xdb, 0xd2, 0x76, 0x57, 0xf6, 0x3f, 0x31, 0x26, + 0xe5, 0xc8, 0x24, 0x27, 0x15, 0x91, 0x68, 0x63, 0xb0, 0x67, 0x9c, 0xb7, 0x7f, 0x00, 0x47, 0x9c, + 0x82, 0xa0, 0x16, 0xbe, 0x1a, 0x35, 0x17, 0xc6, 0xa3, 0x26, 0x9a, 0xd8, 0x48, 0xa6, 0x8a, 0xcf, + 0xd1, 0x52, 0x14, 0x82, 0xa3, 0x2f, 0x2a, 0xf5, 0x17, 0xc6, 0x3c, 0xc5, 0x36, 0x6c, 0xe6, 0xb6, + 0x42, 0x70, 0xac, 0xd5, 0x44, 0x7a, 0x49, 0xde, 0x88, 0x12, 0xc2, 0x6f, 0xd1, 0x72, 0x24, 0xa8, + 0xe8, 0x47, 0x7a, 0x49, 0x49, 0x9a, 0xf3, 0x4b, 0x2a, 0x9a, 0xf5, 0x20, 0x11, 0x5d, 0x8e, 0xef, + 0x24, 0x91, 0xdb, 0xfe, 0xbd, 0x84, 0x56, 0x6d, 0xe6, 0x1e, 0xb0, 0xc0, 0xf5, 0x84, 0xc7, 0x02, + 0xfc, 0x12, 0x2d, 0x89, 0x61, 0x08, 0xaa, 0x30, 0x35, 0x6b, 0x2b, 0xcd, 0xe5, 0x62, 0x18, 0xc2, + 0xcd, 0xa8, 0xb9, 0x96, 0xc7, 0x4a, 0x1b, 0x51, 0x68, 0xfc, 0x79, 0x96, 0xdf, 0xa2, 0xe2, 0x3d, + 0x2b, 0x86, 0xbb, 0x19, 0x35, 0x1f, 0x66, 0xb4, 0x62, 0x06, 0xb8, 0x83, 0xea, 0x3d, 0x1a, 0x09, + 0x9b, 0xb3, 0x36, 0x5c, 0x78, 0x3e, 0x24, 0x5f, 0xf8, 0xd1, 0x7c, 0x4f, 0x22, 0x19, 0xd6, 0x46, + 0x12, 0xad, 0x7e, 0x92, 0x17, 0x22, 0x45, 0x5d, 0x3c, 0x40, 0x58, 0x1a, 0x2e, 0x38, 0x0d, 0xa2, + 0x38, 0x7f, 0x19, 0x6d, 0xe9, 0xde, 0xd1, 0x36, 0x93, 0x68, 0xf8, 0x64, 0x4a, 0x8d, 0xcc, 0x88, + 0x80, 0x77, 0xd0, 0x32, 0x07, 0x1a, 0xb1, 0x40, 0x2f, 0xab, 0xda, 0x64, 0x4f, 0x41, 0x94, 0x95, + 0x24, 0x5e, 0xfc, 0x1c, 0x55, 0x7c, 0x88, 0x22, 0xda, 0x01, 0x7d, 0x59, 0x01, 0x1f, 0x26, 0xc0, + 0xca, 0x69, 0x6c, 0x26, 0xa9, 0x7f, 0xfb, 0x0f, 0x0d, 0x55, 0x6c, 0xe6, 0x9e, 0x78, 0x91, 0xc0, + 0xdf, 0x4d, 0x75, 0xb3, 0x31, 0xdf, 0xc7, 0x48, 0xb6, 0xea, 0xe5, 0xb5, 0x24, 0x4e, 0x35, 0xb5, + 0xe4, 0x3a, 0xf9, 0x0c, 0x95, 0x3d, 0x01, 0xbe, 0x7c, 0xd7, 0xd2, 0xee, 0xca, 0xfe, 0xf3, 0xb9, + 0xfb, 0xce, 0xaa, 0x27, 0xaa, 0xe5, 0x63, 0xc9, 0x27, 0xb1, 0xcc, 0xf6, 0x9f, 0x15, 0x95, 0xb9, + 0x6c, 0x6d, 0x7c, 0x82, 0xea, 0x1c, 0x22, 0x41, 0xb9, 0xb0, 0x59, 0xcf, 0x73, 0x86, 0xea, 0xe5, + 0x6b, 0xd6, 0x4e, 0xfa, 0x9a, 0x24, 0xef, 0xbc, 0xb9, 0x6d, 0x20, 0x45, 0x32, 0xee, 0xa0, 0xa7, + 0x02, 0xb8, 0xef, 0x05, 0x54, 0x56, 0xfe, 0x6b, 0x4e, 0x1d, 0xb0, 0x81, 0x7b, 0xcc, 0x6d, 0x81, + 0xc3, 0x02, 0x37, 0x52, 0x2f, 0x5d, 0xb2, 0x9e, 0x8d, 0x47, 0xcd, 0xa7, 0x17, 0x77, 0x01, 0xc9, + 0xdd, 0x3a, 0xf8, 0x1c, 0x6d, 0x50, 0x47, 0x78, 0x03, 0x38, 0x04, 0xea, 0xf6, 0xbc, 0x00, 0xd2, + 0x00, 0x65, 0x15, 0xe0, 0xc9, 0x78, 0xd4, 0xdc, 0x78, 0x33, 0x0b, 0x40, 0x66, 0xf3, 0xf0, 0x10, + 0xad, 0x06, 0xcc, 0x85, 0x16, 0xf4, 0xc0, 0x11, 0x8c, 0xeb, 0x15, 0x55, 0xea, 0xd7, 0xf7, 0x9a, + 0x1a, 0xc6, 0x59, 0x4e, 0xe1, 0xab, 0x40, 0xf0, 0xa1, 0xf5, 0x38, 0xa9, 0xe3, 0x6a, 0xde, 0x45, + 0x0a, 0xa1, 0xf0, 0x37, 0x08, 0x4b, 0x6d, 0xcf, 0x81, 0x37, 0x8e, 0xc3, 0xfa, 0x81, 0x38, 0xa3, + 0x3e, 0xe8, 0x55, 0xf5, 0x0e, 0x59, 0x9f, 0xb7, 0xa6, 0x10, 0x64, 0x06, 0x0b, 0x1f, 0xa1, 0x07, + 0x45, 0xab, 0x5e, 0x2b, 0xcc, 0x10, 0xfd, 0x10, 0x42, 0x0e, 0x8e, 0x1c, 0xc8, 0x45, 0x45, 0x72, + 0x8b, 0x87, 0x3f, 0x46, 0x55, 0x99, 0xa5, 0xca, 0x05, 0x29, 0x8d, 0xac, 0x45, 0xcf, 0x12, 0x3b, + 0xc9, 0x10, 0xf8, 0x53, 0xb4, 0x72, 0xc9, 0x22, 0x71, 0x06, 0xe2, 0x47, 0xc6, 0xbb, 0xfa, 0xca, + 0x96, 0xb6, 0x5b, 0xb5, 0x1e, 0x25, 0x84, 0x95, 0xa3, 0x89, 0x8b, 0xe4, 0x71, 0xf2, 0x77, 0x93, + 0x57, 0xfb, 0xf8, 0x50, 0x5f, 0x55, 0x94, 0xec, 0x77, 0x3b, 0x8a, 0xcd, 0x24, 0xf5, 0xa7, 0xd0, + 0x63, 0xfb, 0x40, 0xaf, 0x4f, 0x43, 0x8f, 0xed, 0x03, 0x92, 0xfa, 0x65, 0xea, 0xf2, 0x18, 0xc8, + 0xd4, 0xd7, 0x8a, 0xa9, 0x1f, 0x25, 0x76, 0x92, 0x21, 0xb0, 0x89, 0x6a, 0x51, 0xbf, 0xed, 0x32, + 0x9f, 0x7a, 0x81, 0xbe, 0xae, 0xe0, 0xeb, 0x09, 0xbc, 0xd6, 0x4a, 0x1d, 0x64, 0x82, 0xc1, 0x5f, + 0xa2, 0xba, 0x5c, 0x6e, 0x6e, 0xbf, 0x07, 0x5c, 0xc5, 0x78, 0xa4, 0x48, 0xd9, 0x00, 0x6c, 0xa5, + 0x4e, 0x55, 0xa3, 0x22, 0x76, 0xf3, 0x35, 0x5a, 0x9f, 0xea, 0x12, 0xbc, 0x86, 0x4a, 0x5d, 0x18, + 0xc6, 0xe3, 0x9e, 0xc8, 0x23, 0x7e, 0x8c, 0xca, 0x03, 0xda, 0xeb, 0x43, 0x3c, 0xca, 0x49, 0x7c, + 0xf9, 0x62, 0xf1, 0x95, 0xb6, 0xfd, 0x5b, 0x09, 0xd5, 0xb2, 0x95, 0x82, 0x4d, 0x54, 0x0e, 0x2f, + 0x69, 0x94, 0xae, 0x8a, 0x27, 0xe9, 0xff, 0x6e, 0x4b, 0xe3, 0xcd, 0xa8, 0x59, 0xb5, 0x99, 0xab, + 0xce, 0x24, 0xc6, 0xe1, 0x77, 0x08, 0x39, 0xe9, 0x12, 0x48, 0x07, 0xca, 0xfe, 0xdc, 0x5d, 0x9e, + 0xed, 0x8f, 0xc9, 0xee, 0xcd, 0x4c, 0x11, 0xc9, 0x29, 0xe7, 0x07, 0x69, 0xe9, 0xee, 0x41, 0x9a, + 0x9b, 0xcd, 0x4b, 0x77, 0xce, 0xe6, 0x1d, 0xb4, 0x1c, 0xbf, 0xf0, 0xed, 0x19, 0x1e, 0x37, 0x00, + 0x49, 0xbc, 0xf8, 0x7f, 0xa8, 0x1c, 0x32, 0xf7, 0xd8, 0x4e, 0x26, 0x78, 0x36, 0x03, 0x6d, 0x69, + 0x24, 0xb1, 0x0f, 0xbf, 0x45, 0x35, 0x35, 0xb8, 0xd4, 0xfe, 0xa9, 0xdc, 0x7b, 0xff, 0xd4, 0x55, + 0x77, 0xa4, 0x02, 0x64, 0xa2, 0x65, 0xed, 0x5e, 0x5d, 0x37, 0x16, 0xde, 0x5f, 0x37, 0x16, 0x3e, + 0x5c, 0x37, 0x16, 0x7e, 0x1e, 0x37, 0xb4, 0xab, 0x71, 0x43, 0x7b, 0x3f, 0x6e, 0x68, 0x1f, 0xc6, + 0x0d, 0xed, 0xaf, 0x71, 0x43, 0xfb, 0xe5, 0xef, 0xc6, 0xc2, 0xb7, 0x8b, 0x83, 0xbd, 0x7f, 0x02, + 0x00, 0x00, 0xff, 0xff, 0xdf, 0x7a, 0x1b, 0x54, 0x4e, 0x0a, 0x00, 0x00, +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto b/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto index e0e222bfab0..821f82537fe 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto +++ b/vendor/k8s.io/apiserver/pkg/apis/example/v1/generated.proto @@ -31,12 +31,12 @@ option go_package = "v1"; // Pod is a collection of containers, used as either input (create, update) or as output (list, get). message Pod { // Standard object's metadata. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata // +optional optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; // Specification of the desired behavior of the pod. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional optional PodSpec spec = 2; @@ -44,7 +44,7 @@ message Pod { // This data may not be up to date. // Populated by the system. // Read-only. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional optional PodStatus status = 3; } @@ -80,7 +80,7 @@ message PodCondition { // PodList is a list of Pods. message PodList { // Standard list metadata. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds // +optional optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; @@ -190,7 +190,7 @@ message PodStatus { optional string message = 3; // A brief CamelCase message indicating details about why the pod is in this state. - // e.g. 'DiskPressure' + // e.g. 'OutOfDisk' // +optional optional string reason = 4; diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/v1/types.go b/vendor/k8s.io/apiserver/pkg/apis/example/v1/types.go index 111cf59be6a..06c3f9f8873 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/v1/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/v1/types.go @@ -33,12 +33,12 @@ type ( type Pod struct { metav1.TypeMeta `json:",inline"` // Standard object's metadata. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Specification of the desired behavior of the pod. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` @@ -46,7 +46,7 @@ type Pod struct { // This data may not be up to date. // Populated by the system. // Read-only. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` } @@ -66,7 +66,7 @@ type PodStatus struct { // +optional Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"` // A brief CamelCase message indicating details about why the pod is in this state. - // e.g. 'DiskPressure' + // e.g. 'OutOfDisk' // +optional Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"` @@ -186,7 +186,7 @@ type PodSpec struct { type PodList struct { metav1.TypeMeta `json:",inline"` // Standard list metadata. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds // +optional metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/example/v1/zz_generated.deepcopy.go index e1fd9496d24..758aa305579 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/v1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/v1/zz_generated.deepcopy.go @@ -74,7 +74,7 @@ func (in *PodCondition) DeepCopy() *PodCondition { func (in *PodList) DeepCopyInto(out *PodList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Pod, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/apis/example/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/apis/example/zz_generated.deepcopy.go index d92ab315c06..c37c0aacd76 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example/zz_generated.deepcopy.go @@ -74,7 +74,7 @@ func (in *PodCondition) DeepCopy() *PodCondition { func (in *PodList) DeepCopyInto(out *PodList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Pod, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/apis/example2/install/roundtrip_test.go b/vendor/k8s.io/apiserver/pkg/apis/example2/install/roundtrip_test.go index 6cb530b1b86..7f67418d245 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example2/install/roundtrip_test.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example2/install/roundtrip_test.go @@ -25,5 +25,4 @@ import ( func TestRoundTrip(t *testing.T) { roundtrip.RoundTripTestForAPIGroup(t, Install, examplefuzzer.Funcs) - roundtrip.RoundTripProtobufTestForAPIGroup(t, Install, examplefuzzer.Funcs) } diff --git a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/conversion.go b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/conversion.go index 1f647b1567f..21abdefd5d6 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/conversion.go @@ -18,9 +18,25 @@ package v1 import ( conversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" example "k8s.io/apiserver/pkg/apis/example" ) +func addConversionFuncs(scheme *runtime.Scheme) error { + // Add non-generated conversion functions to handle the *int32 -> int32 + // conversion. A pointer is useful in the versioned type so we can default + // it, but a plain int32 is more convenient in the internal type. These + // functions are the same as the autogenerated ones in every other way. + err := scheme.AddConversionFuncs( + Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec, + Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec, + ) + if err != nil { + return err + } + return nil +} + func Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec(in *example.ReplicaSetSpec, out *ReplicaSetSpec, s conversion.Scope) error { out.Replicas = new(int32) *out.Replicas = int32(in.Replicas) diff --git a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/register.go b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/register.go index d1543f2fcf3..1cb0f5eb8d5 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/register.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/register.go @@ -50,7 +50,7 @@ func init() { // We only register manually written functions here. The registration of the // generated functions takes place in the generated files. The separation // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs) + localSchemeBuilder.Register(addKnownTypes, addConversionFuncs, addDefaultingFuncs) } // Adds the list of known types to the given scheme. diff --git a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/types.go b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/types.go index 9939edb4a7c..e6e6fb00c19 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/types.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/types.go @@ -28,12 +28,12 @@ type ReplicaSet struct { // If the Labels of a ReplicaSet are empty, they are defaulted to // be the same as the Pod(s) that the ReplicaSet manages. - // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Spec defines the specification of the desired behavior of the ReplicaSet. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional Spec ReplicaSetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` @@ -41,7 +41,7 @@ type ReplicaSet struct { // This data may be out of date by some window of time. // Populated by the system. // Read-only. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status // +optional Status ReplicaSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` } diff --git a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/zz_generated.conversion.go b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/zz_generated.conversion.go index 344e06a207a..91884503cc6 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/example2/v1/zz_generated.conversion.go +++ b/vendor/k8s.io/apiserver/pkg/apis/example2/v1/zz_generated.conversion.go @@ -44,6 +44,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*ReplicaSetSpec)(nil), (*example.ReplicaSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ReplicaSetSpec_To_example_ReplicaSetSpec(a.(*ReplicaSetSpec), b.(*example.ReplicaSetSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.ReplicaSetSpec)(nil), (*ReplicaSetSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_ReplicaSetSpec_To_v1_ReplicaSetSpec(a.(*example.ReplicaSetSpec), b.(*ReplicaSetSpec), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*ReplicaSetStatus)(nil), (*example.ReplicaSetStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1_ReplicaSetStatus_To_example_ReplicaSetStatus(a.(*ReplicaSetStatus), b.(*example.ReplicaSetStatus), scope) }); err != nil { diff --git a/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go b/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go deleted file mode 100644 index 200cc8a7e01..00000000000 --- a/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go +++ /dev/null @@ -1,475 +0,0 @@ -/* -Copyright 2019 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 bootstrap - -import ( - coordinationv1 "k8s.io/api/coordination/v1" - corev1 "k8s.io/api/core/v1" - flowcontrol "k8s.io/api/flowcontrol/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/authentication/serviceaccount" - "k8s.io/apiserver/pkg/authentication/user" -) - -// The objects that define an apiserver's initial behavior. The -// registered defaulting procedures make no changes to these -// particular objects (this is verified in the unit tests of the -// internalbootstrap package; it can not be verified in this package -// because that would require importing k8s.io/kubernetes). -var ( - MandatoryPriorityLevelConfigurations = []*flowcontrol.PriorityLevelConfiguration{ - MandatoryPriorityLevelConfigurationExempt, - MandatoryPriorityLevelConfigurationCatchAll, - } - MandatoryFlowSchemas = []*flowcontrol.FlowSchema{ - MandatoryFlowSchemaExempt, - MandatoryFlowSchemaCatchAll, - } -) - -// The objects that define the current suggested additional configuration -var ( - SuggestedPriorityLevelConfigurations = []*flowcontrol.PriorityLevelConfiguration{ - // "system" priority-level is for the system components that affects self-maintenance of the - // cluster and the availability of those running pods in the cluster, including kubelet and - // kube-proxy. - SuggestedPriorityLevelConfigurationSystem, - // "leader-election" is dedicated for controllers' leader-election, which majorly affects the - // availability of any controller runs in the cluster. - SuggestedPriorityLevelConfigurationLeaderElection, - // "workload-high" is used by those workloads with higher priority but their failure won't directly - // impact the existing running pods in the cluster, which includes kube-scheduler, and those well-known - // built-in workloads such as "deployments", "replicasets" and other low-level custom workload which - // is important for the cluster. - SuggestedPriorityLevelConfigurationWorkloadHigh, - // "workload-low" is used by those workloads with lower priority which availability only has a - // minor impact on the cluster. - SuggestedPriorityLevelConfigurationWorkloadLow, - // "global-default" serves the rest traffic not handled by the other suggested flow-schemas above. - SuggestedPriorityLevelConfigurationGlobalDefault, - } - SuggestedFlowSchemas = []*flowcontrol.FlowSchema{ - SuggestedFlowSchemaSystemNodes, // references "system" priority-level - SuggestedFlowSchemaSystemLeaderElection, // references "leader-election" priority-level - SuggestedFlowSchemaWorkloadLeaderElection, // references "leader-election" priority-level - SuggestedFlowSchemaKubeControllerManager, // references "workload-high" priority-level - SuggestedFlowSchemaKubeScheduler, // references "workload-high" priority-level - SuggestedFlowSchemaKubeSystemServiceAccounts, // references "workload-high" priority-level - SuggestedFlowSchemaServiceAccounts, // references "workload-low" priority-level - SuggestedFlowSchemaGlobalDefault, // references "global-default" priority-level - } -) - -// Mandatory PriorityLevelConfiguration objects -var ( - MandatoryPriorityLevelConfigurationExempt = newPriorityLevelConfiguration( - flowcontrol.PriorityLevelConfigurationNameExempt, - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementExempt, - }, - ) - MandatoryPriorityLevelConfigurationCatchAll = newPriorityLevelConfiguration( - "catch-all", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 1, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeReject, - }, - }, - }) -) - -// Mandatory FlowSchema objects -var ( - // "exempt" priority-level is used for preventing priority inversion and ensuring that sysadmin - // requests are always possible. - MandatoryFlowSchemaExempt = newFlowSchema( - "exempt", - flowcontrol.PriorityLevelConfigurationNameExempt, - 1, // matchingPrecedence - "", // distinguisherMethodType - flowcontrol.PolicyRulesWithSubjects{ - Subjects: groups(user.SystemPrivilegedGroup), - ResourceRules: []flowcontrol.ResourcePolicyRule{ - resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true, - ), - }, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}, - ), - }, - }, - ) - // "catch-all" priority-level only gets a minimal positive share of concurrency and won't be reaching - // ideally unless you intentionally deleted the suggested "global-default". - MandatoryFlowSchemaCatchAll = newFlowSchema( - "catch-all", - "catch-all", - 10000, // matchingPrecedence - flowcontrol.FlowDistinguisherMethodByUserType, // distinguisherMethodType - flowcontrol.PolicyRulesWithSubjects{ - Subjects: groups(user.AllUnauthenticated, user.AllAuthenticated), - ResourceRules: []flowcontrol.ResourcePolicyRule{ - resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true, - ), - }, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}, - ), - }, - }, - ) -) - -// Suggested PriorityLevelConfiguration objects -var ( - // system priority-level - SuggestedPriorityLevelConfigurationSystem = newPriorityLevelConfiguration( - "system", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 30, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeQueue, - Queuing: &flowcontrol.QueuingConfiguration{ - Queues: 64, - HandSize: 6, - QueueLengthLimit: 50, - }, - }, - }, - }) - // leader-election priority-level - SuggestedPriorityLevelConfigurationLeaderElection = newPriorityLevelConfiguration( - "leader-election", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 10, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeQueue, - Queuing: &flowcontrol.QueuingConfiguration{ - Queues: 16, - HandSize: 4, - QueueLengthLimit: 50, - }, - }, - }, - }) - // workload-high priority-level - SuggestedPriorityLevelConfigurationWorkloadHigh = newPriorityLevelConfiguration( - "workload-high", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 40, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeQueue, - Queuing: &flowcontrol.QueuingConfiguration{ - Queues: 128, - HandSize: 6, - QueueLengthLimit: 50, - }, - }, - }, - }) - // workload-low priority-level - SuggestedPriorityLevelConfigurationWorkloadLow = newPriorityLevelConfiguration( - "workload-low", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 20, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeQueue, - Queuing: &flowcontrol.QueuingConfiguration{ - Queues: 128, - HandSize: 6, - QueueLengthLimit: 50, - }, - }, - }, - }) - // global-default priority-level - SuggestedPriorityLevelConfigurationGlobalDefault = newPriorityLevelConfiguration( - "global-default", - flowcontrol.PriorityLevelConfigurationSpec{ - Type: flowcontrol.PriorityLevelEnablementLimited, - Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 100, - LimitResponse: flowcontrol.LimitResponse{ - Type: flowcontrol.LimitResponseTypeQueue, - Queuing: &flowcontrol.QueuingConfiguration{ - Queues: 128, - HandSize: 6, - QueueLengthLimit: 50, - }, - }, - }, - }) -) - -// Suggested FlowSchema objects -var ( - SuggestedFlowSchemaSystemNodes = newFlowSchema( - "system-nodes", "system", 500, - flowcontrol.FlowDistinguisherMethodByUserType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: groups(user.NodesGroup), // the nodes group - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) - SuggestedFlowSchemaSystemLeaderElection = newFlowSchema( - "system-leader-election", "leader-election", 100, - flowcontrol.FlowDistinguisherMethodByUserType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: append( - users(user.KubeControllerManager, user.KubeScheduler), - kubeSystemServiceAccount(flowcontrol.NameAll)...), - ResourceRules: []flowcontrol.ResourcePolicyRule{ - resourceRule( - []string{"get", "create", "update"}, - []string{corev1.GroupName}, - []string{"endpoints", "configmaps"}, - []string{"kube-system"}, - false), - resourceRule( - []string{"get", "create", "update"}, - []string{coordinationv1.GroupName}, - []string{"leases"}, - []string{flowcontrol.NamespaceEvery}, - false), - }, - }, - ) - SuggestedFlowSchemaWorkloadLeaderElection = newFlowSchema( - "workload-leader-election", "leader-election", 200, - flowcontrol.FlowDistinguisherMethodByUserType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: kubeSystemServiceAccount(flowcontrol.NameAll), - ResourceRules: []flowcontrol.ResourcePolicyRule{ - resourceRule( - []string{"get", "create", "update"}, - []string{corev1.GroupName}, - []string{"endpoints", "configmaps"}, - []string{flowcontrol.NamespaceEvery}, - false), - resourceRule( - []string{"get", "create", "update"}, - []string{coordinationv1.GroupName}, - []string{"leases"}, - []string{flowcontrol.NamespaceEvery}, - false), - }, - }, - ) - SuggestedFlowSchemaKubeControllerManager = newFlowSchema( - "kube-controller-manager", "workload-high", 800, - flowcontrol.FlowDistinguisherMethodByNamespaceType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: users(user.KubeControllerManager), - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) - SuggestedFlowSchemaKubeScheduler = newFlowSchema( - "kube-scheduler", "workload-high", 800, - flowcontrol.FlowDistinguisherMethodByNamespaceType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: users(user.KubeScheduler), - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) - SuggestedFlowSchemaKubeSystemServiceAccounts = newFlowSchema( - "kube-system-service-accounts", "workload-high", 900, - flowcontrol.FlowDistinguisherMethodByNamespaceType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: kubeSystemServiceAccount(flowcontrol.NameAll), - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) - SuggestedFlowSchemaServiceAccounts = newFlowSchema( - "service-accounts", "workload-low", 9000, - flowcontrol.FlowDistinguisherMethodByUserType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: groups(serviceaccount.AllServiceAccountsGroup), - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) - SuggestedFlowSchemaGlobalDefault = newFlowSchema( - "global-default", "global-default", 9900, - flowcontrol.FlowDistinguisherMethodByUserType, - flowcontrol.PolicyRulesWithSubjects{ - Subjects: groups(serviceaccount.AllServiceAccountsGroup), - ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.APIGroupAll}, - []string{flowcontrol.ResourceAll}, - []string{flowcontrol.NamespaceEvery}, - true)}, - NonResourceRules: []flowcontrol.NonResourcePolicyRule{ - nonResourceRule( - []string{flowcontrol.VerbAll}, - []string{flowcontrol.NonResourceAll}), - }, - }, - ) -) - -func newPriorityLevelConfiguration(name string, spec flowcontrol.PriorityLevelConfigurationSpec) *flowcontrol.PriorityLevelConfiguration { - return &flowcontrol.PriorityLevelConfiguration{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - Spec: spec} -} - -func newFlowSchema(name, plName string, matchingPrecedence int32, dmType flowcontrol.FlowDistinguisherMethodType, rules ...flowcontrol.PolicyRulesWithSubjects) *flowcontrol.FlowSchema { - var dm *flowcontrol.FlowDistinguisherMethod - if dmType != "" { - dm = &flowcontrol.FlowDistinguisherMethod{Type: dmType} - } - return &flowcontrol.FlowSchema{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - Spec: flowcontrol.FlowSchemaSpec{ - PriorityLevelConfiguration: flowcontrol.PriorityLevelConfigurationReference{ - Name: plName, - }, - MatchingPrecedence: matchingPrecedence, - DistinguisherMethod: dm, - Rules: rules}, - } - -} - -func groups(names ...string) []flowcontrol.Subject { - ans := make([]flowcontrol.Subject, len(names)) - for idx, name := range names { - ans[idx] = flowcontrol.Subject{ - Kind: flowcontrol.SubjectKindGroup, - Group: &flowcontrol.GroupSubject{ - Name: name, - }, - } - } - return ans -} - -func users(names ...string) []flowcontrol.Subject { - ans := make([]flowcontrol.Subject, len(names)) - for idx, name := range names { - ans[idx] = flowcontrol.Subject{ - Kind: flowcontrol.SubjectKindUser, - User: &flowcontrol.UserSubject{ - Name: name, - }, - } - } - return ans -} - -func kubeSystemServiceAccount(names ...string) []flowcontrol.Subject { - subjects := []flowcontrol.Subject{} - for _, name := range names { - subjects = append(subjects, flowcontrol.Subject{ - Kind: flowcontrol.SubjectKindServiceAccount, - ServiceAccount: &flowcontrol.ServiceAccountSubject{ - Name: name, - Namespace: metav1.NamespaceSystem, - }, - }) - } - return subjects -} - -func resourceRule(verbs []string, groups []string, resources []string, namespaces []string, clusterScoped bool) flowcontrol.ResourcePolicyRule { - return flowcontrol.ResourcePolicyRule{ - Verbs: verbs, - APIGroups: groups, - Resources: resources, - Namespaces: namespaces, - ClusterScope: clusterScoped, - } -} - -func nonResourceRule(verbs []string, nonResourceURLs []string) flowcontrol.NonResourcePolicyRule { - return flowcontrol.NonResourcePolicyRule{Verbs: verbs, NonResourceURLs: nonResourceURLs} -} diff --git a/vendor/k8s.io/apiserver/pkg/audit/OWNERS b/vendor/k8s.io/apiserver/pkg/audit/OWNERS index c3486ad5ded..178ce84a5ce 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/audit/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - sig-auth-audit-approvers reviewers: diff --git a/vendor/k8s.io/apiserver/pkg/audit/context.go b/vendor/k8s.io/apiserver/pkg/audit/context.go deleted file mode 100644 index 3d616bbd4cc..00000000000 --- a/vendor/k8s.io/apiserver/pkg/audit/context.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2020 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 audit - -import ( - "context" - - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" -) - -// The key type is unexported to prevent collisions -type key int - -const ( - // auditAnnotationsKey is the context key for the audit annotations. - auditAnnotationsKey key = iota -) - -// annotations = *[]annotation instead of a map to preserve order of insertions -type annotation struct { - key, value string -} - -// WithAuditAnnotations returns a new context that can store audit annotations -// via the AddAuditAnnotation function. This function is meant to be called from -// an early request handler to allow all later layers to set audit annotations. -// This is required to support flows where handlers that come before WithAudit -// (such as WithAuthentication) wish to set audit annotations. -func WithAuditAnnotations(parent context.Context) context.Context { - // this should never really happen, but prevent double registration of this slice - if _, ok := parent.Value(auditAnnotationsKey).(*[]annotation); ok { - return parent - } - - var annotations []annotation // avoid allocations until we actually need it - return genericapirequest.WithValue(parent, auditAnnotationsKey, &annotations) -} - -// AddAuditAnnotation sets the audit annotation for the given key, value pair. -// It is safe to call at most parts of request flow that come after WithAuditAnnotations. -// The notable exception being that this function must not be called via a -// defer statement (i.e. after ServeHTTP) in a handler that runs before WithAudit -// as at that point the audit event has already been sent to the audit sink. -// Handlers that are unaware of their position in the overall request flow should -// prefer AddAuditAnnotation over LogAnnotation to avoid dropping annotations. -func AddAuditAnnotation(ctx context.Context, key, value string) { - // use the audit event directly if we have it - if ae := genericapirequest.AuditEventFrom(ctx); ae != nil { - LogAnnotation(ae, key, value) - return - } - - annotations, ok := ctx.Value(auditAnnotationsKey).(*[]annotation) - if !ok { - return // adding audit annotation is not supported at this call site - } - - *annotations = append(*annotations, annotation{key: key, value: value}) -} - -// This is private to prevent reads/write to the slice from outside of this package. -// The audit event should be directly read to get access to the annotations. -func auditAnnotationsFrom(ctx context.Context) []annotation { - annotations, ok := ctx.Value(auditAnnotationsKey).(*[]annotation) - if !ok { - return nil // adding audit annotation is not supported at this call site - } - - return *annotations -} diff --git a/vendor/k8s.io/apiserver/pkg/audit/event/attributes.go b/vendor/k8s.io/apiserver/pkg/audit/event/attributes.go index d832a7ea53d..576b8db8482 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/event/attributes.go +++ b/vendor/k8s.io/apiserver/pkg/audit/event/attributes.go @@ -20,7 +20,6 @@ import ( "fmt" "net/url" - authnv1 "k8s.io/api/authentication/v1" "k8s.io/apiserver/pkg/apis/audit" authuser "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" @@ -127,7 +126,7 @@ func (a *attributes) GetPath() string { } // user represents the event user -type user authnv1.UserInfo +type user audit.UserInfo // GetName returns the user name func (u user) GetName() string { return u.Username } diff --git a/vendor/k8s.io/apiserver/pkg/audit/metrics.go b/vendor/k8s.io/apiserver/pkg/audit/metrics.go index 88d4154e8ae..9b81b30cc26 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/metrics.go +++ b/vendor/k8s.io/apiserver/pkg/audit/metrics.go @@ -19,9 +19,8 @@ package audit import ( "fmt" + "github.com/prometheus/client_golang/prometheus" auditinternal "k8s.io/apiserver/pkg/apis/audit" - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" "k8s.io/klog" ) @@ -29,58 +28,46 @@ const ( subsystem = "apiserver_audit" ) -/* - * By default, all the following metrics are defined as falling under - * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes) - * - * Promoting the stability level of the metric is a responsibility of the component owner, since it - * involves explicitly acknowledging support for the metric across multiple releases, in accordance with - * the metric stability policy. - */ var ( - eventCounter = metrics.NewCounter( - &metrics.CounterOpts{ - Subsystem: subsystem, - Name: "event_total", - Help: "Counter of audit events generated and sent to the audit backend.", - StabilityLevel: metrics.ALPHA, + eventCounter = prometheus.NewCounter( + prometheus.CounterOpts{ + Subsystem: subsystem, + Name: "event_total", + Help: "Counter of audit events generated and sent to the audit backend.", }) - errorCounter = metrics.NewCounterVec( - &metrics.CounterOpts{ + errorCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ Subsystem: subsystem, Name: "error_total", Help: "Counter of audit events that failed to be audited properly. " + "Plugin identifies the plugin affected by the error.", - StabilityLevel: metrics.ALPHA, }, []string{"plugin"}, ) - levelCounter = metrics.NewCounterVec( - &metrics.CounterOpts{ - Subsystem: subsystem, - Name: "level_total", - Help: "Counter of policy levels for audit events (1 per request).", - StabilityLevel: metrics.ALPHA, + levelCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: subsystem, + Name: "level_total", + Help: "Counter of policy levels for audit events (1 per request).", }, []string{"level"}, ) - ApiserverAuditDroppedCounter = metrics.NewCounter( - &metrics.CounterOpts{ + ApiserverAuditDroppedCounter = prometheus.NewCounter( + prometheus.CounterOpts{ Subsystem: subsystem, Name: "requests_rejected_total", Help: "Counter of apiserver requests rejected due to an error " + "in audit logging backend.", - StabilityLevel: metrics.ALPHA, }, ) ) func init() { - legacyregistry.MustRegister(eventCounter) - legacyregistry.MustRegister(errorCounter) - legacyregistry.MustRegister(levelCounter) - legacyregistry.MustRegister(ApiserverAuditDroppedCounter) + prometheus.MustRegister(eventCounter) + prometheus.MustRegister(errorCounter) + prometheus.MustRegister(levelCounter) + prometheus.MustRegister(ApiserverAuditDroppedCounter) } // ObserveEvent updates the relevant prometheus metrics for the generated audit event. diff --git a/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go b/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go index e9a901abf64..41c6b1a491f 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go +++ b/vendor/k8s.io/apiserver/pkg/audit/policy/checker.go @@ -185,11 +185,11 @@ func ruleMatchesResource(r *audit.PolicyRule, attrs authorizer.Attributes) bool return true } // match "*/subresource" - if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimPrefix(res, "*/") { + if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") { return true } // match "resource/*" - if strings.HasSuffix(res, "/*") && resource == strings.TrimSuffix(res, "/*") { + if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") { return true } } diff --git a/vendor/k8s.io/apiserver/pkg/audit/request.go b/vendor/k8s.io/apiserver/pkg/audit/request.go index a3c44ff307f..d4b12770eab 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/request.go +++ b/vendor/k8s.io/apiserver/pkg/audit/request.go @@ -20,14 +20,13 @@ import ( "bytes" "fmt" "net/http" - "reflect" "time" - "github.com/google/uuid" + "github.com/pborman/uuid" "k8s.io/klog" - authnv1 "k8s.io/api/authentication/v1" - "k8s.io/apimachinery/pkg/api/meta" + "reflect" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -58,7 +57,7 @@ func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs a if ids != "" { ev.AuditID = types.UID(ids) } else { - ev.AuditID = types.UID(uuid.New().String()) + ev.AuditID = types.UID(uuid.NewRandom().String()) } ips := utilnet.SourceIPs(req) @@ -69,9 +68,9 @@ func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs a if user := attribs.GetUser(); user != nil { ev.User.Username = user.GetName() - ev.User.Extra = map[string]authnv1.ExtraValue{} + ev.User.Extra = map[string]auditinternal.ExtraValue{} for k, v := range user.GetExtra() { - ev.User.Extra[k] = authnv1.ExtraValue(v) + ev.User.Extra[k] = auditinternal.ExtraValue(v) } ev.User.Groups = user.GetGroups() ev.User.UID = user.GetUID() @@ -88,10 +87,6 @@ func NewEventFromRequest(req *http.Request, level auditinternal.Level, attribs a } } - for _, kv := range auditAnnotationsFrom(req.Context()) { - LogAnnotation(ev, kv.key, kv.value) - } - return ev, nil } @@ -100,14 +95,14 @@ func LogImpersonatedUser(ae *auditinternal.Event, user user.Info) { if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) { return } - ae.ImpersonatedUser = &authnv1.UserInfo{ + ae.ImpersonatedUser = &auditinternal.UserInfo{ Username: user.GetName(), } ae.ImpersonatedUser.Groups = user.GetGroups() ae.ImpersonatedUser.UID = user.GetUID() - ae.ImpersonatedUser.Extra = map[string]authnv1.ExtraValue{} + ae.ImpersonatedUser.Extra = map[string]auditinternal.ExtraValue{} for k, v := range user.GetExtra() { - ae.ImpersonatedUser.Extra[k] = authnv1.ExtraValue(v) + ae.ImpersonatedUser.Extra[k] = auditinternal.ExtraValue(v) } } @@ -122,9 +117,8 @@ func LogRequestObject(ae *auditinternal.Event, obj runtime.Object, gvr schema.Gr if ae.ObjectRef == nil { ae.ObjectRef = &auditinternal.ObjectReference{} } - - // meta.Accessor is more general than ObjectMetaAccessor, but if it fails, we can just skip setting these bits - if meta, err := meta.Accessor(obj); err == nil { + if acc, ok := obj.(metav1.ObjectMetaAccessor); ok { + meta := acc.GetObjectMeta() if len(ae.ObjectRef.Namespace) == 0 { ae.ObjectRef.Namespace = meta.GetNamespace() } @@ -202,22 +196,22 @@ func LogResponseObject(ae *auditinternal.Event, obj runtime.Object, gv schema.Gr } func encodeObject(obj runtime.Object, gv schema.GroupVersion, serializer runtime.NegotiatedSerializer) (*runtime.Unknown, error) { - const mediaType = runtime.ContentTypeJSON - info, ok := runtime.SerializerInfoForMediaType(serializer.SupportedMediaTypes(), mediaType) - if !ok { - return nil, fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType) - } - - enc := serializer.EncoderForVersion(info.Serializer, gv) - var buf bytes.Buffer - if err := enc.Encode(obj, &buf); err != nil { - return nil, fmt.Errorf("encoding failed: %v", err) + supported := serializer.SupportedMediaTypes() + for i := range supported { + if supported[i].MediaType == "application/json" { + enc := serializer.EncoderForVersion(supported[i].Serializer, gv) + var buf bytes.Buffer + if err := enc.Encode(obj, &buf); err != nil { + return nil, fmt.Errorf("encoding failed: %v", err) + } + + return &runtime.Unknown{ + Raw: buf.Bytes(), + ContentType: runtime.ContentTypeJSON, + }, nil + } } - - return &runtime.Unknown{ - Raw: buf.Bytes(), - ContentType: runtime.ContentTypeJSON, - }, nil + return nil, fmt.Errorf("no json encoder found") } // LogAnnotation fills in the Annotations according to the key value pair. @@ -235,6 +229,16 @@ func LogAnnotation(ae *auditinternal.Event, key, value string) { ae.Annotations[key] = value } +// LogAnnotations fills in the Annotations according to the annotations map. +func LogAnnotations(ae *auditinternal.Event, annotations map[string]string) { + if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) { + return + } + for key, value := range annotations { + LogAnnotation(ae, key, value) + } +} + // truncate User-Agent if too long, otherwise return it directly. func maybeTruncateUserAgent(req *http.Request) string { ua := req.UserAgent() diff --git a/vendor/k8s.io/apiserver/pkg/audit/scheme.go b/vendor/k8s.io/apiserver/pkg/audit/scheme.go index 031759ec75f..d72e394ec0d 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/scheme.go +++ b/vendor/k8s.io/apiserver/pkg/audit/scheme.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/apis/audit/v1" "k8s.io/apiserver/pkg/apis/audit/v1alpha1" "k8s.io/apiserver/pkg/apis/audit/v1beta1" @@ -37,6 +36,4 @@ func init() { utilruntime.Must(v1.AddToScheme(Scheme)) utilruntime.Must(v1alpha1.AddToScheme(Scheme)) utilruntime.Must(v1beta1.AddToScheme(Scheme)) - utilruntime.Must(auditinternal.AddToScheme(Scheme)) - utilruntime.Must(Scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta1.SchemeGroupVersion, v1alpha1.SchemeGroupVersion)) } diff --git a/vendor/k8s.io/apiserver/pkg/audit/util/conversion.go b/vendor/k8s.io/apiserver/pkg/audit/util/conversion.go index 9e2930bd365..6b1f35c4395 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/util/conversion.go +++ b/vendor/k8s.io/apiserver/pkg/audit/util/conversion.go @@ -35,12 +35,6 @@ func HookClientConfigForSink(a *v1alpha1.AuditSink) webhook.ClientConfig { Name: c.Service.Name, Namespace: c.Service.Namespace, } - if c.Service.Port != nil { - ret.Service.Port = *c.Service.Port - } else { - ret.Service.Port = 443 - } - if c.Service.Path != nil { ret.Service.Path = *c.Service.Path } diff --git a/vendor/k8s.io/apiserver/pkg/audit/util/conversion_test.go b/vendor/k8s.io/apiserver/pkg/audit/util/conversion_test.go index c8f0c66da14..4cd23c13d19 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/util/conversion_test.go +++ b/vendor/k8s.io/apiserver/pkg/audit/util/conversion_test.go @@ -24,7 +24,6 @@ import ( auditregv1alpha1 "k8s.io/api/auditregistration/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/util/webhook" - "k8s.io/utils/pointer" ) func TestHookClientConfigForSink(t *testing.T) { @@ -49,7 +48,6 @@ func TestHookClientConfigForSink(t *testing.T) { Name: "test", Path: &path, Namespace: "test", - Port: pointer.Int32Ptr(123), }, }, }, @@ -62,7 +60,6 @@ func TestHookClientConfigForSink(t *testing.T) { Name: "test", Namespace: "test", Path: path, - Port: 123, }, }, }, diff --git a/vendor/k8s.io/apiserver/pkg/authentication/OWNERS b/vendor/k8s.io/apiserver/pkg/authentication/OWNERS index 3e05d309be5..c607d2aa8c5 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/authentication/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - sig-auth-authenticators-approvers reviewers: diff --git a/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go b/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go index 8ff979b8074..e3b1b622cba 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/authenticator/interfaces.go @@ -35,6 +35,13 @@ type Request interface { AuthenticateRequest(req *http.Request) (*Response, bool, error) } +// Password checks a username and password against a backing authentication +// store and returns a Response or an error if the password could not be +// checked. +type Password interface { + AuthenticatePassword(ctx context.Context, user, password string) (*Response, bool, error) +} + // TokenFunc is a function that implements the Token interface. type TokenFunc func(ctx context.Context, token string) (*Response, bool, error) @@ -51,6 +58,14 @@ func (f RequestFunc) AuthenticateRequest(req *http.Request) (*Response, bool, er return f(req) } +// PasswordFunc is a function that implements the Password interface. +type PasswordFunc func(ctx context.Context, user, password string) (*Response, bool, error) + +// AuthenticatePassword implements authenticator.Password. +func (f PasswordFunc) AuthenticatePassword(ctx context.Context, user, password string) (*Response, bool, error) { + return f(ctx, user, password) +} + // Response is the struct returned by authenticator interfaces upon successful // authentication. It contains information about whether the authenticator // authenticated the request, information about the context of the diff --git a/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go b/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go index b9c7e2e6eee..67958c3639b 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/delegating.go @@ -18,6 +18,7 @@ package authenticatorfactory import ( "errors" + "fmt" "time" "github.com/go-openapi/spec" @@ -32,7 +33,8 @@ import ( "k8s.io/apiserver/pkg/authentication/request/x509" "k8s.io/apiserver/pkg/authentication/token/cache" webhooktoken "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook" - authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1" + authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1beta1" + "k8s.io/client-go/util/cert" ) // DelegatingAuthenticatorConfig is the minimal configuration needed to create an authenticator @@ -46,10 +48,8 @@ type DelegatingAuthenticatorConfig struct { // CacheTTL is the length of time that a token authentication answer will be cached. CacheTTL time.Duration - // CAContentProvider are the options for verifying incoming connections using mTLS and directly assigning to users. - // Generally this is the CA bundle file used to authenticate client certificates - // If this is nil, then mTLS will not be used. - ClientCertificateCAContentProvider CAContentProvider + // ClientCAFile is the CA bundle file used to authenticate client certificates + ClientCAFile string APIAudiences authenticator.Audiences @@ -63,19 +63,28 @@ func (c DelegatingAuthenticatorConfig) New() (authenticator.Request, *spec.Secur // front-proxy first, then remote // Add the front proxy authenticator if requested if c.RequestHeaderConfig != nil { - requestHeaderAuthenticator := headerrequest.NewDynamicVerifyOptionsSecure( - c.RequestHeaderConfig.CAContentProvider.VerifyOptions, + requestHeaderAuthenticator, err := headerrequest.NewSecure( + c.RequestHeaderConfig.ClientCA, c.RequestHeaderConfig.AllowedClientNames, c.RequestHeaderConfig.UsernameHeaders, c.RequestHeaderConfig.GroupHeaders, c.RequestHeaderConfig.ExtraHeaderPrefixes, ) + if err != nil { + return nil, nil, err + } authenticators = append(authenticators, requestHeaderAuthenticator) } // x509 client cert auth - if c.ClientCertificateCAContentProvider != nil { - authenticators = append(authenticators, x509.NewDynamic(c.ClientCertificateCAContentProvider.VerifyOptions, x509.CommonNameUserConversion)) + if len(c.ClientCAFile) > 0 { + clientCAs, err := cert.NewPool(c.ClientCAFile) + if err != nil { + return nil, nil, fmt.Errorf("unable to load client CA file %s: %v", c.ClientCAFile, err) + } + verifyOpts := x509.DefaultVerifyOptions() + verifyOpts.Roots = clientCAs + authenticators = append(authenticators, x509.New(verifyOpts, x509.CommonNameUserConversion)) } if c.TokenAccessReviewClient != nil { diff --git a/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go b/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go index b5aa1c524a7..3eeb238f056 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/authenticatorfactory/requestheader.go @@ -16,33 +16,16 @@ limitations under the License. package authenticatorfactory -import ( - "crypto/x509" - - "k8s.io/apiserver/pkg/authentication/request/headerrequest" -) - type RequestHeaderConfig struct { // UsernameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins. - UsernameHeaders headerrequest.StringSliceProvider + UsernameHeaders []string // GroupHeaders are the headers to check (case-insensitively) for a group names. All values will be used. - GroupHeaders headerrequest.StringSliceProvider + GroupHeaders []string // ExtraHeaderPrefixes are the head prefixes to check (case-insentively) for filling in // the user.Info.Extra. All values of all matching headers will be added. - ExtraHeaderPrefixes headerrequest.StringSliceProvider - // CAContentProvider the options for verifying incoming connections using mTLS. Generally this points to CA bundle file which is used verify the identity of the front proxy. - // It may produce different options at will. - CAContentProvider CAContentProvider + ExtraHeaderPrefixes []string + // ClientCA points to CA bundle file which is used verify the identity of the front proxy + ClientCA string // AllowedClientNames is a list of common names that may be presented by the authenticating front proxy. Empty means: accept any. - AllowedClientNames headerrequest.StringSliceProvider -} - -// CAContentProvider provides ca bundle byte content -type CAContentProvider interface { - // Name is just an identifier - Name() string - // CurrentCABundleContent provides ca bundle byte content - CurrentCABundleContent() []byte - // VerifyOptions provides VerifyOptions for authenticators - VerifyOptions() (x509.VerifyOptions, bool) + AllowedClientNames []string } diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go b/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go index abf509a97d9..70af861d8b5 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader.go @@ -24,47 +24,26 @@ import ( "net/url" "strings" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/authenticator" x509request "k8s.io/apiserver/pkg/authentication/request/x509" "k8s.io/apiserver/pkg/authentication/user" utilcert "k8s.io/client-go/util/cert" ) -// StringSliceProvider is a way to get a string slice value. It is heavily used for authentication headers among other places. -type StringSliceProvider interface { - // Value returns the current string slice. Callers should never mutate the returned value. - Value() []string -} - -// StringSliceProviderFunc is a function that matches the StringSliceProvider interface -type StringSliceProviderFunc func() []string - -// Value returns the current string slice. Callers should never mutate the returned value. -func (d StringSliceProviderFunc) Value() []string { - return d() -} - -// StaticStringSlice a StringSliceProvider that returns a fixed value -type StaticStringSlice []string - -// Value returns the current string slice. Callers should never mutate the returned value. -func (s StaticStringSlice) Value() []string { - return s -} - type requestHeaderAuthRequestHandler struct { // nameHeaders are the headers to check (in order, case-insensitively) for an identity. The first header with a value wins. - nameHeaders StringSliceProvider + nameHeaders []string // groupHeaders are the headers to check (case-insensitively) for group membership. All values of all headers will be added. - groupHeaders StringSliceProvider + groupHeaders []string // extraHeaderPrefixes are the head prefixes to check (case-insensitively) for filling in // the user.Info.Extra. All values of all matching headers will be added. - extraHeaderPrefixes StringSliceProvider + extraHeaderPrefixes []string } -func New(nameHeaders, groupHeaders, extraHeaderPrefixes []string) (authenticator.Request, error) { +func New(nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) { trimmedNameHeaders, err := trimHeaders(nameHeaders...) if err != nil { return nil, err @@ -78,19 +57,11 @@ func New(nameHeaders, groupHeaders, extraHeaderPrefixes []string) (authenticator return nil, err } - return NewDynamic( - StaticStringSlice(trimmedNameHeaders), - StaticStringSlice(trimmedGroupHeaders), - StaticStringSlice(trimmedExtraHeaderPrefixes), - ), nil -} - -func NewDynamic(nameHeaders, groupHeaders, extraHeaderPrefixes StringSliceProvider) authenticator.Request { return &requestHeaderAuthRequestHandler{ - nameHeaders: nameHeaders, - groupHeaders: groupHeaders, - extraHeaderPrefixes: extraHeaderPrefixes, - } + nameHeaders: trimmedNameHeaders, + groupHeaders: trimmedGroupHeaders, + extraHeaderPrefixes: trimmedExtraHeaderPrefixes, + }, nil } func trimHeaders(headerNames ...string) ([]string, error) { @@ -107,6 +78,11 @@ func trimHeaders(headerNames ...string) ([]string, error) { } func NewSecure(clientCA string, proxyClientNames []string, nameHeaders []string, groupHeaders []string, extraHeaderPrefixes []string) (authenticator.Request, error) { + headerAuthenticator, err := New(nameHeaders, groupHeaders, extraHeaderPrefixes) + if err != nil { + return nil, err + } + if len(clientCA) == 0 { return nil, fmt.Errorf("missing clientCA file") } @@ -126,51 +102,26 @@ func NewSecure(clientCA string, proxyClientNames []string, nameHeaders []string, opts.Roots.AddCert(cert) } - trimmedNameHeaders, err := trimHeaders(nameHeaders...) - if err != nil { - return nil, err - } - trimmedGroupHeaders, err := trimHeaders(groupHeaders...) - if err != nil { - return nil, err - } - trimmedExtraHeaderPrefixes, err := trimHeaders(extraHeaderPrefixes...) - if err != nil { - return nil, err - } - - return NewDynamicVerifyOptionsSecure( - x509request.StaticVerifierFn(opts), - StaticStringSlice(proxyClientNames), - StaticStringSlice(trimmedNameHeaders), - StaticStringSlice(trimmedGroupHeaders), - StaticStringSlice(trimmedExtraHeaderPrefixes), - ), nil -} - -func NewDynamicVerifyOptionsSecure(verifyOptionFn x509request.VerifyOptionFunc, proxyClientNames, nameHeaders, groupHeaders, extraHeaderPrefixes StringSliceProvider) authenticator.Request { - headerAuthenticator := NewDynamic(nameHeaders, groupHeaders, extraHeaderPrefixes) - - return x509request.NewDynamicCAVerifier(verifyOptionFn, headerAuthenticator, proxyClientNames) + return x509request.NewVerifier(opts, headerAuthenticator, sets.NewString(proxyClientNames...)), nil } func (a *requestHeaderAuthRequestHandler) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { - name := headerValue(req.Header, a.nameHeaders.Value()) + name := headerValue(req.Header, a.nameHeaders) if len(name) == 0 { return nil, false, nil } - groups := allHeaderValues(req.Header, a.groupHeaders.Value()) - extra := newExtra(req.Header, a.extraHeaderPrefixes.Value()) + groups := allHeaderValues(req.Header, a.groupHeaders) + extra := newExtra(req.Header, a.extraHeaderPrefixes) // clear headers used for authentication - for _, headerName := range a.nameHeaders.Value() { + for _, headerName := range a.nameHeaders { req.Header.Del(headerName) } - for _, headerName := range a.groupHeaders.Value() { + for _, headerName := range a.groupHeaders { req.Header.Del(headerName) } for k := range extra { - for _, prefix := range a.extraHeaderPrefixes.Value() { + for _, prefix := range a.extraHeaderPrefixes { req.Header.Del(prefix + k) } } diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go b/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go deleted file mode 100644 index 9e8bc8b21d9..00000000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller.go +++ /dev/null @@ -1,337 +0,0 @@ -/* -Copyright 2020 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 headerrequest - -import ( - "context" - "encoding/json" - "fmt" - "time" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - coreinformers "k8s.io/client-go/informers/core/v1" - "k8s.io/client-go/kubernetes" - corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - "k8s.io/klog" - "sync/atomic" -) - -const ( - authenticationRoleName = "extension-apiserver-authentication-reader" -) - -// RequestHeaderAuthRequestProvider a provider that knows how to dynamically fill parts of RequestHeaderConfig struct -type RequestHeaderAuthRequestProvider interface { - UsernameHeaders() []string - GroupHeaders() []string - ExtraHeaderPrefixes() []string - AllowedClientNames() []string -} - -var _ RequestHeaderAuthRequestProvider = &RequestHeaderAuthRequestController{} - -type requestHeaderBundle struct { - UsernameHeaders []string - GroupHeaders []string - ExtraHeaderPrefixes []string - AllowedClientNames []string -} - -// RequestHeaderAuthRequestController a controller that exposes a set of methods for dynamically filling parts of RequestHeaderConfig struct. -// The methods are sourced from the config map which is being monitored by this controller. -// The controller is primed from the server at the construction time for components that don't want to dynamically react to changes -// in the config map. -type RequestHeaderAuthRequestController struct { - name string - - configmapName string - configmapNamespace string - - client kubernetes.Interface - configmapLister corev1listers.ConfigMapNamespaceLister - configmapInformer cache.SharedIndexInformer - configmapInformerSynced cache.InformerSynced - - queue workqueue.RateLimitingInterface - - // exportedRequestHeaderBundle is a requestHeaderBundle that contains the last read, non-zero length content of the configmap - exportedRequestHeaderBundle atomic.Value - - usernameHeadersKey string - groupHeadersKey string - extraHeaderPrefixesKey string - allowedClientNamesKey string -} - -// NewRequestHeaderAuthRequestController creates a new controller that implements RequestHeaderAuthRequestController -func NewRequestHeaderAuthRequestController( - cmName string, - cmNamespace string, - client kubernetes.Interface, - usernameHeadersKey, groupHeadersKey, extraHeaderPrefixesKey, allowedClientNamesKey string) *RequestHeaderAuthRequestController { - c := &RequestHeaderAuthRequestController{ - name: "RequestHeaderAuthRequestController", - - client: client, - - configmapName: cmName, - configmapNamespace: cmNamespace, - - usernameHeadersKey: usernameHeadersKey, - groupHeadersKey: groupHeadersKey, - extraHeaderPrefixesKey: extraHeaderPrefixesKey, - allowedClientNamesKey: allowedClientNamesKey, - - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "RequestHeaderAuthRequestController"), - } - - // we construct our own informer because we need such a small subset of the information available. Just one namespace. - c.configmapInformer = coreinformers.NewFilteredConfigMapInformer(client, c.configmapNamespace, 12*time.Hour, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, func(listOptions *metav1.ListOptions) { - listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", c.configmapName).String() - }) - - c.configmapInformer.AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: func(obj interface{}) bool { - if cast, ok := obj.(*corev1.ConfigMap); ok { - return cast.Name == c.configmapName && cast.Namespace == c.configmapNamespace - } - if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok { - if cast, ok := tombstone.Obj.(*corev1.ConfigMap); ok { - return cast.Name == c.configmapName && cast.Namespace == c.configmapNamespace - } - } - return true // always return true just in case. The checks are fairly cheap - }, - Handler: cache.ResourceEventHandlerFuncs{ - // we have a filter, so any time we're called, we may as well queue. We only ever check one configmap - // so we don't have to be choosy about our key. - AddFunc: func(obj interface{}) { - c.queue.Add(c.keyFn()) - }, - UpdateFunc: func(oldObj, newObj interface{}) { - c.queue.Add(c.keyFn()) - }, - DeleteFunc: func(obj interface{}) { - c.queue.Add(c.keyFn()) - }, - }, - }) - - c.configmapLister = corev1listers.NewConfigMapLister(c.configmapInformer.GetIndexer()).ConfigMaps(c.configmapNamespace) - c.configmapInformerSynced = c.configmapInformer.HasSynced - - return c -} - -func (c *RequestHeaderAuthRequestController) UsernameHeaders() []string { - return c.loadRequestHeaderFor(c.usernameHeadersKey) -} - -func (c *RequestHeaderAuthRequestController) GroupHeaders() []string { - return c.loadRequestHeaderFor(c.groupHeadersKey) -} - -func (c *RequestHeaderAuthRequestController) ExtraHeaderPrefixes() []string { - return c.loadRequestHeaderFor(c.extraHeaderPrefixesKey) -} - -func (c *RequestHeaderAuthRequestController) AllowedClientNames() []string { - return c.loadRequestHeaderFor(c.allowedClientNamesKey) -} - -// Run starts RequestHeaderAuthRequestController controller and blocks until stopCh is closed. -func (c *RequestHeaderAuthRequestController) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - - klog.Infof("Starting %s", c.name) - defer klog.Infof("Shutting down %s", c.name) - - go c.configmapInformer.Run(stopCh) - - // wait for caches to fill before starting your work - if !cache.WaitForNamedCacheSync(c.name, stopCh, c.configmapInformerSynced) { - return - } - - // doesn't matter what workers say, only start one. - go wait.Until(c.runWorker, time.Second, stopCh) - - <-stopCh -} - -// // RunOnce runs a single sync loop -func (c *RequestHeaderAuthRequestController) RunOnce() error { - configMap, err := c.client.CoreV1().ConfigMaps(c.configmapNamespace).Get(context.TODO(), c.configmapName, metav1.GetOptions{}) - switch { - case errors.IsNotFound(err): - // ignore, authConfigMap is nil now - return nil - case errors.IsForbidden(err): - klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+ - "'kubectl create rolebinding -n %s ROLEBINDING_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'", - c.configmapName, c.configmapNamespace, c.configmapNamespace, authenticationRoleName) - return err - case err != nil: - return err - } - return c.syncConfigMap(configMap) -} - -func (c *RequestHeaderAuthRequestController) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *RequestHeaderAuthRequestController) processNextWorkItem() bool { - dsKey, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(dsKey) - - err := c.sync() - if err == nil { - c.queue.Forget(dsKey) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) - c.queue.AddRateLimited(dsKey) - - return true -} - -// sync reads the config and propagates the changes to exportedRequestHeaderBundle -// which is exposed by the set of methods that are used to fill RequestHeaderConfig struct -func (c *RequestHeaderAuthRequestController) sync() error { - configMap, err := c.configmapLister.Get(c.configmapName) - if err != nil { - return err - } - return c.syncConfigMap(configMap) -} - -func (c *RequestHeaderAuthRequestController) syncConfigMap(configMap *corev1.ConfigMap) error { - hasChanged, newRequestHeaderBundle, err := c.hasRequestHeaderBundleChanged(configMap) - if err != nil { - return err - } - if hasChanged { - c.exportedRequestHeaderBundle.Store(newRequestHeaderBundle) - klog.V(2).Infof("Loaded a new request header values for %v", c.name) - } - return nil -} - -func (c *RequestHeaderAuthRequestController) hasRequestHeaderBundleChanged(cm *corev1.ConfigMap) (bool, *requestHeaderBundle, error) { - currentHeadersBundle, err := c.getRequestHeaderBundleFromConfigMap(cm) - if err != nil { - return false, nil, err - } - - rawHeaderBundle := c.exportedRequestHeaderBundle.Load() - if rawHeaderBundle == nil { - return true, currentHeadersBundle, nil - } - - // check to see if we have a change. If the values are the same, do nothing. - loadedHeadersBundle, ok := rawHeaderBundle.(*requestHeaderBundle) - if !ok { - return true, currentHeadersBundle, nil - } - - if !equality.Semantic.DeepEqual(loadedHeadersBundle, currentHeadersBundle) { - return true, currentHeadersBundle, nil - } - return false, nil, nil -} - -func (c *RequestHeaderAuthRequestController) getRequestHeaderBundleFromConfigMap(cm *corev1.ConfigMap) (*requestHeaderBundle, error) { - usernameHeaderCurrentValue, err := deserializeStrings(cm.Data[c.usernameHeadersKey]) - if err != nil { - return nil, err - } - - groupHeadersCurrentValue, err := deserializeStrings(cm.Data[c.groupHeadersKey]) - if err != nil { - return nil, err - } - - extraHeaderPrefixesCurrentValue, err := deserializeStrings(cm.Data[c.extraHeaderPrefixesKey]) - if err != nil { - return nil, err - - } - - allowedClientNamesCurrentValue, err := deserializeStrings(cm.Data[c.allowedClientNamesKey]) - if err != nil { - return nil, err - } - - return &requestHeaderBundle{ - UsernameHeaders: usernameHeaderCurrentValue, - GroupHeaders: groupHeadersCurrentValue, - ExtraHeaderPrefixes: extraHeaderPrefixesCurrentValue, - AllowedClientNames: allowedClientNamesCurrentValue, - }, nil -} - -func (c *RequestHeaderAuthRequestController) loadRequestHeaderFor(key string) []string { - rawHeaderBundle := c.exportedRequestHeaderBundle.Load() - if rawHeaderBundle == nil { - return nil // this can happen if we've been unable load data from the apiserver for some reason - } - headerBundle := rawHeaderBundle.(*requestHeaderBundle) - - switch key { - case c.usernameHeadersKey: - return headerBundle.UsernameHeaders - case c.groupHeadersKey: - return headerBundle.GroupHeaders - case c.extraHeaderPrefixesKey: - return headerBundle.ExtraHeaderPrefixes - case c.allowedClientNamesKey: - return headerBundle.AllowedClientNames - default: - return nil - } -} - -func (c *RequestHeaderAuthRequestController) keyFn() string { - // this format matches DeletionHandlingMetaNamespaceKeyFunc for our single key - return c.configmapNamespace + "/" + c.configmapName -} - -func deserializeStrings(in string) ([]string, error) { - if len(in) == 0 { - return nil, nil - } - var ret []string - if err := json.Unmarshal([]byte(in), &ret); err != nil { - return nil, err - } - return ret, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go b/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go deleted file mode 100644 index 2577d2635b2..00000000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/headerrequest/requestheader_controller_test.go +++ /dev/null @@ -1,285 +0,0 @@ -/* -Copyright 2020 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 headerrequest - -import ( - "encoding/json" - "k8s.io/apimachinery/pkg/api/equality" - "testing" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" - corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/tools/cache" -) - -const ( - defConfigMapName = "extension-apiserver-authentication" - defConfigMapNamespace = "kube-system" - - defUsernameHeadersKey = "user-key" - defGroupHeadersKey = "group-key" - defExtraHeaderPrefixesKey = "extra-key" - defAllowedClientNamesKey = "names-key" -) - -type expectedHeadersHolder struct { - usernameHeaders []string - groupHeaders []string - extraHeaderPrefixes []string - allowedClientNames []string -} - -func TestRequestHeaderAuthRequestController(t *testing.T) { - scenarios := []struct { - name string - cm *corev1.ConfigMap - expectedHeader expectedHeadersHolder - expectErr bool - }{ - { - name: "happy-path: headers values are populated form a config map", - cm: defaultConfigMap(t, []string{"user-val"}, []string{"group-val"}, []string{"extra-val"}, []string{"names-val"}), - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val"}, - groupHeaders: []string{"group-val"}, - extraHeaderPrefixes: []string{"extra-val"}, - allowedClientNames: []string{"names-val"}, - }, - }, - { - name: "passing an empty config map doesn't break the controller", - cm: func() *corev1.ConfigMap { - c := defaultConfigMap(t, nil, nil, nil, nil) - c.Data = map[string]string{} - return c - }(), - }, - { - name: "an invalid config map produces an error", - cm: func() *corev1.ConfigMap { - c := defaultConfigMap(t, nil, nil, nil, nil) - c.Data = map[string]string{ - defUsernameHeadersKey: "incorrect-json-array", - } - return c - }(), - expectErr: true, - }, - } - - for _, scenario := range scenarios { - t.Run(scenario.name, func(t *testing.T) { - // test data - indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) - if err := indexer.Add(scenario.cm); err != nil { - t.Fatal(err.Error()) - } - target := newDefaultTarget() - target.configmapLister = corev1listers.NewConfigMapLister(indexer).ConfigMaps(defConfigMapNamespace) - - // act - err := target.sync() - - if err != nil && !scenario.expectErr { - t.Errorf("got unexpected error %v", err) - } - if err == nil && scenario.expectErr { - t.Error("expected an error but didn't get one") - } - - // validate - validateExpectedHeaders(t, target, scenario.expectedHeader) - }) - } -} - -func TestRequestHeaderAuthRequestControllerPreserveState(t *testing.T) { - scenarios := []struct { - name string - cm *corev1.ConfigMap - expectedHeader expectedHeadersHolder - expectErr bool - }{ - { - name: "scenario 1: headers values are populated form a config map", - cm: defaultConfigMap(t, []string{"user-val"}, []string{"group-val"}, []string{"extra-val"}, []string{"names-val"}), - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val"}, - groupHeaders: []string{"group-val"}, - extraHeaderPrefixes: []string{"extra-val"}, - allowedClientNames: []string{"names-val"}, - }, - }, - { - name: "scenario 2: an invalid config map produces an error but doesn't destroy the state (scenario 1)", - cm: func() *corev1.ConfigMap { - c := defaultConfigMap(t, nil, nil, nil, nil) - c.Data = map[string]string{ - defUsernameHeadersKey: "incorrect-json-array", - } - return c - }(), - expectErr: true, - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val"}, - groupHeaders: []string{"group-val"}, - extraHeaderPrefixes: []string{"extra-val"}, - allowedClientNames: []string{"names-val"}, - }, - }, - { - name: "scenario 3: some headers values have changed (prev set by scenario 1)", - cm: defaultConfigMap(t, []string{"user-val"}, []string{"group-val-scenario-3"}, []string{"extra-val"}, []string{"names-val"}), - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val"}, - groupHeaders: []string{"group-val-scenario-3"}, - extraHeaderPrefixes: []string{"extra-val"}, - allowedClientNames: []string{"names-val"}, - }, - }, - { - name: "scenario 4: all headers values have changed (prev set by scenario 3)", - cm: defaultConfigMap(t, []string{"user-val-scenario-4"}, []string{"group-val-scenario-4"}, []string{"extra-val-scenario-4"}, []string{"names-val-scenario-4"}), - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val-scenario-4"}, - groupHeaders: []string{"group-val-scenario-4"}, - extraHeaderPrefixes: []string{"extra-val-scenario-4"}, - allowedClientNames: []string{"names-val-scenario-4"}, - }, - }, - } - - target := newDefaultTarget() - - for _, scenario := range scenarios { - t.Run(scenario.name, func(t *testing.T) { - // test data - if scenario.cm != nil { - indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) - if err := indexer.Add(scenario.cm); err != nil { - t.Fatal(err.Error()) - } - target.configmapLister = corev1listers.NewConfigMapLister(indexer).ConfigMaps(defConfigMapNamespace) - } - - // act - err := target.sync() - - if err != nil && !scenario.expectErr { - t.Errorf("got unexpected error %v", err) - } - if err == nil && scenario.expectErr { - t.Error("expected an error but didn't get one") - } - - // validate - validateExpectedHeaders(t, target, scenario.expectedHeader) - }) - } -} - -func TestRequestHeaderAuthRequestControllerSyncOnce(t *testing.T) { - scenarios := []struct { - name string - cm *corev1.ConfigMap - expectedHeader expectedHeadersHolder - expectErr bool - }{ - { - name: "headers values are populated form a config map", - cm: defaultConfigMap(t, []string{"user-val"}, []string{"group-val"}, []string{"extra-val"}, []string{"names-val"}), - expectedHeader: expectedHeadersHolder{ - usernameHeaders: []string{"user-val"}, - groupHeaders: []string{"group-val"}, - extraHeaderPrefixes: []string{"extra-val"}, - allowedClientNames: []string{"names-val"}, - }, - }, - } - - for _, scenario := range scenarios { - t.Run(scenario.name, func(t *testing.T) { - // test data - target := newDefaultTarget() - fakeKubeClient := fake.NewSimpleClientset(scenario.cm) - target.client = fakeKubeClient - - // act - err := target.RunOnce() - - if err != nil && !scenario.expectErr { - t.Errorf("got unexpected error %v", err) - } - if err == nil && scenario.expectErr { - t.Error("expected an error but didn't get one") - } - - // validate - validateExpectedHeaders(t, target, scenario.expectedHeader) - }) - } -} - -func defaultConfigMap(t *testing.T, usernameHeaderVal, groupHeadersVal, extraHeaderPrefixesVal, allowedClientNamesVal []string) *corev1.ConfigMap { - encode := func(val []string) string { - encodedVal, err := json.Marshal(val) - if err != nil { - t.Fatalf("unable to marshal %q , due to %v", usernameHeaderVal, err) - } - return string(encodedVal) - } - return &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: defConfigMapName, - Namespace: defConfigMapNamespace, - }, - Data: map[string]string{ - defUsernameHeadersKey: encode(usernameHeaderVal), - defGroupHeadersKey: encode(groupHeadersVal), - defExtraHeaderPrefixesKey: encode(extraHeaderPrefixesVal), - defAllowedClientNamesKey: encode(allowedClientNamesVal), - }, - } -} - -func newDefaultTarget() *RequestHeaderAuthRequestController { - return &RequestHeaderAuthRequestController{ - configmapName: defConfigMapName, - configmapNamespace: defConfigMapNamespace, - usernameHeadersKey: defUsernameHeadersKey, - groupHeadersKey: defGroupHeadersKey, - extraHeaderPrefixesKey: defExtraHeaderPrefixesKey, - allowedClientNamesKey: defAllowedClientNamesKey, - } -} - -func validateExpectedHeaders(t *testing.T, target *RequestHeaderAuthRequestController, expected expectedHeadersHolder) { - if !equality.Semantic.DeepEqual(target.UsernameHeaders(), expected.usernameHeaders) { - t.Fatalf("incorrect usernameHeaders, got %v, wanted %v", target.UsernameHeaders(), expected.usernameHeaders) - } - if !equality.Semantic.DeepEqual(target.GroupHeaders(), expected.groupHeaders) { - t.Fatalf("incorrect groupHeaders, got %v, wanted %v", target.GroupHeaders(), expected.groupHeaders) - } - if !equality.Semantic.DeepEqual(target.ExtraHeaderPrefixes(), expected.extraHeaderPrefixes) { - t.Fatalf("incorrect extraheaderPrefixes, got %v, wanted %v", target.ExtraHeaderPrefixes(), expected.extraHeaderPrefixes) - } - if !equality.Semantic.DeepEqual(target.AllowedClientNames(), expected.allowedClientNames) { - t.Fatalf("incorrect expectedAllowedClientNames, got %v, wanted %v", target.AllowedClientNames(), expected.allowedClientNames) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS index 3cf03643835..470b7a1c92d 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - sig-auth-certificates-approvers reviewers: diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/testdata/generate.sh b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/testdata/generate.sh index 0bb39c0aa33..07171057db5 100755 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/testdata/generate.sh +++ b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/testdata/generate.sh @@ -21,4 +21,4 @@ cfssl sign -ca root.pem -ca-key root-key.pem -config intermediate.config.json in cfssl gencert -ca intermediate.pem -ca-key intermediate-key.pem -config client.config.json --profile=valid client.csr.json | cfssljson -bare client-valid cfssl gencert -ca intermediate.pem -ca-key intermediate-key.pem -config client.config.json --profile=expired client.csr.json | cfssljson -bare client-expired - + diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/verify_options.go b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/verify_options.go deleted file mode 100644 index 462eb4cc95f..00000000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/verify_options.go +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright 2019 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 x509 - -import ( - "crypto/x509" - "fmt" - - "k8s.io/client-go/util/cert" -) - -// StaticVerifierFn is a VerifyOptionFunc that always returns the same value. This allows verify options that cannot change. -func StaticVerifierFn(opts x509.VerifyOptions) VerifyOptionFunc { - return func() (x509.VerifyOptions, bool) { - return opts, true - } -} - -// NewStaticVerifierFromFile creates a new verification func from a file. It reads the content and then fails. -// It will return a nil function if you pass an empty CA file. -func NewStaticVerifierFromFile(clientCA string) (VerifyOptionFunc, error) { - if len(clientCA) == 0 { - return nil, nil - } - - // Wrap with an x509 verifier - var err error - opts := DefaultVerifyOptions() - opts.Roots, err = cert.NewPool(clientCA) - if err != nil { - return nil, fmt.Errorf("error loading certs from %s: %v", clientCA, err) - } - - return StaticVerifierFn(opts), nil -} - -// StringSliceProvider is a way to get a string slice value. It is heavily used for authentication headers among other places. -type StringSliceProvider interface { - // Value returns the current string slice. Callers should never mutate the returned value. - Value() []string -} - -// StringSliceProviderFunc is a function that matches the StringSliceProvider interface -type StringSliceProviderFunc func() []string - -// Value returns the current string slice. Callers should never mutate the returned value. -func (d StringSliceProviderFunc) Value() []string { - return d() -} - -// StaticStringSlice a StringSliceProvider that returns a fixed value -type StaticStringSlice []string - -// Value returns the current string slice. Callers should never mutate the returned value. -func (s StaticStringSlice) Value() []string { - return s -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go index 6fe5299fcdd..bc875adacf1 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509.go @@ -23,33 +23,22 @@ import ( "net/http" "time" + "github.com/prometheus/client_golang/prometheus" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" ) -/* - * By default, the following metric is defined as falling under - * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes) - * - * Promoting the stability level of the metric is a responsibility of the component owner, since it - * involves explicitly acknowledging support for the metric across multiple releases, in accordance with - * the metric stability policy. - */ -var clientCertificateExpirationHistogram = metrics.NewHistogram( - &metrics.HistogramOpts{ +var clientCertificateExpirationHistogram = prometheus.NewHistogram( + prometheus.HistogramOpts{ Namespace: "apiserver", Subsystem: "client", Name: "certificate_expiration_seconds", Help: "Distribution of the remaining lifetime on the certificate used to authenticate a request.", Buckets: []float64{ 0, - (30 * time.Minute).Seconds(), - (1 * time.Hour).Seconds(), - (2 * time.Hour).Seconds(), (6 * time.Hour).Seconds(), (12 * time.Hour).Seconds(), (24 * time.Hour).Seconds(), @@ -61,12 +50,11 @@ var clientCertificateExpirationHistogram = metrics.NewHistogram( (6 * 30 * 24 * time.Hour).Seconds(), (12 * 30 * 24 * time.Hour).Seconds(), }, - StabilityLevel: metrics.ALPHA, }, ) func init() { - legacyregistry.MustRegister(clientCertificateExpirationHistogram) + prometheus.MustRegister(clientCertificateExpirationHistogram) } // UserConversion defines an interface for extracting user info from a client certificate chain @@ -82,28 +70,16 @@ func (f UserConversionFunc) User(chain []*x509.Certificate) (*authenticator.Resp return f(chain) } -// VerifyOptionFunc is function which provides a shallow copy of the VerifyOptions to the authenticator. This allows -// for cases where the options (particularly the CAs) can change. If the bool is false, then the returned VerifyOptions -// are ignored and the authenticator will express "no opinion". This allows a clear signal for cases where a CertPool -// is eventually expected, but not currently present. -type VerifyOptionFunc func() (x509.VerifyOptions, bool) - // Authenticator implements request.Authenticator by extracting user info from verified client certificates type Authenticator struct { - verifyOptionsFn VerifyOptionFunc - user UserConversion + opts x509.VerifyOptions + user UserConversion } // New returns a request.Authenticator that verifies client certificates using the provided // VerifyOptions, and converts valid certificate chains into user.Info using the provided UserConversion func New(opts x509.VerifyOptions, user UserConversion) *Authenticator { - return NewDynamic(StaticVerifierFn(opts), user) -} - -// NewDynamic returns a request.Authenticator that verifies client certificates using the provided -// VerifyOptionFunc (which may be dynamic), and converts valid certificate chains into user.Info using the provided UserConversion -func NewDynamic(verifyOptionsFn VerifyOptionFunc, user UserConversion) *Authenticator { - return &Authenticator{verifyOptionsFn, user} + return &Authenticator{opts, user} } // AuthenticateRequest authenticates the request using presented client certificates @@ -113,11 +89,7 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.R } // Use intermediates, if provided - optsCopy, ok := a.verifyOptionsFn() - // if there are intentionally no verify options, then we cannot authenticate this request - if !ok { - return nil, false, nil - } + optsCopy := a.opts if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 { optsCopy.Intermediates = x509.NewCertPool() for _, intermediate := range req.TLS.PeerCertificates[1:] { @@ -149,22 +121,17 @@ func (a *Authenticator) AuthenticateRequest(req *http.Request) (*authenticator.R // Verifier implements request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth type Verifier struct { - verifyOptionsFn VerifyOptionFunc - auth authenticator.Request + opts x509.VerifyOptions + auth authenticator.Request // allowedCommonNames contains the common names which a verified certificate is allowed to have. // If empty, all verified certificates are allowed. - allowedCommonNames StringSliceProvider + allowedCommonNames sets.String } // NewVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth func NewVerifier(opts x509.VerifyOptions, auth authenticator.Request, allowedCommonNames sets.String) authenticator.Request { - return NewDynamicCAVerifier(StaticVerifierFn(opts), auth, StaticStringSlice(allowedCommonNames.List())) -} - -// NewDynamicCAVerifier create a request.Authenticator by verifying a client cert on the request, then delegating to the wrapped auth -func NewDynamicCAVerifier(verifyOptionsFn VerifyOptionFunc, auth authenticator.Request, allowedCommonNames StringSliceProvider) authenticator.Request { - return &Verifier{verifyOptionsFn, auth, allowedCommonNames} + return &Verifier{opts, auth, allowedCommonNames} } // AuthenticateRequest verifies the presented client certificate, then delegates to the wrapped auth @@ -174,11 +141,7 @@ func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Respon } // Use intermediates, if provided - optsCopy, ok := a.verifyOptionsFn() - // if there are intentionally no verify options, then we cannot authenticate this request - if !ok { - return nil, false, nil - } + optsCopy := a.opts if optsCopy.Intermediates == nil && len(req.TLS.PeerCertificates) > 1 { optsCopy.Intermediates = x509.NewCertPool() for _, intermediate := range req.TLS.PeerCertificates[1:] { @@ -197,14 +160,12 @@ func (a *Verifier) AuthenticateRequest(req *http.Request) (*authenticator.Respon func (a *Verifier) verifySubject(subject pkix.Name) error { // No CN restrictions - if len(a.allowedCommonNames.Value()) == 0 { + if len(a.allowedCommonNames) == 0 { return nil } // Enforce CN restrictions - for _, allowedCommonName := range a.allowedCommonNames.Value() { - if allowedCommonName == subject.CommonName { - return nil - } + if a.allowedCommonNames.Has(subject.CommonName) { + return nil } return fmt.Errorf("x509: subject with cn=%s is not in the allowed list", subject.CommonName) } diff --git a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509_test.go b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509_test.go index e2d156152e5..2628d532f2c 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509_test.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/request/x509/x509_test.go @@ -657,7 +657,6 @@ func TestX509(t *testing.T) { req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs} } - // this effectively tests the simple dynamic verify function. a := New(testCase.Opts, testCase.User) resp, ok, err := a.AuthenticateRequest(req) diff --git a/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go b/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go index d4e2162fa52..1b7bbc1390d 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util.go @@ -36,27 +36,6 @@ func MakeUsername(namespace, name string) string { return ServiceAccountUsernamePrefix + namespace + ServiceAccountUsernameSeparator + name } -// MatchesUsername checks whether the provided username matches the namespace and name without -// allocating. Use this when checking a service account namespace and name against a known string. -func MatchesUsername(namespace, name string, username string) bool { - if !strings.HasPrefix(username, ServiceAccountUsernamePrefix) { - return false - } - username = username[len(ServiceAccountUsernamePrefix):] - - if !strings.HasPrefix(username, namespace) { - return false - } - username = username[len(namespace):] - - if !strings.HasPrefix(username, ServiceAccountUsernameSeparator) { - return false - } - username = username[len(ServiceAccountUsernameSeparator):] - - return username == name -} - var invalidUsernameErr = fmt.Errorf("Username must be in the form %s", MakeUsername("namespace", "name")) // SplitUsername returns the namespace and ServiceAccount name embedded in the given username, diff --git a/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util_test.go b/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util_test.go index 91c8cb0ddd8..14784b16cdd 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util_test.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/serviceaccount/util_test.go @@ -62,9 +62,7 @@ func TestMakeUsername(t *testing.T) { for k, tc := range testCases { username := MakeUsername(tc.Namespace, tc.Name) - if !MatchesUsername(tc.Namespace, tc.Name, username) { - t.Errorf("%s: Expected to match username", k) - } + namespace, name, err := SplitUsername(username) if (err != nil) != tc.ExpectedErr { t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedErr, err) @@ -82,39 +80,3 @@ func TestMakeUsername(t *testing.T) { } } } - -func TestMatchUsername(t *testing.T) { - - testCases := []struct { - TestName string - Namespace string - Name string - Username string - Expect bool - }{ - {Namespace: "foo", Name: "bar", Username: "foo", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount:", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount:foo", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount:foo:", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount:foo:bar", Expect: true}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount::bar", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "system:serviceaccount:bar", Expect: false}, - {Namespace: "foo", Name: "bar", Username: ":bar", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "foo:bar", Expect: false}, - {Namespace: "foo", Name: "bar", Username: "", Expect: false}, - - {Namespace: "foo2", Name: "bar", Username: "system:serviceaccount:foo:bar", Expect: false}, - {Namespace: "foo", Name: "bar2", Username: "system:serviceaccount:foo:bar", Expect: false}, - {Namespace: "foo:", Name: "bar", Username: "system:serviceaccount:foo:bar", Expect: false}, - {Namespace: "foo", Name: ":bar", Username: "system:serviceaccount:foo:bar", Expect: false}, - } - - for _, tc := range testCases { - t.Run(tc.TestName, func(t *testing.T) { - actual := MatchesUsername(tc.Namespace, tc.Name, tc.Username) - if actual != tc.Expect { - t.Fatalf("unexpected match") - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go index 8e0520af169..18d5692d7a7 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_simple.go @@ -19,20 +19,20 @@ package cache import ( "time" - utilcache "k8s.io/apimachinery/pkg/util/cache" + lrucache "k8s.io/apimachinery/pkg/util/cache" "k8s.io/apimachinery/pkg/util/clock" ) type simpleCache struct { - cache *utilcache.Expiring + lru *lrucache.LRUExpireCache } -func newSimpleCache(clock clock.Clock) cache { - return &simpleCache{cache: utilcache.NewExpiringWithClock(clock)} +func newSimpleCache(size int, clock clock.Clock) cache { + return &simpleCache{lru: lrucache.NewLRUExpireCacheWithClock(size, clock)} } func (c *simpleCache) get(key string) (*cacheRecord, bool) { - record, ok := c.cache.Get(key) + record, ok := c.lru.Get(key) if !ok { return nil, false } @@ -41,9 +41,9 @@ func (c *simpleCache) get(key string) (*cacheRecord, bool) { } func (c *simpleCache) set(key string, value *cacheRecord, ttl time.Duration) { - c.cache.Set(key, value, ttl) + c.lru.Add(key, value, ttl) } func (c *simpleCache) remove(key string) { - c.cache.Delete(key) + c.lru.Remove(key) } diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_test.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_test.go index bd0457ac6ca..afc3e30c9ab 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_test.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cache_test.go @@ -17,12 +17,11 @@ limitations under the License. package cache import ( - "fmt" "math/rand" "testing" "time" - "github.com/google/uuid" + "github.com/pborman/uuid" "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apiserver/pkg/authentication/authenticator" @@ -30,31 +29,25 @@ import ( ) func TestSimpleCache(t *testing.T) { - testCache(newSimpleCache(clock.RealClock{}), t) + testCache(newSimpleCache(4096, clock.RealClock{}), t) } -// Note: the performance profile of this benchmark may not match that in the production. -// When making change to SimpleCache, run test with and without concurrency to better understand the impact. -// This is a tool to test and measure high concurrency of the cache in isolation and not to the Kubernetes usage of the Cache. -func BenchmarkCacheContentions(b *testing.B) { - for _, numKeys := range []int{1 << 8, 1 << 12, 1 << 16} { - b.Run(fmt.Sprintf("Simple/keys=%d", numKeys), func(b *testing.B) { - benchmarkCache(newSimpleCache(clock.RealClock{}), b, numKeys) - }) - b.Run(fmt.Sprintf("Striped/keys=%d", numKeys), func(b *testing.B) { - benchmarkCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(clock.RealClock{}) }), b, numKeys) - }) - } +func BenchmarkSimpleCache(b *testing.B) { + benchmarkCache(newSimpleCache(4096, clock.RealClock{}), b) } func TestStripedCache(t *testing.T) { - testCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(clock.RealClock{}) }), t) + testCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), t) +} + +func BenchmarkStripedCache(b *testing.B) { + benchmarkCache(newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock.RealClock{}) }), b) } -func benchmarkCache(cache cache, b *testing.B, numKeys int) { +func benchmarkCache(cache cache, b *testing.B) { keys := []string{} - for i := 0; i < numKeys; i++ { - key := uuid.New().String() + for i := 0; i < b.N; i++ { + key := uuid.NewRandom().String() keys = append(keys, key) } @@ -63,7 +56,7 @@ func benchmarkCache(cache cache, b *testing.B, numKeys int) { b.SetParallelism(500) b.RunParallel(func(pb *testing.PB) { for pb.Next() { - key := keys[rand.Intn(numKeys)] + key := keys[rand.Intn(b.N)] _, ok := cache.get(key) if ok { cache.remove(key) diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go index 8edd6b646cf..ea3853a38b4 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go @@ -18,30 +18,13 @@ package cache import ( "context" - "crypto/hmac" - "crypto/rand" - "crypto/sha256" - "encoding/binary" - "errors" - "hash" - "io" - "runtime" - "sync" + "fmt" "time" - "unsafe" - "golang.org/x/sync/singleflight" - - apierrors "k8s.io/apimachinery/pkg/api/errors" utilclock "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/klog" ) -var errAuthnCrash = apierrors.NewInternalError(errors.New("authentication failed unexpectedly")) - -const sharedLookupTimeout = 30 * time.Second - // cacheRecord holds the three return values of the authenticator.Token AuthenticateToken method type cacheRecord struct { resp *authenticator.Response @@ -57,12 +40,6 @@ type cachedTokenAuthenticator struct { failureTTL time.Duration cache cache - group singleflight.Group - - // hashPool is a per authenticator pool of hash.Hash (to avoid allocations from building the Hash) - // HMAC with SHA-256 and a random key is used to prevent precomputation and length extension attacks - // It also mitigates hash map DOS attacks via collisions (the inputs are supplied by untrusted users) - hashPool *sync.Pool } type cache interface { @@ -80,162 +57,39 @@ func New(authenticator authenticator.Token, cacheErrs bool, successTTL, failureT } func newWithClock(authenticator authenticator.Token, cacheErrs bool, successTTL, failureTTL time.Duration, clock utilclock.Clock) authenticator.Token { - randomCacheKey := make([]byte, 32) - if _, err := rand.Read(randomCacheKey); err != nil { - panic(err) // rand should never fail - } - return &cachedTokenAuthenticator{ authenticator: authenticator, cacheErrs: cacheErrs, successTTL: successTTL, failureTTL: failureTTL, - // Cache performance degrades noticeably when the number of - // tokens in operation exceeds the size of the cache. It is - // cheap to make the cache big in the second dimension below, - // the memory is only consumed when that many tokens are being - // used. Currently we advertise support 5k nodes and 10k - // namespaces; a 32k entry cache is therefore a 2x safety - // margin. - cache: newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(clock) }), - - hashPool: &sync.Pool{ - New: func() interface{} { - return hmac.New(sha256.New, randomCacheKey) - }, - }, + cache: newStripedCache(32, fnvHashFunc, func() cache { return newSimpleCache(128, clock) }), } } // AuthenticateToken implements authenticator.Token func (a *cachedTokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) { - doneAuthenticating := stats.authenticating() + auds, _ := authenticator.AudiencesFrom(ctx) - auds, audsOk := authenticator.AudiencesFrom(ctx) - - key := keyFunc(a.hashPool, auds, token) + key := keyFunc(auds, token) if record, ok := a.cache.get(key); ok { - // Record cache hit - doneAuthenticating(true) return record.resp, record.ok, record.err } - // Record cache miss - doneBlocking := stats.blocking() - defer doneBlocking() - defer doneAuthenticating(false) - - type lookup struct { - resp *authenticator.Response - ok bool - } - - c := a.group.DoChan(key, func() (val interface{}, err error) { - doneFetching := stats.fetching() - // We're leaving the request handling stack so we need to handle crashes - // ourselves. Log a stack trace and return a 500 if something panics. - defer func() { - if r := recover(); r != nil { - err = errAuthnCrash - // Same as stdlib http server code. Manually allocate stack - // trace buffer size to prevent excessively large logs - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:runtime.Stack(buf, false)] - klog.Errorf("%v\n%s", r, buf) - } - doneFetching(err == nil) - }() - - // Check again for a cached record. We may have raced with a fetch. - if record, ok := a.cache.get(key); ok { - return lookup{record.resp, record.ok}, record.err - } - - // Detach the context because the lookup may be shared by multiple callers, - // however propagate the audience. - ctx, cancel := context.WithTimeout(context.Background(), sharedLookupTimeout) - defer cancel() - - if audsOk { - ctx = authenticator.WithAudiences(ctx, auds) - } - - resp, ok, err := a.authenticator.AuthenticateToken(ctx, token) - if !a.cacheErrs && err != nil { - return nil, err - } - - switch { - case ok && a.successTTL > 0: - a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.successTTL) - case !ok && a.failureTTL > 0: - a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.failureTTL) - } - return lookup{resp, ok}, err - }) - - select { - case result := <-c: - if result.Err != nil { - return nil, false, result.Err - } - lookup := result.Val.(lookup) - return lookup.resp, lookup.ok, nil - case <-ctx.Done(): - return nil, false, ctx.Err() - } -} - -// keyFunc generates a string key by hashing the inputs. -// This lowers the memory requirement of the cache and keeps tokens out of memory. -func keyFunc(hashPool *sync.Pool, auds []string, token string) string { - h := hashPool.Get().(hash.Hash) - - h.Reset() - - // try to force stack allocation - var a [4]byte - b := a[:] - - writeLengthPrefixedString(h, b, token) - // encode the length of audiences to avoid ambiguities - writeLength(h, b, len(auds)) - for _, aud := range auds { - writeLengthPrefixedString(h, b, aud) - } - - key := toString(h.Sum(nil)) // skip base64 encoding to save an allocation - - hashPool.Put(h) - - return key -} - -// writeLengthPrefixedString writes s with a length prefix to prevent ambiguities, i.e. "xy" + "z" == "x" + "yz" -// the length of b is assumed to be 4 (b is mutated by this function to store the length of s) -func writeLengthPrefixedString(w io.Writer, b []byte, s string) { - writeLength(w, b, len(s)) - if _, err := w.Write(toBytes(s)); err != nil { - panic(err) // Write() on hash never fails + resp, ok, err := a.authenticator.AuthenticateToken(ctx, token) + if !a.cacheErrs && err != nil { + return resp, ok, err } -} -// writeLength encodes length into b and then writes it via the given writer -// the length of b is assumed to be 4 -func writeLength(w io.Writer, b []byte, length int) { - binary.BigEndian.PutUint32(b, uint32(length)) - if _, err := w.Write(b); err != nil { - panic(err) // Write() on hash never fails + switch { + case ok && a.successTTL > 0: + a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.successTTL) + case !ok && a.failureTTL > 0: + a.cache.set(key, &cacheRecord{resp: resp, ok: ok, err: err}, a.failureTTL) } -} -// toBytes performs unholy acts to avoid allocations -func toBytes(s string) []byte { - return *(*[]byte)(unsafe.Pointer(&s)) + return resp, ok, err } -// toString performs unholy acts to avoid allocations -func toString(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) +func keyFunc(auds []string, token string) string { + return fmt.Sprintf("%#v|%v", auds, token) } diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator_test.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator_test.go index 7252a0a24d4..09901b40033 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator_test.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator_test.go @@ -18,21 +18,11 @@ package cache import ( "context" - "crypto/hmac" - "crypto/rand" - "crypto/sha256" - "errors" - "fmt" - mathrand "math/rand" "reflect" - "sync" - "sync/atomic" "testing" "time" - "github.com/google/go-cmp/cmp" utilclock "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" ) @@ -57,13 +47,11 @@ func TestCachedTokenAuthenticator(t *testing.T) { a.AuthenticateToken(context.Background(), "bad1") a.AuthenticateToken(context.Background(), "bad2") a.AuthenticateToken(context.Background(), "bad3") - fakeClock.Step(2 * time.Microsecond) a.AuthenticateToken(context.Background(), "bad1") a.AuthenticateToken(context.Background(), "bad2") a.AuthenticateToken(context.Background(), "bad3") - fakeClock.Step(2 * time.Microsecond) if !reflect.DeepEqual(calledWithToken, []string{"bad1", "bad2", "bad3", "bad1", "bad2", "bad3"}) { - t.Errorf("Expected failing calls to not stay in the cache, got %v", calledWithToken) + t.Errorf("Expected failing calls to bypass cache, got %v", calledWithToken) } // reset calls, make the backend return success for three user tokens @@ -137,275 +125,3 @@ func TestCachedTokenAuthenticatorWithAudiences(t *testing.T) { t.Errorf("Expected user1-different") } } - -var bKey string - -// use a realistic token for benchmarking -const jwtToken = `eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVuc2hpZnQtc2RuIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNkbi10b2tlbi1nNndtYyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJzZG4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIzYzM5YzNhYS1kM2Q5LTExZTktYTVkMC0wMmI3YjllODg1OWUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6b3BlbnNoaWZ0LXNkbjpzZG4ifQ.PIs0rsUTekj5AX8yJeLDyW4vQB17YS4IOgO026yjEvsCY7Wv_2TD0lwyZWqyQh639q3jPh2_3LTQq2Cp0cReBP1PYOIGgprNm3C-3OFZRnkls-GH09kvPYE8J_-a1YwjxucOwytzJvEM5QTC9iXfEJNSTBfLge-HMYT1y0AGKs8DWTSC4rtd_2PedK3OYiAyDg_xHA8qNpG9pRNM8vfjV9VsmqJtlbnTVlTngqC0t5vyMaWrmLNRxN0rTbN2W9L3diXRnYqI8BUfgPQb7uhYcPuXGeypaFrN4d3yNN4NbgVxnkgdd2IXQ8elSJuQn6ynrvLgG0JPMmThOHnwvsZDeA` - -func BenchmarkKeyFunc(b *testing.B) { - randomCacheKey := make([]byte, 32) - if _, err := rand.Read(randomCacheKey); err != nil { - b.Fatal(err) // rand should never fail - } - hashPool := &sync.Pool{ - New: func() interface{} { - return hmac.New(sha256.New, randomCacheKey) - }, - } - - // use realistic audiences for benchmarking - auds := []string{"7daf30b7-a85c-429b-8b21-e666aecbb235", "c22aa267-bdde-4acb-8505-998be7818400", "44f9b4f3-7125-4333-b04c-1446a16c6113"} - - b.Run("has audiences", func(b *testing.B) { - var key string - for n := 0; n < b.N; n++ { - key = keyFunc(hashPool, auds, jwtToken) - } - bKey = key - }) - - b.Run("nil audiences", func(b *testing.B) { - var key string - for n := 0; n < b.N; n++ { - key = keyFunc(hashPool, nil, jwtToken) - } - bKey = key - }) -} - -func TestSharedLookup(t *testing.T) { - var chewie = &authenticator.Response{User: &user.DefaultInfo{Name: "chewbacca"}} - - t.Run("actually shared", func(t *testing.T) { - var lookups uint32 - c := make(chan struct{}) - a := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - <-c - atomic.AddUint32(&lookups, 1) - return chewie, true, nil - }), true, time.Minute, 0) - - var wg sync.WaitGroup - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() - a.AuthenticateToken(context.Background(), "") - }() - } - - // no good way to make sure that all the callers are queued so we sleep. - time.Sleep(1 * time.Second) - close(c) - wg.Wait() - - if lookups > 3 { - t.Fatalf("unexpected number of lookups: got=%d, wanted less than 3", lookups) - } - }) - - t.Run("first caller bails, second caller gets result", func(t *testing.T) { - c := make(chan struct{}) - a := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - <-c - return chewie, true, nil - }), true, time.Minute, 0) - - var wg sync.WaitGroup - wg.Add(2) - - ctx1, cancel1 := context.WithCancel(context.Background()) - go func() { - defer wg.Done() - a.AuthenticateToken(ctx1, "") - }() - - ctx2 := context.Background() - - var ( - resp *authenticator.Response - ok bool - err error - ) - go func() { - defer wg.Done() - resp, ok, err = a.AuthenticateToken(ctx2, "") - }() - - time.Sleep(1 * time.Second) - cancel1() - close(c) - wg.Wait() - - if want := chewie; !cmp.Equal(resp, want) { - t.Errorf("Unexpected diff: %v", cmp.Diff(resp, want)) - } - if !ok { - t.Errorf("Expected ok response") - } - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - }) - - t.Run("lookup panics", func(t *testing.T) { - a := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - panic("uh oh") - }), true, time.Minute, 0) - - _, _, err := a.AuthenticateToken(context.Background(), "") - if err != errAuthnCrash { - t.Errorf("expected error: %v", err) - } - }) - - t.Run("audiences are forwarded", func(t *testing.T) { - ctx := authenticator.WithAudiences(context.Background(), []string{"a"}) - a := New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - auds, _ := authenticator.AudiencesFrom(ctx) - if got, want := auds, []string{"a"}; cmp.Equal(got, want) { - t.Fatalf("unexpeced audiences: %v", cmp.Diff(got, want)) - } - return nil, false, nil - }), true, time.Minute, 0) - - a.AuthenticateToken(ctx, "") - }) -} - -func BenchmarkCachedTokenAuthenticator(b *testing.B) { - tokenCount := []int{100, 500, 2500, 12500, 62500} - threadCount := []int{1, 16, 256} - for _, tokens := range tokenCount { - for _, threads := range threadCount { - newSingleBenchmark(tokens, threads).run(b) - } - } -} - -func newSingleBenchmark(tokens, threads int) *singleBenchmark { - s := &singleBenchmark{ - threadCount: threads, - tokenCount: tokens, - } - s.makeTokens() - return s -} - -// singleBenchmark collects all the state needed to run a benchmark. The -// question this benchmark answers is, "what's the average latency added by the -// cache for N concurrent tokens?" -// -// Given the size of the key range constructed by this test, the default go -// benchtime of 1 second is often inadequate to test caching and expiration -// behavior. A benchtime of 10 to 30 seconds is adequate to stress these -// code paths. -type singleBenchmark struct { - threadCount int - // These token.* variables are set by makeTokens() - tokenCount int - // pre-computed response for a token - tokenToResponse map[string]*cacheRecord - // include audiences for some - tokenToAuds map[string]authenticator.Audiences - // a list makes it easy to select a random one - tokens []string -} - -func (s *singleBenchmark) makeTokens() { - s.tokenToResponse = map[string]*cacheRecord{} - s.tokenToAuds = map[string]authenticator.Audiences{} - s.tokens = []string{} - - for i := 0; i < s.tokenCount; i++ { - tok := fmt.Sprintf("%v-%v", jwtToken, i) - r := cacheRecord{ - resp: &authenticator.Response{ - User: &user.DefaultInfo{Name: fmt.Sprintf("holder of token %v", i)}, - }, - } - // make different combinations of audience, failures, denies for the tokens. - auds := []string{} - for i := 0; i < mathrand.Intn(4); i++ { - auds = append(auds, string(uuid.NewUUID())) - } - choice := mathrand.Float64() - switch { - case choice < 0.9: - r.ok = true - r.err = nil - case choice < 0.99: - r.ok = false - r.err = nil - default: - r.ok = false - r.err = errors.New("I can't think of a clever error name right now") - } - s.tokens = append(s.tokens, tok) - s.tokenToResponse[tok] = &r - if len(auds) > 0 { - s.tokenToAuds[tok] = auds - } - } -} - -func (s *singleBenchmark) lookup(ctx context.Context, token string) (*authenticator.Response, bool, error) { - r, ok := s.tokenToResponse[token] - if !ok { - panic("test setup problem") - } - return r.resp, r.ok, r.err -} - -func (s *singleBenchmark) doAuthForTokenN(n int, a authenticator.Token) { - tok := s.tokens[n] - auds := s.tokenToAuds[tok] - ctx := context.Background() - ctx = authenticator.WithAudiences(ctx, auds) - a.AuthenticateToken(ctx, tok) -} - -func (s *singleBenchmark) run(b *testing.B) { - b.Run(fmt.Sprintf("tokens=%d threads=%d", s.tokenCount, s.threadCount), s.bench) -} - -func (s *singleBenchmark) bench(b *testing.B) { - // Simulate slowness, qps limit, external service limitation, etc - const maxInFlight = 40 - chokepoint := make(chan struct{}, maxInFlight) - // lookup count - var lookups uint64 - - a := newWithClock( - authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - atomic.AddUint64(&lookups, 1) - - chokepoint <- struct{}{} - defer func() { <-chokepoint }() - - time.Sleep(1 * time.Millisecond) - - return s.lookup(ctx, token) - }), - true, - 4*time.Second, - 500*time.Millisecond, - utilclock.RealClock{}, - ) - - b.ResetTimer() - b.SetParallelism(s.threadCount) - b.RunParallel(func(pb *testing.PB) { - r := mathrand.New(mathrand.NewSource(mathrand.Int63())) - for pb.Next() { - // some problems appear with random access, some appear with many - // requests for a single entry, so we do both. - s.doAuthForTokenN(r.Intn(s.tokenCount), a) - s.doAuthForTokenN(0, a) - } - }) - b.StopTimer() - - b.ReportMetric(float64(lookups)/float64(b.N), "lookups/op") -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/stats.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/stats.go deleted file mode 100644 index dbe745718e7..00000000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/stats.go +++ /dev/null @@ -1,125 +0,0 @@ -/* -Copyright 2019 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 cache - -import ( - "time" - - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" -) - -var ( - requestLatency = metrics.NewHistogramVec( - &metrics.HistogramOpts{ - Namespace: "authentication", - Subsystem: "token_cache", - Name: "request_duration_seconds", - StabilityLevel: metrics.ALPHA, - }, - []string{"status"}, - ) - requestCount = metrics.NewCounterVec( - &metrics.CounterOpts{ - Namespace: "authentication", - Subsystem: "token_cache", - Name: "request_total", - StabilityLevel: metrics.ALPHA, - }, - []string{"status"}, - ) - fetchCount = metrics.NewCounterVec( - &metrics.CounterOpts{ - Namespace: "authentication", - Subsystem: "token_cache", - Name: "fetch_total", - StabilityLevel: metrics.ALPHA, - }, - []string{"status"}, - ) - activeFetchCount = metrics.NewGaugeVec( - &metrics.GaugeOpts{ - Namespace: "authentication", - Subsystem: "token_cache", - Name: "active_fetch_count", - StabilityLevel: metrics.ALPHA, - }, - []string{"status"}, - ) -) - -func init() { - legacyregistry.MustRegister( - requestLatency, - requestCount, - fetchCount, - activeFetchCount, - ) -} - -const ( - hitTag = "hit" - missTag = "miss" - - fetchFailedTag = "error" - fetchOkTag = "ok" - - fetchInFlightTag = "in_flight" - fetchBlockedTag = "blocked" -) - -type statsCollector struct{} - -var stats = statsCollector{} - -func (statsCollector) authenticating() func(hit bool) { - start := time.Now() - return func(hit bool) { - var tag string - if hit { - tag = hitTag - } else { - tag = missTag - } - - latency := time.Since(start) - - requestCount.WithLabelValues(tag).Inc() - requestLatency.WithLabelValues(tag).Observe(float64(latency.Milliseconds()) / 1000) - } -} - -func (statsCollector) blocking() func() { - activeFetchCount.WithLabelValues(fetchBlockedTag).Inc() - return activeFetchCount.WithLabelValues(fetchBlockedTag).Dec -} - -func (statsCollector) fetching() func(ok bool) { - activeFetchCount.WithLabelValues(fetchInFlightTag).Inc() - return func(ok bool) { - var tag string - if ok { - tag = fetchOkTag - } else { - tag = fetchFailedTag - } - - fetchCount.WithLabelValues(tag).Inc() - - activeFetchCount.WithLabelValues(fetchInFlightTag).Dec() - } -} diff --git a/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go b/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go index 3d87fd72caf..570c51ae995 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package user contains utilities for dealing with simple user exchange in the auth // packages. The user.Info interface defines an interface for exchanging that info. -package user // import "k8s.io/apiserver/pkg/authentication/user" +package user diff --git a/vendor/k8s.io/apiserver/pkg/authorization/OWNERS b/vendor/k8s.io/apiserver/pkg/authorization/OWNERS index 7b3130fdcbc..cd0d70a0f8f 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/authorization/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - sig-auth-authorizers-approvers reviewers: diff --git a/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go b/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go index ce70710fa3b..95ade009e3d 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go @@ -17,7 +17,6 @@ limitations under the License. package authorizer import ( - "context" "net/http" "k8s.io/apiserver/pkg/authentication/user" @@ -57,7 +56,7 @@ type Attributes interface { GetAPIVersion() string // IsResourceRequest returns true for requests to API resources, like /api/v1/nodes, - // and false for non-resource endpoints like /api, /healthz + // and false for non-resource endpoints like /api, /healthz, and /swaggerapi IsResourceRequest() bool // GetPath returns the path of the request @@ -68,12 +67,12 @@ type Attributes interface { // zero or more calls to methods of the Attributes interface. It returns nil when an action is // authorized, otherwise it returns an error. type Authorizer interface { - Authorize(ctx context.Context, a Attributes) (authorized Decision, reason string, err error) + Authorize(a Attributes) (authorized Decision, reason string, err error) } type AuthorizerFunc func(a Attributes) (Decision, string, error) -func (f AuthorizerFunc) Authorize(ctx context.Context, a Attributes) (Decision, string, error) { +func (f AuthorizerFunc) Authorize(a Attributes) (Decision, string, error) { return f(a) } diff --git a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/OWNERS b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/OWNERS old mode 100644 new mode 100755 index a5ccdcbd1b0..cb2ae800f36 --- a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - deads2k - dims diff --git a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go index 6fe3fa96ed8..fc36bc0bc93 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go @@ -17,7 +17,6 @@ limitations under the License. package authorizerfactory import ( - "context" "errors" "k8s.io/apiserver/pkg/authentication/user" @@ -29,7 +28,7 @@ import ( // It is useful in tests and when using kubernetes in an open manner. type alwaysAllowAuthorizer struct{} -func (alwaysAllowAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { +func (alwaysAllowAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { return authorizer.DecisionAllow, "", nil } @@ -57,7 +56,7 @@ func NewAlwaysAllowAuthorizer() *alwaysAllowAuthorizer { // It is useful in unit tests to force an operation to be forbidden. type alwaysDenyAuthorizer struct{} -func (alwaysDenyAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) { +func (alwaysDenyAuthorizer) Authorize(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) { return authorizer.DecisionNoOpinion, "Everything is forbidden.", nil } @@ -73,7 +72,7 @@ type privilegedGroupAuthorizer struct { groups []string } -func (r *privilegedGroupAuthorizer) Authorize(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) { +func (r *privilegedGroupAuthorizer) Authorize(attr authorizer.Attributes) (authorizer.Decision, string, error) { if attr.GetUser() == nil { return authorizer.DecisionNoOpinion, "Error", errors.New("no user on request.") } diff --git a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin_test.go b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin_test.go index 620bd0f1a53..4e22b551fa2 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin_test.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin_test.go @@ -17,7 +17,6 @@ limitations under the License. package authorizerfactory import ( - "context" "testing" "k8s.io/apiserver/pkg/authentication/user" @@ -26,14 +25,14 @@ import ( func TestNewAlwaysAllowAuthorizer(t *testing.T) { aaa := NewAlwaysAllowAuthorizer() - if decision, _, _ := aaa.Authorize(context.Background(), nil); decision != authorizer.DecisionAllow { + if decision, _, _ := aaa.Authorize(nil); decision != authorizer.DecisionAllow { t.Errorf("AlwaysAllowAuthorizer.Authorize did not authorize successfully.") } } func TestNewAlwaysDenyAuthorizer(t *testing.T) { ada := NewAlwaysDenyAuthorizer() - if decision, _, _ := ada.Authorize(context.Background(), nil); decision == authorizer.DecisionAllow { + if decision, _, _ := ada.Authorize(nil); decision == authorizer.DecisionAllow { t.Errorf("AlwaysDenyAuthorizer.Authorize returned nil instead of error.") } } @@ -44,10 +43,10 @@ func TestPrivilegedGroupAuthorizer(t *testing.T) { yes := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "allow-01"}}} no := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "deny-01"}}} - if authorized, _, _ := auth.Authorize(context.Background(), yes); authorized != authorizer.DecisionAllow { + if authorized, _, _ := auth.Authorize(yes); authorized != authorizer.DecisionAllow { t.Errorf("failed") } - if authorized, _, _ := auth.Authorize(context.Background(), no); authorized == authorizer.DecisionAllow { + if authorized, _, _ := auth.Authorize(no); authorized == authorizer.DecisionAllow { t.Errorf("failed") } } diff --git a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go index fa385e12554..c75c0a7552b 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/authorizerfactory/delegating.go @@ -21,7 +21,7 @@ import ( "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/plugin/pkg/authorizer/webhook" - authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" + authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1beta1" ) // DelegatingAuthorizerConfig is the minimal configuration needed to create an authenticator diff --git a/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go b/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go index 654aaeb7424..743d945b46b 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/path/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package path contains an authorizer that allows certain paths and path prefixes. -package path // import "k8s.io/apiserver/pkg/authorization/path" +package path diff --git a/vendor/k8s.io/apiserver/pkg/authorization/path/path_test.go b/vendor/k8s.io/apiserver/pkg/authorization/path/path_test.go index 92620a24fb2..be48c52bc88 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/path/path_test.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/path/path_test.go @@ -17,7 +17,6 @@ limitations under the License. package path import ( - "context" "testing" "k8s.io/apiserver/pkg/authorization/authorizer" @@ -66,7 +65,7 @@ func TestNewAuthorizer(t *testing.T) { info := authorizer.AttributesRecord{ Path: pth, } - if got, _, err := a.Authorize(context.Background(), info); err != nil { + if got, _, err := a.Authorize(info); err != nil { t.Errorf("NewAuthorizer(%v).Authorize(%q) return unexpected error: %v", tt.excludedPaths, pth, err) } else if got != cases.want { t.Errorf("NewAuthorizer(%v).Authorize(%q) = %v, want %v", tt.excludedPaths, pth, got, cases.want) diff --git a/vendor/k8s.io/apiserver/pkg/authorization/union/union.go b/vendor/k8s.io/apiserver/pkg/authorization/union/union.go index 89d68ffed10..15753789ced 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/union/union.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/union/union.go @@ -25,7 +25,6 @@ limitations under the License. package union import ( - "context" "strings" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -42,14 +41,14 @@ func New(authorizationHandlers ...authorizer.Authorizer) authorizer.Authorizer { } // Authorizes against a chain of authorizer.Authorizer objects and returns nil if successful and returns error if unsuccessful -func (authzHandler unionAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { +func (authzHandler unionAuthzHandler) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) { var ( errlist []error reasonlist []string ) for _, currAuthzHandler := range authzHandler { - decision, reason, err := currAuthzHandler.Authorize(ctx, a) + decision, reason, err := currAuthzHandler.Authorize(a) if err != nil { errlist = append(errlist, err) diff --git a/vendor/k8s.io/apiserver/pkg/authorization/union/union_test.go b/vendor/k8s.io/apiserver/pkg/authorization/union/union_test.go index 057c1cefe1e..a6413897915 100644 --- a/vendor/k8s.io/apiserver/pkg/authorization/union/union_test.go +++ b/vendor/k8s.io/apiserver/pkg/authorization/union/union_test.go @@ -17,7 +17,6 @@ limitations under the License. package union import ( - "context" "errors" "fmt" "reflect" @@ -32,7 +31,7 @@ type mockAuthzHandler struct { err error } -func (mock *mockAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { +func (mock *mockAuthzHandler) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) { return mock.decision, "", mock.err } @@ -41,7 +40,7 @@ func TestAuthorizationSecondPasses(t *testing.T) { handler2 := &mockAuthzHandler{decision: authorizer.DecisionAllow} authzHandler := New(handler1, handler2) - authorized, _, _ := authzHandler.Authorize(context.Background(), nil) + authorized, _, _ := authzHandler.Authorize(nil) if authorized != authorizer.DecisionAllow { t.Errorf("Unexpected authorization failure") } @@ -52,7 +51,7 @@ func TestAuthorizationFirstPasses(t *testing.T) { handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} authzHandler := New(handler1, handler2) - authorized, _, _ := authzHandler.Authorize(context.Background(), nil) + authorized, _, _ := authzHandler.Authorize(nil) if authorized != authorizer.DecisionAllow { t.Errorf("Unexpected authorization failure") } @@ -63,7 +62,7 @@ func TestAuthorizationNonePasses(t *testing.T) { handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} authzHandler := New(handler1, handler2) - authorized, _, _ := authzHandler.Authorize(context.Background(), nil) + authorized, _, _ := authzHandler.Authorize(nil) if authorized == authorizer.DecisionAllow { t.Errorf("Expected failed authorization") } @@ -74,7 +73,7 @@ func TestAuthorizationError(t *testing.T) { handler2 := &mockAuthzHandler{err: fmt.Errorf("foo")} authzHandler := New(handler1, handler2) - _, _, err := authzHandler.Authorize(context.Background(), nil) + _, _, err := authzHandler.Authorize(nil) if err == nil { t.Errorf("Expected error: %v", err) } @@ -258,7 +257,7 @@ func TestAuthorizationUnequivocalDeny(t *testing.T) { t.Run(fmt.Sprintf("case %v", i), func(t *testing.T) { authzHandler := New(c.authorizers...) - decision, _, _ := authzHandler.Authorize(context.Background(), nil) + decision, _, _ := authzHandler.Authorize(nil) if decision != c.decision { t.Errorf("Unexpected authorization failure: %v, expected: %v", decision, c.decision) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/apiserver_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/apiserver_test.go index cbc72255b23..6d8bac3adb0 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/apiserver_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/apiserver_test.go @@ -37,14 +37,12 @@ import ( "testing" "time" - restful "github.com/emicklei/go-restful" - + "github.com/emicklei/go-restful" fuzzer "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" apiequality "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" + apierrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" @@ -53,7 +51,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/runtime/serializer/streaming" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/diff" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -67,19 +64,19 @@ import ( "k8s.io/apiserver/pkg/audit" auditpolicy "k8s.io/apiserver/pkg/audit/policy" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" - "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/request" genericapitesting "k8s.io/apiserver/pkg/endpoints/testing" "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/server/filters" utilfeature "k8s.io/apiserver/pkg/util/feature" - featuregatetesting "k8s.io/component-base/featuregate/testing" + utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" ) type alwaysMutatingDeny struct{} -func (alwaysMutatingDeny) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (alwaysMutatingDeny) Admit(a admission.Attributes) (err error) { return admission.NewForbidden(a, errors.New("Mutating admission control is denying all modifications")) } @@ -87,11 +84,9 @@ func (alwaysMutatingDeny) Handles(operation admission.Operation) bool { return true } -var _ admission.MutationInterface = &alwaysMutatingDeny{} - type alwaysValidatingDeny struct{} -func (alwaysValidatingDeny) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { +func (alwaysValidatingDeny) Validate(a admission.Attributes) (err error) { return admission.NewForbidden(a, errors.New("Validating admission control is denying all modifications")) } @@ -99,8 +94,6 @@ func (alwaysValidatingDeny) Handles(operation admission.Operation) bool { return true } -var _ admission.ValidationInterface = &alwaysValidatingDeny{} - // This creates fake API versions, similar to api/latest.go. var testAPIGroup = "test.group" var testAPIGroup2 = "test.group2" @@ -147,8 +140,6 @@ func addGrouplessTypes() { scheme.AddKnownTypes(grouplessInternalGroupVersion, &genericapitesting.Simple{}, &genericapitesting.SimpleList{}, &metav1.ExportOptions{}, &genericapitesting.SimpleGetOptions{}, &genericapitesting.SimpleRoot{}) - - utilruntime.Must(genericapitesting.RegisterConversions(scheme)) } func addTestTypes() { @@ -168,8 +159,6 @@ func addTestTypes() { scheme.AddKnownTypes(testGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{}) scheme.AddKnownTypes(testInternalGroup2Version, &genericapitesting.SimpleXGSubresource{}, &metav1.ExportOptions{}) metav1.AddToGroupVersion(scheme, testGroupVersion) - - utilruntime.Must(genericapitesting.RegisterConversions(scheme)) } func addNewTestTypes() { @@ -179,8 +168,6 @@ func addNewTestTypes() { &examplev1.Pod{}, ) metav1.AddToGroupVersion(scheme, newGroupVersion) - - utilruntime.Must(genericapitesting.RegisterConversions(scheme)) } func init() { @@ -240,8 +227,6 @@ func handleInternal(storage map[string]rest.Storage, admissionControl admission. Linker: selfLinker, RootScopedKinds: sets.NewString("SimpleRoot"), - EquivalentResourceRegistry: runtime.NewEquivalentResourceRegistry(), - ParameterCodec: parameterCodec, Admit: admissionControl, @@ -350,6 +335,7 @@ type SimpleRESTStorage struct { fakeWatch *watch.FakeWatcher requestedLabelSelector labels.Selector requestedFieldSelector fields.Selector + requestedUninitialized bool requestedResourceVersion string requestedResourceNamespace string @@ -383,7 +369,7 @@ func (storage *SimpleRESTStorage) Export(ctx context.Context, name string, opts return obj, storage.errors["export"] } -func (storage *SimpleRESTStorage) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { +func (storage *SimpleRESTStorage) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) { return rest.NewDefaultTableConvertor(schema.GroupResource{Resource: "simple"}).ConvertToTable(ctx, obj, tableOptions) } @@ -404,6 +390,7 @@ func (storage *SimpleRESTStorage) List(ctx context.Context, options *metainterna if options != nil && options.FieldSelector != nil { storage.requestedFieldSelector = options.FieldSelector } + storage.requestedUninitialized = options.IncludeUninitialized return result, storage.errors["list"] } @@ -453,16 +440,13 @@ func (storage *SimpleRESTStorage) checkContext(ctx context.Context) { storage.actualNamespace, storage.namespacePresent = request.NamespaceFrom(ctx) } -func (storage *SimpleRESTStorage) Delete(ctx context.Context, id string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { +func (storage *SimpleRESTStorage) Delete(ctx context.Context, id string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { storage.checkContext(ctx) storage.deleted = id storage.deleteOptions = options if err := storage.errors["delete"]; err != nil { return nil, false, err } - if err := deleteValidation(ctx, &storage.item); err != nil { - return nil, false, err - } var obj runtime.Object = &metav1.Status{Status: metav1.StatusSuccess} var err error if storage.injectedFunction != nil { @@ -489,7 +473,7 @@ func (storage *SimpleRESTStorage) Create(ctx context.Context, obj runtime.Object if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := createValidation(ctx, obj); err != nil { + if err := createValidation(obj); err != nil { return nil, err } return obj, err @@ -508,7 +492,7 @@ func (storage *SimpleRESTStorage) Update(ctx context.Context, name string, objIn if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := updateValidation(ctx, &storage.item, obj); err != nil { + if err := updateValidation(&storage.item, obj); err != nil { return nil, false, err } return obj, false, err @@ -666,7 +650,7 @@ func (storage *NamedCreaterRESTStorage) Create(ctx context.Context, name string, if storage.injectedFunction != nil { obj, err = storage.injectedFunction(obj) } - if err := createValidation(ctx, obj); err != nil { + if err := createValidation(obj); err != nil { return nil, err } return obj, err @@ -901,10 +885,6 @@ func (OnlyGetRESTStorage) List(ctx context.Context, options *metainternalversion return nil, nil } -func (OnlyGetRESTStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - return nil, nil -} - // TestSomeUnimplementedRESTStorage ensures that if a rest.Storage does // not implement a given method, that it is literally not registered // with the server. We need to have at least one verb supported inorder @@ -1234,12 +1214,7 @@ func TestListCompression(t *testing.T) { } for i, testCase := range testCases { storage := map[string]rest.Storage{} - simpleStorage := SimpleRESTStorage{ - expectedResourceNamespace: testCase.namespace, - list: []genericapitesting.Simple{ - {Other: strings.Repeat("0123456789abcdef", (128*1024/16)+1)}, - }, - } + simpleStorage := SimpleRESTStorage{expectedResourceNamespace: testCase.namespace} storage["simple"] = &simpleStorage selfLinker := &setTestSelfLinker{ t: t, @@ -1248,6 +1223,7 @@ func TestListCompression(t *testing.T) { } var handler = handleInternal(storage, admissionControl, selfLinker, nil) + handler = filters.WithCompression(handler) handler = genericapifilters.WithRequestInfo(handler, newTestRequestInfoResolver()) server := httptest.NewServer(handler) @@ -1640,86 +1616,11 @@ func TestGet(t *testing.T) { } } -func BenchmarkGet(b *testing.B) { - storage := map[string]rest.Storage{} - simpleStorage := SimpleRESTStorage{ - item: genericapitesting.Simple{ - Other: "foo", - }, - } - selfLinker := &setTestSelfLinker{ - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id", - name: "id", - namespace: "default", - } - storage["simple"] = &simpleStorage - handler := handleLinker(storage, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - - u := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id" - - b.ResetTimer() - for i := 0; i < b.N; i++ { - resp, err := http.Get(u) - if err != nil { - b.Fatalf("unexpected error: %v", err) - } - if resp.StatusCode != http.StatusOK { - b.Fatalf("unexpected response: %#v", resp) - } - if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { - b.Fatalf("unable to read body") - } - } - b.StopTimer() -} - -func BenchmarkGetNoCompression(b *testing.B) { - storage := map[string]rest.Storage{} - simpleStorage := SimpleRESTStorage{ - item: genericapitesting.Simple{ - Other: "foo", - }, - } - selfLinker := &setTestSelfLinker{ - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id", - name: "id", - namespace: "default", - } - storage["simple"] = &simpleStorage - handler := handleLinker(storage, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - - client := &http.Client{ - Transport: &http.Transport{ - DisableCompression: true, - }, - } - - u := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id" - - b.ResetTimer() - for i := 0; i < b.N; i++ { - resp, err := client.Get(u) - if err != nil { - b.Fatalf("unexpected error: %v", err) - } - if resp.StatusCode != http.StatusOK { - b.Fatalf("unexpected response: %#v", resp) - } - if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { - b.Fatalf("unable to read body") - } - } - b.StopTimer() -} func TestGetCompression(t *testing.T) { storage := map[string]rest.Storage{} simpleStorage := SimpleRESTStorage{ item: genericapitesting.Simple{ - Other: strings.Repeat("0123456789abcdef", (128*1024/16)+1), + Other: "foo", }, } selfLinker := &setTestSelfLinker{ @@ -1731,6 +1632,7 @@ func TestGetCompression(t *testing.T) { storage["simple"] = &simpleStorage handler := handleLinker(storage, selfLinker) + handler = filters.WithCompression(handler) handler = genericapifilters.WithRequestInfo(handler, newTestRequestInfoResolver()) server := httptest.NewServer(handler) defer server.Close() @@ -1745,7 +1647,7 @@ func TestGetCompression(t *testing.T) { for _, test := range tests { req, err := http.NewRequest("GET", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/id", nil) if err != nil { - t.Fatalf("unexpected error creating request: %v", err) + t.Fatalf("unexpected error cretaing request: %v", err) } // It's necessary to manually set Accept-Encoding here // to prevent http.DefaultClient from automatically @@ -1787,6 +1689,52 @@ func TestGetCompression(t *testing.T) { } } +func TestGetUninitialized(t *testing.T) { + storage := map[string]rest.Storage{} + simpleStorage := SimpleRESTStorage{ + list: []genericapitesting.Simple{ + { + ObjectMeta: metav1.ObjectMeta{ + Initializers: &metav1.Initializers{ + Pending: []metav1.Initializer{{Name: "test"}}, + }, + }, + Other: "foo", + }, + }, + } + selfLinker := &setTestSelfLinker{ + t: t, + expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/id", + alternativeSet: sets.NewString("/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple"), + name: "id", + namespace: "default", + } + storage["simple"] = &simpleStorage + handler := handleLinker(storage, selfLinker) + server := httptest.NewServer(handler) + defer server.Close() + + resp, err := http.Get(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple?includeUninitialized=true") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp.StatusCode != http.StatusOK { + t.Fatalf("unexpected response: %#v", resp) + } + var itemOut genericapitesting.SimpleList + body, err := extractBody(resp, &itemOut) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(itemOut.Items) != 1 || itemOut.Items[0].Other != "foo" { + t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body)) + } + if !simpleStorage.requestedUninitialized { + t.Errorf("Didn't set correct flag") + } +} + func TestGetPretty(t *testing.T) { storage := map[string]rest.Storage{} simpleStorage := SimpleRESTStorage{ @@ -1812,14 +1760,14 @@ func TestGetPretty(t *testing.T) { pretty bool }{ {accept: runtime.ContentTypeJSON}, - {accept: "application/json;pretty=0"}, + {accept: runtime.ContentTypeJSON + ";pretty=0"}, {accept: runtime.ContentTypeJSON, userAgent: "kubectl"}, {accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"0"}}}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "curl"}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Mozilla/5.0"}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Wget"}, - {pretty: true, accept: "application/json;pretty=1"}, + {pretty: true, accept: runtime.ContentTypeJSON + ";pretty=1"}, {pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"1"}}}, {pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"true"}}}, } @@ -1881,28 +1829,14 @@ func TestGetTable(t *testing.T) { if err != nil { t.Fatal(err) } - var encodedV1Beta1Body []byte - { - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) - encodedBody, err := runtime.Encode(metainternalversionscheme.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion), partial) - if err != nil { - t.Fatal(err) - } - // the codec includes a trailing newline that is not present during decode - encodedV1Beta1Body = bytes.TrimSpace(encodedBody) - } - var encodedV1Body []byte - { - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) - encodedBody, err := runtime.Encode(metainternalversionscheme.Codecs.LegacyCodec(metav1.SchemeGroupVersion), partial) - if err != nil { - t.Fatal(err) - } - // the codec includes a trailing newline that is not present during decode - encodedV1Body = bytes.TrimSpace(encodedBody) + partial := meta.AsPartialObjectMetadata(m) + partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) + encodedBody, err := runtime.Encode(metainternalversion.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion), partial) + if err != nil { + t.Fatal(err) } + // the codec includes a trailing newline that is not present during decode + encodedBody = bytes.TrimSpace(encodedBody) metaDoc := metav1.ObjectMeta{}.SwaggerDoc() @@ -1910,99 +1844,57 @@ func TestGetTable(t *testing.T) { accept string params url.Values pretty bool - expected *metav1.Table + expected *metav1beta1.Table statusCode int item bool }{ { - accept: "application/json;as=Table;v=v1alpha1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=Table;v=v1;g=meta.k8s.io", statusCode: http.StatusNotAcceptable, }, - { - accept: runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io", - statusCode: http.StatusNotAcceptable, - }, - { - accept: runtime.ContentTypeProtobuf + ";as=Table;v=v1;g=meta.k8s.io", - statusCode: http.StatusNotAcceptable, - }, - - { - item: true, - accept: "application/json;as=Table;v=v1;g=meta.k8s.io", - expected: &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, - {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, - }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Body}}, - }, - }, - }, { item: true, - accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io", - expected: &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, - {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, - }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}}, - }, - }, - }, - { - item: true, - accept: strings.Join([]string{ - runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io", - "application/json;as=Table;v=v1beta1;g=meta.k8s.io", - }, ","), - expected: &metav1.Table{ + accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", + expected: &metav1beta1.Table{ TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ + ColumnDefinitions: []metav1beta1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}}, + Rows: []metav1beta1.TableRow{ + {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, }, }, }, { item: true, - accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", params: url.Values{"includeObject": []string{"Metadata"}}, - expected: &metav1.Table{ + expected: &metav1beta1.Table{ TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ + ColumnDefinitions: []metav1beta1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}}, + Rows: []metav1beta1.TableRow{ + {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, }, }, }, { - accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", params: url.Values{"includeObject": []string{"Metadata"}}, - expected: &metav1.Table{ + expected: &metav1beta1.Table{ TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/test/link"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ + ColumnDefinitions: []metav1beta1.TableColumnDefinition{ {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}}, + Rows: []metav1beta1.TableRow{ + {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, }, }, }, @@ -2061,7 +1953,7 @@ func TestGetTable(t *testing.T) { if resp.StatusCode != http.StatusOK { t.Errorf("%d: unexpected response: %#v", i, resp) } - var itemOut metav1.Table + var itemOut metav1beta1.Table body, err := extractBody(resp, &itemOut) if err != nil { t.Fatal(err) @@ -2074,261 +1966,6 @@ func TestGetTable(t *testing.T) { } } -func TestWatchTable(t *testing.T) { - obj := genericapitesting.Simple{ - ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", ResourceVersion: "10", SelfLink: "/blah", CreationTimestamp: metav1.NewTime(time.Unix(1, 0)), UID: types.UID("abcdef0123")}, - Other: "foo", - } - - m, err := meta.Accessor(&obj) - if err != nil { - t.Fatal(err) - } - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) - encodedBody, err := runtime.Encode(metainternalversionscheme.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion), partial) - if err != nil { - t.Fatal(err) - } - // the codec includes a trailing newline that is not present during decode - encodedBody = bytes.TrimSpace(encodedBody) - - encodedBodyV1, err := runtime.Encode(metainternalversionscheme.Codecs.LegacyCodec(metav1.SchemeGroupVersion), partial) - if err != nil { - t.Fatal(err) - } - // the codec includes a trailing newline that is not present during decode - encodedBodyV1 = bytes.TrimSpace(encodedBodyV1) - - metaDoc := metav1.ObjectMeta{}.SwaggerDoc() - - s := metainternalversionscheme.Codecs.SupportedMediaTypes()[0].Serializer - - tests := []struct { - accept string - params url.Values - send func(w *watch.FakeWatcher) - - expected []*metav1.WatchEvent - contentType string - statusCode int - item bool - }{ - { - accept: "application/json;as=Table;v=v1alpha1;g=meta.k8s.io", - statusCode: http.StatusNotAcceptable, - }, - { - accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io", - send: func(w *watch.FakeWatcher) { - w.Add(&obj) - }, - expected: []*metav1.WatchEvent{ - { - Type: "ADDED", - Object: runtime.RawExtension{ - Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, - {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, - }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, - }, - }))), - }, - }, - }, - }, - { - accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io", - send: func(w *watch.FakeWatcher) { - w.Add(&obj) - w.Modify(&obj) - }, - expected: []*metav1.WatchEvent{ - { - Type: "ADDED", - Object: runtime.RawExtension{ - Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, - {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, - }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, - }, - }))), - }, - }, - { - Type: "MODIFIED", - Object: runtime.RawExtension{ - Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, - }, - }))), - }, - }, - }, - }, - { - accept: "application/json;as=Table;v=v1;g=meta.k8s.io", - send: func(w *watch.FakeWatcher) { - w.Add(&obj) - w.Modify(&obj) - }, - expected: []*metav1.WatchEvent{ - { - Type: "ADDED", - Object: runtime.RawExtension{ - Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]}, - {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, - }, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBodyV1}}, - }, - }))), - }, - }, - { - Type: "MODIFIED", - Object: runtime.RawExtension{ - Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{ - TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"}, - ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, - Rows: []metav1.TableRow{ - {Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBodyV1}}, - }, - }))), - }, - }, - }, - }, - } - for i, test := range tests { - t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - storage := map[string]rest.Storage{} - simpleStorage := SimpleRESTStorage{ - item: obj, - list: []genericapitesting.Simple{obj}, - } - - selfLinker := &setTestSelfLinker{ - t: t, - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple", - namespace: "default", - } - if test.item { - selfLinker.expectedSet += "/id" - selfLinker.name = "id" - } - storage["simple"] = &simpleStorage - handler := handleLinker(storage, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - - var id string - if test.item { - id = "/id" - } - u, err := url.Parse(server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple") - if err != nil { - t.Fatal(err) - } - if test.params == nil { - test.params = url.Values{} - } - if test.item { - test.params["fieldSelector"] = []string{fmt.Sprintf("metadata.name=%s", id)} - } - test.params["watch"] = []string{"1"} - - u.RawQuery = test.params.Encode() - req := &http.Request{Method: "GET", URL: u} - req.Header = http.Header{} - req.Header.Set("Accept", test.accept) - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if test.statusCode != 0 { - if resp.StatusCode != test.statusCode { - t.Fatalf("%d: unexpected response: %#v", i, resp) - } - obj, _, err := extractBodyObject(resp, unstructured.UnstructuredJSONScheme) - if err != nil { - t.Fatalf("%d: unexpected body read error: %v", i, err) - } - gvk := schema.GroupVersionKind{Version: "v1", Kind: "Status"} - if obj.GetObjectKind().GroupVersionKind() != gvk { - t.Fatalf("%d: unexpected error body: %#v", i, obj) - } - return - } - if resp.StatusCode != http.StatusOK { - t.Fatalf("%d: unexpected response: %#v", i, resp) - } - - go func() { - defer simpleStorage.fakeWatch.Stop() - test.send(simpleStorage.fakeWatch) - }() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - t.Logf("Body:\n%s", string(body)) - d := watcher(resp.Header.Get("Content-Type"), ioutil.NopCloser(bytes.NewReader(body))) - var actual []*metav1.WatchEvent - for { - var event metav1.WatchEvent - _, _, err := d.Decode(nil, &event) - if err == io.EOF { - break - } - if err != nil { - t.Fatal(err) - } - actual = append(actual, &event) - } - if !reflect.DeepEqual(test.expected, actual) { - for i := range test.expected { - if i >= len(actual) { - break - } - t.Logf("%s", diff.StringDiff(string(test.expected[i].Object.Raw), string(actual[i].Object.Raw))) - } - t.Fatalf("unexpected: %s", diff.ObjectReflectDiff(test.expected, actual)) - } - }) - } -} - -func watcher(mediaType string, r io.ReadCloser) streaming.Decoder { - info, ok := runtime.SerializerInfoForMediaType(metainternalversionscheme.Codecs.SupportedMediaTypes(), mediaType) - if !ok || info.StreamSerializer == nil { - panic(info) - } - streamSerializer := info.StreamSerializer - fr := streamSerializer.Framer.NewFrameReader(r) - d := streaming.NewDecoder(fr, streamSerializer.Serializer) - return d -} - func TestGetPartialObjectMetadata(t *testing.T) { now := metav1.Time{metav1.Now().Rfc3339Copy().Local()} storage := map[string]rest.Storage{} @@ -2370,78 +2007,48 @@ func TestGetPartialObjectMetadata(t *testing.T) { statusCode int }{ { - accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io", statusCode: http.StatusNotAcceptable, }, { - accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io, application/json", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json", expectKind: schema.GroupVersionKind{Kind: "Simple", Group: testGroupVersion.Group, Version: testGroupVersion.Version}, }, { - accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json", expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, }, { list: true, - accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", statusCode: http.StatusNotAcceptable, }, - - // verify preferred version overrides supported version - { - accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json", - expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, - }, - { - accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json", - expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"}, - }, - { - accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io", - expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, - }, - { - accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", - expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"}, - }, - { list: true, - accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io, application/json", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json", expectKind: schema.GroupVersionKind{Kind: "SimpleList", Group: testGroupVersion.Group, Version: testGroupVersion.Version}, }, { list: true, - accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io, application/json", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io, application/json", expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadataList", Group: "meta.k8s.io", Version: "v1beta1"}, }, { - accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", statusCode: http.StatusNotAcceptable, }, { - accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", expected: &metav1beta1.PartialObjectMetadata{ ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("abcdef0123")}, }, expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, }, - { - accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io", - expected: &metav1.PartialObjectMetadata{ - ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("abcdef0123")}, - }, - expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"}, - }, { list: true, - accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", + accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", expected: &metav1beta1.PartialObjectMetadataList{ - ListMeta: metav1.ListMeta{ - ResourceVersion: "10", - SelfLink: "/test/link", - }, - Items: []metav1beta1.PartialObjectMetadata{ + Items: []*metav1beta1.PartialObjectMetadata{ { TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1beta1", Kind: "PartialObjectMetadata"}, ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("newer")}, @@ -2493,7 +2100,7 @@ func TestGetPartialObjectMetadata(t *testing.T) { } body := "" if test.expected != nil { - itemOut, d, err := extractBodyObject(resp, metainternalversionscheme.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion)) + itemOut, d, err := extractBodyObject(resp, metainternalversion.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion)) if err != nil { t.Fatal(err) } @@ -2685,25 +2292,16 @@ func TestGetWithOptions(t *testing.T) { t.Errorf("%s: unexpected response: %#v", test.name, resp) continue } - - var itemOut runtime.Object - if test.rootScoped { - itemOut = &genericapitesting.SimpleRoot{} - } else { - itemOut = &genericapitesting.Simple{} - } - body, err := extractBody(resp, itemOut) + var itemOut genericapitesting.Simple + body, err := extractBody(resp, &itemOut) if err != nil { t.Errorf("%s: %v", test.name, err) continue } - if metadata, err := meta.Accessor(itemOut); err == nil { - if metadata.GetName() != simpleStorage.item.Name { - t.Errorf("%s: Unexpected data: %#v, expected %#v (%s)", test.name, itemOut, simpleStorage.item, string(body)) - continue - } - } else { - t.Errorf("%s: Couldn't get name from %#v: %v", test.name, itemOut, err) + + if itemOut.Name != simpleStorage.item.Name { + t.Errorf("%s: Unexpected data: %#v, expected %#v (%s)", test.name, itemOut, simpleStorage.item, string(body)) + continue } var opts *genericapitesting.SimpleGetOptions @@ -2808,7 +2406,7 @@ func TestGetNamespaceSelfLink(t *testing.T) { func TestGetMissing(t *testing.T) { storage := map[string]rest.Storage{} simpleStorage := SimpleRESTStorage{ - errors: map[string]error{"get": apierrors.NewNotFound(schema.GroupResource{Resource: "simples"}, "id")}, + errors: map[string]error{"get": apierrs.NewNotFound(schema.GroupResource{Resource: "simples"}, "id")}, } storage["simple"] = &simpleStorage handler := handle(storage) @@ -2828,7 +2426,7 @@ func TestGetMissing(t *testing.T) { func TestGetRetryAfter(t *testing.T) { storage := map[string]rest.Storage{} simpleStorage := SimpleRESTStorage{ - errors: map[string]error{"get": apierrors.NewServerTimeout(schema.GroupResource{Resource: "simples"}, "id", 2)}, + errors: map[string]error{"get": apierrs.NewServerTimeout(schema.GroupResource{Resource: "simples"}, "id", 2)}, } storage["simple"] = &simpleStorage handler := handle(storage) @@ -2931,7 +2529,7 @@ func TestConnectResponderError(t *testing.T) { connectStorage := &ConnecterRESTStorage{} connectStorage.handlerFunc = func() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - connectStorage.receivedResponder.Error(apierrors.NewForbidden(schema.GroupResource{Resource: "simples"}, itemID, errors.New("you are terminated"))) + connectStorage.receivedResponder.Error(apierrs.NewForbidden(schema.GroupResource{Resource: "simples"}, itemID, errors.New("you are terminated"))) }) } storage := map[string]rest.Storage{ @@ -3103,9 +2701,6 @@ func TestDelete(t *testing.T) { client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -3138,9 +2733,6 @@ func TestDeleteWithOptions(t *testing.T) { client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -3178,9 +2770,6 @@ func TestDeleteWithOptionsQuery(t *testing.T) { client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID+"?gracePeriodSeconds="+strconv.FormatInt(grace, 10), nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -3221,9 +2810,6 @@ func TestDeleteWithOptionsQueryAndBody(t *testing.T) { } client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID+"?gracePeriodSeconds="+strconv.FormatInt(grace+10, 10), bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } res, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) @@ -3260,9 +2846,6 @@ func TestDeleteInvokesAdmissionControl(t *testing.T) { client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3277,7 +2860,7 @@ func TestDeleteMissing(t *testing.T) { storage := map[string]rest.Storage{} ID := "id" simpleStorage := SimpleRESTStorage{ - errors: map[string]error{"delete": apierrors.NewNotFound(schema.GroupResource{Resource: "simples"}, ID)}, + errors: map[string]error{"delete": apierrs.NewNotFound(schema.GroupResource{Resource: "simples"}, ID)}, } storage["simple"] = &simpleStorage handler := handle(storage) @@ -3286,9 +2869,6 @@ func TestDeleteMissing(t *testing.T) { client := http.Client{} request, err := http.NewRequest("DELETE", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3329,9 +2909,6 @@ func TestUpdate(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3374,9 +2951,6 @@ func TestUpdateInvokesAdmissionControl(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3410,9 +2984,6 @@ func TestUpdateRequiresMatchingName(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3447,9 +3018,6 @@ func TestUpdateAllowsMissingNamespace(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3491,9 +3059,6 @@ func TestUpdateDisallowsMismatchedNamespaceOnError(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3533,9 +3098,6 @@ func TestUpdatePreventsMismatchedNamespace(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3549,7 +3111,7 @@ func TestUpdateMissing(t *testing.T) { storage := map[string]rest.Storage{} ID := "id" simpleStorage := SimpleRESTStorage{ - errors: map[string]error{"update": apierrors.NewNotFound(schema.GroupResource{Resource: "simples"}, ID)}, + errors: map[string]error{"update": apierrs.NewNotFound(schema.GroupResource{Resource: "simples"}, ID)}, } storage["simple"] = &simpleStorage handler := handle(storage) @@ -3570,9 +3132,6 @@ func TestUpdateMissing(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader(body)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) @@ -3587,7 +3146,7 @@ func TestCreateNotFound(t *testing.T) { "simple": &SimpleRESTStorage{ // storage.Create can fail with not found error in theory. // See http://pr.k8s.io/486#discussion_r15037092. - errors: map[string]error{"create": apierrors.NewNotFound(schema.GroupResource{Resource: "simples"}, "id")}, + errors: map[string]error{"create": apierrs.NewNotFound(schema.GroupResource{Resource: "simples"}, "id")}, }, }) server := httptest.NewServer(handler) @@ -3662,8 +3221,6 @@ func TestParentResourceIsRequired(t *testing.T) { Linker: selfLinker, RootScopedKinds: sets.NewString("SimpleRoot"), - EquivalentResourceRegistry: runtime.NewEquivalentResourceRegistry(), - Admit: admissionControl, GroupVersion: newGroupVersion, @@ -3694,8 +3251,6 @@ func TestParentResourceIsRequired(t *testing.T) { Typer: scheme, Linker: selfLinker, - EquivalentResourceRegistry: runtime.NewEquivalentResourceRegistry(), - Admit: admissionControl, GroupVersion: newGroupVersion, @@ -3729,7 +3284,7 @@ func TestParentResourceIsRequired(t *testing.T) { } } -func TestNamedCreaterWithName(t *testing.T) { +func TestCreateWithName(t *testing.T) { pathName := "helloworld" storage := &NamedCreaterRESTStorage{SimpleRESTStorage: &SimpleRESTStorage{}} handler := handle(map[string]rest.Storage{ @@ -3761,147 +3316,6 @@ func TestNamedCreaterWithName(t *testing.T) { } } -func TestNamedCreaterWithoutName(t *testing.T) { - storage := &NamedCreaterRESTStorage{ - SimpleRESTStorage: &SimpleRESTStorage{ - injectedFunction: func(obj runtime.Object) (runtime.Object, error) { - time.Sleep(5 * time.Millisecond) - return obj, nil - }, - }, - } - - selfLinker := &setTestSelfLinker{ - t: t, - name: "bar", - namespace: "default", - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/foo", - } - handler := handleLinker(map[string]rest.Storage{"foo": storage}, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - client := http.Client{} - - simple := &genericapitesting.Simple{ - Other: "bar", - } - data, err := runtime.Encode(testCodec, simple) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo", bytes.NewBuffer(data)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - wg := sync.WaitGroup{} - wg.Add(1) - var response *http.Response - go func() { - response, err = client.Do(request) - wg.Done() - }() - wg.Wait() - if err != nil { - t.Errorf("unexpected error: %v", err) - } - // empty name is not allowed for NamedCreater - if response.StatusCode != http.StatusBadRequest { - t.Errorf("Unexpected response %#v", response) - } -} - -type namePopulatorAdmissionControl struct { - t *testing.T - populateName string -} - -func (npac *namePopulatorAdmissionControl) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { - if a.GetName() != npac.populateName { - npac.t.Errorf("Unexpected name: got %q, expected %q", a.GetName(), npac.populateName) - } - return nil -} - -func (npac *namePopulatorAdmissionControl) Handles(operation admission.Operation) bool { - return true -} - -var _ admission.ValidationInterface = &namePopulatorAdmissionControl{} - -func TestNamedCreaterWithGenerateName(t *testing.T) { - populateName := "bar" - storage := &SimpleRESTStorage{ - injectedFunction: func(obj runtime.Object) (runtime.Object, error) { - time.Sleep(5 * time.Millisecond) - if metadata, err := meta.Accessor(obj); err == nil { - if len(metadata.GetName()) != 0 { - t.Errorf("Unexpected name %q", metadata.GetName()) - } - metadata.SetName(populateName) - } else { - return nil, err - } - return obj, nil - }, - } - - selfLinker := &setTestSelfLinker{ - t: t, - namespace: "default", - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/foo", - } - - ac := &namePopulatorAdmissionControl{ - t: t, - populateName: populateName, - } - - handler := handleInternal(map[string]rest.Storage{"foo": storage}, ac, selfLinker, nil) - server := httptest.NewServer(handler) - defer server.Close() - client := http.Client{} - - simple := &genericapitesting.Simple{ - Other: "bar", - } - data, err := runtime.Encode(testCodec, simple) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - request, err := http.NewRequest("POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo", bytes.NewBuffer(data)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - wg := sync.WaitGroup{} - wg.Add(1) - var response *http.Response - go func() { - response, err = client.Do(request) - wg.Done() - }() - wg.Wait() - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if response.StatusCode != http.StatusCreated { - t.Errorf("Unexpected status: %d, Expected: %d, %#v", response.StatusCode, http.StatusOK, response) - } - - var itemOut genericapitesting.Simple - body, err := extractBody(response, &itemOut) - if err != nil { - t.Errorf("unexpected error: %v %#v", err, response) - } - - itemOut.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{}) - simple.Name = populateName - if !reflect.DeepEqual(&itemOut, simple) { - t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simple, string(body)) - } -} - func TestUpdateChecksDecode(t *testing.T) { handler := handle(map[string]rest.Storage{"simple": &SimpleRESTStorage{}}) server := httptest.NewServer(handler) @@ -4084,7 +3498,6 @@ func TestCreateYAML(t *testing.T) { t.Errorf("Never set self link") } } - func TestCreateInNamespace(t *testing.T) { storage := SimpleRESTStorage{ injectedFunction: func(obj runtime.Object) (runtime.Object, error) { @@ -4195,7 +3608,7 @@ func TestCreateInvokeAdmissionControl(t *testing.T) { } } -func expectAPIStatus(t *testing.T, method, url string, data []byte, code int) *metav1.Status { +func expectApiStatus(t *testing.T, method, url string, data []byte, code int) *metav1.Status { t.Helper() client := http.Client{} request, err := http.NewRequest(method, url, bytes.NewBuffer(data)) @@ -4223,14 +3636,14 @@ func expectAPIStatus(t *testing.T, method, url string, data []byte, code int) *m func TestDelayReturnsError(t *testing.T) { storage := SimpleRESTStorage{ injectedFunction: func(obj runtime.Object) (runtime.Object, error) { - return nil, apierrors.NewAlreadyExists(schema.GroupResource{Resource: "foos"}, "bar") + return nil, apierrs.NewAlreadyExists(schema.GroupResource{Resource: "foos"}, "bar") }, } handler := handle(map[string]rest.Storage{"foo": &storage}) server := httptest.NewServer(handler) defer server.Close() - status := expectAPIStatus(t, "DELETE", fmt.Sprintf("%s/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo/bar", server.URL), nil, http.StatusConflict) + status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo/bar", server.URL), nil, http.StatusConflict) if status.Status != metav1.StatusFailure || status.Message == "" || status.Details == nil || status.Reason != metav1.StatusReasonAlreadyExists { t.Errorf("Unexpected status %#v", status) } @@ -4253,7 +3666,7 @@ func (obj *UnregisteredAPIObject) DeepCopyObject() runtime.Object { func TestWriteJSONDecodeError(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - responsewriters.WriteObjectNegotiated(codecs, negotiation.DefaultEndpointRestrictions, newGroupVersion, w, req, http.StatusOK, &UnregisteredAPIObject{"Undecodable"}) + responsewriters.WriteObjectNegotiated(codecs, newGroupVersion, w, req, http.StatusOK, &UnregisteredAPIObject{"Undecodable"}) })) defer server.Close() // Decode error response behavior is dictated by @@ -4261,7 +3674,7 @@ func TestWriteJSONDecodeError(t *testing.T) { // Unless specific metav1.Status() parameters are implemented for the particular error in question, such that // the status code is defined, metav1 errors where error.status == metav1.StatusFailure // will throw a '500 Internal Server Error'. Non-metav1 type errors will always throw a '500 Internal Server Error'. - status := expectAPIStatus(t, "GET", server.URL, nil, http.StatusInternalServerError) + status := expectApiStatus(t, "GET", server.URL, nil, http.StatusInternalServerError) if status.Reason != metav1.StatusReasonUnknown { t.Errorf("unexpected reason %#v", status) } @@ -4315,7 +3728,7 @@ func TestCreateTimeout(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - itemOut := expectAPIStatus(t, "POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo?timeout=4ms", data, http.StatusGatewayTimeout) + itemOut := expectApiStatus(t, "POST", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/foo?timeout=4ms", data, http.StatusGatewayTimeout) if itemOut.Status != metav1.StatusFailure || itemOut.Reason != metav1.StatusReasonTimeout { t.Errorf("Unexpected status %#v", itemOut) } @@ -4449,13 +3862,13 @@ type SimpleRESTStorageWithDeleteCollection struct { } // Delete collection doesn't do much, but let us test this path. -func (storage *SimpleRESTStorageWithDeleteCollection) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { +func (storage *SimpleRESTStorageWithDeleteCollection) DeleteCollection(ctx context.Context, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { storage.checkContext(ctx) return nil, nil } func TestDryRunDisabled(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DryRun, false)() + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DryRun, false)() tests := []struct { path string @@ -4493,12 +3906,12 @@ func TestDryRunDisabled(t *testing.T) { })) defer server.Close() for _, test := range tests { - baseURL := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version - response := runRequest(t, baseURL+test.path, test.verb, test.data, test.contentType) + baseUrl := server.URL + "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + response := runRequest(t, baseUrl+test.path, test.verb, test.data, test.contentType) if response.StatusCode == http.StatusBadRequest { t.Fatalf("unexpected BadRequest: %#v", response) } - response = runRequest(t, baseURL+test.path+"?dryRun", test.verb, test.data, test.contentType) + response = runRequest(t, baseUrl+test.path+"?dryRun", test.verb, test.data, test.contentType) if response.StatusCode != http.StatusBadRequest { t.Fatalf("unexpected non BadRequest: %#v", response) } @@ -4520,7 +3933,7 @@ func (storage *SimpleXGSubresourceRESTStorage) Get(ctx context.Context, id strin return storage.item.DeepCopyObject(), nil } -func (storage *SimpleXGSubresourceRESTStorage) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { +func (storage *SimpleXGSubresourceRESTStorage) Delete(ctx context.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { return nil, true, nil } @@ -4555,8 +3968,6 @@ func TestXGSubresource(t *testing.T) { Typer: scheme, Linker: selfLinker, - EquivalentResourceRegistry: runtime.NewEquivalentResourceRegistry(), - ParameterCodec: parameterCodec, Admit: admissionControl, diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/group.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/group.go index 7e9927a3a55..02330e9f3e7 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/group.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/group.go @@ -69,5 +69,5 @@ func (s *APIGroupHandler) handle(req *restful.Request, resp *restful.Response) { } func (s *APIGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, w, req, http.StatusOK, &s.group) + responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, w, req, http.StatusOK, &s.group) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/legacy.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/legacy.go index b33ecec6532..837cd0130e5 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/legacy.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/legacy.go @@ -72,5 +72,5 @@ func (s *legacyRootAPIHandler) handle(req *restful.Request, resp *restful.Respon Versions: []string{"v1"}, } - responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, resp.ResponseWriter, req.Request, http.StatusOK, apiVersions) + responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, resp.ResponseWriter, req.Request, http.StatusOK, apiVersions) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/root.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/root.go index beba9c8a41d..7ed64a9f579 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/root.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/root.go @@ -111,7 +111,7 @@ func (s *rootAPIsHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) groups[i].ServerAddressByClientCIDRs = serverCIDR } - responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, resp, req, http.StatusOK, &metav1.APIGroupList{Groups: groups}) + responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, resp, req, http.StatusOK, &metav1.APIGroupList{Groups: groups}) } func (s *rootAPIsHandler) restfulHandle(req *restful.Request, resp *restful.Response) { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/storageversionhash.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/storageversionhash.go deleted file mode 100644 index a1b00decbae..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/storageversionhash.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2019 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 discovery - -import ( - "crypto/sha256" - "encoding/base64" -) - -// StorageVersionHash calculates the storage version hash for a -// tuple. -// WARNING: this function is subject to change. Clients shouldn't depend on -// this function. -func StorageVersionHash(group, version, kind string) string { - gvk := group + "/" + version + "/" + kind - if gvk == "" { - return "" - } - bytes := sha256.Sum256([]byte(gvk)) - // Assuming there are N kinds in the cluster, and the hash is X-byte long, - // the chance of colliding hash P(N,X) approximates to 1-e^(-(N^2)/2^(8X+1)). - // P(10,000, 8) ~= 2.7*10^(-12), which is low enough. - // See https://en.wikipedia.org/wiki/Birthday_problem#Approximations. - return base64.StdEncoding.EncodeToString( - bytes[:8]) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/util.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/util.go index 2411a780d1c..81a13d64a00 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/util.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/util.go @@ -18,12 +18,10 @@ package discovery import ( "bytes" - "encoding/json" "fmt" "io" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/klog" ) const APIGroupPrefix = "/apis" @@ -38,39 +36,9 @@ func keepUnversioned(group string) bool { type stripVersionEncoder struct { encoder runtime.Encoder serializer runtime.Serializer - identifier runtime.Identifier -} - -func newStripVersionEncoder(e runtime.Encoder, s runtime.Serializer) runtime.Encoder { - return stripVersionEncoder{ - encoder: e, - serializer: s, - identifier: identifier(e), - } -} - -func identifier(e runtime.Encoder) runtime.Identifier { - result := map[string]string{ - "name": "stripVersion", - } - if e != nil { - result["encoder"] = string(e.Identifier()) - } - identifier, err := json.Marshal(result) - if err != nil { - klog.Fatalf("Failed marshaling identifier for stripVersionEncoder: %v", err) - } - return runtime.Identifier(identifier) } func (c stripVersionEncoder) Encode(obj runtime.Object, w io.Writer) error { - if co, ok := obj.(runtime.CacheableObject); ok { - return co.CacheEncode(c.Identifier(), c.doEncode, w) - } - return c.doEncode(obj, w) -} - -func (c stripVersionEncoder) doEncode(obj runtime.Object, w io.Writer) error { buf := bytes.NewBuffer([]byte{}) err := c.encoder.Encode(obj, buf) if err != nil { @@ -86,11 +54,6 @@ func (c stripVersionEncoder) doEncode(obj runtime.Object, w io.Writer) error { return c.serializer.Encode(roundTrippedObj, w) } -// Identifier implements runtime.Encoder interface. -func (c stripVersionEncoder) Identifier() runtime.Identifier { - return c.identifier -} - // stripVersionNegotiatedSerializer will return stripVersionEncoder when // EncoderForVersion is called. See comments for stripVersionEncoder. type stripVersionNegotiatedSerializer struct { @@ -106,5 +69,5 @@ func (n stripVersionNegotiatedSerializer) EncoderForVersion(encoder runtime.Enco panic(fmt.Sprintf("Unable to extract serializer from %#v", encoder)) } versioned := n.NegotiatedSerializer.EncoderForVersion(encoder, gv) - return newStripVersionEncoder(versioned, serializer) + return stripVersionEncoder{versioned, serializer} } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/version.go b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/version.go index 0976041bff0..aadfc7a5b49 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/discovery/version.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/discovery/version.go @@ -78,6 +78,6 @@ func (s *APIVersionHandler) handle(req *restful.Request, resp *restful.Response) } func (s *APIVersionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, w, req, http.StatusOK, + responsewriters.WriteObjectNegotiated(s.serializer, schema.GroupVersion{}, w, req, http.StatusOK, &metav1.APIResourceList{GroupVersion: s.groupVersion.String(), APIResources: s.apiResourceLister.ListAPIResources()}) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/filters/OWNERS old mode 100644 new mode 100755 index 05259ce3538..6f780ff899b --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - deads2k - sttts diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_annotations.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_annotations.go deleted file mode 100644 index 22b276991c6..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_annotations.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2020 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 filters - -import ( - "net/http" - - "k8s.io/apiserver/pkg/audit" - "k8s.io/apiserver/pkg/audit/policy" -) - -// WithAuditAnnotations decorates a http.Handler with a []{key, value} that is merged -// with the audit.Event.Annotations map. This allows layers that run before WithAudit -// (such as authentication) to assert annotations. -// If sink or audit policy is nil, no decoration takes place. -func WithAuditAnnotations(handler http.Handler, sink audit.Sink, policy policy.Checker) http.Handler { - // no need to wrap if auditing is disabled - if sink == nil || policy == nil { - return handler - } - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - req = req.WithContext(audit.WithAuditAnnotations(req.Context())) - handler.ServeHTTP(w, req) - }) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go index e885644f8bd..3d3edd68f8f 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit_test.go @@ -26,7 +26,7 @@ import ( "testing" "time" - "github.com/google/uuid" + "github.com/pborman/uuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -223,7 +223,7 @@ func TestAudit(t *testing.T) { "short running with auditID", shortRunningPath, "GET", - uuid.New().String(), + uuid.NewRandom().String(), nil, func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("foo")) @@ -422,7 +422,7 @@ func TestAudit(t *testing.T) { "empty longrunning with audit id", longRunningPath, "GET", - uuid.New().String(), + uuid.NewRandom().String(), nil, func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("foo")) @@ -778,7 +778,7 @@ func TestAuditIDHttpHeader(t *testing.T) { }, { "no http header when there is no audit even the request header specified", - uuid.New().String(), + uuid.NewRandom().String(), auditinternal.LevelNone, false, }, @@ -790,7 +790,7 @@ func TestAuditIDHttpHeader(t *testing.T) { }, { "user provided header", - uuid.New().String(), + uuid.NewRandom().String(), auditinternal.LevelRequestResponse, true, }, diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go index 2806edc79b0..d9f70efac26 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication.go @@ -18,9 +18,11 @@ package filters import ( "errors" - "fmt" "net/http" - "time" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "k8s.io/klog" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -28,9 +30,22 @@ import ( "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/klog" ) +var ( + authenticatedUserCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "authenticated_user_requests", + Help: "Counter of authenticated requests broken out by username.", + }, + []string{"username"}, + ) +) + +func init() { + prometheus.MustRegister(authenticatedUserCounter) +} + // WithAuthentication creates an http handler that tries to authenticate the given request as a user, and then // stores any such user found onto the provided context for the request. If authentication fails or returns an error // the failed handler is used. On success, "Authorization" header is removed from the request and handler @@ -41,13 +56,10 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request, failed return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - authenticationStart := time.Now() - if len(apiAuds) > 0 { req = req.WithContext(authenticator.WithAudiences(req.Context(), apiAuds)) } resp, ok, err := auth.AuthenticateRequest(req) - defer recordAuthMetrics(resp, ok, err, apiAuds, authenticationStart) if err != nil || !ok { if err != nil { klog.Errorf("Unable to authenticate the request due to an error: %v", err) @@ -56,23 +68,25 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request, failed return } - if !audiencesAreAcceptable(apiAuds, resp.Audiences) { - err = fmt.Errorf("unable to match the audience: %v , accepted: %v", resp.Audiences, apiAuds) - klog.Error(err) - failed.ServeHTTP(w, req) - return - } + // TODO(mikedanese): verify the response audience matches one of apiAuds if + // non-empty // authorization header is not required anymore in case of a successful authentication. req.Header.Del("Authorization") req = req.WithContext(genericapirequest.WithUser(req.Context(), resp.User)) + + authenticatedUserCounter.WithLabelValues(compressUsername(resp.User.GetName())).Inc() + handler.ServeHTTP(w, req) }) } -func Unauthorized(s runtime.NegotiatedSerializer) http.Handler { +func Unauthorized(s runtime.NegotiatedSerializer, supportsBasicAuth bool) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if supportsBasicAuth { + w.Header().Set("WWW-Authenticate", `Basic realm="kubernetes-master"`) + } ctx := req.Context() requestInfo, found := genericapirequest.RequestInfoFrom(ctx) if !found { @@ -85,10 +99,24 @@ func Unauthorized(s runtime.NegotiatedSerializer) http.Handler { }) } -func audiencesAreAcceptable(apiAuds, responseAudiences authenticator.Audiences) bool { - if len(apiAuds) == 0 || len(responseAudiences) == 0 { - return true +// compressUsername maps all possible usernames onto a small set of categories +// of usernames. This is done both to limit the cardinality of the +// authorized_user_requests metric, and to avoid pushing actual usernames in the +// metric. +func compressUsername(username string) string { + switch { + // Known internal identities. + case username == "admin" || + username == "client" || + username == "kube_proxy" || + username == "kubelet" || + username == "system:serviceaccount:kube-system:default": + return username + // Probably an email address. + case strings.Contains(username, "@"): + return "email_id" + // Anything else (custom service accounts, custom external identities, etc.) + default: + return "other" } - - return len(apiAuds.Intersect(responseAudiences)) > 0 } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go index 2873c67cb3d..887baebc93e 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authentication_test.go @@ -18,91 +18,14 @@ package filters import ( "errors" - "github.com/stretchr/testify/assert" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "net/http" "net/http/httptest" "testing" -) -func TestAuthenticateRequestWithAud(t *testing.T) { - success, failed := 0, 0 - testcases := []struct { - name string - apiAuds []string - respAuds []string - expectSuccess bool - }{ - { - name: "no api audience and no audience in response", - apiAuds: nil, - respAuds: nil, - expectSuccess: true, - }, - { - name: "audience in response", - apiAuds: nil, - respAuds: []string{"other"}, - expectSuccess: true, - }, - { - name: "with api audience", - apiAuds: authenticator.Audiences([]string{"other"}), - respAuds: nil, - expectSuccess: true, - }, - { - name: "api audience matching response audience", - apiAuds: authenticator.Audiences([]string{"other"}), - respAuds: []string{"other"}, - expectSuccess: true, - }, - { - name: "api audience non-matching response audience", - apiAuds: authenticator.Audiences([]string{"other"}), - respAuds: []string{"some"}, - expectSuccess: false, - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - success, failed = 0, 0 - auth := WithAuthentication( - http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) { - if tc.expectSuccess { - success = 1 - } else { - t.Errorf("unexpected call to handler") - } - }), - authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { - if req.Header.Get("Authorization") == "Something" { - return &authenticator.Response{User: &user.DefaultInfo{Name: "user"}, Audiences: authenticator.Audiences(tc.respAuds)}, true, nil - } - return nil, false, errors.New("Authorization header is missing.") - }), - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { - if tc.expectSuccess { - t.Errorf("unexpected call to failed") - } else { - failed = 1 - } - }), - tc.apiAuds, - ) - auth.ServeHTTP(httptest.NewRecorder(), &http.Request{Header: map[string][]string{"Authorization": {"Something"}}}) - if tc.expectSuccess { - assert.Equal(t, 1, success) - assert.Equal(t, 0, failed) - } else { - assert.Equal(t, 0, success) - assert.Equal(t, 1, failed) - } - }) - } -} + "k8s.io/apiserver/pkg/authentication/authenticator" + "k8s.io/apiserver/pkg/authentication/user" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" +) func TestAuthenticateRequest(t *testing.T) { success := make(chan struct{}) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go index 73bbe6b3fb7..c6ab15b3d67 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization.go @@ -56,7 +56,7 @@ func WithAuthorization(handler http.Handler, a authorizer.Authorizer, s runtime. responsewriters.InternalError(w, req, err) return } - authorized, reason, err := a.Authorize(ctx, attributes) + authorized, reason, err := a.Authorize(attributes) // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here. if authorized == authorizer.DecisionAllow { audit.LogAnnotation(ae, decisionAnnotationKey, decisionAllow) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization_test.go index e00b9d642a3..5b72cf944f1 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authorization_test.go @@ -17,7 +17,6 @@ limitations under the License. package filters import ( - "context" "errors" "net/http" "net/http/httptest" @@ -130,7 +129,7 @@ type fakeAuthorizer struct { err error } -func (f fakeAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { +func (f fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) { return f.decision, f.reason, f.err } @@ -170,7 +169,7 @@ func TestAuditAnnotation(t *testing.T) { } scheme := runtime.NewScheme() - negotiatedSerializer := serializer.NewCodecFactory(scheme).WithoutConversion() + negotiatedSerializer := serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)} for k, tc := range testcases { audit := &auditinternal.Event{Level: auditinternal.LevelMetadata} handler := WithAuthorization(&fakeHTTPHandler{}, tc.authorizer, negotiatedSerializer) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol.go deleted file mode 100644 index e19f9d055fd..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2019 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 filters - -import ( - "net/http" -) - -// WithCacheControl sets the Cache-Control header to "no-cache, private" because all servers are protected by authn/authz. -// see https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#defining_optimal_cache-control_policy -func WithCacheControl(handler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - // Set the cache-control header if it is not already set - if _, ok := w.Header()["Cache-Control"]; !ok { - w.Header().Set("Cache-Control", "no-cache, private") - } - handler.ServeHTTP(w, req) - }) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol_test.go deleted file mode 100644 index 1bfdf0a1aa8..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/cachecontrol_test.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright 2019 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 filters - -import ( - "net/http" - "net/http/httptest" - "testing" -) - -func TestCacheControl(t *testing.T) { - tests := []struct { - name string - path string - - startingHeader string - expectedHeader string - }{ - { - name: "simple", - path: "/api/v1/namespaces", - expectedHeader: "no-cache, private", - }, - { - name: "openapi", - path: "/openapi/v2", - expectedHeader: "no-cache, private", - }, - { - name: "already-set", - path: "/api/v1/namespaces", - startingHeader: "nonsense", - expectedHeader: "nonsense", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - handler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { - //do nothing - }) - wrapped := WithCacheControl(handler) - - testRequest, err := http.NewRequest(http.MethodGet, test.path, nil) - if err != nil { - t.Fatal(err) - } - w := httptest.NewRecorder() - if len(test.startingHeader) > 0 { - w.Header().Set("Cache-Control", test.startingHeader) - } - - wrapped.ServeHTTP(w, testRequest) - actual := w.Header().Get("Cache-Control") - - if actual != test.expectedHeader { - t.Fatal(actual) - } - }) - } - -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go index a18b51ba00d..d017f2bf687 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go @@ -68,18 +68,16 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime. groups := []string{} userExtra := map[string][]string{} for _, impersonationRequest := range impersonationRequests { - gvk := impersonationRequest.GetObjectKind().GroupVersionKind() actingAsAttributes := &authorizer.AttributesRecord{ User: requestor, Verb: "impersonate", - APIGroup: gvk.Group, - APIVersion: gvk.Version, + APIGroup: impersonationRequest.GetObjectKind().GroupVersionKind().Group, Namespace: impersonationRequest.Namespace, Name: impersonationRequest.Name, ResourceRequest: true, } - switch gvk.GroupKind() { + switch impersonationRequest.GetObjectKind().GroupVersionKind().GroupKind() { case v1.SchemeGroupVersion.WithKind("ServiceAccount").GroupKind(): actingAsAttributes.Resource = "serviceaccounts" username = serviceaccount.MakeUsername(impersonationRequest.Namespace, impersonationRequest.Name) @@ -109,7 +107,7 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime. return } - decision, reason, err := a.Authorize(ctx, actingAsAttributes) + decision, reason, err := a.Authorize(actingAsAttributes) if err != nil || decision != authorizer.DecisionAllow { klog.V(4).Infof("Forbidden: %#v, Reason: %s, Error: %v", req.RequestURI, reason, err) responsewriters.Forbidden(ctx, actingAsAttributes, w, req, reason, s) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation_test.go index 1408d2b1c49..d309a21098d 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation_test.go @@ -36,7 +36,7 @@ import ( type impersonateAuthorizer struct{} -func (impersonateAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { +func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { user := a.GetUser() switch { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics.go deleted file mode 100644 index 421c0e0a2ba..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2020 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 filters - -import ( - "strings" - "time" - - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" -) - -/* - * By default, all the following metrics are defined as falling under - * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes) - * - * Promoting the stability level of the metric is a responsibility of the component owner, since it - * involves explicitly acknowledging support for the metric across multiple releases, in accordance with - * the metric stability policy. - */ -const ( - successLabel = "success" - failureLabel = "failure" - errorLabel = "error" -) - -var ( - authenticatedUserCounter = metrics.NewCounterVec( - &metrics.CounterOpts{ - Name: "authenticated_user_requests", - Help: "Counter of authenticated requests broken out by username.", - StabilityLevel: metrics.ALPHA, - }, - []string{"username"}, - ) - - authenticatedAttemptsCounter = metrics.NewCounterVec( - &metrics.CounterOpts{ - Name: "authentication_attempts", - Help: "Counter of authenticated attempts.", - StabilityLevel: metrics.ALPHA, - }, - []string{"result"}, - ) - - authenticationLatency = metrics.NewHistogramVec( - &metrics.HistogramOpts{ - Name: "authentication_duration_seconds", - Help: "Authentication duration in seconds broken out by result.", - Buckets: metrics.ExponentialBuckets(0.001, 2, 15), - StabilityLevel: metrics.ALPHA, - }, - []string{"result"}, - ) -) - -func init() { - legacyregistry.MustRegister(authenticatedUserCounter) - legacyregistry.MustRegister(authenticatedAttemptsCounter) - legacyregistry.MustRegister(authenticationLatency) -} - -func recordAuthMetrics(resp *authenticator.Response, ok bool, err error, apiAudiences authenticator.Audiences, authStart time.Time) { - var resultLabel string - - switch { - case err != nil || (resp != nil && !audiencesAreAcceptable(apiAudiences, resp.Audiences)): - resultLabel = errorLabel - case !ok: - resultLabel = failureLabel - default: - resultLabel = successLabel - authenticatedUserCounter.WithLabelValues(compressUsername(resp.User.GetName())).Inc() - } - - authenticatedAttemptsCounter.WithLabelValues(resultLabel).Inc() - authenticationLatency.WithLabelValues(resultLabel).Observe(time.Since(authStart).Seconds()) -} - -// compressUsername maps all possible usernames onto a small set of categories -// of usernames. This is done both to limit the cardinality of the -// authorized_user_requests metric, and to avoid pushing actual usernames in the -// metric. -func compressUsername(username string) string { - switch { - // Known internal identities. - case username == "admin" || - username == "client" || - username == "kube_proxy" || - username == "kubelet" || - username == "system:serviceaccount:kube-system:default": - return username - // Probably an email address. - case strings.Contains(username, "@"): - return "email_id" - // Anything else (custom service accounts, custom external identities, etc.) - default: - return "other" - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics_test.go deleted file mode 100644 index d3a647c18d4..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/metrics_test.go +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright 2020 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 filters - -import ( - "errors" - "net/http" - "net/http/httptest" - "strings" - "testing" - - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/component-base/metrics/legacyregistry" - "k8s.io/component-base/metrics/testutil" -) - -func TestMetrics(t *testing.T) { - // Excluding authentication_duration_seconds since it is difficult to predict its values. - metrics := []string{ - "authenticated_user_requests", - "authentication_attempts", - } - - testCases := []struct { - desc string - response *authenticator.Response - status bool - err error - apiAudience authenticator.Audiences - want string - }{ - { - desc: "auth ok", - response: &authenticator.Response{ - User: &user.DefaultInfo{Name: "admin"}, - }, - status: true, - want: ` - # HELP authenticated_user_requests [ALPHA] Counter of authenticated requests broken out by username. - # TYPE authenticated_user_requests counter - authenticated_user_requests{username="admin"} 1 - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="success"} 1 - `, - }, - { - desc: "auth failed with error", - err: errors.New("some error"), - want: ` - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="error"} 1 - `, - }, - { - desc: "auth failed with status false", - want: ` - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="failure"} 1 - `, - }, - { - desc: "auth failed due to audiences not intersecting", - response: &authenticator.Response{ - User: &user.DefaultInfo{Name: "admin"}, - Audiences: authenticator.Audiences{"audience-x"}, - }, - status: true, - apiAudience: authenticator.Audiences{"audience-y"}, - want: ` - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="error"} 1 - `, - }, - { - desc: "audiences not supplied in the response", - response: &authenticator.Response{ - User: &user.DefaultInfo{Name: "admin"}, - }, - status: true, - apiAudience: authenticator.Audiences{"audience-y"}, - want: ` - # HELP authenticated_user_requests [ALPHA] Counter of authenticated requests broken out by username. - # TYPE authenticated_user_requests counter - authenticated_user_requests{username="admin"} 1 - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="success"} 1 - `, - }, - { - desc: "audiences not supplied to the handler", - response: &authenticator.Response{ - User: &user.DefaultInfo{Name: "admin"}, - Audiences: authenticator.Audiences{"audience-x"}, - }, - status: true, - want: ` - # HELP authenticated_user_requests [ALPHA] Counter of authenticated requests broken out by username. - # TYPE authenticated_user_requests counter - authenticated_user_requests{username="admin"} 1 - # HELP authentication_attempts [ALPHA] Counter of authenticated attempts. - # TYPE authentication_attempts counter - authentication_attempts{result="success"} 1 - `, - }, - } - - // Since prometheus' gatherer is global, other tests may have updated metrics already, so - // we need to reset them prior running this test. - // This also implies that we can't run this test in parallel with other auth tests. - authenticatedUserCounter.Reset() - authenticatedAttemptsCounter.Reset() - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - defer authenticatedUserCounter.Reset() - defer authenticatedAttemptsCounter.Reset() - done := make(chan struct{}) - auth := WithAuthentication( - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { - close(done) - }), - authenticator.RequestFunc(func(_ *http.Request) (*authenticator.Response, bool, error) { - return tt.response, tt.status, tt.err - }), - http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { - close(done) - }), - tt.apiAudience, - ) - - auth.ServeHTTP(httptest.NewRecorder(), &http.Request{}) - <-done - - if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tt.want), metrics...); err != nil { - t.Fatal(err) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go b/vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go index 920369977a9..79cfefe4669 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/groupversion.go @@ -20,7 +20,7 @@ import ( "path" "time" - restful "github.com/emicklei/go-restful" + "github.com/emicklei/go-restful" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -72,8 +72,6 @@ type APIGroupVersion struct { Linker runtime.SelfLinker UnsafeConvertor runtime.ObjectConvertor - EquivalentResourceRegistry runtime.EquivalentResourceRegistry - // Authorizer determines whether a user is allowed to make a certain request. The Handler does a preliminary // authorization check using the request URI but it may be necessary to make additional checks, such as in // the create-on-update case @@ -83,6 +81,10 @@ type APIGroupVersion struct { MinRequestTimeout time.Duration + // EnableAPIResponseCompression indicates whether API Responses should support compression + // if the client requests it via Accept-Encoding + EnableAPIResponseCompression bool + // OpenAPIModels exposes the OpenAPI models to each individual handler. OpenAPIModels openapiproto.Models @@ -97,9 +99,10 @@ type APIGroupVersion struct { func (g *APIGroupVersion) InstallREST(container *restful.Container) error { prefix := path.Join(g.Root, g.GroupVersion.Group, g.GroupVersion.Version) installer := &APIInstaller{ - group: g, - prefix: prefix, - minRequestTimeout: g.MinRequestTimeout, + group: g, + prefix: prefix, + minRequestTimeout: g.MinRequestTimeout, + enableAPIResponseCompression: g.EnableAPIResponseCompression, } apiResources, ws, registrationErrors := installer.Install() diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go index f97cbaa2c85..6293a72867a 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go @@ -17,18 +17,14 @@ limitations under the License. package handlers import ( - "bytes" "context" "fmt" "net/http" - "strings" "time" - "unicode" - "unicode/utf8" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" @@ -41,55 +37,46 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/util/dryrun" utilfeature "k8s.io/apiserver/pkg/util/feature" - utiltrace "k8s.io/utils/trace" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) -func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Interface, includeName bool) http.HandlerFunc { +func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Interface, includeName bool) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { // For performance tracking purposes. - trace := utiltrace.New("Create", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("Create " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) if isDryRun(req.URL) && !utilfeature.DefaultFeatureGate.Enabled(features.DryRun) { - scope.err(errors.NewBadRequest("the dryRun feature is disabled"), w, req) + scope.err(errors.NewBadRequest("the dryRun alpha feature is disabled"), w, req) return } // TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer) timeout := parseTimeout(req.URL.Query().Get("timeout")) - namespace, name, err := scope.Namer.Name(req) - if err != nil { - if includeName { - // name was required, return - scope.err(err, w, req) - return - } - - // otherwise attempt to look up the namespace + var ( + namespace, name string + err error + ) + if includeName { + namespace, name, err = scope.Namer.Name(req) + } else { namespace, err = scope.Namer.Namespace(req) - if err != nil { - scope.err(err, w, req) - return - } } - - ctx, cancel := context.WithTimeout(req.Context(), timeout) - defer cancel() - ctx = request.WithNamespace(ctx, namespace) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) if err != nil { scope.err(err, w, req) return } + ctx := req.Context() + ctx = request.WithNamespace(ctx, namespace) + gv := scope.Kind.GroupVersion() s, err := negotiation.NegotiateInputSerializer(req, false, scope.Serializer) if err != nil { scope.err(err, w, req) return } - decoder := scope.Serializer.DecoderToVersion(s.Serializer, scope.HubGroupVersion) body, err := limitedReadBody(req, scope.MaxRequestBodyBytes) @@ -100,7 +87,7 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int options := &metav1.CreateOptions{} values := req.URL.Query() - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, options); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, options); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -110,7 +97,6 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int scope.err(err, w, req) return } - options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("CreateOptions")) defaultGVK := scope.Kind original := r.New() @@ -133,49 +119,24 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer) userInfo, _ := request.UserFrom(ctx) - - // On create, get name from new object if unset - if len(name) == 0 { - _, name, _ = scope.Namer.ObjectName(obj) + admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo) + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) { + err = mutatingAdmission.Admit(admissionAttributes) + if err != nil { + scope.err(err, w, req) + return + } } trace.Step("About to store object in database") - admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, options, dryrun.IsDryRun(options.DryRun), userInfo) - requestFunc := func() (runtime.Object, error) { + result, err := finishRequest(timeout, func() (runtime.Object, error) { return r.Create( ctx, name, obj, - rest.AdmissionToValidateObjectFunc(admit, admissionAttributes, scope), + rest.AdmissionToValidateObjectFunc(admit, admissionAttributes), options, ) - } - result, err := finishRequest(timeout, func() (runtime.Object, error) { - if scope.FieldManager != nil { - liveObj, err := scope.Creater.New(scope.Kind) - if err != nil { - return nil, fmt.Errorf("failed to create new object (Create for %v): %v", scope.Kind, err) - } - obj, err = scope.FieldManager.Update(liveObj, obj, managerOrUserAgent(options.FieldManager, req.UserAgent())) - if err != nil { - return nil, fmt.Errorf("failed to update object (Create for %v) managed fields: %v", scope.Kind, err) - } - } - if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) { - if err := mutatingAdmission.Admit(ctx, admissionAttributes, scope); err != nil { - return nil, err - } - } - result, err := requestFunc() - // If the object wasn't committed to storage because it's serialized size was too large, - // it is safe to remove managedFields (which can be large) and try again. - if isTooLargeError(err) { - if accessor, accessorErr := meta.Accessor(obj); accessorErr == nil { - accessor.SetManagedFields(nil) - result, err = requestFunc() - } - } - return result, err }) if err != nil { scope.err(err, w, req) @@ -183,23 +144,41 @@ func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Int } trace.Step("Object stored in database") + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } + if err := setSelfLink(result, requestInfo, scope.Namer); err != nil { + scope.err(err, w, req) + return + } + trace.Step("Self-link added") + + // If the object is partially initialized, always indicate it via StatusAccepted code := http.StatusCreated + if accessor, err := meta.Accessor(result); err == nil { + if accessor.GetInitializers() != nil { + code = http.StatusAccepted + } + } status, ok := result.(*metav1.Status) if ok && err == nil && status.Code == 0 { status.Code = int32(code) } - transformResponseObject(ctx, scope, trace, req, w, code, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, code, result) } } // CreateNamedResource returns a function that will handle a resource creation with name. -func CreateNamedResource(r rest.NamedCreater, scope *RequestScope, admission admission.Interface) http.HandlerFunc { +func CreateNamedResource(r rest.NamedCreater, scope RequestScope, admission admission.Interface) http.HandlerFunc { return createHandler(r, scope, admission, true) } // CreateResource returns a function that will handle a resource creation. -func CreateResource(r rest.Creater, scope *RequestScope, admission admission.Interface) http.HandlerFunc { +func CreateResource(r rest.Creater, scope RequestScope, admission admission.Interface) http.HandlerFunc { return createHandler(&namedCreaterAdapter{r}, scope, admission, false) } @@ -210,32 +189,3 @@ type namedCreaterAdapter struct { func (c *namedCreaterAdapter) Create(ctx context.Context, name string, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { return c.Creater.Create(ctx, obj, createValidatingAdmission, options) } - -// manager is assumed to be already a valid value, we need to make -// userAgent into a valid value too. -func managerOrUserAgent(manager, userAgent string) string { - if manager != "" { - return manager - } - return prefixFromUserAgent(userAgent) -} - -// prefixFromUserAgent takes the characters preceding the first /, quote -// unprintable character and then trim what's beyond the -// FieldManagerMaxLength limit. -func prefixFromUserAgent(u string) string { - m := strings.Split(u, "/")[0] - buf := bytes.NewBuffer(nil) - for _, r := range m { - // Ignore non-printable characters - if !unicode.IsPrint(r) { - continue - } - // Only append if we have room for it - if buf.Len()+utf8.RuneLen(r) > validation.FieldManagerMaxLength { - break - } - buf.WriteRune(r) - } - return buf.String() -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create_test.go deleted file mode 100644 index 76094727671..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/create_test.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2019 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 handlers - -import ( - "fmt" - "testing" -) - -func TestManagerOrUserAgent(t *testing.T) { - tests := []struct { - manager string - userAgent string - expected string - }{ - { - manager: "", - userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", - expected: "Mozilla", - }, - { - manager: "", - userAgent: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff/Something", - expected: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - }, - { - manager: "", - userAgent: "🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔", - expected: "🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔🍔", - }, - { - manager: "manager", - userAgent: "userAgent", - expected: "manager", - }, - } - - for _, test := range tests { - t.Run(fmt.Sprintf("%v-%v", test.manager, test.userAgent), func(t *testing.T) { - got := managerOrUserAgent(test.manager, test.userAgent) - if got != test.expected { - t.Errorf("Wanted %#v, got %#v", test.expected, got) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/delete.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/delete.go index 1fa5550ba70..2961eb75c85 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/delete.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/delete.go @@ -17,14 +17,12 @@ limitations under the License. package handlers import ( - "context" "fmt" "net/http" "time" "k8s.io/apimachinery/pkg/api/errors" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" @@ -37,19 +35,19 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/util/dryrun" utilfeature "k8s.io/apiserver/pkg/util/feature" - utiltrace "k8s.io/utils/trace" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) // DeleteResource returns a function that will handle a resource deletion // TODO admission here becomes solely validating admission -func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestScope, admit admission.Interface) http.HandlerFunc { +func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { // For performance tracking purposes. - trace := utiltrace.New("Delete", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("Delete " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) if isDryRun(req.URL) && !utilfeature.DefaultFeatureGate.Enabled(features.DryRun) { - scope.err(errors.NewBadRequest("the dryRun feature is disabled"), w, req) + scope.err(errors.NewBadRequest("the dryRun alpha feature is disabled"), w, req) return } @@ -61,18 +59,11 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc scope.err(err, w, req) return } - ctx, cancel := context.WithTimeout(req.Context(), timeout) - defer cancel() + ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) ae := request.AuditEventFrom(ctx) admit = admission.WithAudit(admit, ae) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) - if err != nil { - scope.err(err, w, req) - return - } - options := &metav1.DeleteOptions{} if allowsOptions { body, err := limitedReadBody(req, scope.MaxRequestBodyBytes) @@ -81,7 +72,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc return } if len(body) > 0 { - s, err := negotiation.NegotiateInputSerializer(req, false, metainternalversionscheme.Codecs) + s, err := negotiation.NegotiateInputSerializer(req, false, metainternalversion.Codecs) if err != nil { scope.err(err, w, req) return @@ -89,7 +80,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc // For backwards compatibility, we need to allow existing clients to submit per group DeleteOptions // It is also allowed to pass a body with meta.k8s.io/v1.DeleteOptions defaultGVK := scope.MetaGroupVersion.WithKind("DeleteOptions") - obj, _, err := metainternalversionscheme.Codecs.DecoderToVersion(s.Serializer, defaultGVK.GroupVersion()).Decode(body, &defaultGVK, options) + obj, _, err := metainternalversion.Codecs.DecoderToVersion(s.Serializer, defaultGVK.GroupVersion()).Decode(body, &defaultGVK, options) if err != nil { scope.err(err, w, req) return @@ -104,7 +95,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer) trace.Step("Recorded the audit event") } else { - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -116,14 +107,29 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc scope.err(err, w, req) return } - options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("DeleteOptions")) + + trace.Step("About to check admission control") + if admit != nil && admit.Handles(admission.Delete) { + userInfo, _ := request.UserFrom(ctx) + attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo) + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { + if err := mutatingAdmission.Admit(attrs); err != nil { + scope.err(err, w, req) + return + } + } + if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { + if err := validatingAdmission.Validate(attrs); err != nil { + scope.err(err, w, req) + return + } + } + } trace.Step("About to delete object from database") wasDeleted := true - userInfo, _ := request.UserFrom(ctx) - staticAdmissionAttrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, options, dryrun.IsDryRun(options.DryRun), userInfo) result, err := finishRequest(timeout, func() (runtime.Object, error) { - obj, deleted, err := r.Delete(ctx, name, rest.AdmissionToValidateObjectDeleteFunc(admit, staticAdmissionAttrs, scope), options) + obj, deleted, err := r.Delete(ctx, name, options) wasDeleted = deleted return obj, err }) @@ -154,20 +160,34 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestSc Kind: scope.Kind.Kind, }, } + } else { + // when a non-status response is returned, set the self link + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } + if _, ok := result.(*metav1.Status); !ok { + if err := setSelfLink(result, requestInfo, scope.Namer); err != nil { + scope.err(err, w, req) + return + } + } } - transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, status, result) } } // DeleteCollection returns a function that will handle a collection deletion -func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestScope, admit admission.Interface) http.HandlerFunc { +func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestScope, admit admission.Interface) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - trace := utiltrace.New("Delete", utiltrace.Field{"url", req.URL.Path}) + trace := utiltrace.New("Delete " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) if isDryRun(req.URL) && !utilfeature.DefaultFeatureGate.Enabled(features.DryRun) { - scope.err(errors.NewBadRequest("the dryRun feature is disabled"), w, req) + scope.err(errors.NewBadRequest("the dryRun alpha feature is disabled"), w, req) return } @@ -180,19 +200,12 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestSc return } - ctx, cancel := context.WithTimeout(req.Context(), timeout) - defer cancel() + ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) ae := request.AuditEventFrom(ctx) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) - if err != nil { - scope.err(err, w, req) - return - } - listOptions := metainternalversion.ListOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, &listOptions); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, &listOptions); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -225,8 +238,6 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestSc scope.err(err, w, req) return } - // For backwards compatibility, we need to allow existing clients to submit per group DeleteOptions - // It is also allowed to pass a body with meta.k8s.io/v1.DeleteOptions defaultGVK := scope.Kind.GroupVersion().WithKind("DeleteOptions") obj, _, err := scope.Serializer.DecoderToVersion(s.Serializer, defaultGVK.GroupVersion()).Decode(body, &defaultGVK, options) if err != nil { @@ -241,7 +252,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestSc ae := request.AuditEventFrom(ctx) audit.LogRequestObject(ae, obj, scope.Resource, scope.Subresource, scope.Serializer) } else { - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -253,13 +264,30 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestSc scope.err(err, w, req) return } - options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("DeleteOptions")) admit = admission.WithAudit(admit, ae) - userInfo, _ := request.UserFrom(ctx) - staticAdmissionAttrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, options, dryrun.IsDryRun(options.DryRun), userInfo) + if admit != nil && admit.Handles(admission.Delete) { + userInfo, _ := request.UserFrom(ctx) + attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo) + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { + err = mutatingAdmission.Admit(attrs) + if err != nil { + scope.err(err, w, req) + return + } + } + + if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { + err = validatingAdmission.Validate(attrs) + if err != nil { + scope.err(err, w, req) + return + } + } + } + result, err := finishRequest(timeout, func() (runtime.Object, error) { - return r.DeleteCollection(ctx, rest.AdmissionToValidateObjectDeleteFunc(admit, staticAdmissionAttrs, scope), options, &listOptions) + return r.DeleteCollection(ctx, options, &listOptions) }) if err != nil { scope.err(err, w, req) @@ -276,8 +304,17 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestSc Kind: scope.Kind.Kind, }, } + } else { + // when a non-status response is returned, set the self link + if _, ok := result.(*metav1.Status); !ok { + if _, err := setListSelfLink(result, ctx, req, scope.Namer); err != nil { + scope.err(err, w, req) + return + } + } } - transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, http.StatusOK, result) } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/OWNERS deleted file mode 100644 index a7470137b87..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -approvers: -- jennybuckley -- apelisse -reviewers: -- kwiesmueller diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/buildmanagerinfo.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/buildmanagerinfo.go deleted file mode 100644 index fc471e79759..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/buildmanagerinfo.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright 2019 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 fieldmanager - -import ( - "fmt" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" -) - -type buildManagerInfoManager struct { - fieldManager Manager - groupVersion schema.GroupVersion -} - -var _ Manager = &buildManagerInfoManager{} - -// NewBuildManagerInfoManager creates a new Manager that converts the manager name into a unique identifier -// combining operation and version for update requests, and just operation for apply requests. -func NewBuildManagerInfoManager(f Manager, gv schema.GroupVersion) Manager { - return &buildManagerInfoManager{ - fieldManager: f, - groupVersion: gv, - } -} - -// Update implements Manager. -func (f *buildManagerInfoManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationUpdate) - if err != nil { - return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err) - } - return f.fieldManager.Update(liveObj, newObj, managed, manager) -} - -// Apply implements Manager. -func (f *buildManagerInfoManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) { - manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationApply) - if err != nil { - return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err) - } - return f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force) -} - -func (f *buildManagerInfoManager) buildManagerInfo(prefix string, operation metav1.ManagedFieldsOperationType) (string, error) { - managerInfo := metav1.ManagedFieldsEntry{ - Manager: prefix, - Operation: operation, - APIVersion: f.groupVersion.String(), - } - if managerInfo.Manager == "" { - managerInfo.Manager = "unknown" - } - return internal.BuildManagerIdentifier(&managerInfo) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers.go deleted file mode 100644 index 8e926995329..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers.go +++ /dev/null @@ -1,134 +0,0 @@ -/* -Copyright 2019 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 fieldmanager - -import ( - "fmt" - "sort" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -type capManagersManager struct { - fieldManager Manager - maxUpdateManagers int - oldUpdatesManagerName string -} - -var _ Manager = &capManagersManager{} - -// NewCapManagersManager creates a new wrapped FieldManager which ensures that the number of managers from updates -// does not exceed maxUpdateManagers, by merging some of the oldest entries on each update. -func NewCapManagersManager(fieldManager Manager, maxUpdateManagers int) Manager { - return &capManagersManager{ - fieldManager: fieldManager, - maxUpdateManagers: maxUpdateManagers, - oldUpdatesManagerName: "ancient-changes", - } -} - -// Update implements Manager. -func (f *capManagersManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - object, managed, err := f.fieldManager.Update(liveObj, newObj, managed, manager) - if err != nil { - return object, managed, err - } - if managed, err = f.capUpdateManagers(managed); err != nil { - return nil, nil, fmt.Errorf("failed to cap update managers: %v", err) - } - return object, managed, nil -} - -// Apply implements Manager. -func (f *capManagersManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) { - return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force) -} - -// capUpdateManagers merges a number of the oldest update entries into versioned buckets, -// such that the number of entries from updates does not exceed f.maxUpdateManagers. -func (f *capManagersManager) capUpdateManagers(managed Managed) (newManaged Managed, err error) { - // Gather all entries from updates - updaters := []string{} - for manager, fields := range managed.Fields() { - if fields.Applied() == false { - updaters = append(updaters, manager) - } - } - if len(updaters) <= f.maxUpdateManagers { - return managed, nil - } - - // If we have more than the maximum, sort the update entries by time, oldest first. - sort.Slice(updaters, func(i, j int) bool { - iTime, jTime, iSeconds, jSeconds := managed.Times()[updaters[i]], managed.Times()[updaters[j]], int64(0), int64(0) - if iTime != nil { - iSeconds = iTime.Unix() - } - if jTime != nil { - jSeconds = jTime.Unix() - } - if iSeconds != jSeconds { - return iSeconds < jSeconds - } - return updaters[i] < updaters[j] - }) - - // Merge the oldest updaters with versioned bucket managers until the number of updaters is under the cap - versionToFirstManager := map[string]string{} - for i, length := 0, len(updaters); i < len(updaters) && length > f.maxUpdateManagers; i++ { - manager := updaters[i] - vs := managed.Fields()[manager] - time := managed.Times()[manager] - version := string(vs.APIVersion()) - - // Create a new manager identifier for the versioned bucket entry. - // The version for this manager comes from the version of the update being merged into the bucket. - bucket, err := internal.BuildManagerIdentifier(&metav1.ManagedFieldsEntry{ - Manager: f.oldUpdatesManagerName, - Operation: metav1.ManagedFieldsOperationUpdate, - APIVersion: version, - }) - if err != nil { - return managed, fmt.Errorf("failed to create bucket manager for version %v: %v", version, err) - } - - // Merge the fieldets if this is not the first time the version was seen. - // Otherwise just record the manager name in versionToFirstManager - if first, ok := versionToFirstManager[version]; ok { - // If the bucket doesn't exists yet, create one. - if _, ok := managed.Fields()[bucket]; !ok { - s := managed.Fields()[first] - delete(managed.Fields(), first) - managed.Fields()[bucket] = s - } - - managed.Fields()[bucket] = fieldpath.NewVersionedSet(vs.Set().Union(managed.Fields()[bucket].Set()), vs.APIVersion(), vs.Applied()) - delete(managed.Fields(), manager) - length-- - - // Use the time from the update being merged into the bucket, since it is more recent. - managed.Times()[bucket] = time - } else { - versionToFirstManager[version] = manager - } - } - - return managed, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers_test.go deleted file mode 100644 index 6b20850d481..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/capmanagers_test.go +++ /dev/null @@ -1,286 +0,0 @@ -/* -Copyright 2019 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 fieldmanager_test - -import ( - "bytes" - "encoding/json" - "fmt" - "testing" - "time" - - apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -type fakeManager struct{} - -var _ fieldmanager.Manager = &fakeManager{} - -func (*fakeManager) Update(_, newObj runtime.Object, managed fieldmanager.Managed, _ string) (runtime.Object, fieldmanager.Managed, error) { - return newObj, managed, nil -} - -func (*fakeManager) Apply(_, _ runtime.Object, _ fieldmanager.Managed, _ string, force bool) (runtime.Object, fieldmanager.Managed, error) { - panic("not implemented") - return nil, nil, nil -} - -func TestCapManagersManagerMergesEntries(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - f.fieldManager = fieldmanager.NewCapManagersManager(f.fieldManager, 3) - - podWithLabels := func(labels ...string) runtime.Object { - labelMap := map[string]interface{}{} - for _, key := range labels { - labelMap[key] = "true" - } - obj := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": labelMap, - }, - }, - } - obj.SetKind("Pod") - obj.SetAPIVersion("v1") - return obj - } - - if err := f.Update(podWithLabels("one"), "fieldmanager_test_update_1"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - expectIdempotence(t, f) - - if err := f.Update(podWithLabels("one", "two"), "fieldmanager_test_update_2"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - expectIdempotence(t, f) - - if err := f.Update(podWithLabels("one", "two", "three"), "fieldmanager_test_update_3"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - expectIdempotence(t, f) - - if err := f.Update(podWithLabels("one", "two", "three", "four"), "fieldmanager_test_update_4"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - expectIdempotence(t, f) - - if e, a := 3, len(f.ManagedFields()); e != a { - t.Fatalf("exected %v entries in managedFields, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "ancient-changes", f.ManagedFields()[0].Manager; e != a { - t.Fatalf("exected first manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "fieldmanager_test_update_3", f.ManagedFields()[1].Manager; e != a { - t.Fatalf("exected second manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "fieldmanager_test_update_4", f.ManagedFields()[2].Manager; e != a { - t.Fatalf("exected third manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } - - expectManagesField(t, f, "ancient-changes", fieldpath.MakePathOrDie("metadata", "labels", "one")) - expectManagesField(t, f, "ancient-changes", fieldpath.MakePathOrDie("metadata", "labels", "two")) - expectManagesField(t, f, "fieldmanager_test_update_3", fieldpath.MakePathOrDie("metadata", "labels", "three")) - expectManagesField(t, f, "fieldmanager_test_update_4", fieldpath.MakePathOrDie("metadata", "labels", "four")) -} - -func TestCapUpdateManagers(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - f.fieldManager = fieldmanager.NewCapManagersManager(&fakeManager{}, 3) - - set := func(fields ...string) *metav1.FieldsV1 { - s := fieldpath.NewSet() - for _, f := range fields { - s.Insert(fieldpath.MakePathOrDie(f)) - } - b, err := s.ToJSON() - if err != nil { - panic(fmt.Sprintf("error building ManagedFieldsEntry for test: %v", err)) - } - return &metav1.FieldsV1{Raw: b} - } - - entry := func(name string, version string, order int, fields *metav1.FieldsV1) metav1.ManagedFieldsEntry { - return metav1.ManagedFieldsEntry{ - Manager: name, - APIVersion: version, - Operation: "Update", - FieldsType: "FieldsV1", - FieldsV1: fields, - Time: &metav1.Time{Time: time.Time{}.Add(time.Hour * time.Duration(order))}, - } - } - - testCases := []struct { - name string - input []metav1.ManagedFieldsEntry - expected []metav1.ManagedFieldsEntry - }{ - { - name: "one version, no ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("update-manager1", "v1", 1, set("a")), - entry("update-manager2", "v1", 2, set("b")), - entry("update-manager3", "v1", 3, set("c")), - entry("update-manager4", "v1", 4, set("d")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 2, set("a", "b")), - entry("update-manager3", "v1", 3, set("c")), - entry("update-manager4", "v1", 4, set("d")), - }, - }, { - name: "one version, one ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 2, set("a", "b")), - entry("update-manager3", "v1", 3, set("c")), - entry("update-manager4", "v1", 4, set("d")), - entry("update-manager5", "v1", 5, set("e")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 3, set("a", "b", "c")), - entry("update-manager4", "v1", 4, set("d")), - entry("update-manager5", "v1", 5, set("e")), - }, - }, { - name: "two versions, no ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("update-manager1", "v1", 1, set("a")), - entry("update-manager2", "v2", 2, set("b")), - entry("update-manager3", "v1", 3, set("c")), - entry("update-manager4", "v1", 4, set("d")), - entry("update-manager5", "v1", 5, set("e")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("update-manager2", "v2", 2, set("b")), - entry("ancient-changes", "v1", 4, set("a", "c", "d")), - entry("update-manager5", "v1", 5, set("e")), - }, - }, { - name: "three versions, one ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("update-manager2", "v2", 2, set("b")), - entry("ancient-changes", "v1", 4, set("a", "c", "d")), - entry("update-manager5", "v1", 5, set("e")), - entry("update-manager6", "v3", 6, set("f")), - entry("update-manager7", "v2", 7, set("g")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")), - entry("update-manager6", "v3", 6, set("f")), - entry("ancient-changes", "v2", 7, set("b", "g")), - }, - }, { - name: "three versions, two ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")), - entry("update-manager6", "v3", 6, set("f")), - entry("ancient-changes", "v2", 7, set("b", "g")), - entry("update-manager8", "v3", 8, set("h")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")), - entry("ancient-changes", "v2", 7, set("b", "g")), - entry("ancient-changes", "v3", 8, set("f", "h")), - }, - }, { - name: "four versions, two ancient changes", - input: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")), - entry("update-manager6", "v3", 6, set("f")), - entry("ancient-changes", "v2", 7, set("b", "g")), - entry("update-manager8", "v4", 8, set("h")), - }, - expected: []metav1.ManagedFieldsEntry{ - entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")), - entry("update-manager6", "v3", 6, set("f")), - entry("ancient-changes", "v2", 7, set("b", "g")), - entry("update-manager8", "v4", 8, set("h")), - }, - }, - } - - for _, tc := range testCases { - f.Reset() - accessor, err := meta.Accessor(f.liveObj) - if err != nil { - t.Fatalf("%v: couldn't get accessor: %v", tc.name, err) - } - accessor.SetManagedFields(tc.input) - if err := f.Update(f.liveObj, "no-op-update"); err != nil { - t.Fatalf("%v: failed to do no-op update to object: %v", tc.name, err) - } - - if e, a := tc.expected, f.ManagedFields(); !apiequality.Semantic.DeepEqual(e, a) { - t.Errorf("%v: unexpected value for managedFields:\nexpected: %v\n but got: %v", tc.name, mustMarshal(e), mustMarshal(a)) - } - expectIdempotence(t, f) - } -} - -// expectIdempotence does a no-op update and ensures that managedFields doesn't change by calling capUpdateManagers. -func expectIdempotence(t *testing.T, f TestFieldManager) { - before := []metav1.ManagedFieldsEntry{} - for _, m := range f.ManagedFields() { - before = append(before, *m.DeepCopy()) - } - - if err := f.Update(f.liveObj, "no-op-update"); err != nil { - t.Fatalf("failed to do no-op update to object: %v", err) - } - - if after := f.ManagedFields(); !apiequality.Semantic.DeepEqual(before, after) { - t.Fatalf("exected idempotence, but managedFields changed:\nbefore: %v\n after: %v", mustMarshal(before), mustMarshal(after)) - } -} - -// expectManagesField ensures that manager m currently manages field path p. -func expectManagesField(t *testing.T, f TestFieldManager, m string, p fieldpath.Path) { - for _, e := range f.ManagedFields() { - if e.Manager == m { - var s fieldpath.Set - err := s.FromJSON(bytes.NewReader(e.FieldsV1.Raw)) - if err != nil { - t.Fatalf("error parsing managedFields for %v: %v: %#v", m, err, f.ManagedFields()) - } - if !s.Has(p) { - t.Fatalf("expected managedFields for %v to contain %v, but got:\n%v", m, p.String(), s.String()) - } - return - } - } - t.Fatalf("exected to find manager name %v, but got: %#v", m, f.ManagedFields()) -} - -func mustMarshal(i interface{}) string { - b, err := json.MarshalIndent(i, "", " ") - if err != nil { - panic(fmt.Sprintf("error marshalling %v to json: %v", i, err)) - } - return string(b) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/endpoints.yaml b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/endpoints.yaml deleted file mode 100644 index a667e983426..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/endpoints.yaml +++ /dev/null @@ -1,7018 +0,0 @@ -apiVersion: v1 -kind: Endpoints -metadata: - creationTimestamp: '2016-10-04T17:45:58Z' - labels: - app: my-app - name: app-server - namespace: default - resourceVersion: '184597135' - selfLink: /self/link - uid: 6826f086-8a5a-11e6-8d09-42010a800005 -subsets: -- addresses: - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0000 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0001 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0002 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0003 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0004 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0005 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0006 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0007 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0008 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0009 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0010 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0011 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0012 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0013 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0014 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0015 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0016 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0017 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0018 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0019 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0020 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0021 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0022 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0023 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0024 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0025 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0026 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0027 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0028 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0029 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0030 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0031 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0032 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0033 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0034 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0035 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0036 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0037 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0038 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0039 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0040 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0041 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0042 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0043 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0044 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0045 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0046 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0047 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0048 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0049 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0050 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0051 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0052 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0053 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0054 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0055 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0056 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0057 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0058 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0059 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0060 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0061 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0062 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0063 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0064 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0065 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0066 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0067 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0068 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0069 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0070 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0071 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0072 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0073 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0074 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0075 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0076 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0077 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0078 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0079 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0080 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0081 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0082 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0083 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0084 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0085 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0086 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0087 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0088 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0089 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0090 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0091 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0092 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0093 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0094 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0095 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0096 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0097 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0098 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0099 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0100 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0101 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0102 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0103 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0104 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0105 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0106 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0107 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0108 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0109 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0110 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0111 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0112 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0113 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0114 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0115 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0116 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0117 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0118 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0119 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0120 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0121 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0122 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0123 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0124 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0125 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0126 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0127 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0128 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0129 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0130 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0131 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0132 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0133 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0134 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0135 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0136 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0137 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0138 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0139 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0140 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0141 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0142 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0143 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0144 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0145 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0146 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0147 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0148 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0149 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0150 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0151 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0152 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0153 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0154 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0155 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0156 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0157 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0158 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0159 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0160 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0161 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0162 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0163 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0164 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0165 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0166 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0167 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0168 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0169 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0170 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0171 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0172 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0173 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0174 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0175 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0176 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0177 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0178 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0179 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0180 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0181 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0182 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0183 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0184 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0185 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0186 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0187 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0188 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0189 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0190 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0191 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0192 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0193 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0194 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0195 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0196 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0197 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0198 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0199 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0200 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0201 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0202 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0203 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0204 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0205 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0206 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0207 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0208 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0209 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0210 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0211 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0212 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0213 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0214 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0215 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0216 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0217 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0218 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0219 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0220 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0221 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0222 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0223 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0224 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0225 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0226 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0227 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0228 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0229 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0230 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0231 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0232 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0233 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0234 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0235 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0236 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0237 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0238 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0239 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0240 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0241 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0242 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0243 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0244 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0245 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0246 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0247 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0248 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0249 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0250 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0251 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0252 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0253 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0254 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0255 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0256 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0257 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0258 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0259 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0260 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0261 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0262 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0263 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0264 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0265 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0266 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0267 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0268 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0269 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0270 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0271 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0272 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0273 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0274 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0275 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0276 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0277 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0278 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0279 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0280 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0281 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0282 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0283 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0284 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0285 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0286 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0287 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0288 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0289 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0290 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0291 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0292 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0293 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0294 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0295 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0296 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0297 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0298 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0299 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0300 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0301 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0302 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0303 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0304 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0305 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0306 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0307 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0308 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0309 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0310 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0311 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0312 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0313 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0314 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0315 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0316 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0317 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0318 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0319 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0320 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0321 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0322 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0323 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0324 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0325 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0326 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0327 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0328 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0329 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0330 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0331 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0332 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0333 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0334 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0335 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0336 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0337 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0338 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0339 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0340 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0341 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0342 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0343 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0344 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0345 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0346 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0347 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0348 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0349 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0350 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0351 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0352 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0353 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0354 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0355 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0356 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0357 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0358 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0359 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0360 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0361 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0362 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0363 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0364 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0365 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0366 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0367 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0368 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0369 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0370 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0371 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0372 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0373 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0374 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0375 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0376 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0377 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0378 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0379 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0380 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0381 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0382 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0383 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0384 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0385 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0386 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0387 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0388 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0389 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0390 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0391 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0392 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0393 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0394 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0395 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0396 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0397 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0398 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0399 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0400 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0401 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0402 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0403 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0404 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0405 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0406 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0407 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0408 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0409 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0410 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0411 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0412 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0413 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0414 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0415 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0416 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0417 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0418 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0419 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0420 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0421 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0422 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0423 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0424 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0425 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0426 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0427 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0428 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0429 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0430 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0431 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0432 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0433 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0434 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0435 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0436 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0437 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0438 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0439 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0440 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0441 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0442 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0443 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0444 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0445 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0446 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0447 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0448 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0449 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0450 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0451 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0452 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0453 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0454 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0455 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0456 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0457 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0458 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0459 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0460 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0461 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0462 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0463 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0464 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0465 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0466 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0467 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0468 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0469 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0470 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0471 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0472 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0473 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0474 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0475 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0476 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0477 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0478 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0479 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0480 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0481 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0482 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0483 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0484 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0485 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0486 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0487 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0488 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0489 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0490 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0491 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0492 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0493 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0494 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0495 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0496 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0497 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0498 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0499 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0500 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0501 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0502 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0503 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0504 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0505 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0506 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0507 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0508 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0509 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0510 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0511 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0512 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0513 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0514 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0515 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0516 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0517 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0518 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0519 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0520 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0521 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0522 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0523 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0524 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0525 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0526 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0527 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0528 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0529 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0530 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0531 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0532 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0533 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0534 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0535 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0536 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0537 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0538 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0539 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0540 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0541 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0542 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0543 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0544 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0545 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0546 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0547 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0548 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0549 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0550 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0551 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0552 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0553 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0554 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0555 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0556 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0557 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0558 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0559 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0560 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0561 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0562 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0563 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0564 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0565 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0566 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0567 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0568 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0569 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0570 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0571 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0572 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0573 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0574 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0575 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0576 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0577 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0578 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0579 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0580 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0581 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0582 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0583 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0584 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0585 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0586 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0587 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0588 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0589 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0590 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0591 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0592 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0593 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0594 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0595 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0596 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0597 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0598 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0599 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0600 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0601 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0602 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0603 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0604 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0605 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0606 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0607 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0608 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0609 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0610 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0611 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0612 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0613 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0614 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0615 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0616 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0617 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0618 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0619 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0620 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0621 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0622 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0623 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0624 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0625 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0626 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0627 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0628 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0629 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0630 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0631 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0632 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0633 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0634 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0635 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0636 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0637 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0638 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0639 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0640 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0641 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0642 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0643 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0644 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0645 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0646 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0647 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0648 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0649 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0650 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0651 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0652 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0653 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0654 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0655 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0656 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0657 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0658 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0659 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0660 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0661 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0662 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0663 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0664 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0665 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0666 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0667 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0668 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0669 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0670 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0671 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0672 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0673 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0674 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0675 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0676 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0677 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0678 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0679 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0680 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0681 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0682 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0683 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0684 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0685 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0686 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0687 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0688 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0689 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0690 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0691 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0692 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0693 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0694 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0695 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0696 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0697 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0698 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0699 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0700 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0701 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0702 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0703 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0704 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0705 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0706 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0707 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0708 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0709 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0710 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0711 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0712 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0713 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0714 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0715 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0716 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0717 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0718 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0719 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0720 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0721 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0722 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0723 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0724 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0725 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0726 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0727 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0728 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0729 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0730 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0731 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0732 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0733 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0734 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0735 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0736 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0737 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0738 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0739 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0740 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0741 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0742 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0743 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0744 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0745 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0746 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0747 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0748 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0749 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0750 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0751 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0752 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0753 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0754 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0755 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0756 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0757 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0758 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0759 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0760 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0761 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0762 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0763 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0764 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0765 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0766 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0767 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0768 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0769 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0770 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0771 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0772 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0773 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0774 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0775 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0776 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0777 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0778 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0779 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0780 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0781 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0782 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0783 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0784 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0785 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0786 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0787 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0788 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0789 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0790 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0791 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0792 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0793 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0794 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0795 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0796 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0797 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0798 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0799 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0800 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0801 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0802 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0803 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0804 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0805 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0806 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0807 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0808 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0809 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0810 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0811 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0812 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0813 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0814 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0815 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0816 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0817 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0818 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0819 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0820 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0821 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0822 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0823 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0824 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0825 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0826 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0827 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0828 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0829 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0830 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0831 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0832 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0833 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0834 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0835 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0836 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0837 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0838 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0839 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0840 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0841 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0842 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0843 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0844 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0845 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0846 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0847 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0848 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0849 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0850 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0851 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0852 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0853 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0854 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0855 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0856 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0857 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0858 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0859 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0860 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0861 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0862 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0863 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0864 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0865 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0866 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0867 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0868 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0869 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0870 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0871 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0872 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0873 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0874 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0875 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0876 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0877 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0878 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0879 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0880 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0881 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0882 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0883 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0884 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0885 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0886 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0887 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0888 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0889 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0890 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0891 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0892 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0893 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0894 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0895 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0896 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0897 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0898 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0899 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0900 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0901 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0902 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0903 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0904 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0905 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0906 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0907 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0908 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0909 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0910 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0911 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0912 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0913 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0914 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0915 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0916 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0917 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0918 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0919 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0920 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0921 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0922 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0923 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0924 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0925 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0926 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0927 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0928 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0929 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0930 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0931 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0932 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0933 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0934 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0935 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0936 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0937 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0938 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0939 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0940 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0941 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0942 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0943 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0944 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0945 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0946 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0947 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0948 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0949 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0950 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0951 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0952 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0953 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0954 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0955 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0956 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0957 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0958 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0959 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0960 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0961 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0962 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0963 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0964 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0965 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0966 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0967 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0968 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0969 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0970 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0971 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0972 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0973 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0974 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0975 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0976 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0977 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0978 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0979 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0980 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0981 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0982 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0983 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0984 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0985 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0986 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0987 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0988 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0989 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0990 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0991 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0992 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0993 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0994 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0995 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0996 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0997 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0998 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - - ip: 10.0.0.1 - targetRef: - kind: Pod - name: pod-name-1234-0999 - namespace: default - resourceVersion: '1234567890' - uid: 11111111-2222-3333-4444-555555555555 - ports: - - name: port-name - port: 8080 - protocol: TCP - diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager.go deleted file mode 100644 index bd47efe2227..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager.go +++ /dev/null @@ -1,166 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package fieldmanager - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - openapiproto "k8s.io/kube-openapi/pkg/util/proto" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -// DefaultMaxUpdateManagers defines the default maximum retained number of managedFields entries from updates -// if the number of update managers exceeds this, the oldest entries will be merged until the number is below the maximum. -// TODO(jennybuckley): Determine if this is really the best value. Ideally we wouldn't unnecessarily merge too many entries. -const DefaultMaxUpdateManagers int = 10 - -// DefaultTrackOnCreateProbability defines the default probability that the field management of an object -// starts being tracked from the object's creation, instead of from the first time the object is applied to. -const DefaultTrackOnCreateProbability float32 = 1 - -// Managed groups a fieldpath.ManagedFields together with the timestamps associated with each operation. -type Managed interface { - // Fields gets the fieldpath.ManagedFields. - Fields() fieldpath.ManagedFields - - // Times gets the timestamps associated with each operation. - Times() map[string]*metav1.Time -} - -// Manager updates the managed fields and merges applied configurations. -type Manager interface { - // Update is used when the object has already been merged (non-apply - // use-case), and simply updates the managed fields in the output - // object. - Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) - - // Apply is used when server-side apply is called, as it merges the - // object and updates the managed fields. - Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) -} - -// FieldManager updates the managed fields and merge applied -// configurations. -type FieldManager struct { - fieldManager Manager -} - -// NewFieldManager creates a new FieldManager that decodes, manages, then re-encodes managedFields -// on update and apply requests. -func NewFieldManager(f Manager) *FieldManager { - return &FieldManager{f} -} - -// NewDefaultFieldManager creates a new FieldManager that merges apply requests -// and update managed fields for other types of requests. -func NewDefaultFieldManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion) (*FieldManager, error) { - f, err := NewStructuredMergeManager(models, objectConverter, objectDefaulter, kind.GroupVersion(), hub) - if err != nil { - return nil, fmt.Errorf("failed to create field manager: %v", err) - } - return newDefaultFieldManager(f, objectCreater, kind), nil -} - -// NewDefaultCRDFieldManager creates a new FieldManager specifically for -// CRDs. This allows for the possibility of fields which are not defined -// in models, as well as having no models defined at all. -func NewDefaultCRDFieldManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, preserveUnknownFields bool) (_ *FieldManager, err error) { - f, err := NewCRDStructuredMergeManager(models, objectConverter, objectDefaulter, kind.GroupVersion(), hub, preserveUnknownFields) - if err != nil { - return nil, fmt.Errorf("failed to create field manager: %v", err) - } - return newDefaultFieldManager(f, objectCreater, kind), nil -} - -// newDefaultFieldManager is a helper function which wraps a Manager with certain default logic. -func newDefaultFieldManager(f Manager, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind) *FieldManager { - f = NewStripMetaManager(f) - f = NewManagedFieldsUpdater(f) - f = NewBuildManagerInfoManager(f, kind.GroupVersion()) - f = NewCapManagersManager(f, DefaultMaxUpdateManagers) - f = NewProbabilisticSkipNonAppliedManager(f, objectCreater, kind, DefaultTrackOnCreateProbability) - return NewFieldManager(f) -} - -// Update is used when the object has already been merged (non-apply -// use-case), and simply updates the managed fields in the output -// object. -func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (object runtime.Object, err error) { - // If the object doesn't have metadata, we should just return without trying to - // set the managedFields at all, so creates/updates/patches will work normally. - if _, err = meta.Accessor(newObj); err != nil { - return newObj, nil - } - - // First try to decode the managed fields provided in the update, - // This is necessary to allow directly updating managed fields. - var managed Managed - if managed, err = internal.DecodeObjectManagedFields(newObj); err != nil || len(managed.Fields()) == 0 { - // If the managed field is empty or we failed to decode it, - // let's try the live object. This is to prevent clients who - // don't understand managedFields from deleting it accidentally. - managed, err = internal.DecodeObjectManagedFields(liveObj) - if err != nil { - return nil, fmt.Errorf("failed to decode managed fields: %v", err) - } - } - - internal.RemoveObjectManagedFields(liveObj) - internal.RemoveObjectManagedFields(newObj) - - if object, managed, err = f.fieldManager.Update(liveObj, newObj, managed, manager); err != nil { - return nil, err - } - - if err = internal.EncodeObjectManagedFields(object, managed); err != nil { - return nil, fmt.Errorf("failed to encode managed fields: %v", err) - } - - return object, nil -} - -// Apply is used when server-side apply is called, as it merges the -// object and updates the managed fields. -func (f *FieldManager) Apply(liveObj, appliedObj runtime.Object, manager string, force bool) (object runtime.Object, err error) { - // If the object doesn't have metadata, apply isn't allowed. - if _, err = meta.Accessor(liveObj); err != nil { - return nil, fmt.Errorf("couldn't get accessor: %v", err) - } - - // Decode the managed fields in the live object, since it isn't allowed in the patch. - var managed Managed - if managed, err = internal.DecodeObjectManagedFields(liveObj); err != nil { - return nil, fmt.Errorf("failed to decode managed fields: %v", err) - } - - internal.RemoveObjectManagedFields(liveObj) - - if object, managed, err = f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force); err != nil { - return nil, err - } - - if err = internal.EncodeObjectManagedFields(object, managed); err != nil { - return nil, fmt.Errorf("failed to encode managed fields: %v", err) - } - - return object, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go deleted file mode 100644 index 629f3fe0c68..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go +++ /dev/null @@ -1,785 +0,0 @@ -/* -Copyright 2019 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 fieldmanager_test - -import ( - "errors" - "fmt" - "io/ioutil" - "net/http" - "path/filepath" - "reflect" - "strings" - "testing" - "time" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - - "k8s.io/kube-openapi/pkg/util/proto" - prototesting "k8s.io/kube-openapi/pkg/util/proto/testing" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/merge" - "sigs.k8s.io/structured-merge-diff/v3/typed" - "sigs.k8s.io/yaml" -) - -var fakeSchema = prototesting.Fake{ - Path: filepath.Join( - strings.Repeat(".."+string(filepath.Separator), 8), - "api", "openapi-spec", "swagger.json"), -} - -type fakeObjectConvertor struct { - converter merge.Converter - apiVersion fieldpath.APIVersion -} - -func (c *fakeObjectConvertor) Convert(in, out, context interface{}) error { - if typedValue, ok := in.(*typed.TypedValue); ok { - var err error - out, err = c.converter.Convert(typedValue, c.apiVersion) - return err - } - out = in - return nil -} - -func (c *fakeObjectConvertor) ConvertToVersion(in runtime.Object, _ runtime.GroupVersioner) (runtime.Object, error) { - return in, nil -} - -func (c *fakeObjectConvertor) ConvertFieldLabel(_ schema.GroupVersionKind, _, _ string) (string, string, error) { - return "", "", errors.New("not implemented") -} - -type fakeObjectDefaulter struct{} - -func (d *fakeObjectDefaulter) Default(in runtime.Object) {} - -type TestFieldManager struct { - fieldManager fieldmanager.Manager - emptyObj runtime.Object - liveObj runtime.Object -} - -func NewTestFieldManager(gvk schema.GroupVersionKind) TestFieldManager { - m := NewFakeOpenAPIModels() - tc := NewFakeTypeConverter(m) - - converter := internal.NewVersionConverter(tc, &fakeObjectConvertor{}, gvk.GroupVersion()) - apiVersion := fieldpath.APIVersion(gvk.GroupVersion().String()) - f, err := fieldmanager.NewStructuredMergeManager( - m, - &fakeObjectConvertor{converter, apiVersion}, - &fakeObjectDefaulter{}, - gvk.GroupVersion(), - gvk.GroupVersion(), - ) - if err != nil { - panic(err) - } - live := &unstructured.Unstructured{} - live.SetKind(gvk.Kind) - live.SetAPIVersion(gvk.GroupVersion().String()) - f = fieldmanager.NewStripMetaManager(f) - f = fieldmanager.NewManagedFieldsUpdater(f) - f = fieldmanager.NewBuildManagerInfoManager(f, gvk.GroupVersion()) - return TestFieldManager{ - fieldManager: f, - emptyObj: live, - liveObj: live.DeepCopyObject(), - } -} - -func NewFakeTypeConverter(m proto.Models) internal.TypeConverter { - tc, err := internal.NewTypeConverter(m, false) - if err != nil { - panic(fmt.Sprintf("Failed to build TypeConverter: %v", err)) - } - return tc -} - -func NewFakeOpenAPIModels() proto.Models { - d, err := fakeSchema.OpenAPISchema() - if err != nil { - panic(err) - } - m, err := proto.NewOpenAPIData(d) - if err != nil { - panic(err) - } - return m -} - -func (f *TestFieldManager) Reset() { - f.liveObj = f.emptyObj.DeepCopyObject() -} - -func (f *TestFieldManager) Apply(obj runtime.Object, manager string, force bool) error { - out, err := fieldmanager.NewFieldManager(f.fieldManager).Apply(f.liveObj, obj, manager, force) - if err == nil { - f.liveObj = out - } - return err -} - -func (f *TestFieldManager) Update(obj runtime.Object, manager string) error { - out, err := fieldmanager.NewFieldManager(f.fieldManager).Update(f.liveObj, obj, manager) - if err == nil { - f.liveObj = out - } - return err -} - -func (f *TestFieldManager) ManagedFields() []metav1.ManagedFieldsEntry { - accessor, err := meta.Accessor(f.liveObj) - if err != nil { - panic(fmt.Errorf("couldn't get accessor: %v", err)) - } - - return accessor.GetManagedFields() -} - -// TestUpdateApplyConflict tests that applying to an object, which -// wasn't created by apply, will give conflicts -func TestUpdateApplyConflict(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment")) - - patch := []byte(`{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "name": "deployment", - "labels": {"app": "nginx"} - }, - "spec": { - "replicas": 3, - "selector": { - "matchLabels": { - "app": "nginx" - } - }, - "template": { - "metadata": { - "labels": { - "app": "nginx" - } - }, - "spec": { - "containers": [{ - "name": "nginx", - "image": "nginx:latest" - }] - } - } - } - }`) - newObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal(patch, &newObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - if err := f.Update(newObj, "fieldmanager_test"); err != nil { - t.Fatalf("failed to apply object: %v", err) - } - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "name": "deployment", - }, - "spec": { - "replicas": 101, - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - err := f.Apply(appliedObj, "fieldmanager_conflict", false) - if err == nil || !apierrors.IsConflict(err) { - t.Fatalf("Expecting to get conflicts but got %v", err) - } -} - -func TestApplyStripsFields(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment")) - - newObj := &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": "apps/v1", - "kind": "Deployment", - }, - } - - newObj.SetName("b") - newObj.SetNamespace("b") - newObj.SetUID("b") - newObj.SetClusterName("b") - newObj.SetGeneration(0) - newObj.SetResourceVersion("b") - newObj.SetCreationTimestamp(metav1.NewTime(time.Now())) - newObj.SetManagedFields([]metav1.ManagedFieldsEntry{ - { - Manager: "update", - Operation: metav1.ManagedFieldsOperationApply, - APIVersion: "apps/v1", - }, - }) - if err := f.Update(newObj, "fieldmanager_test"); err != nil { - t.Fatalf("failed to apply object: %v", err) - } - - if m := f.ManagedFields(); len(m) != 0 { - t.Fatalf("fields did not get stripped: %v", m) - } -} - -func TestVersionCheck(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment")) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "apps/v1", - "kind": "Deployment", - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - // patch has 'apiVersion: apps/v1' and live version is apps/v1 -> no errors - err := f.Apply(appliedObj, "fieldmanager_test", false) - if err != nil { - t.Fatalf("failed to apply object: %v", err) - } - - appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "apps/v1beta1", - "kind": "Deployment", - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - // patch has 'apiVersion: apps/v2' but live version is apps/v1 -> error - err = f.Apply(appliedObj, "fieldmanager_test", false) - if err == nil { - t.Fatalf("expected an error from mismatched patch and live versions") - } - switch typ := err.(type) { - default: - t.Fatalf("expected error to be of type %T was %T", apierrors.StatusError{}, typ) - case apierrors.APIStatus: - if typ.Status().Code != http.StatusBadRequest { - t.Fatalf("expected status code to be %d but was %d", - http.StatusBadRequest, typ.Status().Code) - } - } -} -func TestVersionCheckDoesNotPanic(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment")) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "apps/v1", - "kind": "Deployment", - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - // patch has 'apiVersion: apps/v1' and live version is apps/v1 -> no errors - err := f.Apply(appliedObj, "fieldmanager_test", false) - if err != nil { - t.Fatalf("failed to apply object: %v", err) - } - - appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - // patch has 'apiVersion: apps/v2' but live version is apps/v1 -> error - err = f.Apply(appliedObj, "fieldmanager_test", false) - if err == nil { - t.Fatalf("expected an error from mismatched patch and live versions") - } - switch typ := err.(type) { - default: - t.Fatalf("expected error to be of type %T was %T", apierrors.StatusError{}, typ) - case apierrors.APIStatus: - if typ.Status().Code != http.StatusBadRequest { - t.Fatalf("expected status code to be %d but was %d", - http.StatusBadRequest, typ.Status().Code) - } - } -} - -func TestApplyDoesNotStripLabels(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "a": "b" - }, - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - err := f.Apply(appliedObj, "fieldmanager_test", false) - if err != nil { - t.Fatalf("failed to apply object: %v", err) - } - - if m := f.ManagedFields(); len(m) != 1 { - t.Fatalf("labels shouldn't get stripped on apply: %v", m) - } -} - -func getObjectBytes(file string) []byte { - s, err := ioutil.ReadFile(file) - if err != nil { - panic(err) - } - return s -} - -func TestApplyNewObject(t *testing.T) { - tests := []struct { - gvk schema.GroupVersionKind - obj []byte - }{ - { - gvk: schema.FromAPIVersionAndKind("v1", "Pod"), - obj: getObjectBytes("pod.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Node"), - obj: getObjectBytes("node.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Endpoints"), - obj: getObjectBytes("endpoints.yaml"), - }, - } - - for _, test := range tests { - t.Run(test.gvk.String(), func(t *testing.T) { - f := NewTestFieldManager(test.gvk) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal(test.obj, &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - if err := f.Apply(appliedObj, "fieldmanager_test", false); err != nil { - t.Fatal(err) - } - }) - } -} - -func BenchmarkNewObject(b *testing.B) { - tests := []struct { - gvk schema.GroupVersionKind - obj []byte - }{ - { - gvk: schema.FromAPIVersionAndKind("v1", "Pod"), - obj: getObjectBytes("pod.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Node"), - obj: getObjectBytes("node.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Endpoints"), - obj: getObjectBytes("endpoints.yaml"), - }, - } - scheme := runtime.NewScheme() - if err := corev1.AddToScheme(scheme); err != nil { - b.Fatalf("Failed to add to scheme: %v", err) - } - for _, test := range tests { - b.Run(test.gvk.Kind, func(b *testing.B) { - f := NewTestFieldManager(test.gvk) - - decoder := serializer.NewCodecFactory(scheme).UniversalDecoder(test.gvk.GroupVersion()) - newObj, err := runtime.Decode(decoder, test.obj) - if err != nil { - b.Fatalf("Failed to parse yaml object: %v", err) - } - objMeta, err := meta.Accessor(newObj) - if err != nil { - b.Fatalf("Failed to get object meta: %v", err) - } - objMeta.SetManagedFields([]metav1.ManagedFieldsEntry{ - { - Manager: "default", - Operation: "Update", - APIVersion: "v1", - }, - }) - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal(test.obj, &appliedObj.Object); err != nil { - b.Fatalf("Failed to parse yaml object: %v", err) - } - b.Run("Update", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - if err := f.Update(newObj, "fieldmanager_test"); err != nil { - b.Fatal(err) - } - f.Reset() - } - }) - b.Run("UpdateTwice", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - if err := f.Update(newObj, "fieldmanager_test"); err != nil { - b.Fatal(err) - } - if err := f.Update(newObj, "fieldmanager_test_2"); err != nil { - b.Fatal(err) - } - f.Reset() - } - }) - b.Run("Apply", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - if err := f.Apply(appliedObj, "fieldmanager_test", false); err != nil { - b.Fatal(err) - } - f.Reset() - } - }) - b.Run("UpdateApply", func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - if err := f.Update(newObj, "fieldmanager_test"); err != nil { - b.Fatal(err) - } - if err := f.Apply(appliedObj, "fieldmanager_test", false); err != nil { - b.Fatal(err) - } - f.Reset() - } - }) - }) - } -} - -func toUnstructured(b *testing.B, o runtime.Object) *unstructured.Unstructured { - u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(o) - if err != nil { - b.Fatalf("Failed to unmarshal to json: %v", err) - } - return &unstructured.Unstructured{Object: u} -} - -func BenchmarkConvertObjectToTyped(b *testing.B) { - tests := []struct { - gvk schema.GroupVersionKind - obj []byte - }{ - { - gvk: schema.FromAPIVersionAndKind("v1", "Pod"), - obj: getObjectBytes("pod.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Node"), - obj: getObjectBytes("node.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Endpoints"), - obj: getObjectBytes("endpoints.yaml"), - }, - } - scheme := runtime.NewScheme() - if err := corev1.AddToScheme(scheme); err != nil { - b.Fatalf("Failed to add to scheme: %v", err) - } - - for _, test := range tests { - b.Run(test.gvk.Kind, func(b *testing.B) { - decoder := serializer.NewCodecFactory(scheme).UniversalDecoder(test.gvk.GroupVersion()) - m := NewFakeOpenAPIModels() - typeConverter := NewFakeTypeConverter(m) - - structured, err := runtime.Decode(decoder, test.obj) - if err != nil { - b.Fatalf("Failed to parse yaml object: %v", err) - } - b.Run("structured", func(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - _, err := typeConverter.ObjectToTyped(structured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - } - }) - }) - - unstructured := toUnstructured(b, structured) - b.Run("unstructured", func(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - _, err := typeConverter.ObjectToTyped(unstructured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - } - }) - }) - }) - } -} - -func BenchmarkCompare(b *testing.B) { - tests := []struct { - gvk schema.GroupVersionKind - obj []byte - }{ - { - gvk: schema.FromAPIVersionAndKind("v1", "Pod"), - obj: getObjectBytes("pod.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Node"), - obj: getObjectBytes("node.yaml"), - }, - { - gvk: schema.FromAPIVersionAndKind("v1", "Endpoints"), - obj: getObjectBytes("endpoints.yaml"), - }, - } - - scheme := runtime.NewScheme() - if err := corev1.AddToScheme(scheme); err != nil { - b.Fatalf("Failed to add to scheme: %v", err) - } - - for _, test := range tests { - b.Run(test.gvk.Kind, func(b *testing.B) { - decoder := serializer.NewCodecFactory(scheme).UniversalDecoder(test.gvk.GroupVersion()) - m := NewFakeOpenAPIModels() - typeConverter := NewFakeTypeConverter(m) - - structured, err := runtime.Decode(decoder, test.obj) - if err != nil { - b.Fatal(err) - } - tv1, err := typeConverter.ObjectToTyped(structured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - tv2, err := typeConverter.ObjectToTyped(structured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - - b.Run("structured", func(b *testing.B) { - b.ReportAllocs() - for n := 0; n < b.N; n++ { - _, err = tv1.Compare(tv2) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - } - }) - - unstructured := toUnstructured(b, structured) - utv1, err := typeConverter.ObjectToTyped(unstructured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - utv2, err := typeConverter.ObjectToTyped(unstructured) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - b.Run("unstructured", func(b *testing.B) { - b.ReportAllocs() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - _, err = utv1.Compare(utv2) - if err != nil { - b.Errorf("Error in ObjectToTyped: %v", err) - } - } - }) - }) - }) - } -} - -func BenchmarkRepeatedUpdate(b *testing.B) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - podBytes := getObjectBytes("pod.yaml") - - var obj *corev1.Pod - if err := yaml.Unmarshal(podBytes, &obj); err != nil { - b.Fatalf("Failed to parse yaml object: %v", err) - } - obj.Spec.Containers[0].Image = "nginx:latest" - objs := []*corev1.Pod{obj} - obj = obj.DeepCopy() - obj.Spec.Containers[0].Image = "nginx:4.3" - objs = append(objs, obj) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal(podBytes, &appliedObj.Object); err != nil { - b.Fatalf("error decoding YAML: %v", err) - } - - err := f.Apply(appliedObj, "fieldmanager_apply", false) - if err != nil { - b.Fatal(err) - } - - if err := f.Update(objs[1], "fieldmanager_1"); err != nil { - b.Fatal(err) - } - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - err := f.Update(objs[n%len(objs)], fmt.Sprintf("fieldmanager_%d", n%len(objs))) - if err != nil { - b.Fatal(err) - } - f.Reset() - } -} - -func TestApplyFailsWithManagedFields(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "managedFields": [ - { - "manager": "test", - } - ] - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - err := f.Apply(appliedObj, "fieldmanager_test", false) - - if err == nil { - t.Fatalf("successfully applied with set managed fields") - } -} - -func TestApplySuccessWithNoManagedFields(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "a": "b" - }, - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - err := f.Apply(appliedObj, "fieldmanager_test", false) - - if err != nil { - t.Fatalf("failed to apply object: %v", err) - } -} - -// Run an update and apply, and make sure that nothing has changed. -func TestNoOpChanges(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - - obj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "a": "b" - }, - } - }`), &obj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - if err := f.Apply(obj, "fieldmanager_test_apply", false); err != nil { - t.Fatalf("failed to apply object: %v", err) - } - before := f.liveObj.DeepCopyObject() - // Wait to make sure the timestamp is different - time.Sleep(time.Second) - // Applying with a different fieldmanager will create an entry.. - if err := f.Apply(obj, "fieldmanager_test_apply_other", false); err != nil { - t.Fatalf("failed to update object: %v", err) - } - if reflect.DeepEqual(before, f.liveObj) { - t.Fatalf("Applying no-op apply with new manager didn't change object: \n%v", f.liveObj) - } - before = f.liveObj.DeepCopyObject() - // Wait to make sure the timestamp is different - time.Sleep(time.Second) - if err := f.Update(obj, "fieldmanager_test_update"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - if !reflect.DeepEqual(before, f.liveObj) { - t.Fatalf("No-op update has changed the object:\n%v\n---\n%v", before, f.liveObj) - } - before = f.liveObj.DeepCopyObject() - // Wait to make sure the timestamp is different - time.Sleep(time.Second) - if err := f.Apply(obj, "fieldmanager_test_apply", true); err != nil { - t.Fatalf("failed to re-apply object: %v", err) - } - if !reflect.DeepEqual(before, f.liveObj) { - t.Fatalf("No-op apply has changed the object:\n%v\n---\n%v", before, f.liveObj) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery.go deleted file mode 100644 index b75ef7416e7..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2020 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 internal - -import ( - "sync" - "time" -) - -// AtMostEvery will never run the method more than once every specified -// duration. -type AtMostEvery struct { - delay time.Duration - lastCall time.Time - mutex sync.Mutex -} - -// NewAtMostEvery creates a new AtMostEvery, that will run the method at -// most every given duration. -func NewAtMostEvery(delay time.Duration) *AtMostEvery { - return &AtMostEvery{ - delay: delay, - } -} - -// updateLastCall returns true if the lastCall time has been updated, -// false if it was too early. -func (s *AtMostEvery) updateLastCall() bool { - s.mutex.Lock() - defer s.mutex.Unlock() - if time.Since(s.lastCall) < s.delay { - return false - } - s.lastCall = time.Now() - return true -} - -// Do will run the method if enough time has passed, and return true. -// Otherwise, it does nothing and returns false. -func (s *AtMostEvery) Do(fn func()) bool { - if !s.updateLastCall() { - return false - } - fn() - return true -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery_test.go deleted file mode 100644 index 46fe4f7e867..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/atmostevery_test.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright 2020 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 internal_test - -import ( - "testing" - "time" - - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" -) - -func TestAtMostEvery(t *testing.T) { - duration := time.Second - delay := 179 * time.Millisecond - atMostEvery := internal.NewAtMostEvery(delay) - count := 0 - exit := time.NewTicker(duration) - tick := time.NewTicker(2 * time.Millisecond) - defer exit.Stop() - defer tick.Stop() - - done := false - for !done { - select { - case <-exit.C: - done = true - case <-tick.C: - atMostEvery.Do(func() { - count++ - }) - } - } - - if expected := int(duration/delay) + 1; count != expected { - t.Fatalf("Function called %d times, should have been called exactly %d times", count, expected) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict.go deleted file mode 100644 index 2bc0d0ad8a8..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict.go +++ /dev/null @@ -1,85 +0,0 @@ -/* -Copyright 2019 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 internal - -import ( - "encoding/json" - "fmt" - "sort" - "strings" - "time" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/merge" -) - -// NewConflictError returns an error including details on the requests apply conflicts -func NewConflictError(conflicts merge.Conflicts) *errors.StatusError { - causes := []metav1.StatusCause{} - for _, conflict := range conflicts { - causes = append(causes, metav1.StatusCause{ - Type: metav1.CauseTypeFieldManagerConflict, - Message: fmt.Sprintf("conflict with %v", printManager(conflict.Manager)), - Field: conflict.Path.String(), - }) - } - return errors.NewApplyConflict(causes, getConflictMessage(conflicts)) -} - -func getConflictMessage(conflicts merge.Conflicts) string { - if len(conflicts) == 1 { - return fmt.Sprintf("Apply failed with 1 conflict: conflict with %v: %v", printManager(conflicts[0].Manager), conflicts[0].Path) - } - - m := map[string][]fieldpath.Path{} - for _, conflict := range conflicts { - m[conflict.Manager] = append(m[conflict.Manager], conflict.Path) - } - - uniqueManagers := []string{} - for manager := range m { - uniqueManagers = append(uniqueManagers, manager) - } - - // Print conflicts by sorted managers. - sort.Strings(uniqueManagers) - - messages := []string{} - for _, manager := range uniqueManagers { - messages = append(messages, fmt.Sprintf("conflicts with %v:", printManager(manager))) - for _, path := range m[manager] { - messages = append(messages, fmt.Sprintf("- %v", path)) - } - } - return fmt.Sprintf("Apply failed with %d conflicts: %s", len(conflicts), strings.Join(messages, "\n")) -} - -func printManager(manager string) string { - encodedManager := &metav1.ManagedFieldsEntry{} - if err := json.Unmarshal([]byte(manager), encodedManager); err != nil { - return fmt.Sprintf("%q", manager) - } - if encodedManager.Operation == metav1.ManagedFieldsOperationUpdate { - if encodedManager.Time == nil { - return fmt.Sprintf("%q using %v", encodedManager.Manager, encodedManager.APIVersion) - } - return fmt.Sprintf("%q using %v at %v", encodedManager.Manager, encodedManager.APIVersion, encodedManager.Time.UTC().Format(time.RFC3339)) - } - return fmt.Sprintf("%q", encodedManager.Manager) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict_test.go deleted file mode 100644 index 1270eefc750..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/conflict_test.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright 2019 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 internal_test - -import ( - "net/http" - "reflect" - "testing" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/merge" -) - -// TestNewConflictError tests that NewConflictError creates the correct StatusError for a given smd Conflicts -func TestNewConflictError(t *testing.T) { - testCases := []struct { - conflict merge.Conflicts - expected *errors.StatusError - }{ - { - conflict: merge.Conflicts{ - merge.Conflict{ - Manager: `{"manager":"foo","operation":"Update","apiVersion":"v1","time":"2001-02-03T04:05:06Z"}`, - Path: fieldpath.MakePathOrDie("spec", "replicas"), - }, - }, - expected: &errors.StatusError{ - ErrStatus: metav1.Status{ - Status: metav1.StatusFailure, - Code: http.StatusConflict, - Reason: metav1.StatusReasonConflict, - Details: &metav1.StatusDetails{ - Causes: []metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldManagerConflict, - Message: `conflict with "foo" using v1 at 2001-02-03T04:05:06Z`, - Field: ".spec.replicas", - }, - }, - }, - Message: `Apply failed with 1 conflict: conflict with "foo" using v1 at 2001-02-03T04:05:06Z: .spec.replicas`, - }, - }, - }, - { - conflict: merge.Conflicts{ - merge.Conflict{ - Manager: `{"manager":"foo","operation":"Update","apiVersion":"v1","time":"2001-02-03T04:05:06Z"}`, - Path: fieldpath.MakePathOrDie("spec", "replicas"), - }, - merge.Conflict{ - Manager: `{"manager":"bar","operation":"Apply"}`, - Path: fieldpath.MakePathOrDie("metadata", "labels", "app"), - }, - }, - expected: &errors.StatusError{ - ErrStatus: metav1.Status{ - Status: metav1.StatusFailure, - Code: http.StatusConflict, - Reason: metav1.StatusReasonConflict, - Details: &metav1.StatusDetails{ - Causes: []metav1.StatusCause{ - { - Type: metav1.CauseTypeFieldManagerConflict, - Message: `conflict with "foo" using v1 at 2001-02-03T04:05:06Z`, - Field: ".spec.replicas", - }, - { - Type: metav1.CauseTypeFieldManagerConflict, - Message: `conflict with "bar"`, - Field: ".metadata.labels.app", - }, - }, - }, - Message: `Apply failed with 2 conflicts: conflicts with "bar": -- .metadata.labels.app -conflicts with "foo" using v1 at 2001-02-03T04:05:06Z: -- .spec.replicas`, - }, - }, - }, - } - for _, tc := range testCases { - actual := internal.NewConflictError(tc.conflict) - if !reflect.DeepEqual(tc.expected, actual) { - t.Errorf("Expected to get\n%+v\nbut got\n%+v", tc.expected.ErrStatus, actual.ErrStatus) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields.go deleted file mode 100644 index 60117211a6a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "bytes" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -// EmptyFields represents a set with no paths -// It looks like metav1.Fields{Raw: []byte("{}")} -var EmptyFields = func() metav1.FieldsV1 { - f, err := SetToFields(*fieldpath.NewSet()) - if err != nil { - panic("should never happen") - } - return f -}() - -// FieldsToSet creates a set paths from an input trie of fields -func FieldsToSet(f metav1.FieldsV1) (s fieldpath.Set, err error) { - err = s.FromJSON(bytes.NewReader(f.Raw)) - return s, err -} - -// SetToFields creates a trie of fields from an input set of paths -func SetToFields(s fieldpath.Set) (f metav1.FieldsV1, err error) { - f.Raw, err = s.ToJSON() - return f, err -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields_test.go deleted file mode 100644 index 01976cd260b..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/fields_test.go +++ /dev/null @@ -1,145 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "reflect" - "strings" - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -// TestFieldsRoundTrip tests that a fields trie can be round tripped as a path set -func TestFieldsRoundTrip(t *testing.T) { - tests := []metav1.FieldsV1{ - { - Raw: []byte(`{"f:metadata":{".":{},"f:name":{}}}`), - }, - EmptyFields, - } - - for _, test := range tests { - set, err := FieldsToSet(test) - if err != nil { - t.Fatalf("Failed to create path set: %v", err) - } - output, err := SetToFields(set) - if err != nil { - t.Fatalf("Failed to create fields trie from path set: %v", err) - } - if !reflect.DeepEqual(test, output) { - t.Fatalf("Expected round-trip:\ninput: %v\noutput: %v", test, output) - } - } -} - -// TestFieldsToSetError tests that errors are picked up by FieldsToSet -func TestFieldsToSetError(t *testing.T) { - tests := []struct { - fields metav1.FieldsV1 - errString string - }{ - { - fields: metav1.FieldsV1{ - Raw: []byte(`{"k:{invalid json}":{"f:name":{},".":{}}}`), - }, - errString: "ReadObjectCB", - }, - } - - for _, test := range tests { - _, err := FieldsToSet(test.fields) - if err == nil || !strings.Contains(err.Error(), test.errString) { - t.Fatalf("Expected error to contain %q but got: %v", test.errString, err) - } - } -} - -// TestSetToFieldsError tests that errors are picked up by SetToFields -func TestSetToFieldsError(t *testing.T) { - validName := "ok" - invalidPath := fieldpath.Path([]fieldpath.PathElement{{}, {FieldName: &validName}}) - - tests := []struct { - set fieldpath.Set - errString string - }{ - { - set: *fieldpath.NewSet(invalidPath), - errString: "invalid PathElement", - }, - } - - for _, test := range tests { - _, err := SetToFields(test.set) - if err == nil || !strings.Contains(err.Error(), test.errString) { - t.Fatalf("Expected error to contain %q but got: %v", test.errString, err) - } - } -} - -func BenchmarkSetToFields(b *testing.B) { - set := fieldpath.NewSet( - fieldpath.MakePathOrDie("foo", 0, "bar", "baz"), - fieldpath.MakePathOrDie("foo", 0, "bar", "zot"), - fieldpath.MakePathOrDie("foo", 0, "bar"), - fieldpath.MakePathOrDie("foo", 0), - fieldpath.MakePathOrDie("foo", 1, "bar", "baz"), - fieldpath.MakePathOrDie("foo", 1, "bar"), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "first")), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "first"), "bar"), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "second"), "bar"), - ) - - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := SetToFields(*set) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkFieldsToSet(b *testing.B) { - set := fieldpath.NewSet( - fieldpath.MakePathOrDie("foo", 0, "bar", "baz"), - fieldpath.MakePathOrDie("foo", 0, "bar", "zot"), - fieldpath.MakePathOrDie("foo", 0, "bar"), - fieldpath.MakePathOrDie("foo", 0), - fieldpath.MakePathOrDie("foo", 1, "bar", "baz"), - fieldpath.MakePathOrDie("foo", 1, "bar"), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "first")), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "first"), "bar"), - fieldpath.MakePathOrDie("qux", fieldpath.KeyByFields("name", "second"), "bar"), - ) - fields, err := SetToFields(*set) - if err != nil { - b.Fatal(err) - } - b.ReportAllocs() - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := FieldsToSet(fields) - if err != nil { - b.Fatal(err) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/gvkparser.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/gvkparser.go deleted file mode 100644 index f917fcd435a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/gvkparser.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kube-openapi/pkg/schemaconv" - "k8s.io/kube-openapi/pkg/util/proto" - "sigs.k8s.io/structured-merge-diff/v3/typed" -) - -// groupVersionKindExtensionKey is the key used to lookup the -// GroupVersionKind value for an object definition from the -// definition's "extensions" map. -const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind" - -type gvkParser struct { - gvks map[schema.GroupVersionKind]string - parser typed.Parser -} - -func (p *gvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType { - typeName, ok := p.gvks[gvk] - if !ok { - return nil - } - t := p.parser.Type(typeName) - return &t -} - -func newGVKParser(models proto.Models, preserveUnknownFields bool) (*gvkParser, error) { - typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields) - if err != nil { - return nil, fmt.Errorf("failed to convert models to schema: %v", err) - } - parser := gvkParser{ - gvks: map[schema.GroupVersionKind]string{}, - } - parser.parser = typed.Parser{Schema: *typeSchema} - for _, modelName := range models.ListModels() { - model := models.LookupModel(modelName) - if model == nil { - panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName)) - } - gvkList := parseGroupVersionKind(model) - for _, gvk := range gvkList { - if len(gvk.Kind) > 0 { - _, ok := parser.gvks[gvk] - if ok { - return nil, fmt.Errorf("duplicate entry for %v", gvk) - } - parser.gvks[gvk] = modelName - } - } - } - return &parser, nil -} - -// Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one. -func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind { - extensions := s.GetExtensions() - - gvkListResult := []schema.GroupVersionKind{} - - // Get the extensions - gvkExtension, ok := extensions[groupVersionKindExtensionKey] - if !ok { - return []schema.GroupVersionKind{} - } - - // gvk extension must be a list of at least 1 element. - gvkList, ok := gvkExtension.([]interface{}) - if !ok { - return []schema.GroupVersionKind{} - } - - for _, gvk := range gvkList { - // gvk extension list must be a map with group, version, and - // kind fields - gvkMap, ok := gvk.(map[interface{}]interface{}) - if !ok { - continue - } - group, ok := gvkMap["group"].(string) - if !ok { - continue - } - version, ok := gvkMap["version"].(string) - if !ok { - continue - } - kind, ok := gvkMap["kind"].(string) - if !ok { - continue - } - - gvkListResult = append(gvkListResult, schema.GroupVersionKind{ - Group: group, - Version: version, - Kind: kind, - }) - } - - return gvkListResult -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields.go deleted file mode 100644 index 4778fa79259..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields.go +++ /dev/null @@ -1,238 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "encoding/json" - "fmt" - "sort" - - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -// ManagedInterface groups a fieldpath.ManagedFields together with the timestamps associated with each operation. -type ManagedInterface interface { - // Fields gets the fieldpath.ManagedFields. - Fields() fieldpath.ManagedFields - - // Times gets the timestamps associated with each operation. - Times() map[string]*metav1.Time -} - -type managedStruct struct { - fields fieldpath.ManagedFields - times map[string]*metav1.Time -} - -var _ ManagedInterface = &managedStruct{} - -// Fields implements ManagedInterface. -func (m *managedStruct) Fields() fieldpath.ManagedFields { - return m.fields -} - -// Times implements ManagedInterface. -func (m *managedStruct) Times() map[string]*metav1.Time { - return m.times -} - -// NewManaged creates a ManagedInterface from a fieldpath.ManagedFields and the timestamps associated with each operation. -func NewManaged(f fieldpath.ManagedFields, t map[string]*metav1.Time) ManagedInterface { - return &managedStruct{ - fields: f, - times: t, - } -} - -// RemoveObjectManagedFields removes the ManagedFields from the object -// before we merge so that it doesn't appear in the ManagedFields -// recursively. -func RemoveObjectManagedFields(obj runtime.Object) { - accessor, err := meta.Accessor(obj) - if err != nil { - panic(fmt.Sprintf("couldn't get accessor: %v", err)) - } - accessor.SetManagedFields(nil) -} - -// DecodeObjectManagedFields extracts and converts the objects ManagedFields into a fieldpath.ManagedFields. -func DecodeObjectManagedFields(from runtime.Object) (ManagedInterface, error) { - if from == nil { - return &managedStruct{}, nil - } - accessor, err := meta.Accessor(from) - if err != nil { - panic(fmt.Sprintf("couldn't get accessor: %v", err)) - } - - managed, err := decodeManagedFields(accessor.GetManagedFields()) - if err != nil { - return nil, fmt.Errorf("failed to convert managed fields from API: %v", err) - } - return &managed, nil -} - -// EncodeObjectManagedFields converts and stores the fieldpathManagedFields into the objects ManagedFields -func EncodeObjectManagedFields(obj runtime.Object, managed ManagedInterface) error { - accessor, err := meta.Accessor(obj) - if err != nil { - panic(fmt.Sprintf("couldn't get accessor: %v", err)) - } - - encodedManagedFields, err := encodeManagedFields(managed) - if err != nil { - return fmt.Errorf("failed to convert back managed fields to API: %v", err) - } - accessor.SetManagedFields(encodedManagedFields) - - return nil -} - -// decodeManagedFields converts ManagedFields from the wire format (api format) -// to the format used by sigs.k8s.io/structured-merge-diff -func decodeManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (managed managedStruct, err error) { - managed.fields = make(fieldpath.ManagedFields, len(encodedManagedFields)) - managed.times = make(map[string]*metav1.Time, len(encodedManagedFields)) - for _, encodedVersionedSet := range encodedManagedFields { - manager, err := BuildManagerIdentifier(&encodedVersionedSet) - if err != nil { - return managedStruct{}, fmt.Errorf("error decoding manager from %v: %v", encodedVersionedSet, err) - } - managed.fields[manager], err = decodeVersionedSet(&encodedVersionedSet) - if err != nil { - return managedStruct{}, fmt.Errorf("error decoding versioned set from %v: %v", encodedVersionedSet, err) - } - managed.times[manager] = encodedVersionedSet.Time - } - return managed, nil -} - -// BuildManagerIdentifier creates a manager identifier string from a ManagedFieldsEntry -func BuildManagerIdentifier(encodedManager *metav1.ManagedFieldsEntry) (manager string, err error) { - encodedManagerCopy := *encodedManager - - // Never include fields type in the manager identifier - encodedManagerCopy.FieldsType = "" - - // Never include the fields in the manager identifier - encodedManagerCopy.FieldsV1 = nil - - // Never include the time in the manager identifier - encodedManagerCopy.Time = nil - - // For appliers, don't include the APIVersion in the manager identifier, - // so it will always have the same manager identifier each time it applied. - if encodedManager.Operation == metav1.ManagedFieldsOperationApply { - encodedManagerCopy.APIVersion = "" - } - - // Use the remaining fields to build the manager identifier - b, err := json.Marshal(&encodedManagerCopy) - if err != nil { - return "", fmt.Errorf("error marshalling manager identifier: %v", err) - } - - return string(b), nil -} - -func decodeVersionedSet(encodedVersionedSet *metav1.ManagedFieldsEntry) (versionedSet fieldpath.VersionedSet, err error) { - fields := EmptyFields - if encodedVersionedSet.FieldsV1 != nil { - fields = *encodedVersionedSet.FieldsV1 - } - set, err := FieldsToSet(fields) - if err != nil { - return nil, fmt.Errorf("error decoding set: %v", err) - } - return fieldpath.NewVersionedSet(&set, fieldpath.APIVersion(encodedVersionedSet.APIVersion), encodedVersionedSet.Operation == metav1.ManagedFieldsOperationApply), nil -} - -// encodeManagedFields converts ManagedFields from the format used by -// sigs.k8s.io/structured-merge-diff to the wire format (api format) -func encodeManagedFields(managed ManagedInterface) (encodedManagedFields []metav1.ManagedFieldsEntry, err error) { - if len(managed.Fields()) == 0 { - return nil, nil - } - encodedManagedFields = []metav1.ManagedFieldsEntry{} - for manager := range managed.Fields() { - versionedSet := managed.Fields()[manager] - v, err := encodeManagerVersionedSet(manager, versionedSet) - if err != nil { - return nil, fmt.Errorf("error encoding versioned set for %v: %v", manager, err) - } - if t, ok := managed.Times()[manager]; ok { - v.Time = t - } - encodedManagedFields = append(encodedManagedFields, *v) - } - return sortEncodedManagedFields(encodedManagedFields) -} - -func sortEncodedManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (sortedManagedFields []metav1.ManagedFieldsEntry, err error) { - sort.Slice(encodedManagedFields, func(i, j int) bool { - p, q := encodedManagedFields[i], encodedManagedFields[j] - - if p.Operation != q.Operation { - return p.Operation < q.Operation - } - - pSeconds, qSeconds := int64(0), int64(0) - if p.Time != nil { - pSeconds = p.Time.Unix() - } - if q.Time != nil { - qSeconds = q.Time.Unix() - } - if pSeconds != qSeconds { - return pSeconds < qSeconds - } - - if p.Manager != q.Manager { - return p.Manager < q.Manager - } - return p.APIVersion < q.APIVersion - }) - - return encodedManagedFields, nil -} - -func encodeManagerVersionedSet(manager string, versionedSet fieldpath.VersionedSet) (encodedVersionedSet *metav1.ManagedFieldsEntry, err error) { - encodedVersionedSet = &metav1.ManagedFieldsEntry{} - - // Get as many fields as we can from the manager identifier - err = json.Unmarshal([]byte(manager), encodedVersionedSet) - if err != nil { - return nil, fmt.Errorf("error unmarshalling manager identifier %v: %v", manager, err) - } - - // Get the APIVersion, Operation, and Fields from the VersionedSet - encodedVersionedSet.APIVersion = string(versionedSet.APIVersion()) - if versionedSet.Applied() { - encodedVersionedSet.Operation = metav1.ManagedFieldsOperationApply - } - encodedVersionedSet.FieldsType = "FieldsV1" - fields, err := SetToFields(*versionedSet.Set()) - if err != nil { - return nil, fmt.Errorf("error encoding set: %v", err) - } - encodedVersionedSet.FieldsV1 = &fields - - return encodedVersionedSet, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields_test.go deleted file mode 100644 index 4b92ea6ec33..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/managedfields_test.go +++ /dev/null @@ -1,363 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "fmt" - "reflect" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "sigs.k8s.io/yaml" -) - -// TestRoundTripManagedFields will roundtrip ManagedFields from the wire format -// (api format) to the format used by sigs.k8s.io/structured-merge-diff and back -func TestRoundTripManagedFields(t *testing.T) { - tests := []string{ - `null -`, - `- apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - v:3: - f:alsoPi: {} - v:3.1415: - f:pi: {} - v:false: - f:notTrue: {} - manager: foo - operation: Update - time: "2001-02-03T04:05:06Z" -- apiVersion: v1beta1 - fieldsType: FieldsV1 - fieldsV1: - i:5: - f:i: {} - manager: foo - operation: Update - time: "2011-12-13T14:15:16Z" -`, - `- apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - f:spec: - f:containers: - k:{"name":"c"}: - f:image: {} - f:name: {} - manager: foo - operation: Apply -`, - `- apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - f:apiVersion: {} - f:kind: {} - f:metadata: - f:labels: - f:app: {} - f:name: {} - f:spec: - f:replicas: {} - f:selector: - f:matchLabels: - f:app: {} - f:template: - f:medatada: - f:labels: - f:app: {} - f:spec: - f:containers: - k:{"name":"nginx"}: - .: {} - f:image: {} - f:name: {} - f:ports: - i:0: - f:containerPort: {} - manager: foo - operation: Update -`, - `- apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - f:allowVolumeExpansion: {} - f:apiVersion: {} - f:kind: {} - f:metadata: - f:name: {} - f:parameters: - f:resturl: {} - f:restuser: {} - f:secretName: {} - f:secretNamespace: {} - f:provisioner: {} - manager: foo - operation: Apply -`, - `- apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - f:apiVersion: {} - f:kind: {} - f:metadata: - f:name: {} - f:spec: - f:group: {} - f:names: - f:kind: {} - f:plural: {} - f:shortNames: - i:0: {} - f:singular: {} - f:scope: {} - f:versions: - k:{"name":"v1"}: - f:name: {} - f:served: {} - f:storage: {} - manager: foo - operation: Update -`, - } - - for _, test := range tests { - t.Run(test, func(t *testing.T) { - var unmarshaled []metav1.ManagedFieldsEntry - if err := yaml.Unmarshal([]byte(test), &unmarshaled); err != nil { - t.Fatalf("did not expect yaml unmarshalling error but got: %v", err) - } - decoded, err := decodeManagedFields(unmarshaled) - if err != nil { - t.Fatalf("did not expect decoding error but got: %v", err) - } - encoded, err := encodeManagedFields(&decoded) - if err != nil { - t.Fatalf("did not expect encoding error but got: %v", err) - } - marshaled, err := yaml.Marshal(&encoded) - if err != nil { - t.Fatalf("did not expect yaml marshalling error but got: %v", err) - } - if !reflect.DeepEqual(string(marshaled), test) { - t.Fatalf("expected:\n%v\nbut got:\n%v", test, string(marshaled)) - } - }) - } -} - -func TestBuildManagerIdentifier(t *testing.T) { - tests := []struct { - managedFieldsEntry string - expected string - }{ - { - managedFieldsEntry: ` -apiVersion: v1 -fieldsV1: - f:apiVersion: {} -manager: foo -operation: Update -time: "2001-02-03T04:05:06Z" -`, - expected: "{\"manager\":\"foo\",\"operation\":\"Update\",\"apiVersion\":\"v1\"}", - }, - { - managedFieldsEntry: ` -apiVersion: v1 -fieldsV1: - f:apiVersion: {} -manager: foo -operation: Apply -time: "2001-02-03T04:05:06Z" -`, - expected: "{\"manager\":\"foo\",\"operation\":\"Apply\"}", - }, - } - - for _, test := range tests { - t.Run(test.managedFieldsEntry, func(t *testing.T) { - var unmarshaled metav1.ManagedFieldsEntry - if err := yaml.Unmarshal([]byte(test.managedFieldsEntry), &unmarshaled); err != nil { - t.Fatalf("did not expect yaml unmarshalling error but got: %v", err) - } - decoded, err := BuildManagerIdentifier(&unmarshaled) - if err != nil { - t.Fatalf("did not expect decoding error but got: %v", err) - } - if !reflect.DeepEqual(decoded, test.expected) { - t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, decoded) - } - }) - } -} - -func TestSortEncodedManagedFields(t *testing.T) { - tests := []struct { - name string - managedFields []metav1.ManagedFieldsEntry - expected []metav1.ManagedFieldsEntry - }{ - { - name: "empty", - managedFields: []metav1.ManagedFieldsEntry{}, - expected: []metav1.ManagedFieldsEntry{}, - }, - { - name: "nil", - managedFields: nil, - expected: nil, - }, - { - name: "remains untouched", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - }, - { - name: "manager without time first", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - }, - { - name: "manager without time first name last", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - }, - { - name: "apply first", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - }, - { - name: "newest last", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - }, - }, - { - name: "manager last", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - }, - }, - { - name: "manager sorted", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - {Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - {Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")}, - {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - {Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")}, - {Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")}, - }, - }, - { - name: "sort drops nanoseconds", - managedFields: []metav1.ManagedFieldsEntry{ - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}}, - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}}, - }, - expected: []metav1.ManagedFieldsEntry{ - {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}}, - {Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}}, - {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}}, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - sorted, err := sortEncodedManagedFields(test.managedFields) - if err != nil { - t.Fatalf("did not expect error when sorting but got: %v", err) - } - if !reflect.DeepEqual(sorted, test.expected) { - t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, sorted) - } - }) - } -} - -func parseTimeOrPanic(s string) *metav1.Time { - t, err := time.Parse(time.RFC3339, s) - if err != nil { - panic(fmt.Sprintf("failed to parse time %s, got: %v", s, err)) - } - return &metav1.Time{Time: t.UTC()} -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go deleted file mode 100644 index 393420a70b0..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - "strings" - - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/value" -) - -const ( - // Field indicates that the content of this path element is a field's name - Field = "f" - - // Value indicates that the content of this path element is a field's value - Value = "v" - - // Index indicates that the content of this path element is an index in an array - Index = "i" - - // Key indicates that the content of this path element is a key value map - Key = "k" - - // Separator separates the type of a path element from the contents - Separator = ":" -) - -// NewPathElement parses a serialized path element -func NewPathElement(s string) (fieldpath.PathElement, error) { - split := strings.SplitN(s, Separator, 2) - if len(split) < 2 { - return fieldpath.PathElement{}, fmt.Errorf("missing colon: %v", s) - } - switch split[0] { - case Field: - return fieldpath.PathElement{ - FieldName: &split[1], - }, nil - case Value: - val, err := value.FromJSON([]byte(split[1])) - if err != nil { - return fieldpath.PathElement{}, err - } - return fieldpath.PathElement{ - Value: &val, - }, nil - case Index: - i, err := strconv.Atoi(split[1]) - if err != nil { - return fieldpath.PathElement{}, err - } - return fieldpath.PathElement{ - Index: &i, - }, nil - case Key: - kv := map[string]json.RawMessage{} - err := json.Unmarshal([]byte(split[1]), &kv) - if err != nil { - return fieldpath.PathElement{}, err - } - fields := value.FieldList{} - for k, v := range kv { - b, err := json.Marshal(v) - if err != nil { - return fieldpath.PathElement{}, err - } - val, err := value.FromJSON(b) - if err != nil { - return fieldpath.PathElement{}, err - } - - fields = append(fields, value.Field{ - Name: k, - Value: val, - }) - } - return fieldpath.PathElement{ - Key: &fields, - }, nil - default: - // Ignore unknown key types - return fieldpath.PathElement{}, nil - } -} - -// PathElementString serializes a path element -func PathElementString(pe fieldpath.PathElement) (string, error) { - switch { - case pe.FieldName != nil: - return Field + Separator + *pe.FieldName, nil - case pe.Key != nil: - kv := map[string]json.RawMessage{} - for _, k := range *pe.Key { - b, err := value.ToJSON(k.Value) - if err != nil { - return "", err - } - m := json.RawMessage{} - err = json.Unmarshal(b, &m) - if err != nil { - return "", err - } - kv[k.Name] = m - } - b, err := json.Marshal(kv) - if err != nil { - return "", err - } - return Key + ":" + string(b), nil - case pe.Value != nil: - b, err := value.ToJSON(*pe.Value) - if err != nil { - return "", err - } - return Value + ":" + string(b), nil - case pe.Index != nil: - return Index + ":" + strconv.Itoa(*pe.Index), nil - default: - return "", errors.New("Invalid type of path element") - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement_test.go deleted file mode 100644 index bd119e03c2e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import "testing" - -func TestPathElementRoundTrip(t *testing.T) { - tests := []string{ - `i:0`, - `i:1234`, - `f:`, - `f:spec`, - `f:more-complicated-string`, - `k:{"name":"my-container"}`, - `k:{"port":"8080","protocol":"TCP"}`, - `k:{"optionalField":null}`, - `k:{"jsonField":{"A":1,"B":null,"C":"D","E":{"F":"G"}}}`, - `k:{"listField":["1","2","3"]}`, - `v:null`, - `v:"some-string"`, - `v:1234`, - `v:{"some":"json"}`, - } - - for _, test := range tests { - t.Run(test, func(t *testing.T) { - pe, err := NewPathElement(test) - if err != nil { - t.Fatalf("Failed to create path element: %v", err) - } - output, err := PathElementString(pe) - if err != nil { - t.Fatalf("Failed to create string from path element: %v", err) - } - if test != output { - t.Fatalf("Expected round-trip:\ninput: %v\noutput: %v", test, output) - } - }) - } -} - -func TestPathElementIgnoreUnknown(t *testing.T) { - _, err := NewPathElement("r:Hello") - if err != nil { - t.Fatalf("Unknown qualifiers should be ignored") - } -} - -func TestNewPathElementError(t *testing.T) { - tests := []string{ - ``, - `no-colon`, - `i:index is not a number`, - `i:1.23`, - `i:`, - `v:invalid json`, - `v:`, - `k:invalid json`, - `k:{"name":invalid}`, - } - - for _, test := range tests { - t.Run(test, func(t *testing.T) { - _, err := NewPathElement(test) - if err == nil { - t.Fatalf("Expected error, no error found") - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/testdata/swagger.json b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/testdata/swagger.json deleted file mode 100644 index fcc6fd9a1f5..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/testdata/swagger.json +++ /dev/null @@ -1,4195 +0,0 @@ -{ - "definitions": { - "io.k8s.api.apps.v1.Deployment": { - "description": "Deployment enables declarative updates for Pods and ReplicaSets.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object metadata." - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentSpec", - "description": "Specification of the desired behavior of the Deployment." - }, - "status": { - "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStatus", - "description": "Most recently observed status of the Deployment." - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "apps", - "kind": "Deployment", - "version": "v1" - } - ] - }, - "io.k8s.api.apps.v1.DeploymentCondition": { - "description": "DeploymentCondition describes the state of a deployment at a certain point.", - "properties": { - "lastTransitionTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time the condition transitioned from one status to another." - }, - "lastUpdateTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "The last time this condition was updated." - }, - "message": { - "description": "A human readable message indicating details about the transition.", - "type": "string" - }, - "reason": { - "description": "The reason for the condition's last transition.", - "type": "string" - }, - "status": { - "description": "Status of the condition, one of True, False, Unknown.", - "type": "string" - }, - "type": { - "description": "Type of deployment condition.", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.apps.v1.DeploymentSpec": { - "description": "DeploymentSpec is the specification of the desired behavior of the Deployment.", - "properties": { - "minReadySeconds": { - "description": "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)", - "format": "int32", - "type": "integer" - }, - "paused": { - "description": "Indicates that the deployment is paused.", - "type": "boolean" - }, - "progressDeadlineSeconds": { - "description": "The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.", - "format": "int32", - "type": "integer" - }, - "revisionHistoryLimit": { - "description": "The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10.", - "format": "int32", - "type": "integer" - }, - "selector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels." - }, - "strategy": { - "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy", - "description": "The deployment strategy to use to replace existing pods with new ones.", - "x-kubernetes-patch-strategy": "retainKeys" - }, - "template": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", - "description": "Template describes the pods that will be created." - } - }, - "required": [ - "selector", - "template" - ], - "type": "object" - }, - "io.k8s.api.apps.v1.DeploymentStatus": { - "description": "DeploymentStatus is the most recently observed status of the Deployment.", - "properties": { - "availableReplicas": { - "description": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "collisionCount": { - "description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.", - "format": "int32", - "type": "integer" - }, - "conditions": { - "description": "Represents the latest available observations of a deployment's current state.", - "items": { - "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentCondition" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge" - }, - "observedGeneration": { - "description": "The generation observed by the deployment controller.", - "format": "int64", - "type": "integer" - }, - "readyReplicas": { - "description": "Total number of ready pods targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Total number of non-terminated pods targeted by this deployment (their labels match the selector).", - "format": "int32", - "type": "integer" - }, - "unavailableReplicas": { - "description": "Total number of unavailable pods targeted by this deployment. This is the total number of pods that are still required for the deployment to have 100% available capacity. They may either be pods that are running but not yet available or pods that still have not been created.", - "format": "int32", - "type": "integer" - }, - "updatedReplicas": { - "description": "Total number of non-terminated pods targeted by this deployment that have the desired template spec.", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1.DeploymentStrategy": { - "description": "DeploymentStrategy describes how to replace existing pods with new ones.", - "properties": { - "rollingUpdate": { - "$ref": "#/definitions/io.k8s.api.apps.v1.RollingUpdateDeployment", - "description": "Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate." - }, - "type": { - "description": "Type of deployment. Can be \"Recreate\" or \"RollingUpdate\". Default is RollingUpdate.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1.RollingUpdateDeployment": { - "description": "Spec to control the desired behavior of rolling update.", - "properties": { - "maxSurge": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods." - }, - "maxUnavailable": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods." - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta1.Deployment": { - "description": "DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for more information. Deployment enables declarative updates for Pods and ReplicaSets.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object metadata." - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.DeploymentSpec", - "description": "Specification of the desired behavior of the Deployment." - }, - "status": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.DeploymentStatus", - "description": "Most recently observed status of the Deployment." - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "apps", - "kind": "Deployment", - "version": "v1beta1" - } - ] - }, - "io.k8s.api.apps.v1beta1.DeploymentCondition": { - "description": "DeploymentCondition describes the state of a deployment at a certain point.", - "properties": { - "lastTransitionTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time the condition transitioned from one status to another." - }, - "lastUpdateTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "The last time this condition was updated." - }, - "message": { - "description": "A human readable message indicating details about the transition.", - "type": "string" - }, - "reason": { - "description": "The reason for the condition's last transition.", - "type": "string" - }, - "status": { - "description": "Status of the condition, one of True, False, Unknown.", - "type": "string" - }, - "type": { - "description": "Type of deployment condition.", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.apps.v1beta1.DeploymentRollback": { - "description": "DEPRECATED. DeploymentRollback stores the information required to rollback a deployment.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "name": { - "description": "Required: This must match the Name of a deployment.", - "type": "string" - }, - "rollbackTo": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.RollbackConfig", - "description": "The config of this deployment rollback." - }, - "updatedAnnotations": { - "additionalProperties": { - "type": "string" - }, - "description": "The annotations to be updated to a deployment", - "type": "object" - } - }, - "required": [ - "name", - "rollbackTo" - ], - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "apps", - "kind": "DeploymentRollback", - "version": "v1beta1" - } - ] - }, - "io.k8s.api.apps.v1beta1.DeploymentSpec": { - "description": "DeploymentSpec is the specification of the desired behavior of the Deployment.", - "properties": { - "minReadySeconds": { - "description": "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)", - "format": "int32", - "type": "integer" - }, - "paused": { - "description": "Indicates that the deployment is paused.", - "type": "boolean" - }, - "progressDeadlineSeconds": { - "description": "The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.", - "format": "int32", - "type": "integer" - }, - "revisionHistoryLimit": { - "description": "The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 2.", - "format": "int32", - "type": "integer" - }, - "rollbackTo": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.RollbackConfig", - "description": "DEPRECATED. The config this deployment is rolling back to. Will be cleared after rollback is done." - }, - "selector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment." - }, - "strategy": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.DeploymentStrategy", - "description": "The deployment strategy to use to replace existing pods with new ones.", - "x-kubernetes-patch-strategy": "retainKeys" - }, - "template": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", - "description": "Template describes the pods that will be created." - } - }, - "required": [ - "template" - ], - "type": "object" - }, - "io.k8s.api.apps.v1beta1.DeploymentStatus": { - "description": "DeploymentStatus is the most recently observed status of the Deployment.", - "properties": { - "availableReplicas": { - "description": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "collisionCount": { - "description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.", - "format": "int32", - "type": "integer" - }, - "conditions": { - "description": "Represents the latest available observations of a deployment's current state.", - "items": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.DeploymentCondition" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge" - }, - "observedGeneration": { - "description": "The generation observed by the deployment controller.", - "format": "int64", - "type": "integer" - }, - "readyReplicas": { - "description": "Total number of ready pods targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Total number of non-terminated pods targeted by this deployment (their labels match the selector).", - "format": "int32", - "type": "integer" - }, - "unavailableReplicas": { - "description": "Total number of unavailable pods targeted by this deployment. This is the total number of pods that are still required for the deployment to have 100% available capacity. They may either be pods that are running but not yet available or pods that still have not been created.", - "format": "int32", - "type": "integer" - }, - "updatedReplicas": { - "description": "Total number of non-terminated pods targeted by this deployment that have the desired template spec.", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta1.DeploymentStrategy": { - "description": "DeploymentStrategy describes how to replace existing pods with new ones.", - "properties": { - "rollingUpdate": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta1.RollingUpdateDeployment", - "description": "Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate." - }, - "type": { - "description": "Type of deployment. Can be \"Recreate\" or \"RollingUpdate\". Default is RollingUpdate.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta1.RollbackConfig": { - "description": "DEPRECATED.", - "properties": { - "revision": { - "description": "The revision to rollback to. If set to 0, rollback to the last revision.", - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta1.RollingUpdateDeployment": { - "description": "Spec to control the desired behavior of rolling update.", - "properties": { - "maxSurge": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods." - }, - "maxUnavailable": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods." - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta2.Deployment": { - "description": "DEPRECATED - This group version of Deployment is deprecated by apps/v1/Deployment. See the release notes for more information. Deployment enables declarative updates for Pods and ReplicaSets.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object metadata." - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta2.DeploymentSpec", - "description": "Specification of the desired behavior of the Deployment." - }, - "status": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta2.DeploymentStatus", - "description": "Most recently observed status of the Deployment." - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "apps", - "kind": "Deployment", - "version": "v1beta2" - } - ] - }, - "io.k8s.api.apps.v1beta2.DeploymentCondition": { - "description": "DeploymentCondition describes the state of a deployment at a certain point.", - "properties": { - "lastTransitionTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time the condition transitioned from one status to another." - }, - "lastUpdateTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "The last time this condition was updated." - }, - "message": { - "description": "A human readable message indicating details about the transition.", - "type": "string" - }, - "reason": { - "description": "The reason for the condition's last transition.", - "type": "string" - }, - "status": { - "description": "Status of the condition, one of True, False, Unknown.", - "type": "string" - }, - "type": { - "description": "Type of deployment condition.", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.apps.v1beta2.DeploymentSpec": { - "description": "DeploymentSpec is the specification of the desired behavior of the Deployment.", - "properties": { - "minReadySeconds": { - "description": "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)", - "format": "int32", - "type": "integer" - }, - "paused": { - "description": "Indicates that the deployment is paused.", - "type": "boolean" - }, - "progressDeadlineSeconds": { - "description": "The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.", - "format": "int32", - "type": "integer" - }, - "revisionHistoryLimit": { - "description": "The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10.", - "format": "int32", - "type": "integer" - }, - "selector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels." - }, - "strategy": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta2.DeploymentStrategy", - "description": "The deployment strategy to use to replace existing pods with new ones.", - "x-kubernetes-patch-strategy": "retainKeys" - }, - "template": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", - "description": "Template describes the pods that will be created." - } - }, - "required": [ - "selector", - "template" - ], - "type": "object" - }, - "io.k8s.api.apps.v1beta2.DeploymentStatus": { - "description": "DeploymentStatus is the most recently observed status of the Deployment.", - "properties": { - "availableReplicas": { - "description": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "collisionCount": { - "description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.", - "format": "int32", - "type": "integer" - }, - "conditions": { - "description": "Represents the latest available observations of a deployment's current state.", - "items": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta2.DeploymentCondition" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge" - }, - "observedGeneration": { - "description": "The generation observed by the deployment controller.", - "format": "int64", - "type": "integer" - }, - "readyReplicas": { - "description": "Total number of ready pods targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Total number of non-terminated pods targeted by this deployment (their labels match the selector).", - "format": "int32", - "type": "integer" - }, - "unavailableReplicas": { - "description": "Total number of unavailable pods targeted by this deployment. This is the total number of pods that are still required for the deployment to have 100% available capacity. They may either be pods that are running but not yet available or pods that still have not been created.", - "format": "int32", - "type": "integer" - }, - "updatedReplicas": { - "description": "Total number of non-terminated pods targeted by this deployment that have the desired template spec.", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta2.DeploymentStrategy": { - "description": "DeploymentStrategy describes how to replace existing pods with new ones.", - "properties": { - "rollingUpdate": { - "$ref": "#/definitions/io.k8s.api.apps.v1beta2.RollingUpdateDeployment", - "description": "Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate." - }, - "type": { - "description": "Type of deployment. Can be \"Recreate\" or \"RollingUpdate\". Default is RollingUpdate.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.apps.v1beta2.RollingUpdateDeployment": { - "description": "Spec to control the desired behavior of rolling update.", - "properties": { - "maxSurge": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods." - }, - "maxUnavailable": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource": { - "description": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling.", - "properties": { - "fsType": { - "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", - "type": "string" - }, - "partition": { - "description": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).", - "format": "int32", - "type": "integer" - }, - "readOnly": { - "description": "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\". If omitted, the default is \"false\". More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", - "type": "boolean" - }, - "volumeID": { - "description": "Unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", - "type": "string" - } - }, - "required": [ - "volumeID" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Affinity": { - "description": "Affinity is a group of affinity scheduling rules.", - "properties": { - "nodeAffinity": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeAffinity", - "description": "Describes node affinity scheduling rules for the pod." - }, - "podAffinity": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodAffinity", - "description": "Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s))." - }, - "podAntiAffinity": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodAntiAffinity", - "description": "Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s))." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.AttachedVolume": { - "description": "AttachedVolume describes a volume attached to a node", - "properties": { - "devicePath": { - "description": "DevicePath represents the device path where the volume should be available", - "type": "string" - }, - "name": { - "description": "Name of the attached volume", - "type": "string" - } - }, - "required": [ - "name", - "devicePath" - ], - "type": "object" - }, - "io.k8s.api.core.v1.AzureDiskVolumeSource": { - "description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.", - "properties": { - "cachingMode": { - "description": "Host Caching mode: None, Read Only, Read Write.", - "type": "string" - }, - "diskName": { - "description": "The Name of the data disk in the blob storage", - "type": "string" - }, - "diskURI": { - "description": "The URI the data disk in the blob storage", - "type": "string" - }, - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "kind": { - "description": "Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", - "type": "string" - }, - "readOnly": { - "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - } - }, - "required": [ - "diskName", - "diskURI" - ], - "type": "object" - }, - "io.k8s.api.core.v1.AzureFileVolumeSource": { - "description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.", - "properties": { - "readOnly": { - "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "secretName": { - "description": "the name of secret that contains Azure Storage Account Name and Key", - "type": "string" - }, - "shareName": { - "description": "Share Name", - "type": "string" - } - }, - "required": [ - "secretName", - "shareName" - ], - "type": "object" - }, - "io.k8s.api.core.v1.CSIVolumeSource": { - "description": "Represents a source location of a volume to mount, managed by an external CSI driver", - "properties": { - "driver": { - "description": "Driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster.", - "type": "string" - }, - "fsType": { - "description": "Filesystem type to mount. Ex. \"ext4\", \"xfs\", \"ntfs\". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply.", - "type": "string" - }, - "nodePublishSecretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "NodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed." - }, - "readOnly": { - "description": "Specifies a read-only configuration for the volume. Defaults to false (read/write).", - "type": "boolean" - }, - "volumeAttributes": { - "additionalProperties": { - "type": "string" - }, - "description": "VolumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values.", - "type": "object" - } - }, - "required": [ - "driver" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Capabilities": { - "description": "Adds and removes POSIX capabilities from running containers.", - "properties": { - "add": { - "description": "Added capabilities", - "items": { - "type": "string" - }, - "type": "array" - }, - "drop": { - "description": "Removed capabilities", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.CephFSVolumeSource": { - "description": "Represents a Ceph Filesystem mount that lasts the lifetime of a pod Cephfs volumes do not support ownership management or SELinux relabeling.", - "properties": { - "monitors": { - "description": "Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", - "items": { - "type": "string" - }, - "type": "array" - }, - "path": { - "description": "Optional: Used as the mounted root, rather than the full Ceph tree, default is /", - "type": "string" - }, - "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", - "type": "boolean" - }, - "secretFile": { - "description": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", - "type": "string" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it" - }, - "user": { - "description": "Optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it", - "type": "string" - } - }, - "required": [ - "monitors" - ], - "type": "object" - }, - "io.k8s.api.core.v1.CinderVolumeSource": { - "description": "Represents a cinder volume resource in Openstack. A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling.", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", - "type": "string" - }, - "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "Optional: points to a secret object containing parameters used to connect to OpenStack." - }, - "volumeID": { - "description": "volume id used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md", - "type": "string" - } - }, - "required": [ - "volumeID" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ClientIPConfig": { - "description": "ClientIPConfig represents the configurations of Client IP based session affinity.", - "properties": { - "timeoutSeconds": { - "description": "timeoutSeconds specifies the seconds of ClientIP type session sticky time. The value must be >0 && <=86400(for 1 day) if ServiceAffinity == \"ClientIP\". Default value is 10800(for 3 hours).", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ComponentCondition": { - "description": "Information about the condition of a component.", - "properties": { - "error": { - "description": "Condition error code for a component. For example, a health check error code.", - "type": "string" - }, - "message": { - "description": "Message about the condition for a component. For example, information about a health check.", - "type": "string" - }, - "status": { - "description": "Status of the condition for a component. Valid values for \"Healthy\": \"True\", \"False\", or \"Unknown\".", - "type": "string" - }, - "type": { - "description": "Type of condition for a component. Valid value: \"Healthy\"", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ConfigMapEnvSource": { - "description": "ConfigMapEnvSource selects a ConfigMap to populate the environment variables with.\n\nThe contents of the target ConfigMap's Data field will represent the key-value pairs as environment variables.", - "properties": { - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the ConfigMap must be defined", - "type": "boolean" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ConfigMapKeySelector": { - "description": "Selects a key from a ConfigMap.", - "properties": { - "key": { - "description": "The key to select.", - "type": "string" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the ConfigMap or its key must be defined", - "type": "boolean" - } - }, - "required": [ - "key" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ConfigMapNodeConfigSource": { - "description": "ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node.", - "properties": { - "kubeletConfigKey": { - "description": "KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure This field is required in all cases.", - "type": "string" - }, - "name": { - "description": "Name is the metadata.name of the referenced ConfigMap. This field is required in all cases.", - "type": "string" - }, - "namespace": { - "description": "Namespace is the metadata.namespace of the referenced ConfigMap. This field is required in all cases.", - "type": "string" - }, - "resourceVersion": { - "description": "ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status.", - "type": "string" - }, - "uid": { - "description": "UID is the metadata.UID of the referenced ConfigMap. This field is forbidden in Node.Spec, and required in Node.Status.", - "type": "string" - } - }, - "required": [ - "namespace", - "name", - "kubeletConfigKey" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ConfigMapProjection": { - "description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.", - "properties": { - "items": { - "description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.KeyToPath" - }, - "type": "array" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the ConfigMap or its keys must be defined", - "type": "boolean" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ConfigMapVolumeSource": { - "description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.", - "properties": { - "defaultMode": { - "description": "Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "items": { - "description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.KeyToPath" - }, - "type": "array" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the ConfigMap or its keys must be defined", - "type": "boolean" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.Container": { - "description": "A single application container that you want to run within a pod.", - "properties": { - "args": { - "description": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", - "items": { - "type": "string" - }, - "type": "array" - }, - "command": { - "description": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", - "items": { - "type": "string" - }, - "type": "array" - }, - "env": { - "description": "List of environment variables to set in the container. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.EnvVar" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "envFrom": { - "description": "List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.EnvFromSource" - }, - "type": "array" - }, - "image": { - "description": "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.", - "type": "string" - }, - "imagePullPolicy": { - "description": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", - "type": "string" - }, - "lifecycle": { - "$ref": "#/definitions/io.k8s.api.core.v1.Lifecycle", - "description": "Actions that the management system should take in response to container lifecycle events. Cannot be updated." - }, - "livenessProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" - }, - "name": { - "description": "Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated.", - "type": "string" - }, - "ports": { - "description": "List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default \"0.0.0.0\" address inside a container will be accessible from the network. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerPort" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "containerPort", - "protocol" - ], - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "containerPort", - "x-kubernetes-patch-strategy": "merge" - }, - "readinessProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" - }, - "resources": { - "$ref": "#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "description": "Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/" - }, - "securityContext": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecurityContext", - "description": "Security options the pod should run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/" - }, - "startupProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. This is an alpha feature enabled by the StartupProbe feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes" - }, - "stdin": { - "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.", - "type": "boolean" - }, - "stdinOnce": { - "description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false", - "type": "boolean" - }, - "terminationMessagePath": { - "description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.", - "type": "string" - }, - "terminationMessagePolicy": { - "description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", - "type": "string" - }, - "tty": { - "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.", - "type": "boolean" - }, - "volumeDevices": { - "description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.VolumeDevice" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "devicePath", - "x-kubernetes-patch-strategy": "merge" - }, - "volumeMounts": { - "description": "Pod volumes to mount into the container's filesystem. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.VolumeMount" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "mountPath", - "x-kubernetes-patch-strategy": "merge" - }, - "workingDir": { - "description": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.", - "type": "string" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ContainerImage": { - "description": "Describe a container image", - "properties": { - "names": { - "description": "Names by which this image is known. e.g. [\"k8s.gcr.io/hyperkube:v1.0.7\", \"dockerhub.io/google_containers/hyperkube:v1.0.7\"]", - "items": { - "type": "string" - }, - "type": "array" - }, - "sizeBytes": { - "description": "The size of the image in bytes.", - "format": "int64", - "type": "integer" - } - }, - "required": [ - "names" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ContainerPort": { - "description": "ContainerPort represents a network port in a single container.", - "properties": { - "containerPort": { - "description": "Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536.", - "format": "int32", - "type": "integer" - }, - "hostIP": { - "description": "What host IP to bind the external port to.", - "type": "string" - }, - "hostPort": { - "description": "Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this.", - "format": "int32", - "type": "integer" - }, - "name": { - "description": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services.", - "type": "string" - }, - "protocol": { - "description": "Protocol for port. Must be UDP, TCP, or SCTP. Defaults to \"TCP\".", - "type": "string" - } - }, - "required": [ - "containerPort" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ContainerState": { - "description": "ContainerState holds a possible state of container. Only one of its members may be specified. If none of them is specified, the default one is ContainerStateWaiting.", - "properties": { - "running": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStateRunning", - "description": "Details about a running container" - }, - "terminated": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStateTerminated", - "description": "Details about a terminated container" - }, - "waiting": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStateWaiting", - "description": "Details about a waiting container" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ContainerStateRunning": { - "description": "ContainerStateRunning is a running state of a container.", - "properties": { - "startedAt": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Time at which the container was last (re-)started" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ContainerStateTerminated": { - "description": "ContainerStateTerminated is a terminated state of a container.", - "properties": { - "containerID": { - "description": "Container's ID in the format 'docker://'", - "type": "string" - }, - "exitCode": { - "description": "Exit status from the last termination of the container", - "format": "int32", - "type": "integer" - }, - "finishedAt": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Time at which the container last terminated" - }, - "message": { - "description": "Message regarding the last termination of the container", - "type": "string" - }, - "reason": { - "description": "(brief) reason from the last termination of the container", - "type": "string" - }, - "signal": { - "description": "Signal from the last termination of the container", - "format": "int32", - "type": "integer" - }, - "startedAt": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Time at which previous execution of the container started" - } - }, - "required": [ - "exitCode" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ContainerStateWaiting": { - "description": "ContainerStateWaiting is a waiting state of a container.", - "properties": { - "message": { - "description": "Message regarding why the container is not yet running.", - "type": "string" - }, - "reason": { - "description": "(brief) reason the container is not yet running.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ContainerStatus": { - "description": "ContainerStatus contains details for the current status of this container.", - "properties": { - "containerID": { - "description": "Container's ID in the format 'docker://'.", - "type": "string" - }, - "image": { - "description": "The image the container is running. More info: https://kubernetes.io/docs/concepts/containers/images", - "type": "string" - }, - "imageID": { - "description": "ImageID of the container's image.", - "type": "string" - }, - "lastState": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerState", - "description": "Details about the container's last termination condition." - }, - "name": { - "description": "This must be a DNS_LABEL. Each container in a pod must have a unique name. Cannot be updated.", - "type": "string" - }, - "ready": { - "description": "Specifies whether the container has passed its readiness probe.", - "type": "boolean" - }, - "restartCount": { - "description": "The number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed. Note that this is calculated from dead containers. But those containers are subject to garbage collection. This value will get capped at 5 by GC.", - "format": "int32", - "type": "integer" - }, - "started": { - "description": "Specifies whether the container has passed its startup probe. Initialized as false, becomes true after startupProbe is considered successful. Resets to false when the container is restarted, or if kubelet loses state temporarily. Is always true when no startupProbe is defined.", - "type": "boolean" - }, - "state": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerState", - "description": "Details about the container's current condition." - } - }, - "required": [ - "name", - "ready", - "restartCount", - "image", - "imageID" - ], - "type": "object" - }, - "io.k8s.api.core.v1.DownwardAPIProjection": { - "description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.", - "properties": { - "items": { - "description": "Items is a list of DownwardAPIVolume file", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.DownwardAPIVolumeFile" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.DownwardAPIVolumeFile": { - "description": "DownwardAPIVolumeFile represents information to create the file containing the pod field", - "properties": { - "fieldRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ObjectFieldSelector", - "description": "Required: Selects a field of the pod: only annotations, labels, name and namespace are supported." - }, - "mode": { - "description": "Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "path": { - "description": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'", - "type": "string" - }, - "resourceFieldRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ResourceFieldSelector", - "description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported." - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.DownwardAPIVolumeSource": { - "description": "DownwardAPIVolumeSource represents a volume containing downward API info. Downward API volumes support ownership management and SELinux relabeling.", - "properties": { - "defaultMode": { - "description": "Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "items": { - "description": "Items is a list of downward API volume file", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.DownwardAPIVolumeFile" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.EmptyDirVolumeSource": { - "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", - "properties": { - "medium": { - "description": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", - "type": "string" - }, - "sizeLimit": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity", - "description": "Total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.EnvFromSource": { - "description": "EnvFromSource represents the source of a set of ConfigMaps", - "properties": { - "configMapRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapEnvSource", - "description": "The ConfigMap to select from" - }, - "prefix": { - "description": "An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.", - "type": "string" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecretEnvSource", - "description": "The Secret to select from" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.EnvVar": { - "description": "EnvVar represents an environment variable present in a Container.", - "properties": { - "name": { - "description": "Name of the environment variable. Must be a C_IDENTIFIER.", - "type": "string" - }, - "value": { - "description": "Variable references $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to \"\".", - "type": "string" - }, - "valueFrom": { - "$ref": "#/definitions/io.k8s.api.core.v1.EnvVarSource", - "description": "Source for the environment variable's value. Cannot be used if value is not empty." - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "io.k8s.api.core.v1.EnvVarSource": { - "description": "EnvVarSource represents a source for the value of an EnvVar.", - "properties": { - "configMapKeyRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapKeySelector", - "description": "Selects a key of a ConfigMap." - }, - "fieldRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ObjectFieldSelector", - "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs." - }, - "resourceFieldRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.ResourceFieldSelector", - "description": "Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported." - }, - "secretKeyRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecretKeySelector", - "description": "Selects a key of a secret in the pod's namespace" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.EphemeralContainer": { - "description": "An EphemeralContainer is a container that may be added temporarily to an existing pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a pod is removed or restarted. If an ephemeral container causes a pod to exceed its resource allocation, the pod may be evicted. Ephemeral containers may not be added by directly updating the pod spec. They must be added via the pod's ephemeralcontainers subresource, and they will appear in the pod spec once added. This is an alpha feature enabled by the EphemeralContainers feature flag.", - "properties": { - "args": { - "description": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", - "items": { - "type": "string" - }, - "type": "array" - }, - "command": { - "description": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell", - "items": { - "type": "string" - }, - "type": "array" - }, - "env": { - "description": "List of environment variables to set in the container. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.EnvVar" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "envFrom": { - "description": "List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.EnvFromSource" - }, - "type": "array" - }, - "image": { - "description": "Docker image name. More info: https://kubernetes.io/docs/concepts/containers/images", - "type": "string" - }, - "imagePullPolicy": { - "description": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images", - "type": "string" - }, - "lifecycle": { - "$ref": "#/definitions/io.k8s.api.core.v1.Lifecycle", - "description": "Lifecycle is not allowed for ephemeral containers." - }, - "livenessProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "Probes are not allowed for ephemeral containers." - }, - "name": { - "description": "Name of the ephemeral container specified as a DNS_LABEL. This name must be unique among all containers, init containers and ephemeral containers.", - "type": "string" - }, - "ports": { - "description": "Ports are not allowed for ephemeral containers.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerPort" - }, - "type": "array" - }, - "readinessProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "Probes are not allowed for ephemeral containers." - }, - "resources": { - "$ref": "#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "description": "Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources already allocated to the pod." - }, - "securityContext": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecurityContext", - "description": "SecurityContext is not allowed for ephemeral containers." - }, - "startupProbe": { - "$ref": "#/definitions/io.k8s.api.core.v1.Probe", - "description": "Probes are not allowed for ephemeral containers." - }, - "stdin": { - "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.", - "type": "boolean" - }, - "stdinOnce": { - "description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false", - "type": "boolean" - }, - "targetContainerName": { - "description": "If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container is run in whatever namespaces are shared for the pod. Note that the container runtime must support this feature.", - "type": "string" - }, - "terminationMessagePath": { - "description": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.", - "type": "string" - }, - "terminationMessagePolicy": { - "description": "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.", - "type": "string" - }, - "tty": { - "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.", - "type": "boolean" - }, - "volumeDevices": { - "description": "volumeDevices is the list of block devices to be used by the container. This is a beta feature.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.VolumeDevice" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "devicePath", - "x-kubernetes-patch-strategy": "merge" - }, - "volumeMounts": { - "description": "Pod volumes to mount into the container's filesystem. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.VolumeMount" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "mountPath", - "x-kubernetes-patch-strategy": "merge" - }, - "workingDir": { - "description": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.", - "type": "string" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ExecAction": { - "description": "ExecAction describes a \"run in container\" action.", - "properties": { - "command": { - "description": "Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.FCVolumeSource": { - "description": "Represents a Fibre Channel volume. Fibre Channel volumes can only be mounted as read/write once. Fibre Channel volumes support ownership management and SELinux relabeling.", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "lun": { - "description": "Optional: FC target lun number", - "format": "int32", - "type": "integer" - }, - "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "targetWWNs": { - "description": "Optional: FC target worldwide names (WWNs)", - "items": { - "type": "string" - }, - "type": "array" - }, - "wwids": { - "description": "Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.FlexVolumeSource": { - "description": "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin.", - "properties": { - "driver": { - "description": "Driver is the name of the driver to use for this volume.", - "type": "string" - }, - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.", - "type": "string" - }, - "options": { - "additionalProperties": { - "type": "string" - }, - "description": "Optional: Extra command options if any.", - "type": "object" - }, - "readOnly": { - "description": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts." - } - }, - "required": [ - "driver" - ], - "type": "object" - }, - "io.k8s.api.core.v1.FlockerVolumeSource": { - "description": "Represents a Flocker volume mounted by the Flocker agent. One and only one of datasetName and datasetUUID should be set. Flocker volumes do not support ownership management or SELinux relabeling.", - "properties": { - "datasetName": { - "description": "Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated", - "type": "string" - }, - "datasetUUID": { - "description": "UUID of the dataset. This is unique identifier of a Flocker dataset", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.GCEPersistentDiskVolumeSource": { - "description": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist before mounting to a container. The disk must also be in the same GCE project and zone as the kubelet. A GCE PD can only be mounted as read/write once or read-only many times. GCE PDs support ownership management and SELinux relabeling.", - "properties": { - "fsType": { - "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", - "type": "string" - }, - "partition": { - "description": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", - "format": "int32", - "type": "integer" - }, - "pdName": { - "description": "Unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", - "type": "string" - }, - "readOnly": { - "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", - "type": "boolean" - } - }, - "required": [ - "pdName" - ], - "type": "object" - }, - "io.k8s.api.core.v1.GitRepoVolumeSource": { - "description": "Represents a volume that is populated with the contents of a git repository. Git repo volumes do not support ownership management. Git repo volumes support SELinux relabeling.\n\nDEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container.", - "properties": { - "directory": { - "description": "Target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name.", - "type": "string" - }, - "repository": { - "description": "Repository URL", - "type": "string" - }, - "revision": { - "description": "Commit hash for the specified revision.", - "type": "string" - } - }, - "required": [ - "repository" - ], - "type": "object" - }, - "io.k8s.api.core.v1.GlusterfsVolumeSource": { - "description": "Represents a Glusterfs mount that lasts the lifetime of a pod. Glusterfs volumes do not support ownership management or SELinux relabeling.", - "properties": { - "endpoints": { - "description": "EndpointsName is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", - "type": "string" - }, - "path": { - "description": "Path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", - "type": "string" - }, - "readOnly": { - "description": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", - "type": "boolean" - } - }, - "required": [ - "endpoints", - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.HTTPGetAction": { - "description": "HTTPGetAction describes an action based on HTTP Get requests.", - "properties": { - "host": { - "description": "Host name to connect to, defaults to the pod IP. You probably want to set \"Host\" in httpHeaders instead.", - "type": "string" - }, - "httpHeaders": { - "description": "Custom headers to set in the request. HTTP allows repeated headers.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.HTTPHeader" - }, - "type": "array" - }, - "path": { - "description": "Path to access on the HTTP server.", - "type": "string" - }, - "port": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME." - }, - "scheme": { - "description": "Scheme to use for connecting to the host. Defaults to HTTP.", - "type": "string" - } - }, - "required": [ - "port" - ], - "type": "object" - }, - "io.k8s.api.core.v1.HTTPHeader": { - "description": "HTTPHeader describes a custom header to be used in HTTP probes", - "properties": { - "name": { - "description": "The header field name", - "type": "string" - }, - "value": { - "description": "The header field value", - "type": "string" - } - }, - "required": [ - "name", - "value" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Handler": { - "description": "Handler defines a specific action that should be taken", - "properties": { - "exec": { - "$ref": "#/definitions/io.k8s.api.core.v1.ExecAction", - "description": "One and only one of the following should be specified. Exec specifies the action to take." - }, - "httpGet": { - "$ref": "#/definitions/io.k8s.api.core.v1.HTTPGetAction", - "description": "HTTPGet specifies the http request to perform." - }, - "tcpSocket": { - "$ref": "#/definitions/io.k8s.api.core.v1.TCPSocketAction", - "description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.HostAlias": { - "description": "HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file.", - "properties": { - "hostnames": { - "description": "Hostnames for the above IP address.", - "items": { - "type": "string" - }, - "type": "array" - }, - "ip": { - "description": "IP address of the host file entry.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.HostPathVolumeSource": { - "description": "Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling.", - "properties": { - "path": { - "description": "Path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", - "type": "string" - }, - "type": { - "description": "Type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", - "type": "string" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ISCSIVolumeSource": { - "description": "Represents an ISCSI disk. ISCSI volumes can only be mounted as read/write once. ISCSI volumes support ownership management and SELinux relabeling.", - "properties": { - "chapAuthDiscovery": { - "description": "whether support iSCSI Discovery CHAP authentication", - "type": "boolean" - }, - "chapAuthSession": { - "description": "whether support iSCSI Session CHAP authentication", - "type": "boolean" - }, - "fsType": { - "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi", - "type": "string" - }, - "initiatorName": { - "description": "Custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection.", - "type": "string" - }, - "iqn": { - "description": "Target iSCSI Qualified Name.", - "type": "string" - }, - "iscsiInterface": { - "description": "iSCSI Interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).", - "type": "string" - }, - "lun": { - "description": "iSCSI Target Lun number.", - "format": "int32", - "type": "integer" - }, - "portals": { - "description": "iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", - "items": { - "type": "string" - }, - "type": "array" - }, - "readOnly": { - "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "CHAP Secret for iSCSI target and initiator authentication" - }, - "targetPortal": { - "description": "iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).", - "type": "string" - } - }, - "required": [ - "targetPortal", - "iqn", - "lun" - ], - "type": "object" - }, - "io.k8s.api.core.v1.KeyToPath": { - "description": "Maps a string key to a path within a volume.", - "properties": { - "key": { - "description": "The key to project.", - "type": "string" - }, - "mode": { - "description": "Optional: mode bits to use on this file, must be a value between 0 and 0777. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "path": { - "description": "The relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'.", - "type": "string" - } - }, - "required": [ - "key", - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Lifecycle": { - "description": "Lifecycle describes actions that the management system should take in response to container lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted.", - "properties": { - "postStart": { - "$ref": "#/definitions/io.k8s.api.core.v1.Handler", - "description": "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" - }, - "preStop": { - "$ref": "#/definitions/io.k8s.api.core.v1.Handler", - "description": "PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The reason for termination is passed to the handler. The Pod's termination grace period countdown begins before the PreStop hooked is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod's termination grace period. Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.LocalObjectReference": { - "description": "LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.", - "properties": { - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.LocalVolumeSource": { - "description": "Local represents directly-attached storage with node affinity (Beta feature)", - "properties": { - "fsType": { - "description": "Filesystem type to mount. It applies only when the Path is a block device. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default value is to auto-select a fileystem if unspecified.", - "type": "string" - }, - "path": { - "description": "The full path to the volume on the node. It can be either a directory or block device (disk, partition, ...).", - "type": "string" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.NFSVolumeSource": { - "description": "Represents an NFS mount that lasts the lifetime of a pod. NFS volumes do not support ownership management or SELinux relabeling.", - "properties": { - "path": { - "description": "Path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", - "type": "string" - }, - "readOnly": { - "description": "ReadOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", - "type": "boolean" - }, - "server": { - "description": "Server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", - "type": "string" - } - }, - "required": [ - "server", - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.NodeAffinity": { - "description": "Node affinity is a group of node affinity scheduling rules.", - "properties": { - "preferredDuringSchedulingIgnoredDuringExecution": { - "description": "The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding \"weight\" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PreferredSchedulingTerm" - }, - "type": "array" - }, - "requiredDuringSchedulingIgnoredDuringExecution": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelector", - "description": "If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.NodeSelector": { - "description": "A node selector represents the union of the results of one or more label queries over a set of nodes; that is, it represents the OR of the selectors represented by the node selector terms.", - "properties": { - "nodeSelectorTerms": { - "description": "Required. A list of node selector terms. The terms are ORed.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorTerm" - }, - "type": "array" - } - }, - "required": [ - "nodeSelectorTerms" - ], - "type": "object" - }, - "io.k8s.api.core.v1.NodeSelectorRequirement": { - "description": "A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values.", - "properties": { - "key": { - "description": "The label key that the selector applies to.", - "type": "string" - }, - "operator": { - "description": "Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.", - "type": "string" - }, - "values": { - "description": "An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "key", - "operator" - ], - "type": "object" - }, - "io.k8s.api.core.v1.NodeSelectorTerm": { - "description": "A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.", - "properties": { - "matchExpressions": { - "description": "A list of node selector requirements by node's labels.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorRequirement" - }, - "type": "array" - }, - "matchFields": { - "description": "A list of node selector requirements by node's fields.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorRequirement" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ObjectFieldSelector": { - "description": "ObjectFieldSelector selects an APIVersioned field of an object.", - "properties": { - "apiVersion": { - "description": "Version of the schema the FieldPath is written in terms of, defaults to \"v1\".", - "type": "string" - }, - "fieldPath": { - "description": "Path of the field to select in the specified API version.", - "type": "string" - } - }, - "required": [ - "fieldPath" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ObjectReference": { - "description": "ObjectReference contains enough information to let you inspect or modify the referred object.", - "properties": { - "apiVersion": { - "description": "API version of the referent.", - "type": "string" - }, - "fieldPath": { - "description": "If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: \"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered the event) or if no container name is specified \"spec.containers[2]\" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object.", - "type": "string" - }, - "kind": { - "description": "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "namespace": { - "description": "Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/", - "type": "string" - }, - "resourceVersion": { - "description": "Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", - "type": "string" - }, - "uid": { - "description": "UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PersistentVolumeClaimVolumeSource": { - "description": "PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace. This volume finds the bound PV and mounts that volume for the pod. A PersistentVolumeClaimVolumeSource is, essentially, a wrapper around another type of volume that is owned by someone else (the system).", - "properties": { - "claimName": { - "description": "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", - "type": "string" - }, - "readOnly": { - "description": "Will force the ReadOnly setting in VolumeMounts. Default false.", - "type": "boolean" - } - }, - "required": [ - "claimName" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PhotonPersistentDiskVolumeSource": { - "description": "Represents a Photon Controller persistent disk resource.", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "pdID": { - "description": "ID that identifies Photon Controller persistent disk", - "type": "string" - } - }, - "required": [ - "pdID" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Pod": { - "description": "Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodSpec", - "description": "Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" - }, - "status": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodStatus", - "description": "Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "", - "kind": "Pod", - "version": "v1" - } - ] - }, - "io.k8s.api.core.v1.PodAffinity": { - "description": "Pod affinity is a group of inter pod affinity scheduling rules.", - "properties": { - "preferredDuringSchedulingIgnoredDuringExecution": { - "description": "The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding \"weight\" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.WeightedPodAffinityTerm" - }, - "type": "array" - }, - "requiredDuringSchedulingIgnoredDuringExecution": { - "description": "If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodAffinityTerm" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodAffinityTerm": { - "description": "Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running", - "properties": { - "labelSelector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "A label query over a set of resources, in this case pods." - }, - "namespaces": { - "description": "namespaces specifies which namespaces the labelSelector applies to (matches against); null or empty list means \"this pod's namespace\"", - "items": { - "type": "string" - }, - "type": "array" - }, - "topologyKey": { - "description": "This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed.", - "type": "string" - } - }, - "required": [ - "topologyKey" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PodAntiAffinity": { - "description": "Pod anti affinity is a group of inter pod anti affinity scheduling rules.", - "properties": { - "preferredDuringSchedulingIgnoredDuringExecution": { - "description": "The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding \"weight\" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.WeightedPodAffinityTerm" - }, - "type": "array" - }, - "requiredDuringSchedulingIgnoredDuringExecution": { - "description": "If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodAffinityTerm" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodCondition": { - "description": "PodCondition contains details for the current condition of this pod.", - "properties": { - "lastProbeTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time we probed the condition." - }, - "lastTransitionTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time the condition transitioned from one status to another." - }, - "message": { - "description": "Human-readable message indicating details about last transition.", - "type": "string" - }, - "reason": { - "description": "Unique, one-word, CamelCase reason for the condition's last transition.", - "type": "string" - }, - "status": { - "description": "Status is the status of the condition. Can be True, False, Unknown. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", - "type": "string" - }, - "type": { - "description": "Type is the type of the condition. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PodDNSConfig": { - "description": "PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy.", - "properties": { - "nameservers": { - "description": "A list of DNS name server IP addresses. This will be appended to the base nameservers generated from DNSPolicy. Duplicated nameservers will be removed.", - "items": { - "type": "string" - }, - "type": "array" - }, - "options": { - "description": "A list of DNS resolver options. This will be merged with the base options generated from DNSPolicy. Duplicated entries will be removed. Resolution options given in Options will override those that appear in the base DNSPolicy.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodDNSConfigOption" - }, - "type": "array" - }, - "searches": { - "description": "A list of DNS search domains for host-name lookup. This will be appended to the base search paths generated from DNSPolicy. Duplicated search paths will be removed.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodDNSConfigOption": { - "description": "PodDNSConfigOption defines DNS resolver options of a pod.", - "properties": { - "name": { - "description": "Required.", - "type": "string" - }, - "value": { - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodIP": { - "description": "IP address information for entries in the (plural) PodIPs field. Each entry includes:\n IP: An IP address allocated to the pod. Routable at least within the cluster.", - "properties": { - "ip": { - "description": "ip is an IP address (IPv4 or IPv6) assigned to the pod", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodReadinessGate": { - "description": "PodReadinessGate contains the reference to a pod condition", - "properties": { - "conditionType": { - "description": "ConditionType refers to a condition in the pod's condition list with matching type.", - "type": "string" - } - }, - "required": [ - "conditionType" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PodSecurityContext": { - "description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.", - "properties": { - "fsGroup": { - "description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.", - "format": "int64", - "type": "integer" - }, - "runAsGroup": { - "description": "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", - "format": "int64", - "type": "integer" - }, - "runAsNonRoot": { - "description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", - "type": "boolean" - }, - "runAsUser": { - "description": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.", - "format": "int64", - "type": "integer" - }, - "seLinuxOptions": { - "$ref": "#/definitions/io.k8s.api.core.v1.SELinuxOptions", - "description": "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container." - }, - "supplementalGroups": { - "description": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.", - "items": { - "format": "int64", - "type": "integer" - }, - "type": "array" - }, - "sysctls": { - "description": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.Sysctl" - }, - "type": "array" - }, - "windowsOptions": { - "$ref": "#/definitions/io.k8s.api.core.v1.WindowsSecurityContextOptions", - "description": "The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodSpec": { - "description": "PodSpec is a description of a pod.", - "properties": { - "activeDeadlineSeconds": { - "description": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.", - "format": "int64", - "type": "integer" - }, - "affinity": { - "$ref": "#/definitions/io.k8s.api.core.v1.Affinity", - "description": "If specified, the pod's scheduling constraints" - }, - "automountServiceAccountToken": { - "description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.", - "type": "boolean" - }, - "containers": { - "description": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.Container" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "dnsConfig": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodDNSConfig", - "description": "Specifies the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy." - }, - "dnsPolicy": { - "description": "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", - "type": "string" - }, - "enableServiceLinks": { - "description": "EnableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. Optional: Defaults to true.", - "type": "boolean" - }, - "ephemeralContainers": { - "description": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.EphemeralContainer" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "hostAliases": { - "description": "HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. This is only valid for non-hostNetwork pods.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.HostAlias" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "ip", - "x-kubernetes-patch-strategy": "merge" - }, - "hostIPC": { - "description": "Use the host's ipc namespace. Optional: Default to false.", - "type": "boolean" - }, - "hostNetwork": { - "description": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.", - "type": "boolean" - }, - "hostPID": { - "description": "Use the host's pid namespace. Optional: Default to false.", - "type": "boolean" - }, - "hostname": { - "description": "Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value.", - "type": "string" - }, - "imagePullSecrets": { - "description": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "initContainers": { - "description": "List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.Container" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" - }, - "nodeName": { - "description": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.", - "type": "string" - }, - "nodeSelector": { - "additionalProperties": { - "type": "string" - }, - "description": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", - "type": "object" - }, - "overhead": { - "additionalProperties": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" - }, - "description": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.", - "type": "object" - }, - "preemptionPolicy": { - "description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is alpha-level and is only honored by servers that enable the NonPreemptingPriority feature.", - "type": "string" - }, - "priority": { - "description": "The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority.", - "format": "int32", - "type": "integer" - }, - "priorityClassName": { - "description": "If specified, indicates the pod's priority. \"system-node-critical\" and \"system-cluster-critical\" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default.", - "type": "string" - }, - "readinessGates": { - "description": "If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to \"True\" More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodReadinessGate" - }, - "type": "array" - }, - "restartPolicy": { - "description": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy", - "type": "string" - }, - "runtimeClassName": { - "description": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md This is a beta feature as of Kubernetes v1.14.", - "type": "string" - }, - "schedulerName": { - "description": "If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler.", - "type": "string" - }, - "securityContext": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodSecurityContext", - "description": "SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field." - }, - "serviceAccount": { - "description": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.", - "type": "string" - }, - "serviceAccountName": { - "description": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/", - "type": "string" - }, - "shareProcessNamespace": { - "description": "Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.", - "type": "boolean" - }, - "subdomain": { - "description": "If specified, the fully qualified Pod hostname will be \"...svc.\". If not specified, the pod will not have a domainname at all.", - "type": "string" - }, - "terminationGracePeriodSeconds": { - "description": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.", - "format": "int64", - "type": "integer" - }, - "tolerations": { - "description": "If specified, the pod's tolerations.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.Toleration" - }, - "type": "array" - }, - "topologySpreadConstraints": { - "description": "TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. This field is alpha-level and is only honored by clusters that enables the EvenPodsSpread feature. All topologySpreadConstraints are ANDed.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.TopologySpreadConstraint" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "topologyKey", - "whenUnsatisfiable" - ], - "x-kubernetes-list-type": "map", - "x-kubernetes-patch-merge-key": "topologyKey", - "x-kubernetes-patch-strategy": "merge" - }, - "volumes": { - "description": "List of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.Volume" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge,retainKeys" - } - }, - "required": [ - "containers" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PodStatus": { - "description": "PodStatus represents information about the status of a pod. Status may trail the actual state of a system, especially if the node that hosts the pod cannot contact the control plane.", - "properties": { - "conditions": { - "description": "Current service state of pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodCondition" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge" - }, - "containerStatuses": { - "description": "The list has one entry per container in the manifest. Each entry is currently the output of `docker inspect`. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStatus" - }, - "type": "array" - }, - "ephemeralContainerStatuses": { - "description": "Status for any ephemeral containers that have run in this pod. This field is alpha-level and is only populated by servers that enable the EphemeralContainers feature.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStatus" - }, - "type": "array" - }, - "hostIP": { - "description": "IP address of the host to which the pod is assigned. Empty if not yet scheduled.", - "type": "string" - }, - "initContainerStatuses": { - "description": "The list has one entry per init container in the manifest. The most recent successful init container will have ready = true, the most recently started container will have startTime set. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ContainerStatus" - }, - "type": "array" - }, - "message": { - "description": "A human readable message indicating details about why the pod is in this condition.", - "type": "string" - }, - "nominatedNodeName": { - "description": "nominatedNodeName is set only when this pod preempts other pods on the node, but it cannot be scheduled right away as preemption victims receive their graceful termination periods. This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to give the resources on this node to a higher priority pod that is created after preemption. As a result, this field may be different than PodSpec.nodeName when the pod is scheduled.", - "type": "string" - }, - "phase": { - "description": "The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The conditions array, the reason and message fields, and the individual container status arrays contain more detail about the pod's status. There are five possible phase values:\n\nPending: The pod has been accepted by the Kubernetes system, but one or more of the container images has not been created. This includes time before being scheduled as well as time spent downloading images over the network, which could take a while. Running: The pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. Succeeded: All containers in the pod have terminated in success, and will not be restarted. Failed: All containers in the pod have terminated, and at least one container has terminated in failure. The container either exited with non-zero status or was terminated by the system. Unknown: For some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase", - "type": "string" - }, - "podIP": { - "description": "IP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated.", - "type": "string" - }, - "podIPs": { - "description": "podIPs holds the IP addresses allocated to the pod. If this field is specified, the 0th entry must match the podIP field. Pods may be allocated at most 1 value for each of IPv4 and IPv6. This list is empty if no IPs have been allocated yet.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodIP" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "ip", - "x-kubernetes-patch-strategy": "merge" - }, - "qosClass": { - "description": "The Quality of Service (QOS) classification assigned to the pod based on resource requirements See PodQOSClass type for available QOS classes More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md", - "type": "string" - }, - "reason": { - "description": "A brief CamelCase message indicating details about why the pod is in this state. e.g. 'Evicted'", - "type": "string" - }, - "startTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "RFC 3339 date and time at which the object was acknowledged by the Kubelet. This is before the Kubelet pulled the container image(s) for the pod." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PodTemplate": { - "description": "PodTemplate describes a template for creating copies of a predefined pod.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "template": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", - "description": "Template defines the pods that will be created from this pod template. https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "", - "kind": "PodTemplate", - "version": "v1" - } - ] - }, - "io.k8s.api.core.v1.PodTemplateSpec": { - "description": "PodTemplateSpec describes the data a pod should have when created from a template", - "properties": { - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodSpec", - "description": "Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.PortworxVolumeSource": { - "description": "PortworxVolumeSource represents a Portworx volume resource.", - "properties": { - "fsType": { - "description": "FSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "readOnly": { - "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "volumeID": { - "description": "VolumeID uniquely identifies a Portworx volume", - "type": "string" - } - }, - "required": [ - "volumeID" - ], - "type": "object" - }, - "io.k8s.api.core.v1.PreferredSchedulingTerm": { - "description": "An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).", - "properties": { - "preference": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelectorTerm", - "description": "A node selector term, associated with the corresponding weight." - }, - "weight": { - "description": "Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100.", - "format": "int32", - "type": "integer" - } - }, - "required": [ - "weight", - "preference" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Probe": { - "description": "Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.", - "properties": { - "exec": { - "$ref": "#/definitions/io.k8s.api.core.v1.ExecAction", - "description": "One and only one of the following should be specified. Exec specifies the action to take." - }, - "failureThreshold": { - "description": "Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.", - "format": "int32", - "type": "integer" - }, - "httpGet": { - "$ref": "#/definitions/io.k8s.api.core.v1.HTTPGetAction", - "description": "HTTPGet specifies the http request to perform." - }, - "initialDelaySeconds": { - "description": "Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", - "format": "int32", - "type": "integer" - }, - "periodSeconds": { - "description": "How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1.", - "format": "int32", - "type": "integer" - }, - "successThreshold": { - "description": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.", - "format": "int32", - "type": "integer" - }, - "tcpSocket": { - "$ref": "#/definitions/io.k8s.api.core.v1.TCPSocketAction", - "description": "TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported" - }, - "timeoutSeconds": { - "description": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ProjectedVolumeSource": { - "description": "Represents a projected volume source", - "properties": { - "defaultMode": { - "description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "sources": { - "description": "list of volume projections", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.VolumeProjection" - }, - "type": "array" - } - }, - "required": [ - "sources" - ], - "type": "object" - }, - "io.k8s.api.core.v1.QuobyteVolumeSource": { - "description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.", - "properties": { - "group": { - "description": "Group to map volume access to Default is no group", - "type": "string" - }, - "readOnly": { - "description": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.", - "type": "boolean" - }, - "registry": { - "description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes", - "type": "string" - }, - "tenant": { - "description": "Tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin", - "type": "string" - }, - "user": { - "description": "User to map volume access to Defaults to serivceaccount user", - "type": "string" - }, - "volume": { - "description": "Volume is a string that references an already created Quobyte volume by name.", - "type": "string" - } - }, - "required": [ - "registry", - "volume" - ], - "type": "object" - }, - "io.k8s.api.core.v1.RBDVolumeSource": { - "description": "Represents a Rados Block Device mount that lasts the lifetime of a pod. RBD volumes support ownership management and SELinux relabeling.", - "properties": { - "fsType": { - "description": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd", - "type": "string" - }, - "image": { - "description": "The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "type": "string" - }, - "keyring": { - "description": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "type": "string" - }, - "monitors": { - "description": "A collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "items": { - "type": "string" - }, - "type": "array" - }, - "pool": { - "description": "The rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "type": "string" - }, - "readOnly": { - "description": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it" - }, - "user": { - "description": "The rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", - "type": "string" - } - }, - "required": [ - "monitors", - "image" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ResourceFieldSelector": { - "description": "ResourceFieldSelector represents container resources (cpu, memory) and their output format", - "properties": { - "containerName": { - "description": "Container name: required for volumes, optional for env vars", - "type": "string" - }, - "divisor": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity", - "description": "Specifies the output format of the exposed resources, defaults to \"1\"" - }, - "resource": { - "description": "Required: resource to select", - "type": "string" - } - }, - "required": [ - "resource" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ResourceRequirements": { - "description": "ResourceRequirements describes the compute resource requirements.", - "properties": { - "limits": { - "additionalProperties": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" - }, - "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/", - "type": "object" - }, - "requests": { - "additionalProperties": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity" - }, - "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/", - "type": "object" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.SELinuxOptions": { - "description": "SELinuxOptions are the labels to be applied to the container", - "properties": { - "level": { - "description": "Level is SELinux level label that applies to the container.", - "type": "string" - }, - "role": { - "description": "Role is a SELinux role label that applies to the container.", - "type": "string" - }, - "type": { - "description": "Type is a SELinux type label that applies to the container.", - "type": "string" - }, - "user": { - "description": "User is a SELinux user label that applies to the container.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ScaleIOVolumeSource": { - "description": "ScaleIOVolumeSource represents a persistent ScaleIO volume", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Default is \"xfs\".", - "type": "string" - }, - "gateway": { - "description": "The host address of the ScaleIO API Gateway.", - "type": "string" - }, - "protectionDomain": { - "description": "The name of the ScaleIO Protection Domain for the configured storage.", - "type": "string" - }, - "readOnly": { - "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "SecretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail." - }, - "sslEnabled": { - "description": "Flag to enable/disable SSL communication with Gateway, default false", - "type": "boolean" - }, - "storageMode": { - "description": "Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned.", - "type": "string" - }, - "storagePool": { - "description": "The ScaleIO Storage Pool associated with the protection domain.", - "type": "string" - }, - "system": { - "description": "The name of the storage system as configured in ScaleIO.", - "type": "string" - }, - "volumeName": { - "description": "The name of a volume already created in the ScaleIO system that is associated with this volume source.", - "type": "string" - } - }, - "required": [ - "gateway", - "system", - "secretRef" - ], - "type": "object" - }, - "io.k8s.api.core.v1.ScopeSelector": { - "description": "A scope selector represents the AND of the selectors represented by the scoped-resource selector requirements.", - "properties": { - "matchExpressions": { - "description": "A list of scope selector requirements by scope of the resources.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.ScopedResourceSelectorRequirement" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ScopedResourceSelectorRequirement": { - "description": "A scoped-resource selector requirement is a selector that contains values, a scope name, and an operator that relates the scope name and values.", - "properties": { - "operator": { - "description": "Represents a scope's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist.", - "type": "string" - }, - "scopeName": { - "description": "The name of the scope that the selector applies to.", - "type": "string" - }, - "values": { - "description": "An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "scopeName", - "operator" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Secret": { - "description": "Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "data": { - "additionalProperties": { - "format": "byte", - "type": "string" - }, - "description": "Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4", - "type": "object" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "stringData": { - "additionalProperties": { - "type": "string" - }, - "description": "stringData allows specifying non-binary secret data in string form. It is provided as a write-only convenience method. All keys and values are merged into the data field on write, overwriting any existing values. It is never output when reading from the API.", - "type": "object" - }, - "type": { - "description": "Used to facilitate programmatic handling of secret data.", - "type": "string" - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "", - "kind": "Secret", - "version": "v1" - } - ] - }, - "io.k8s.api.core.v1.SecretEnvSource": { - "description": "SecretEnvSource selects a Secret to populate the environment variables with.\n\nThe contents of the target Secret's Data field will represent the key-value pairs as environment variables.", - "properties": { - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the Secret must be defined", - "type": "boolean" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.SecretKeySelector": { - "description": "SecretKeySelector selects a key of a Secret.", - "properties": { - "key": { - "description": "The key of the secret to select from. Must be a valid secret key.", - "type": "string" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the Secret or its key must be defined", - "type": "boolean" - } - }, - "required": [ - "key" - ], - "type": "object" - }, - "io.k8s.api.core.v1.SecretProjection": { - "description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.", - "properties": { - "items": { - "description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.KeyToPath" - }, - "type": "array" - }, - "name": { - "description": "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "optional": { - "description": "Specify whether the Secret or its key must be defined", - "type": "boolean" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.SecretReference": { - "description": "SecretReference represents a Secret Reference. It has enough information to retrieve secret in any namespace", - "properties": { - "name": { - "description": "Name is unique within a namespace to reference a secret resource.", - "type": "string" - }, - "namespace": { - "description": "Namespace defines the space within which the secret name must be unique.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.SecretVolumeSource": { - "description": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.", - "properties": { - "defaultMode": { - "description": "Optional: mode bits to use on created files by default. Must be a value between 0 and 0777. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.", - "format": "int32", - "type": "integer" - }, - "items": { - "description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.KeyToPath" - }, - "type": "array" - }, - "optional": { - "description": "Specify whether the Secret or its keys must be defined", - "type": "boolean" - }, - "secretName": { - "description": "Name of the secret in the pod's namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.SecurityContext": { - "description": "SecurityContext holds security configuration that will be applied to a container. Some fields are present in both SecurityContext and PodSecurityContext. When both are set, the values in SecurityContext take precedence.", - "properties": { - "allowPrivilegeEscalation": { - "description": "AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN", - "type": "boolean" - }, - "capabilities": { - "$ref": "#/definitions/io.k8s.api.core.v1.Capabilities", - "description": "The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime." - }, - "privileged": { - "description": "Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false.", - "type": "boolean" - }, - "procMount": { - "description": "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled.", - "type": "string" - }, - "readOnlyRootFilesystem": { - "description": "Whether this container has a read-only root filesystem. Default is false.", - "type": "boolean" - }, - "runAsGroup": { - "description": "The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", - "format": "int64", - "type": "integer" - }, - "runAsNonRoot": { - "description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", - "type": "boolean" - }, - "runAsUser": { - "description": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.", - "format": "int64", - "type": "integer" - }, - "seLinuxOptions": { - "$ref": "#/definitions/io.k8s.api.core.v1.SELinuxOptions", - "description": "The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." - }, - "windowsOptions": { - "$ref": "#/definitions/io.k8s.api.core.v1.WindowsSecurityContextOptions", - "description": "The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.ServiceAccountTokenProjection": { - "description": "ServiceAccountTokenProjection represents a projected service account token volume. This projection can be used to insert a service account token into the pods runtime filesystem for use against APIs (Kubernetes API Server or otherwise).", - "properties": { - "audience": { - "description": "Audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver.", - "type": "string" - }, - "expirationSeconds": { - "description": "ExpirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes.", - "format": "int64", - "type": "integer" - }, - "path": { - "description": "Path is the path relative to the mount point of the file to project the token into.", - "type": "string" - } - }, - "required": [ - "path" - ], - "type": "object" - }, - "io.k8s.api.core.v1.SessionAffinityConfig": { - "description": "SessionAffinityConfig represents the configurations of session affinity.", - "properties": { - "clientIP": { - "$ref": "#/definitions/io.k8s.api.core.v1.ClientIPConfig", - "description": "clientIP contains the configurations of Client IP based session affinity." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.StorageOSVolumeSource": { - "description": "Represents a StorageOS persistent volume resource.", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "readOnly": { - "description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.", - "type": "boolean" - }, - "secretRef": { - "$ref": "#/definitions/io.k8s.api.core.v1.LocalObjectReference", - "description": "SecretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted." - }, - "volumeName": { - "description": "VolumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace.", - "type": "string" - }, - "volumeNamespace": { - "description": "VolumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to \"default\" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.Sysctl": { - "description": "Sysctl defines a kernel parameter to be set", - "properties": { - "name": { - "description": "Name of a property to set", - "type": "string" - }, - "value": { - "description": "Value of a property to set", - "type": "string" - } - }, - "required": [ - "name", - "value" - ], - "type": "object" - }, - "io.k8s.api.core.v1.TCPSocketAction": { - "description": "TCPSocketAction describes an action based on opening a socket", - "properties": { - "host": { - "description": "Optional: Host name to connect to, defaults to the pod IP.", - "type": "string" - }, - "port": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME." - } - }, - "required": [ - "port" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Toleration": { - "description": "The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator .", - "properties": { - "effect": { - "description": "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.", - "type": "string" - }, - "key": { - "description": "Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.", - "type": "string" - }, - "operator": { - "description": "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.", - "type": "string" - }, - "tolerationSeconds": { - "description": "TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system.", - "format": "int64", - "type": "integer" - }, - "value": { - "description": "Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.TopologySelectorLabelRequirement": { - "description": "A topology selector requirement is a selector that matches given label. This is an alpha feature and may change in the future.", - "properties": { - "key": { - "description": "The label key that the selector applies to.", - "type": "string" - }, - "values": { - "description": "An array of string values. One value must match the label to be selected. Each entry in Values is ORed.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "key", - "values" - ], - "type": "object" - }, - "io.k8s.api.core.v1.TopologySelectorTerm": { - "description": "A topology selector term represents the result of label queries. A null or empty topology selector term matches no objects. The requirements of them are ANDed. It provides a subset of functionality as NodeSelectorTerm. This is an alpha feature and may change in the future.", - "properties": { - "matchLabelExpressions": { - "description": "A list of topology selector requirements by labels.", - "items": { - "$ref": "#/definitions/io.k8s.api.core.v1.TopologySelectorLabelRequirement" - }, - "type": "array" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.TopologySpreadConstraint": { - "description": "TopologySpreadConstraint specifies how to spread matching pods among the given topology.", - "properties": { - "labelSelector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "LabelSelector is used to find matching pods. Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain." - }, - "maxSkew": { - "description": "MaxSkew describes the degree to which pods may be unevenly distributed. It's the maximum permitted difference between the number of matching pods in any two topology domains of a given topology type. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 1/1/0: | zone1 | zone2 | zone3 | | P | P | | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1; scheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. It's a required field. Default value is 1 and 0 is not allowed.", - "format": "int32", - "type": "integer" - }, - "topologyKey": { - "description": "TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a \"bucket\", and try to put balanced number of pods into each bucket. It's a required field.", - "type": "string" - }, - "whenUnsatisfiable": { - "description": "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it - ScheduleAnyway tells the scheduler to still schedule it It's considered as \"Unsatisfiable\" if and only if placing incoming pod on any topology violates \"MaxSkew\". For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won't make it *more* imbalanced. It's a required field.", - "type": "string" - } - }, - "required": [ - "maxSkew", - "topologyKey", - "whenUnsatisfiable" - ], - "type": "object" - }, - "io.k8s.api.core.v1.Volume": { - "description": "Volume represents a named volume in a pod that may be accessed by any container in the pod.", - "properties": { - "awsElasticBlockStore": { - "$ref": "#/definitions/io.k8s.api.core.v1.AWSElasticBlockStoreVolumeSource", - "description": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore" - }, - "azureDisk": { - "$ref": "#/definitions/io.k8s.api.core.v1.AzureDiskVolumeSource", - "description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod." - }, - "azureFile": { - "$ref": "#/definitions/io.k8s.api.core.v1.AzureFileVolumeSource", - "description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod." - }, - "cephfs": { - "$ref": "#/definitions/io.k8s.api.core.v1.CephFSVolumeSource", - "description": "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime" - }, - "cinder": { - "$ref": "#/definitions/io.k8s.api.core.v1.CinderVolumeSource", - "description": "Cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md" - }, - "configMap": { - "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapVolumeSource", - "description": "ConfigMap represents a configMap that should populate this volume" - }, - "csi": { - "$ref": "#/definitions/io.k8s.api.core.v1.CSIVolumeSource", - "description": "CSI (Container Storage Interface) represents storage that is handled by an external CSI driver (Alpha feature)." - }, - "downwardAPI": { - "$ref": "#/definitions/io.k8s.api.core.v1.DownwardAPIVolumeSource", - "description": "DownwardAPI represents downward API about the pod that should populate this volume" - }, - "emptyDir": { - "$ref": "#/definitions/io.k8s.api.core.v1.EmptyDirVolumeSource", - "description": "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir" - }, - "fc": { - "$ref": "#/definitions/io.k8s.api.core.v1.FCVolumeSource", - "description": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod." - }, - "flexVolume": { - "$ref": "#/definitions/io.k8s.api.core.v1.FlexVolumeSource", - "description": "FlexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin." - }, - "flocker": { - "$ref": "#/definitions/io.k8s.api.core.v1.FlockerVolumeSource", - "description": "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running" - }, - "gcePersistentDisk": { - "$ref": "#/definitions/io.k8s.api.core.v1.GCEPersistentDiskVolumeSource", - "description": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk" - }, - "gitRepo": { - "$ref": "#/definitions/io.k8s.api.core.v1.GitRepoVolumeSource", - "description": "GitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container." - }, - "glusterfs": { - "$ref": "#/definitions/io.k8s.api.core.v1.GlusterfsVolumeSource", - "description": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md" - }, - "hostPath": { - "$ref": "#/definitions/io.k8s.api.core.v1.HostPathVolumeSource", - "description": "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath" - }, - "iscsi": { - "$ref": "#/definitions/io.k8s.api.core.v1.ISCSIVolumeSource", - "description": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md" - }, - "name": { - "description": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", - "type": "string" - }, - "nfs": { - "$ref": "#/definitions/io.k8s.api.core.v1.NFSVolumeSource", - "description": "NFS represents an NFS mount on the host that shares a pod's lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs" - }, - "persistentVolumeClaim": { - "$ref": "#/definitions/io.k8s.api.core.v1.PersistentVolumeClaimVolumeSource", - "description": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims" - }, - "photonPersistentDisk": { - "$ref": "#/definitions/io.k8s.api.core.v1.PhotonPersistentDiskVolumeSource", - "description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine" - }, - "portworxVolume": { - "$ref": "#/definitions/io.k8s.api.core.v1.PortworxVolumeSource", - "description": "PortworxVolume represents a portworx volume attached and mounted on kubelets host machine" - }, - "projected": { - "$ref": "#/definitions/io.k8s.api.core.v1.ProjectedVolumeSource", - "description": "Items for all in one resources secrets, configmaps, and downward API" - }, - "quobyte": { - "$ref": "#/definitions/io.k8s.api.core.v1.QuobyteVolumeSource", - "description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime" - }, - "rbd": { - "$ref": "#/definitions/io.k8s.api.core.v1.RBDVolumeSource", - "description": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md" - }, - "scaleIO": { - "$ref": "#/definitions/io.k8s.api.core.v1.ScaleIOVolumeSource", - "description": "ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes." - }, - "secret": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecretVolumeSource", - "description": "Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret" - }, - "storageos": { - "$ref": "#/definitions/io.k8s.api.core.v1.StorageOSVolumeSource", - "description": "StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes." - }, - "vsphereVolume": { - "$ref": "#/definitions/io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource", - "description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "io.k8s.api.core.v1.VolumeDevice": { - "description": "volumeDevice describes a mapping of a raw block device within a container.", - "properties": { - "devicePath": { - "description": "devicePath is the path inside of the container that the device will be mapped to.", - "type": "string" - }, - "name": { - "description": "name must match the name of a persistentVolumeClaim in the pod", - "type": "string" - } - }, - "required": [ - "name", - "devicePath" - ], - "type": "object" - }, - "io.k8s.api.core.v1.VolumeMount": { - "description": "VolumeMount describes a mounting of a Volume within a container.", - "properties": { - "mountPath": { - "description": "Path within the container at which the volume should be mounted. Must not contain ':'.", - "type": "string" - }, - "mountPropagation": { - "description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.", - "type": "string" - }, - "name": { - "description": "This must match the Name of a Volume.", - "type": "string" - }, - "readOnly": { - "description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.", - "type": "boolean" - }, - "subPath": { - "description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).", - "type": "string" - }, - "subPathExpr": { - "description": "Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to \"\" (volume's root). SubPathExpr and SubPath are mutually exclusive.", - "type": "string" - } - }, - "required": [ - "name", - "mountPath" - ], - "type": "object" - }, - "io.k8s.api.core.v1.VolumeNodeAffinity": { - "description": "VolumeNodeAffinity defines constraints that limit what nodes this volume can be accessed from.", - "properties": { - "required": { - "$ref": "#/definitions/io.k8s.api.core.v1.NodeSelector", - "description": "Required specifies hard node constraints that must be met." - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.VolumeProjection": { - "description": "Projection that may be projected along with other supported volume types", - "properties": { - "configMap": { - "$ref": "#/definitions/io.k8s.api.core.v1.ConfigMapProjection", - "description": "information about the configMap data to project" - }, - "downwardAPI": { - "$ref": "#/definitions/io.k8s.api.core.v1.DownwardAPIProjection", - "description": "information about the downwardAPI data to project" - }, - "secret": { - "$ref": "#/definitions/io.k8s.api.core.v1.SecretProjection", - "description": "information about the secret data to project" - }, - "serviceAccountToken": { - "$ref": "#/definitions/io.k8s.api.core.v1.ServiceAccountTokenProjection", - "description": "information about the serviceAccountToken data to project" - } - }, - "type": "object" - }, - "io.k8s.api.core.v1.VsphereVirtualDiskVolumeSource": { - "description": "Represents a vSphere volume resource.", - "properties": { - "fsType": { - "description": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", - "type": "string" - }, - "storagePolicyID": { - "description": "Storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.", - "type": "string" - }, - "storagePolicyName": { - "description": "Storage Policy Based Management (SPBM) profile name.", - "type": "string" - }, - "volumePath": { - "description": "Path that identifies vSphere volume vmdk", - "type": "string" - } - }, - "required": [ - "volumePath" - ], - "type": "object" - }, - "io.k8s.api.core.v1.WeightedPodAffinityTerm": { - "description": "The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s)", - "properties": { - "podAffinityTerm": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodAffinityTerm", - "description": "Required. A pod affinity term, associated with the corresponding weight." - }, - "weight": { - "description": "weight associated with matching the corresponding podAffinityTerm, in the range 1-100.", - "format": "int32", - "type": "integer" - } - }, - "required": [ - "weight", - "podAffinityTerm" - ], - "type": "object" - }, - "io.k8s.api.core.v1.WindowsSecurityContextOptions": { - "description": "WindowsSecurityContextOptions contain Windows-specific options and credentials.", - "properties": { - "gmsaCredentialSpec": { - "description": "GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.", - "type": "string" - }, - "gmsaCredentialSpecName": { - "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use. This field is alpha-level and is only honored by servers that enable the WindowsGMSA feature flag.", - "type": "string" - }, - "runAsUserName": { - "description": "The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. This field is beta-level and may be disabled with the WindowsRunAsUserName feature flag.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.Deployment": { - "description": "DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for more information. Deployment enables declarative updates for Pods and ReplicaSets.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", - "description": "Standard object metadata." - }, - "spec": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentSpec", - "description": "Specification of the desired behavior of the Deployment." - }, - "status": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentStatus", - "description": "Most recently observed status of the Deployment." - } - }, - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "extensions", - "kind": "Deployment", - "version": "v1beta1" - } - ] - }, - "io.k8s.api.extensions.v1beta1.DeploymentCondition": { - "description": "DeploymentCondition describes the state of a deployment at a certain point.", - "properties": { - "lastTransitionTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Last time the condition transitioned from one status to another." - }, - "lastUpdateTime": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "The last time this condition was updated." - }, - "message": { - "description": "A human readable message indicating details about the transition.", - "type": "string" - }, - "reason": { - "description": "The reason for the condition's last transition.", - "type": "string" - }, - "status": { - "description": "Status of the condition, one of True, False, Unknown.", - "type": "string" - }, - "type": { - "description": "Type of deployment condition.", - "type": "string" - } - }, - "required": [ - "type", - "status" - ], - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.DeploymentRollback": { - "description": "DEPRECATED. DeploymentRollback stores the information required to rollback a deployment.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - "type": "string" - }, - "kind": { - "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "name": { - "description": "Required: This must match the Name of a deployment.", - "type": "string" - }, - "rollbackTo": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.RollbackConfig", - "description": "The config of this deployment rollback." - }, - "updatedAnnotations": { - "additionalProperties": { - "type": "string" - }, - "description": "The annotations to be updated to a deployment", - "type": "object" - } - }, - "required": [ - "name", - "rollbackTo" - ], - "type": "object", - "x-kubernetes-group-version-kind": [ - { - "group": "extensions", - "kind": "DeploymentRollback", - "version": "v1beta1" - } - ] - }, - "io.k8s.api.extensions.v1beta1.DeploymentSpec": { - "description": "DeploymentSpec is the specification of the desired behavior of the Deployment.", - "properties": { - "minReadySeconds": { - "description": "Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)", - "format": "int32", - "type": "integer" - }, - "paused": { - "description": "Indicates that the deployment is paused and will not be processed by the deployment controller.", - "type": "boolean" - }, - "progressDeadlineSeconds": { - "description": "The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. This is set to the max value of int32 (i.e. 2147483647) by default, which means \"no deadline\".", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.", - "format": "int32", - "type": "integer" - }, - "revisionHistoryLimit": { - "description": "The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. This is set to the max value of int32 (i.e. 2147483647) by default, which means \"retaining all old RelicaSets\".", - "format": "int32", - "type": "integer" - }, - "rollbackTo": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.RollbackConfig", - "description": "DEPRECATED. The config this deployment is rolling back to. Will be cleared after rollback is done." - }, - "selector": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector", - "description": "Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment." - }, - "strategy": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentStrategy", - "description": "The deployment strategy to use to replace existing pods with new ones.", - "x-kubernetes-patch-strategy": "retainKeys" - }, - "template": { - "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", - "description": "Template describes the pods that will be created." - } - }, - "required": [ - "template" - ], - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.DeploymentStatus": { - "description": "DeploymentStatus is the most recently observed status of the Deployment.", - "properties": { - "availableReplicas": { - "description": "Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "collisionCount": { - "description": "Count of hash collisions for the Deployment. The Deployment controller uses this field as a collision avoidance mechanism when it needs to create the name for the newest ReplicaSet.", - "format": "int32", - "type": "integer" - }, - "conditions": { - "description": "Represents the latest available observations of a deployment's current state.", - "items": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentCondition" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "type", - "x-kubernetes-patch-strategy": "merge" - }, - "observedGeneration": { - "description": "The generation observed by the deployment controller.", - "format": "int64", - "type": "integer" - }, - "readyReplicas": { - "description": "Total number of ready pods targeted by this deployment.", - "format": "int32", - "type": "integer" - }, - "replicas": { - "description": "Total number of non-terminated pods targeted by this deployment (their labels match the selector).", - "format": "int32", - "type": "integer" - }, - "unavailableReplicas": { - "description": "Total number of unavailable pods targeted by this deployment. This is the total number of pods that are still required for the deployment to have 100% available capacity. They may either be pods that are running but not yet available or pods that still have not been created.", - "format": "int32", - "type": "integer" - }, - "updatedReplicas": { - "description": "Total number of non-terminated pods targeted by this deployment that have the desired template spec.", - "format": "int32", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.DeploymentStrategy": { - "description": "DeploymentStrategy describes how to replace existing pods with new ones.", - "properties": { - "rollingUpdate": { - "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.RollingUpdateDeployment", - "description": "Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate." - }, - "type": { - "description": "Type of deployment. Can be \"Recreate\" or \"RollingUpdate\". Default is RollingUpdate.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.RollbackConfig": { - "description": "DEPRECATED.", - "properties": { - "revision": { - "description": "The revision to rollback to. If set to 0, rollback to the last revision.", - "format": "int64", - "type": "integer" - } - }, - "type": "object" - }, - "io.k8s.api.extensions.v1beta1.RollingUpdateDeployment": { - "description": "Spec to control the desired behavior of rolling update.", - "properties": { - "maxSurge": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. By default, a value of 1 is used. Example: when this is set to 30%, the new RC can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new RC can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods." - }, - "maxUnavailable": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", - "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. By default, a fixed value of 1 is used. Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods." - } - }, - "type": "object" - }, - "io.k8s.apimachinery.pkg.api.resource.Quantity": { - "description": "Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors.\n\nThe serialization format is:\n\n ::= \n (Note that may be empty, from the \"\" case in .)\n ::= 0 | 1 | ... | 9 ::= | ::= | . | . | . ::= \"+\" | \"-\" ::= | ::= | | ::= Ki | Mi | Gi | Ti | Pi | Ei\n (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)\n ::= m | \"\" | k | M | G | T | P | E\n (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)\n ::= \"e\" | \"E\" \n\nNo matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities.\n\nWhen a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized.\n\nBefore serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that:\n a. No precision is lost\n b. No fractional digits will be emitted\n c. The exponent (or suffix) is as large as possible.\nThe sign will be omitted unless the number is negative.\n\nExamples:\n 1.5 will be serialized as \"1500m\"\n 1.5Gi will be serialized as \"1536Mi\"\n\nNote that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise.\n\nNon-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.)\n\nThis format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation.", - "type": "string" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1": { - "description": "FieldsV1 stores a set of fields in a data structure like a Trie, in JSON format.\n\nEach key is either a '.' representing the field itself, and will always map to an empty set, or a string representing a sub-field or item. The string will follow one of these four formats: 'f:', where is the name of a field in a struct, or key in a map 'v:', where is the exact json formatted value of a list item 'i:', where is position of a item in a list 'k:', where is a map of a list item's key fields to their unique values If a key maps to an empty Fields value, the field that key represents is part of the set.\n\nThe exact format is defined in sigs.k8s.io/structured-merge-diff", - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector": { - "description": "A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.", - "properties": { - "matchExpressions": { - "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", - "items": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement" - }, - "type": "array" - }, - "matchLabels": { - "additionalProperties": { - "type": "string" - }, - "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.", - "type": "object" - } - }, - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement": { - "description": "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.", - "properties": { - "key": { - "description": "key is the label key that the selector applies to.", - "type": "string", - "x-kubernetes-patch-merge-key": "key", - "x-kubernetes-patch-strategy": "merge" - }, - "operator": { - "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", - "type": "string" - }, - "values": { - "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "key", - "operator" - ], - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta": { - "description": "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", - "properties": { - "continue": { - "description": "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", - "type": "string" - }, - "remainingItemCount": { - "description": "remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact.", - "format": "int64", - "type": "integer" - }, - "resourceVersion": { - "description": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", - "type": "string" - }, - "selfLink": { - "description": "selfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry": { - "description": "ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource that the fieldset applies to.", - "properties": { - "apiVersion": { - "description": "APIVersion defines the version of this resource that this field set applies to. The format is \"group/version\" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted.", - "type": "string" - }, - "fieldsType": { - "description": "FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: \"FieldsV1\"", - "type": "string" - }, - "fieldsV1": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1", - "description": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type." - }, - "manager": { - "description": "Manager is an identifier of the workflow managing these fields.", - "type": "string" - }, - "operation": { - "description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'.", - "type": "string" - }, - "time": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'" - } - }, - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": { - "description": "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", - "properties": { - "annotations": { - "additionalProperties": { - "type": "string" - }, - "description": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations", - "type": "object" - }, - "clusterName": { - "description": "The name of the cluster which the object belongs to. This is used to distinguish resources with same name and namespace in different clusters. This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.", - "type": "string" - }, - "creationTimestamp": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "deletionGracePeriodSeconds": { - "description": "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.", - "format": "int64", - "type": "integer" - }, - "deletionTimestamp": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Time", - "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" - }, - "finalizers": { - "description": "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list.", - "items": { - "type": "string" - }, - "type": "array", - "x-kubernetes-patch-strategy": "merge" - }, - "generateName": { - "description": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", - "type": "string" - }, - "generation": { - "description": "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.", - "format": "int64", - "type": "integer" - }, - "labels": { - "additionalProperties": { - "type": "string" - }, - "description": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels", - "type": "object" - }, - "managedFields": { - "description": "ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like \"ci-cd\". The set of fields is always in the version that the workflow used when modifying the object.", - "items": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ManagedFieldsEntry" - }, - "type": "array" - }, - "name": { - "description": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - "type": "string" - }, - "namespace": { - "description": "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/namespaces", - "type": "string" - }, - "ownerReferences": { - "description": "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.", - "items": { - "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference" - }, - "type": "array", - "x-kubernetes-patch-merge-key": "uid", - "x-kubernetes-patch-strategy": "merge" - }, - "resourceVersion": { - "description": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", - "type": "string" - }, - "selfLink": { - "description": "SelfLink is a URL representing this object. Populated by the system. Read-only.\n\nDEPRECATED Kubernetes will stop propagating this field in 1.20 release and the field is planned to be removed in 1.21 release.", - "type": "string" - }, - "uid": { - "description": "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type": "string" - } - }, - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.OwnerReference": { - "description": "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.", - "properties": { - "apiVersion": { - "description": "API version of the referent.", - "type": "string" - }, - "blockOwnerDeletion": { - "description": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", - "type": "boolean" - }, - "controller": { - "description": "If true, this reference points to the managing controller.", - "type": "boolean" - }, - "kind": { - "description": "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - "type": "string" - }, - "name": { - "description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names", - "type": "string" - }, - "uid": { - "description": "UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids", - "type": "string" - } - }, - "required": [ - "apiVersion", - "kind", - "name", - "uid" - ], - "type": "object" - }, - "io.k8s.apimachinery.pkg.apis.meta.v1.Time": { - "description": "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", - "format": "date-time", - "type": "string" - }, - "io.k8s.apimachinery.pkg.util.intstr.IntOrString": { - "description": "IntOrString is a type that can hold an int32 or a string. When used in JSON or YAML marshalling and unmarshalling, it produces or consumes the inner type. This allows you to have, for example, a JSON field that can accept a name or number.", - "format": "int-or-string", - "type": "string" - } - }, - "info": { - "title": "Kubernetes", - "version": "test" - }, - "paths": { - }, - "swagger": "2.0" -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter.go deleted file mode 100644 index 7b87009a16f..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter.go +++ /dev/null @@ -1,129 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kube-openapi/pkg/util/proto" - "sigs.k8s.io/structured-merge-diff/v3/typed" - "sigs.k8s.io/structured-merge-diff/v3/value" -) - -// TypeConverter allows you to convert from runtime.Object to -// typed.TypedValue and the other way around. -type TypeConverter interface { - ObjectToTyped(runtime.Object) (*typed.TypedValue, error) - TypedToObject(*typed.TypedValue) (runtime.Object, error) -} - -// DeducedTypeConverter is a TypeConverter for CRDs that don't have a -// schema. It does implement the same interface though (and create the -// same types of objects), so that everything can still work the same. -// CRDs are merged with all their fields being "atomic" (lists -// included). -// -// Note that this is not going to be sufficient for converting to/from -// CRDs that have a schema defined (we don't support that schema yet). -// TODO(jennybuckley): Use the schema provided by a CRD if it exists. -type DeducedTypeConverter struct{} - -var _ TypeConverter = DeducedTypeConverter{} - -// ObjectToTyped converts an object into a TypedValue with a "deduced type". -func (DeducedTypeConverter) ObjectToTyped(obj runtime.Object) (*typed.TypedValue, error) { - switch o := obj.(type) { - case *unstructured.Unstructured: - return typed.DeducedParseableType.FromUnstructured(o.UnstructuredContent()) - default: - return typed.DeducedParseableType.FromStructured(obj) - } -} - -// TypedToObject transforms the typed value into a runtime.Object. That -// is not specific to deduced type. -func (DeducedTypeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) { - return valueToObject(value.AsValue()) -} - -type typeConverter struct { - parser *gvkParser -} - -var _ TypeConverter = &typeConverter{} - -// NewTypeConverter builds a TypeConverter from a proto.Models. This -// will automatically find the proper version of the object, and the -// corresponding schema information. -func NewTypeConverter(models proto.Models, preserveUnknownFields bool) (TypeConverter, error) { - parser, err := newGVKParser(models, preserveUnknownFields) - if err != nil { - return nil, err - } - return &typeConverter{parser: parser}, nil -} - -func (c *typeConverter) ObjectToTyped(obj runtime.Object) (*typed.TypedValue, error) { - gvk := obj.GetObjectKind().GroupVersionKind() - t := c.parser.Type(gvk) - if t == nil { - return nil, newNoCorrespondingTypeError(gvk) - } - switch o := obj.(type) { - case *unstructured.Unstructured: - return t.FromUnstructured(o.UnstructuredContent()) - default: - return t.FromStructured(obj) - } -} - -func (c *typeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) { - return valueToObject(value.AsValue()) -} - -func valueToObject(val value.Value) (runtime.Object, error) { - vu := val.Unstructured() - switch o := vu.(type) { - case map[string]interface{}: - return &unstructured.Unstructured{Object: o}, nil - default: - return nil, fmt.Errorf("failed to convert value to unstructured for type %T", vu) - } -} - -type noCorrespondingTypeErr struct { - gvk schema.GroupVersionKind -} - -func newNoCorrespondingTypeError(gvk schema.GroupVersionKind) error { - return &noCorrespondingTypeErr{gvk: gvk} -} - -func (k *noCorrespondingTypeErr) Error() string { - return fmt.Sprintf("no corresponding type for %v", k.gvk) -} - -func isNoCorrespondingTypeError(err error) bool { - if err == nil { - return false - } - _, ok := err.(*noCorrespondingTypeErr) - return ok -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter_test.go deleted file mode 100644 index 6d70b480ba3..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/typeconverter_test.go +++ /dev/null @@ -1,206 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal_test - -import ( - "fmt" - "path/filepath" - "reflect" - "testing" - - "sigs.k8s.io/structured-merge-diff/v3/typed" - "sigs.k8s.io/yaml" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - "k8s.io/kube-openapi/pkg/util/proto" - prototesting "k8s.io/kube-openapi/pkg/util/proto/testing" -) - -var fakeSchema = prototesting.Fake{ - Path: filepath.Join("testdata", "swagger.json"), -} - -func TestTypeConverter(t *testing.T) { - d, err := fakeSchema.OpenAPISchema() - if err != nil { - t.Fatalf("Failed to parse OpenAPI schema: %v", err) - } - m, err := proto.NewOpenAPIData(d) - if err != nil { - t.Fatalf("Failed to build OpenAPI models: %v", err) - } - - tc, err := internal.NewTypeConverter(m, false) - if err != nil { - t.Fatalf("Failed to build TypeConverter: %v", err) - } - - dtc := internal.DeducedTypeConverter{} - - testCases := []struct { - name string - yaml string - }{ - { - name: "apps/v1.Deployment", - yaml: ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-deployment - labels: - app: nginx -spec: - selector: - matchLabels: - app: nginx - template: - metadata: - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx:1.15.4 -`, - }, { - name: "extensions/v1beta1.Deployment", - yaml: ` -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-deployment - labels: - app: nginx -spec: - selector: - matchLabels: - app: nginx - template: - metadata: - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx:1.15.4 -`, - }, { - name: "v1.Pod", - yaml: ` -apiVersion: v1 -kind: Pod -metadata: - name: nginx-pod - labels: - app: nginx -spec: - containers: - - name: nginx - image: nginx:1.15.4 -`, - }, - } - - for _, testCase := range testCases { - t.Run(fmt.Sprintf("%v ObjectToTyped with TypeConverter", testCase.name), func(t *testing.T) { - testObjectToTyped(t, tc, testCase.yaml) - }) - t.Run(fmt.Sprintf("%v ObjectToTyped with DeducedTypeConverter", testCase.name), func(t *testing.T) { - testObjectToTyped(t, dtc, testCase.yaml) - }) - } -} - -func testObjectToTyped(t *testing.T, tc internal.TypeConverter, y string) { - obj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(y), &obj.Object); err != nil { - t.Fatalf("Failed to parse yaml object: %v", err) - } - typed, err := tc.ObjectToTyped(obj) - if err != nil { - t.Fatalf("Failed to convert object to typed: %v", err) - } - newObj, err := tc.TypedToObject(typed) - if err != nil { - t.Fatalf("Failed to convert typed to object: %v", err) - } - if !reflect.DeepEqual(obj, newObj) { - t.Errorf(`Round-trip failed: -Original object: -%#v -Final object: -%#v`, obj, newObj) - } -} - -var result typed.TypedValue - -func BenchmarkObjectToTyped(b *testing.B) { - y := ` -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: nginx-deployment - labels: - app: nginx -spec: - selector: - matchLabels: - app: nginx - template: - metadata: - labels: - app: nginx - spec: - containers: - - name: nginx - image: nginx:1.15.4 -` - obj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(y), &obj.Object); err != nil { - b.Fatalf("Failed to parse yaml object: %v", err) - } - - d, err := fakeSchema.OpenAPISchema() - if err != nil { - b.Fatalf("Failed to parse OpenAPI schema: %v", err) - } - m, err := proto.NewOpenAPIData(d) - if err != nil { - b.Fatalf("Failed to build OpenAPI models: %v", err) - } - - tc, err := internal.NewTypeConverter(m, false) - if err != nil { - b.Fatalf("Failed to build TypeConverter: %v", err) - } - - b.ResetTimer() - b.ReportAllocs() - - var r *typed.TypedValue - for i := 0; i < b.N; i++ { - var err error - r, err = tc.ObjectToTyped(obj) - if err != nil { - b.Fatalf("Failed to convert object to typed: %v", err) - } - } - result = *r -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter.go deleted file mode 100644 index 15628b0275e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/merge" - "sigs.k8s.io/structured-merge-diff/v3/typed" -) - -// versionConverter is an implementation of -// sigs.k8s.io/structured-merge-diff/merge.Converter -type versionConverter struct { - typeConverter TypeConverter - objectConvertor runtime.ObjectConvertor - hubGetter func(from schema.GroupVersion) schema.GroupVersion -} - -var _ merge.Converter = &versionConverter{} - -// NewVersionConverter builds a VersionConverter from a TypeConverter and an ObjectConvertor. -func NewVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter { - return &versionConverter{ - typeConverter: t, - objectConvertor: o, - hubGetter: func(from schema.GroupVersion) schema.GroupVersion { - return schema.GroupVersion{ - Group: from.Group, - Version: h.Version, - } - }, - } -} - -// NewCRDVersionConverter builds a VersionConverter for CRDs from a TypeConverter and an ObjectConvertor. -func NewCRDVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter { - return &versionConverter{ - typeConverter: t, - objectConvertor: o, - hubGetter: func(from schema.GroupVersion) schema.GroupVersion { - return h - }, - } -} - -// Convert implements sigs.k8s.io/structured-merge-diff/merge.Converter -func (v *versionConverter) Convert(object *typed.TypedValue, version fieldpath.APIVersion) (*typed.TypedValue, error) { - // Convert the smd typed value to a kubernetes object. - objectToConvert, err := v.typeConverter.TypedToObject(object) - if err != nil { - return object, err - } - - // Parse the target groupVersion. - groupVersion, err := schema.ParseGroupVersion(string(version)) - if err != nil { - return object, err - } - - // If attempting to convert to the same version as we already have, just return it. - fromVersion := objectToConvert.GetObjectKind().GroupVersionKind().GroupVersion() - if fromVersion == groupVersion { - return object, nil - } - - // Convert to internal - internalObject, err := v.objectConvertor.ConvertToVersion(objectToConvert, v.hubGetter(fromVersion)) - if err != nil { - return object, err - } - - // Convert the object into the target version - convertedObject, err := v.objectConvertor.ConvertToVersion(internalObject, groupVersion) - if err != nil { - return object, err - } - - // Convert the object back to a smd typed value and return it. - return v.typeConverter.ObjectToTyped(convertedObject) -} - -// IsMissingVersionError -func (v *versionConverter) IsMissingVersionError(err error) bool { - return runtime.IsNotRegisteredError(err) || isNoCorrespondingTypeError(err) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter_test.go deleted file mode 100644 index d873f0e1015..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/versionconverter_test.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package internal_test - -import ( - "fmt" - "reflect" - "testing" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - "k8s.io/kube-openapi/pkg/util/proto" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -// TestVersionConverter tests the version converter -func TestVersionConverter(t *testing.T) { - d, err := fakeSchema.OpenAPISchema() - if err != nil { - t.Fatalf("Failed to parse OpenAPI schema: %v", err) - } - m, err := proto.NewOpenAPIData(d) - if err != nil { - t.Fatalf("Failed to build OpenAPI models: %v", err) - } - tc, err := internal.NewTypeConverter(m, false) - if err != nil { - t.Fatalf("Failed to build TypeConverter: %v", err) - } - oc := fakeObjectConvertor{ - gvkForVersion("v1beta1"): objForGroupVersion("apps/v1beta1"), - gvkForVersion("v1"): objForGroupVersion("apps/v1"), - } - vc := internal.NewVersionConverter(tc, oc, schema.GroupVersion{Group: "apps", Version: runtime.APIVersionInternal}) - - input, err := tc.ObjectToTyped(objForGroupVersion("apps/v1beta1")) - if err != nil { - t.Fatalf("error creating converting input object to a typed value: %v", err) - } - expected := objForGroupVersion("apps/v1") - output, err := vc.Convert(input, fieldpath.APIVersion("apps/v1")) - if err != nil { - t.Fatalf("expected err to be nil but got %v", err) - } - actual, err := tc.TypedToObject(output) - if err != nil { - t.Fatalf("error converting output typed value to an object %v", err) - } - - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("expected to get %v but got %v", expected, actual) - } -} - -func gvkForVersion(v string) schema.GroupVersionKind { - return schema.GroupVersionKind{ - Group: "apps", - Version: v, - Kind: "Deployment", - } -} - -func objForGroupVersion(gv string) runtime.Object { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": gv, - "kind": "Deployment", - }, - } -} - -type fakeObjectConvertor map[schema.GroupVersionKind]runtime.Object - -var _ runtime.ObjectConvertor = fakeObjectConvertor{} - -func (c fakeObjectConvertor) ConvertToVersion(_ runtime.Object, gv runtime.GroupVersioner) (runtime.Object, error) { - allKinds := make([]schema.GroupVersionKind, 0) - for kind := range c { - allKinds = append(allKinds, kind) - } - gvk, _ := gv.KindForGroupVersionKinds(allKinds) - return c[gvk], nil -} - -func (fakeObjectConvertor) Convert(_, _, _ interface{}) error { - return fmt.Errorf("function not implemented") -} - -func (fakeObjectConvertor) ConvertFieldLabel(_ schema.GroupVersionKind, _, _ string) (string, string, error) { - return "", "", fmt.Errorf("function not implemented") -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/managedfieldsupdater.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/managedfieldsupdater.go deleted file mode 100644 index a015e002ae0..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/managedfieldsupdater.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2020 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 fieldmanager - -import ( - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -type managedFieldsUpdater struct { - fieldManager Manager -} - -var _ Manager = &managedFieldsUpdater{} - -// NewManagedFieldsUpdater is responsible for updating the managedfields -// in the object, updating the time of the operation as necessary. For -// updates, it uses a hard-coded manager to detect if things have -// changed, and swaps back the correct manager after the operation is -// done. -func NewManagedFieldsUpdater(fieldManager Manager) Manager { - return &managedFieldsUpdater{ - fieldManager: fieldManager, - } -} - -// Update implements Manager. -func (f *managedFieldsUpdater) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - self := "current-operation" - object, managed, err := f.fieldManager.Update(liveObj, newObj, managed, self) - if err != nil { - return object, managed, err - } - - // If the current operation took any fields from anything, it means the object changed, - // so update the timestamp of the managedFieldsEntry and merge with any previous updates from the same manager - if vs, ok := managed.Fields()[self]; ok { - delete(managed.Fields(), self) - - managed.Times()[manager] = &metav1.Time{Time: time.Now().UTC()} - if previous, ok := managed.Fields()[manager]; ok { - managed.Fields()[manager] = fieldpath.NewVersionedSet(vs.Set().Union(previous.Set()), vs.APIVersion(), vs.Applied()) - } else { - managed.Fields()[manager] = vs - } - } - - return object, managed, nil -} - -// Apply implements Manager. -func (f *managedFieldsUpdater) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) { - formerManaged := managed.Fields().Copy() - object, managed, err := f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force) - if err != nil { - return object, managed, err - } - if object != nil || !managed.Fields().Equals(formerManaged) { - managed.Times()[fieldManager] = &metav1.Time{Time: time.Now().UTC()} - } - if object == nil { - object = liveObj - } - return object, managed, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/node.yaml b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/node.yaml deleted file mode 100644 index 13a14cf449b..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/node.yaml +++ /dev/null @@ -1,259 +0,0 @@ -apiVersion: v1 -kind: Node -metadata: - annotations: - container.googleapis.com/instance_id: "123456789321654789" - node.alpha.kubernetes.io/ttl: "0" - volumes.kubernetes.io/controller-managed-attach-detach: "true" - creationTimestamp: "2019-07-09T16:17:29Z" - labels: - kubernetes.io/arch: amd64 - beta.kubernetes.io/fluentd-ds-ready: "true" - beta.kubernetes.io/instance-type: n1-standard-4 - kubernetes.io/os: linux - cloud.google.com/gke-nodepool: default-pool - cloud.google.com/gke-os-distribution: cos - failure-domain.beta.kubernetes.io/region: us-central1 - failure-domain.beta.kubernetes.io/zone: us-central1-b - kubernetes.io/hostname: node-default-pool-something - name: node-default-pool-something - resourceVersion: "211582541" - selfLink: /api/v1/nodes/node-default-pool-something - uid: 0c24d0e1-a265-11e9-abe4-42010a80026b -spec: - podCIDR: 10.0.0.1/24 - providerID: some-provider-id-of-some-sort -status: - addresses: - - address: 10.0.0.1 - type: InternalIP - - address: 192.168.0.1 - type: ExternalIP - - address: node-default-pool-something - type: Hostname - allocatable: - cpu: 3920m - ephemeral-storage: "104638878617" - hugepages-2Mi: "0" - memory: 12700100Ki - pods: "110" - capacity: - cpu: "4" - ephemeral-storage: 202086868Ki - hugepages-2Mi: "0" - memory: 15399364Ki - pods: "110" - conditions: - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:22:08Z" - message: containerd is functioning properly - reason: FrequentContainerdRestart - status: "False" - type: FrequentContainerdRestart - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:22:06Z" - message: docker overlay2 is functioning properly - reason: CorruptDockerOverlay2 - status: "False" - type: CorruptDockerOverlay2 - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:22:06Z" - message: node is functioning properly - reason: UnregisterNetDevice - status: "False" - type: FrequentUnregisterNetDevice - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:17:04Z" - message: kernel has no deadlock - reason: KernelHasNoDeadlock - status: "False" - type: KernelDeadlock - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:17:04Z" - message: Filesystem is not read-only - reason: FilesystemIsNotReadOnly - status: "False" - type: ReadonlyFilesystem - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:22:05Z" - message: kubelet is functioning properly - reason: FrequentKubeletRestart - status: "False" - type: FrequentKubeletRestart - - lastHeartbeatTime: "2019-09-20T19:32:08Z" - lastTransitionTime: "2019-07-09T16:22:06Z" - message: docker is functioning properly - reason: FrequentDockerRestart - status: "False" - type: FrequentDockerRestart - - lastHeartbeatTime: "2019-07-09T16:17:47Z" - lastTransitionTime: "2019-07-09T16:17:47Z" - message: RouteController created a route - reason: RouteCreated - status: "False" - type: NetworkUnavailable - - lastHeartbeatTime: "2019-09-20T19:32:50Z" - lastTransitionTime: "2019-07-09T16:17:29Z" - message: kubelet has sufficient disk space available - reason: KubeletHasSufficientDisk - status: "False" - type: OutOfDisk - - lastHeartbeatTime: "2019-09-20T19:32:50Z" - lastTransitionTime: "2019-07-09T16:17:29Z" - message: kubelet has sufficient memory available - reason: KubeletHasSufficientMemory - status: "False" - type: MemoryPressure - - lastHeartbeatTime: "2019-09-20T19:32:50Z" - lastTransitionTime: "2019-07-09T16:17:29Z" - message: kubelet has no disk pressure - reason: KubeletHasNoDiskPressure - status: "False" - type: DiskPressure - - lastHeartbeatTime: "2019-09-20T19:32:50Z" - lastTransitionTime: "2019-07-09T16:17:29Z" - message: kubelet has sufficient PID available - reason: KubeletHasSufficientPID - status: "False" - type: PIDPressure - - lastHeartbeatTime: "2019-09-20T19:32:50Z" - lastTransitionTime: "2019-07-09T16:17:49Z" - message: kubelet is posting ready status. AppArmor enabled - reason: KubeletReady - status: "True" - type: Ready - daemonEndpoints: - kubeletEndpoint: - Port: 10250 - images: - - names: - - grafana/grafana@sha256:80e5e113a984d74836aa16f5b4524012099436b1a50df293f00ac6377fb512c8 - - grafana/grafana:4.4.2 - sizeBytes: 287008013 - - names: - - k8s.gcr.io/node-problem-detector@sha256:f95cab985c26b2f46e9bd43283e0bfa88860c14e0fb0649266babe8b65e9eb2b - - k8s.gcr.io/node-problem-detector:v0.4.1 - sizeBytes: 286572743 - - names: - - grafana/grafana@sha256:7ff7f9b2501a5d55b55ce3f58d21771b1c5af1f2a4ab7dbf11bef7142aae7033 - - grafana/grafana:4.2.0 - sizeBytes: 277940263 - - names: - - influxdb@sha256:7dddf03376348876ed4bdf33d6dfa3326f45a2bae0930dbd80781a374eb519bc - - influxdb:1.2.2 - sizeBytes: 223948571 - - names: - - gcr.io/stackdriver-agents/stackdriver-logging-agent@sha256:f8d5231b67b9c53f60068b535a11811d29d1b3efd53d2b79f2a2591ea338e4f2 - - gcr.io/stackdriver-agents/stackdriver-logging-agent:0.6-1.6.0-1 - sizeBytes: 223242132 - - names: - - nginx@sha256:35779791c05d119df4fe476db8f47c0bee5943c83eba5656a15fc046db48178b - - nginx:1.10.1 - sizeBytes: 180708613 - - names: - - k8s.gcr.io/fluentd-elasticsearch@sha256:b8c94527b489fb61d3d81ce5ad7f3ddbb7be71e9620a3a36e2bede2f2e487d73 - - k8s.gcr.io/fluentd-elasticsearch:v2.0.4 - sizeBytes: 135716379 - - names: - - nginx@sha256:00be67d6ba53d5318cd91c57771530f5251cfbe028b7be2c4b70526f988cfc9f - - nginx:latest - sizeBytes: 109357355 - - names: - - k8s.gcr.io/kubernetes-dashboard-amd64@sha256:dc4026c1b595435ef5527ca598e1e9c4343076926d7d62b365c44831395adbd0 - - k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 - sizeBytes: 102319441 - - names: - - gcr.io/google_containers/kube-proxy:v1.11.10-gke.5 - - k8s.gcr.io/kube-proxy:v1.11.10-gke.5 - sizeBytes: 102279340 - - names: - - k8s.gcr.io/event-exporter@sha256:7f9cd7cb04d6959b0aa960727d04fa86759008048c785397b7b0d9dff0007516 - - k8s.gcr.io/event-exporter:v0.2.3 - sizeBytes: 94171943 - - names: - - k8s.gcr.io/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662 - - k8s.gcr.io/prometheus-to-sd:v0.3.1 - sizeBytes: 88077694 - - names: - - k8s.gcr.io/fluentd-gcp-scaler@sha256:a5ace7506d393c4ed65eb2cbb6312c64ab357fcea16dff76b9055bc6e498e5ff - - k8s.gcr.io/fluentd-gcp-scaler:0.5.1 - sizeBytes: 86637208 - - names: - - k8s.gcr.io/heapster-amd64@sha256:9fae0af136ce0cf4f88393b3670f7139ffc464692060c374d2ae748e13144521 - - k8s.gcr.io/heapster-amd64:v1.6.0-beta.1 - sizeBytes: 76016169 - - names: - - k8s.gcr.io/ingress-glbc-amd64@sha256:31d36bbd9c44caffa135fc78cf0737266fcf25e3cf0cd1c2fcbfbc4f7309cc52 - - k8s.gcr.io/ingress-glbc-amd64:v1.1.1 - sizeBytes: 67801919 - - names: - - k8s.gcr.io/kube-addon-manager@sha256:d53486c3a0b49ebee019932878dc44232735d5622a51dbbdcec7124199020d09 - - k8s.gcr.io/kube-addon-manager:v8.7 - sizeBytes: 63322109 - - names: - - nginx@sha256:4aacdcf186934dcb02f642579314075910f1855590fd3039d8fa4c9f96e48315 - - nginx:1.10-alpine - sizeBytes: 54042627 - - names: - - k8s.gcr.io/cpvpa-amd64@sha256:cfe7b0a11c9c8e18c87b1eb34fef9a7cbb8480a8da11fc2657f78dbf4739f869 - - k8s.gcr.io/cpvpa-amd64:v0.6.0 - sizeBytes: 51785854 - - names: - - k8s.gcr.io/cluster-proportional-autoscaler-amd64@sha256:003f98d9f411ddfa6ff6d539196355e03ddd69fa4ed38c7ffb8fec6f729afe2d - - k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2-r2 - sizeBytes: 49648481 - - names: - - k8s.gcr.io/ip-masq-agent-amd64@sha256:1ffda57d87901bc01324c82ceb2145fe6a0448d3f0dd9cb65aa76a867cd62103 - - k8s.gcr.io/ip-masq-agent-amd64:v2.1.1 - sizeBytes: 49612505 - - names: - - k8s.gcr.io/k8s-dns-kube-dns-amd64@sha256:b99fc3eee2a9f052f7eb4cc00f15eb12fc405fa41019baa2d6b79847ae7284a8 - - k8s.gcr.io/k8s-dns-kube-dns-amd64:1.14.10 - sizeBytes: 49549457 - - names: - - k8s.gcr.io/rescheduler@sha256:156cfbfd05a5a815206fd2eeb6cbdaf1596d71ea4b415d3a6c43071dd7b99450 - - k8s.gcr.io/rescheduler:v0.4.0 - sizeBytes: 48973149 - - names: - - k8s.gcr.io/event-exporter@sha256:16ca66e2b5dc7a1ce6a5aafcb21d0885828b75cdfc08135430480f7ad2364adc - - k8s.gcr.io/event-exporter:v0.2.4 - sizeBytes: 47261019 - - names: - - k8s.gcr.io/coredns@sha256:db2bf53126ed1c761d5a41f24a1b82a461c85f736ff6e90542e9522be4757848 - - k8s.gcr.io/coredns:1.1.3 - sizeBytes: 45587362 - - names: - - prom/prometheus@sha256:483f4c9d7733699ba79facca9f8bcce1cef1af43dfc3e7c5a1882aa85f53cb74 - - prom/prometheus:v1.1.3 - sizeBytes: 45493941 - nodeInfo: - architecture: amd64 - bootID: a32eca78-4ad4-4b76-9252-f143d6c2ae61 - containerRuntimeVersion: docker://17.3.2 - kernelVersion: 4.14.127+ - kubeProxyVersion: v1.11.10-gke.5 - kubeletVersion: v1.11.10-gke.5 - machineID: 1739555e5b231057f0f9a0b5fa29511b - operatingSystem: linux - osImage: Container-Optimized OS from Google - systemUUID: 1739555E-5B23-1057-F0F9-A0B5FA29511B - volumesAttached: - - devicePath: /dev/disk/by-id/b9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049 - - devicePath: /dev/disk/by-id/b9772-pvc-8895a852-fd42-11e6-94d4-42010a800049 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-8895a852-fd42-11e6-94d4-42010a800049 - - devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049 - - devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049 - - devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049 - - devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283 - name: kubernetes.io/pd/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283 - volumesInUse: - - kubernetes.io/pd/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049 - - kubernetes.io/pd/some-random-clusterb9772-pvc-8895a852-fd42-11e6-94d4-42010a800049 - - kubernetes.io/pd/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049 - - kubernetes.io/pd/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283 - - kubernetes.io/pd/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049 - - kubernetes.io/pd/some-random-clusterb9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049 diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/pod.yaml b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/pod.yaml deleted file mode 100644 index 3fb0877d67c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/pod.yaml +++ /dev/null @@ -1,121 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - labels: - app: some-app - plugin1: some-value - plugin2: some-value - plugin3: some-value - plugin4: some-value - name: some-name - namespace: default - ownerReferences: - - apiVersion: apps/v1 - blockOwnerDeletion: true - controller: true - kind: ReplicaSet - name: some-name - uid: 0a9d2b9e-779e-11e7-b422-42010a8001be -spec: - containers: - - args: - - one - - two - - three - - four - - five - - six - - seven - - eight - - nine - env: - - name: VAR_3 - valueFrom: - secretKeyRef: - key: some-other-key - name: some-oher-name - - name: VAR_2 - valueFrom: - secretKeyRef: - key: other-key - name: other-name - - name: VAR_1 - valueFrom: - secretKeyRef: - key: some-key - name: some-name - image: some-image-name - imagePullPolicy: IfNotPresent - name: some-name - resources: - requests: - cpu: '0' - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-hu5jz - readOnly: true - dnsPolicy: ClusterFirst - nodeName: node-name - priority: 0 - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - tolerations: - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 300 - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 300 - volumes: - - name: default-token-hu5jz - secret: - defaultMode: 420 - secretName: default-token-hu5jz -status: - conditions: - - lastProbeTime: null - lastTransitionTime: '2019-07-08T09:31:18Z' - status: 'True' - type: Initialized - - lastProbeTime: null - lastTransitionTime: '2019-07-08T09:41:59Z' - status: 'True' - type: Ready - - lastProbeTime: null - lastTransitionTime: null - status: 'True' - type: ContainersReady - - lastProbeTime: null - lastTransitionTime: '2019-07-08T09:31:18Z' - status: 'True' - type: PodScheduled - containerStatuses: - - containerID: docker://885e82a1ed0b7356541bb410a0126921ac42439607c09875cd8097dd5d7b5376 - image: some-image-name - imageID: docker-pullable://some-image-id - lastState: - terminated: - containerID: docker://d57290f9e00fad626b20d2dd87a3cf69bbc22edae07985374f86a8b2b4e39565 - exitCode: 255 - finishedAt: '2019-07-08T09:39:09Z' - reason: Error - startedAt: '2019-07-08T09:38:54Z' - name: name - ready: true - restartCount: 6 - state: - running: - startedAt: '2019-07-08T09:41:59Z' - hostIP: 10.0.0.1 - phase: Running - podIP: 10.0.0.1 - qosClass: BestEffort - startTime: '2019-07-08T09:31:18Z' diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied.go deleted file mode 100644 index a8c34ad6529..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright 2019 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 fieldmanager - -import ( - "fmt" - "math/rand" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type skipNonAppliedManager struct { - fieldManager Manager - objectCreater runtime.ObjectCreater - gvk schema.GroupVersionKind - beforeApplyManagerName string - probability float32 -} - -var _ Manager = &skipNonAppliedManager{} - -// NewSkipNonAppliedManager creates a new wrapped FieldManager that only starts tracking managers after the first apply. -func NewSkipNonAppliedManager(fieldManager Manager, objectCreater runtime.ObjectCreater, gvk schema.GroupVersionKind) Manager { - return NewProbabilisticSkipNonAppliedManager(fieldManager, objectCreater, gvk, 0.0) -} - -// NewProbabilisticSkipNonAppliedManager creates a new wrapped FieldManager that starts tracking managers after the first apply, -// or starts tracking on create with p probability. -func NewProbabilisticSkipNonAppliedManager(fieldManager Manager, objectCreater runtime.ObjectCreater, gvk schema.GroupVersionKind, p float32) Manager { - return &skipNonAppliedManager{ - fieldManager: fieldManager, - objectCreater: objectCreater, - gvk: gvk, - beforeApplyManagerName: "before-first-apply", - probability: p, - } -} - -// Update implements Manager. -func (f *skipNonAppliedManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - accessor, err := meta.Accessor(liveObj) - if err != nil { - return newObj, managed, nil - } - - // If managed fields is empty, we need to determine whether to skip tracking managed fields. - if len(managed.Fields()) == 0 { - // Check if the operation is a create, by checking whether lastObj's UID is empty. - // If the operation is create, P(tracking managed fields) = f.probability - // If the operation is update, skip tracking managed fields, since we already know managed fields is empty. - if len(accessor.GetUID()) == 0 { - if f.probability <= rand.Float32() { - return newObj, managed, nil - } - } else { - return newObj, managed, nil - } - } - return f.fieldManager.Update(liveObj, newObj, managed, manager) -} - -// Apply implements Manager. -func (f *skipNonAppliedManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) { - if len(managed.Fields()) == 0 { - emptyObj, err := f.objectCreater.New(f.gvk) - if err != nil { - return nil, nil, fmt.Errorf("failed to create empty object of type %v: %v", f.gvk, err) - } - liveObj, managed, err = f.fieldManager.Update(emptyObj, liveObj, managed, f.beforeApplyManagerName) - if err != nil { - return nil, nil, fmt.Errorf("failed to create manager for existing fields: %v", err) - } - } - return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied_test.go deleted file mode 100644 index 2f8d4fdcbcc..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/skipnonapplied_test.go +++ /dev/null @@ -1,152 +0,0 @@ -/* -Copyright 2019 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 fieldmanager_test - -import ( - "strings" - "testing" - - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" - "sigs.k8s.io/yaml" -) - -type fakeObjectCreater struct { - gvk schema.GroupVersionKind -} - -var _ runtime.ObjectCreater = &fakeObjectCreater{} - -func (f *fakeObjectCreater) New(_ schema.GroupVersionKind) (runtime.Object, error) { - u := unstructured.Unstructured{Object: map[string]interface{}{}} - u.SetAPIVersion(f.gvk.GroupVersion().String()) - u.SetKind(f.gvk.Kind) - return &u, nil -} - -func TestNoUpdateBeforeFirstApply(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - f.fieldManager = fieldmanager.NewSkipNonAppliedManager( - f.fieldManager, - &fakeObjectCreater{gvk: schema.GroupVersionKind{Version: "v1", Kind: "Pod"}}, - schema.GroupVersionKind{}, - ) - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "name": "pod", - "labels": {"app": "nginx"} - }, - "spec": { - "containers": [{ - "name": "nginx", - "image": "nginx:latest" - }] - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - if err := f.Apply(appliedObj, "fieldmanager_test_apply", false); err != nil { - t.Fatalf("failed to update object: %v", err) - } - - if e, a := 1, len(f.ManagedFields()); e != a { - t.Fatalf("exected %v entries in managedFields, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "fieldmanager_test_apply", f.ManagedFields()[0].Manager; e != a { - t.Fatalf("exected manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } -} - -func TestUpdateBeforeFirstApply(t *testing.T) { - f := NewTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) - f.fieldManager = fieldmanager.NewSkipNonAppliedManager( - f.fieldManager, - &fakeObjectCreater{gvk: schema.GroupVersionKind{Version: "v1", Kind: "Pod"}}, - schema.GroupVersionKind{}, - ) - - updatedObj := &corev1.Pod{} - updatedObj.Kind = "Pod" - updatedObj.APIVersion = "v1" - updatedObj.ObjectMeta.Labels = map[string]string{"app": "my-nginx"} - - if err := f.Update(updatedObj, "fieldmanager_test_update"); err != nil { - t.Fatalf("failed to update object: %v", err) - } - - if m := f.ManagedFields(); len(m) != 0 { - t.Fatalf("managedFields were tracked on update only: %v", m) - } - - appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal([]byte(`{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "name": "pod", - "labels": {"app": "nginx"} - }, - "spec": { - "containers": [{ - "name": "nginx", - "image": "nginx:latest" - }] - } - }`), &appliedObj.Object); err != nil { - t.Fatalf("error decoding YAML: %v", err) - } - - err := f.Apply(appliedObj, "fieldmanager_test_apply", false) - apiStatus, _ := err.(apierrors.APIStatus) - if err == nil || !apierrors.IsConflict(err) || len(apiStatus.Status().Details.Causes) != 1 { - t.Fatalf("Expecting to get one conflict but got %v", err) - } - - if e, a := ".metadata.labels.app", apiStatus.Status().Details.Causes[0].Field; e != a { - t.Fatalf("Expecting to conflict on field %q but conflicted on field %q: %v", e, a, err) - } - - if e, a := "before-first-apply", apiStatus.Status().Details.Causes[0].Message; !strings.Contains(a, e) { - t.Fatalf("Expecting conflict message to contain %q but got %q: %v", e, a, err) - } - - if err := f.Apply(appliedObj, "fieldmanager_test_apply", true); err != nil { - t.Fatalf("failed to update object: %v", err) - } - - if e, a := 2, len(f.ManagedFields()); e != a { - t.Fatalf("exected %v entries in managedFields, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "fieldmanager_test_apply", f.ManagedFields()[0].Manager; e != a { - t.Fatalf("exected first manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } - - if e, a := "before-first-apply", f.ManagedFields()[1].Manager; e != a { - t.Fatalf("exected second manager name to be %v, but got %v: %#v", e, a, f.ManagedFields()) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/stripmeta.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/stripmeta.go deleted file mode 100644 index fc8ee9b5833..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/stripmeta.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2019 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 fieldmanager - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" -) - -type stripMetaManager struct { - fieldManager Manager - - // stripSet is the list of fields that should never be part of a mangedFields. - stripSet *fieldpath.Set -} - -var _ Manager = &stripMetaManager{} - -// NewStripMetaManager creates a new Manager that strips metadata and typemeta fields from the manager's fieldset. -func NewStripMetaManager(fieldManager Manager) Manager { - return &stripMetaManager{ - fieldManager: fieldManager, - stripSet: fieldpath.NewSet( - fieldpath.MakePathOrDie("apiVersion"), - fieldpath.MakePathOrDie("kind"), - fieldpath.MakePathOrDie("metadata"), - fieldpath.MakePathOrDie("metadata", "name"), - fieldpath.MakePathOrDie("metadata", "namespace"), - fieldpath.MakePathOrDie("metadata", "creationTimestamp"), - fieldpath.MakePathOrDie("metadata", "selfLink"), - fieldpath.MakePathOrDie("metadata", "uid"), - fieldpath.MakePathOrDie("metadata", "clusterName"), - fieldpath.MakePathOrDie("metadata", "generation"), - fieldpath.MakePathOrDie("metadata", "managedFields"), - fieldpath.MakePathOrDie("metadata", "resourceVersion"), - ), - } -} - -// Update implements Manager. -func (f *stripMetaManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - newObj, managed, err := f.fieldManager.Update(liveObj, newObj, managed, manager) - if err != nil { - return nil, nil, err - } - f.stripFields(managed.Fields(), manager) - return newObj, managed, nil -} - -// Apply implements Manager. -func (f *stripMetaManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) { - newObj, managed, err := f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force) - if err != nil { - return nil, nil, err - } - f.stripFields(managed.Fields(), manager) - return newObj, managed, nil -} - -// stripFields removes a predefined set of paths found in typed from managed -func (f *stripMetaManager) stripFields(managed fieldpath.ManagedFields, manager string) { - vs, ok := managed[manager] - if ok { - if vs == nil { - panic(fmt.Sprintf("Found unexpected nil manager which should never happen: %s", manager)) - } - newSet := vs.Set().Difference(f.stripSet) - if newSet.Empty() { - delete(managed, manager) - } else { - managed[manager] = fieldpath.NewVersionedSet(newSet, vs.APIVersion(), vs.Applied()) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/structuredmerge.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/structuredmerge.go deleted file mode 100644 index 32116a94d6d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/structuredmerge.go +++ /dev/null @@ -1,198 +0,0 @@ -/* -Copyright 2019 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 fieldmanager - -import ( - "fmt" - "time" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal" - "k8s.io/klog" - openapiproto "k8s.io/kube-openapi/pkg/util/proto" - "sigs.k8s.io/structured-merge-diff/v3/fieldpath" - "sigs.k8s.io/structured-merge-diff/v3/merge" -) - -type structuredMergeManager struct { - typeConverter internal.TypeConverter - objectConverter runtime.ObjectConvertor - objectDefaulter runtime.ObjectDefaulter - groupVersion schema.GroupVersion - hubVersion schema.GroupVersion - updater merge.Updater -} - -var _ Manager = &structuredMergeManager{} -var atMostEverySecond = internal.NewAtMostEvery(time.Second) - -// NewStructuredMergeManager creates a new Manager that merges apply requests -// and update managed fields for other types of requests. -func NewStructuredMergeManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion) (Manager, error) { - typeConverter, err := internal.NewTypeConverter(models, false) - if err != nil { - return nil, err - } - - return &structuredMergeManager{ - typeConverter: typeConverter, - objectConverter: objectConverter, - objectDefaulter: objectDefaulter, - groupVersion: gv, - hubVersion: hub, - updater: merge.Updater{ - Converter: internal.NewVersionConverter(typeConverter, objectConverter, hub), - }, - }, nil -} - -// NewCRDStructuredMergeManager creates a new Manager specifically for -// CRDs. This allows for the possibility of fields which are not defined -// in models, as well as having no models defined at all. -func NewCRDStructuredMergeManager(models openapiproto.Models, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, preserveUnknownFields bool) (_ Manager, err error) { - var typeConverter internal.TypeConverter = internal.DeducedTypeConverter{} - if models != nil { - typeConverter, err = internal.NewTypeConverter(models, preserveUnknownFields) - if err != nil { - return nil, err - } - } - return &structuredMergeManager{ - typeConverter: typeConverter, - objectConverter: objectConverter, - objectDefaulter: objectDefaulter, - groupVersion: gv, - hubVersion: hub, - updater: merge.Updater{ - Converter: internal.NewCRDVersionConverter(typeConverter, objectConverter, hub), - }, - }, nil -} - -// Update implements Manager. -func (f *structuredMergeManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) { - newObjVersioned, err := f.toVersioned(newObj) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert new object to proper version: %v", err) - } - liveObjVersioned, err := f.toVersioned(liveObj) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert live object to proper version: %v", err) - } - newObjTyped, err := f.typeConverter.ObjectToTyped(newObjVersioned) - if err != nil { - // Return newObj and just by-pass fields update. This really shouldn't happen. - atMostEverySecond.Do(func() { - klog.Errorf("[SHOULD NOT HAPPEN] failed to create typed new object of type %v: %v", newObjVersioned.GetObjectKind().GroupVersionKind(), err) - }) - return newObj, managed, nil - } - liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned) - if err != nil { - // Return newObj and just by-pass fields update. This really shouldn't happen. - atMostEverySecond.Do(func() { - klog.Errorf("[SHOULD NOT HAPPEN] failed to create typed live object of type %v: %v", liveObjVersioned.GetObjectKind().GroupVersionKind(), err) - }) - return newObj, managed, nil - } - apiVersion := fieldpath.APIVersion(f.groupVersion.String()) - - // TODO(apelisse) use the first return value when unions are implemented - _, managedFields, err := f.updater.Update(liveObjTyped, newObjTyped, apiVersion, managed.Fields(), manager) - if err != nil { - return nil, nil, fmt.Errorf("failed to update ManagedFields: %v", err) - } - managed = internal.NewManaged(managedFields, managed.Times()) - - return newObj, managed, nil -} - -// Apply implements Manager. -func (f *structuredMergeManager) Apply(liveObj, patchObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) { - // Check that the patch object has the same version as the live object - if patchVersion := patchObj.GetObjectKind().GroupVersionKind().GroupVersion(); patchVersion != f.groupVersion { - return nil, nil, - errors.NewBadRequest( - fmt.Sprintf("Incorrect version specified in apply patch. "+ - "Specified patch version: %s, expected: %s", - patchVersion, f.groupVersion)) - } - - patchObjMeta, err := meta.Accessor(patchObj) - if err != nil { - return nil, nil, fmt.Errorf("couldn't get accessor: %v", err) - } - if patchObjMeta.GetManagedFields() != nil { - return nil, nil, errors.NewBadRequest(fmt.Sprintf("metadata.managedFields must be nil")) - } - - liveObjVersioned, err := f.toVersioned(liveObj) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert live object to proper version: %v", err) - } - - patchObjTyped, err := f.typeConverter.ObjectToTyped(patchObj) - if err != nil { - return nil, nil, fmt.Errorf("failed to create typed patch object: %v", err) - } - liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned) - if err != nil { - return nil, nil, fmt.Errorf("failed to create typed live object: %v", err) - } - - apiVersion := fieldpath.APIVersion(f.groupVersion.String()) - newObjTyped, managedFields, err := f.updater.Apply(liveObjTyped, patchObjTyped, apiVersion, managed.Fields(), manager, force) - if err != nil { - if conflicts, ok := err.(merge.Conflicts); ok { - return nil, nil, internal.NewConflictError(conflicts) - } - return nil, nil, err - } - managed = internal.NewManaged(managedFields, managed.Times()) - - if newObjTyped == nil { - return nil, managed, nil - } - - newObj, err := f.typeConverter.TypedToObject(newObjTyped) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert new typed object to object: %v", err) - } - - newObjVersioned, err := f.toVersioned(newObj) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert new object to proper version: %v", err) - } - f.objectDefaulter.Default(newObjVersioned) - - newObjUnversioned, err := f.toUnversioned(newObjVersioned) - if err != nil { - return nil, nil, fmt.Errorf("failed to convert to unversioned: %v", err) - } - return newObjUnversioned, managed, nil -} - -func (f *structuredMergeManager) toVersioned(obj runtime.Object) (runtime.Object, error) { - return f.objectConverter.ConvertToVersion(obj, f.groupVersion) -} - -func (f *structuredMergeManager) toUnversioned(obj runtime.Object) (runtime.Object, error) { - return f.objectConverter.ConvertToVersion(obj, f.hubVersion) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go index 3c51318e8ca..0f1c59946a3 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go @@ -30,15 +30,13 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/metrics" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - utiltrace "k8s.io/utils/trace" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) // getterFunc performs a get request with the given context and object name. The request @@ -47,9 +45,9 @@ type getterFunc func(ctx context.Context, name string, req *http.Request, trace // getResourceHandler is an HTTP handler function for get requests. It delegates to the // passed-in getterFunc to perform the actual get. -func getResourceHandler(scope *RequestScope, getter getterFunc) http.HandlerFunc { +func getResourceHandler(scope RequestScope, getter getterFunc) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { - trace := utiltrace.New("Get", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("Get " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) namespace, name, err := scope.Namer.Name(req) @@ -60,33 +58,37 @@ func getResourceHandler(scope *RequestScope, getter getterFunc) http.HandlerFunc ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) + result, err := getter(ctx, name, req, trace) if err != nil { scope.err(err, w, req) return } - - result, err := getter(ctx, name, req, trace) - if err != nil { + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } + if err := setSelfLink(result, requestInfo, scope.Namer); err != nil { scope.err(err, w, req) return } trace.Step("About to write a response") - transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, http.StatusOK, result) trace.Step("Transformed response object") } } // GetResource returns a function that handles retrieving a single resource from a rest.Storage object. -func GetResource(r rest.Getter, e rest.Exporter, scope *RequestScope) http.HandlerFunc { +func GetResource(r rest.Getter, e rest.Exporter, scope RequestScope) http.HandlerFunc { return getResourceHandler(scope, func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) { // check for export options := metav1.GetOptions{} if values := req.URL.Query(); len(values) > 0 { exports := metav1.ExportOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &exports); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &exports); err != nil { err = errors.NewBadRequest(err.Error()) return nil, err } @@ -96,7 +98,7 @@ func GetResource(r rest.Getter, e rest.Exporter, scope *RequestScope) http.Handl } return e.Export(ctx, name, exports) } - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &options); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(values, scope.MetaGroupVersion, &options); err != nil { err = errors.NewBadRequest(err.Error()) return nil, err } @@ -109,7 +111,7 @@ func GetResource(r rest.Getter, e rest.Exporter, scope *RequestScope) http.Handl } // GetResourceWithOptions returns a function that handles retrieving a single resource from a rest.Storage object. -func GetResourceWithOptions(r rest.GetterWithOptions, scope *RequestScope, isSubresource bool) http.HandlerFunc { +func GetResourceWithOptions(r rest.GetterWithOptions, scope RequestScope, isSubresource bool) http.HandlerFunc { return getResourceHandler(scope, func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) { opts, subpath, subpathKey := r.NewGetOptions() @@ -126,7 +128,7 @@ func GetResourceWithOptions(r rest.GetterWithOptions, scope *RequestScope, isSub } // getRequestOptions parses out options and can include path information. The path information shouldn't include the subresource. -func getRequestOptions(req *http.Request, scope *RequestScope, into runtime.Object, subpath bool, subpathKey string, isSubresource bool) error { +func getRequestOptions(req *http.Request, scope RequestScope, into runtime.Object, subpath bool, subpathKey string, isSubresource bool) error { if into == nil { return nil } @@ -163,10 +165,10 @@ func getRequestOptions(req *http.Request, scope *RequestScope, into runtime.Obje return scope.ParameterCodec.DecodeParameters(query, scope.Kind.GroupVersion(), into) } -func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatch bool, minRequestTimeout time.Duration) http.HandlerFunc { +func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch bool, minRequestTimeout time.Duration) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { // For performance tracking purposes. - trace := utiltrace.New("List", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("List " + req.URL.Path) namespace, err := scope.Namer.Namespace(req) if err != nil { @@ -185,14 +187,8 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) - if err != nil { - scope.err(err, w, req) - return - } - opts := metainternalversion.ListOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, &opts); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, &opts); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -249,16 +245,15 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc timeout = time.Duration(float64(minRequestTimeout) * (rand.Float64() + 1.0)) } klog.V(3).Infof("Starting watch for %s, rv=%s labels=%s fields=%s timeout=%s", req.URL.Path, opts.ResourceVersion, opts.LabelSelector, opts.FieldSelector, timeout) - ctx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() + watcher, err := rw.Watch(ctx, &opts) if err != nil { scope.err(err, w, req) return } requestInfo, _ := request.RequestInfoFrom(ctx) - metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() { - serveWatch(watcher, scope, outputMediaType, req, w, timeout) + metrics.RecordLongRunning(req, requestInfo, func() { + serveWatch(watcher, scope, req, w, timeout) }) return } @@ -272,8 +267,22 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc return } trace.Step("Listing from storage done") + numberOfItems, err := setListSelfLink(result, ctx, req, scope.Namer) + if err != nil { + scope.err(err, w, req) + return + } + trace.Step("Self-linking done") + // Ensure empty lists return a non-nil items slice + if numberOfItems == 0 && meta.IsListType(result) { + if err := meta.SetList(result, []runtime.Object{}); err != nil { + scope.err(err, w, req) + return + } + } - transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result) - trace.Step("Writing http response done", utiltrace.Field{"count", meta.LenList(result)}) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, http.StatusOK, result) + trace.Step(fmt.Sprintf("Writing http response done (%d items)", numberOfItems)) } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers.go deleted file mode 100644 index 82170e050ec..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2019 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 handlers - -import ( - "net/http" - - utilnet "k8s.io/apimachinery/pkg/util/net" -) - -const ( - maxUserAgentLength = 1024 - userAgentTruncateSuffix = "...TRUNCATED" -) - -// lazyTruncatedUserAgent implements String() string and it will -// return user-agent which may be truncated. -type lazyTruncatedUserAgent struct { - req *http.Request -} - -func (lazy *lazyTruncatedUserAgent) String() string { - ua := "unknown" - if lazy.req != nil { - ua = utilnet.GetHTTPClient(lazy.req) - if len(ua) > maxUserAgentLength { - ua = ua[:maxUserAgentLength] + userAgentTruncateSuffix - } - } - return ua -} - -// LazyClientIP implements String() string and it will -// calls GetClientIP() lazily only when required. -type lazyClientIP struct { - req *http.Request -} - -func (lazy *lazyClientIP) String() string { - if lazy.req != nil { - if ip := utilnet.GetClientIP(lazy.req); ip != nil { - return ip.String() - } - } - return "unknown" -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers_test.go deleted file mode 100644 index e55b40a1c45..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/helpers_test.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2019 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 handlers - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "net/http" - "testing" -) - -func TestLazyTruncatedUserAgent(t *testing.T) { - req := &http.Request{} - req.Header = http.Header{} - - ua := "short-agent" - req.Header.Set("User-Agent", ua) - uaNotTruncated := &lazyTruncatedUserAgent{req} - assert.Equal(t, ua, fmt.Sprintf("%v", uaNotTruncated)) - - ua = "" - for i := 0; i < maxUserAgentLength*2; i++ { - ua = ua + "a" - } - req.Header.Set("User-Agent", ua) - uaTruncated := &lazyTruncatedUserAgent{req} - assert.NotEqual(t, ua, fmt.Sprintf("%v", uaTruncated)) - - usUnknown := &lazyTruncatedUserAgent{} - assert.Equal(t, "unknown", fmt.Sprintf("%v", usUnknown)) -} - -func TestLazyClientIP(t *testing.T) { - req := &http.Request{} - req.Header = http.Header{} - - ip := "127.0.0.1" - req.Header.Set("X-Forwarded-For", ip) - - clientIPWithReq := &lazyClientIP{req} - assert.Equal(t, ip, fmt.Sprintf("%v", clientIPWithReq)) - - clientIPWithoutReq := &lazyClientIP{} - assert.Equal(t, "unknown", fmt.Sprintf("%v", clientIPWithoutReq)) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer.go index 755da22eea5..16b4199c2b3 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer.go @@ -20,7 +20,6 @@ import ( "fmt" "net/http" "net/url" - "strings" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -87,21 +86,6 @@ func (n ContextBasedNaming) Name(req *http.Request) (namespace, name string, err return ns, requestInfo.Name, nil } -// fastURLPathEncode encodes the provided path as a URL path -func fastURLPathEncode(path string) string { - for _, r := range []byte(path) { - switch { - case r >= '-' && r <= '9', r >= 'A' && r <= 'Z', r >= 'a' && r <= 'z': - // characters within this range do not require escaping - default: - var u url.URL - u.Path = path - return u.EscapedPath() - } - } - return path -} - func (n ContextBasedNaming) GenerateLink(requestInfo *request.RequestInfo, obj runtime.Object) (uri string, err error) { namespace, name, err := n.ObjectName(obj) if err == errEmptyName && len(requestInfo.Name) > 0 { @@ -117,23 +101,19 @@ func (n ContextBasedNaming) GenerateLink(requestInfo *request.RequestInfo, obj r return n.SelfLinkPathPrefix + url.QueryEscape(name) + n.SelfLinkPathSuffix, nil } - builder := strings.Builder{} - builder.Grow(len(n.SelfLinkPathPrefix) + len(namespace) + len(requestInfo.Resource) + len(name) + len(n.SelfLinkPathSuffix) + 8) - builder.WriteString(n.SelfLinkPathPrefix) - builder.WriteString(namespace) - builder.WriteByte('/') - builder.WriteString(requestInfo.Resource) - builder.WriteByte('/') - builder.WriteString(name) - builder.WriteString(n.SelfLinkPathSuffix) - return fastURLPathEncode(builder.String()), nil + return n.SelfLinkPathPrefix + + url.QueryEscape(namespace) + + "/" + url.QueryEscape(requestInfo.Resource) + "/" + + url.QueryEscape(name) + + n.SelfLinkPathSuffix, + nil } func (n ContextBasedNaming) GenerateListLink(req *http.Request) (uri string, err error) { if len(req.URL.RawPath) > 0 { return req.URL.RawPath, nil } - return fastURLPathEncode(req.URL.Path), nil + return req.URL.EscapedPath(), nil } func (n ContextBasedNaming) ObjectName(obj runtime.Object) (namespace, name string, err error) { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer_test.go index 86129627850..15c88189313 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/namer_test.go @@ -17,13 +17,9 @@ limitations under the License. package handlers import ( - "math/rand" - "net/url" "testing" - fuzz "github.com/google/gofuzz" - - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -118,62 +114,3 @@ func TestGenerateLink(t *testing.T) { } } } - -func Test_fastURLPathEncode_fuzz(t *testing.T) { - specialCases := []string{"/", "//", ".", "*", "/abc%"} - for _, test := range specialCases { - got := fastURLPathEncode(test) - u := url.URL{Path: test} - expected := u.EscapedPath() - if got != expected { - t.Errorf("%q did not match %q", got, expected) - } - } - f := fuzz.New().Funcs( - func(s *string, c fuzz.Continue) { - *s = randString(c.Rand) - }, - ) - for i := 0; i < 2000; i++ { - var test string - f.Fuzz(&test) - - got := fastURLPathEncode(test) - u := url.URL{Path: test} - expected := u.EscapedPath() - if got != expected { - t.Errorf("%q did not match %q", got, expected) - } - } -} - -// Unicode range fuzzer from github.com/google/gofuzz/fuzz.go - -type charRange struct { - first, last rune -} - -var unicodeRanges = []charRange{ - {0x00, 0x255}, - {' ', '~'}, // ASCII characters - {'\u00a0', '\u02af'}, // Multi-byte encoded characters - {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) -} - -// randString makes a random string up to 20 characters long. The returned string -// may include a variety of (valid) UTF-8 encodings. -func randString(r *rand.Rand) string { - n := r.Intn(20) - runes := make([]rune, n) - for i := range runes { - runes[i] = unicodeRanges[r.Intn(len(unicodeRanges))].choose(r) - } - return string(runes) -} - -// choose returns a random unicode character from the given range, using the -// given randomness source. -func (r *charRange) choose(rand *rand.Rand) rune { - count := int64(r.last - r.first) - return r.first + rune(rand.Int63n(count)) -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/errors.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/errors.go index 86faf525df1..93b17cfb097 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/errors.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/errors.go @@ -29,7 +29,6 @@ type errNotAcceptable struct { accepted []string } -// NewNotAcceptableError returns an error of NotAcceptable which contains specified string func NewNotAcceptableError(accepted []string) error { return errNotAcceptable{accepted} } @@ -47,40 +46,11 @@ func (e errNotAcceptable) Status() metav1.Status { } } -// errNotAcceptableConversion indicates Accept negotiation has failed specifically -// for a conversion to a known type. -type errNotAcceptableConversion struct { - target string - accepted []string -} - -// NewNotAcceptableConversionError returns an error indicating that the desired -// API transformation to the target group version kind string is not accepted and -// only the listed mime types are allowed. This is temporary while Table does not -// yet support protobuf encoding. -func NewNotAcceptableConversionError(target string, accepted []string) error { - return errNotAcceptableConversion{target, accepted} -} - -func (e errNotAcceptableConversion) Error() string { - return fmt.Sprintf("only the following media types are accepted when converting to %s: %v", e.target, strings.Join(e.accepted, ", ")) -} - -func (e errNotAcceptableConversion) Status() metav1.Status { - return metav1.Status{ - Status: metav1.StatusFailure, - Code: http.StatusNotAcceptable, - Reason: metav1.StatusReasonNotAcceptable, - Message: e.Error(), - } -} - // errUnsupportedMediaType indicates Content-Type is not recognized type errUnsupportedMediaType struct { accepted []string } -// NewUnsupportedMediaTypeError returns an error of UnsupportedMediaType which contains specified string func NewUnsupportedMediaTypeError(accepted []string) error { return errUnsupportedMediaType{accepted} } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go index 9dbad1ea65c..f9bb47babca 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate.go @@ -22,7 +22,7 @@ import ( "strconv" "strings" - "github.com/munnerz/goautoneg" + "bitbucket.org/ww/goautoneg" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -43,27 +43,33 @@ func MediaTypesForSerializer(ns runtime.NegotiatedSerializer) (mediaTypes, strea // NegotiateOutputMediaType negotiates the output structured media type and a serializer, or // returns an error. func NegotiateOutputMediaType(req *http.Request, ns runtime.NegotiatedSerializer, restrictions EndpointRestrictions) (MediaTypeOptions, runtime.SerializerInfo, error) { - mediaType, ok := NegotiateMediaTypeOptions(req.Header.Get("Accept"), ns.SupportedMediaTypes(), restrictions) + mediaType, ok := NegotiateMediaTypeOptions(req.Header.Get("Accept"), AcceptedMediaTypesForEndpoint(ns), restrictions) if !ok { supported, _ := MediaTypesForSerializer(ns) return mediaType, runtime.SerializerInfo{}, NewNotAcceptableError(supported) } // TODO: move into resthandler - info := mediaType.Accepted + info := mediaType.Accepted.Serializer if (mediaType.Pretty || isPrettyPrint(req)) && info.PrettySerializer != nil { info.Serializer = info.PrettySerializer } return mediaType, info, nil } -// NegotiateOutputMediaTypeStream returns a stream serializer for the given request. -func NegotiateOutputMediaTypeStream(req *http.Request, ns runtime.NegotiatedSerializer, restrictions EndpointRestrictions) (runtime.SerializerInfo, error) { - mediaType, ok := NegotiateMediaTypeOptions(req.Header.Get("Accept"), ns.SupportedMediaTypes(), restrictions) - if !ok || mediaType.Accepted.StreamSerializer == nil { +// NegotiateOutputSerializer returns a serializer for the output. +func NegotiateOutputSerializer(req *http.Request, ns runtime.NegotiatedSerializer) (runtime.SerializerInfo, error) { + _, info, err := NegotiateOutputMediaType(req, ns, DefaultEndpointRestrictions) + return info, err +} + +// NegotiateOutputStreamSerializer returns a stream serializer for the given request. +func NegotiateOutputStreamSerializer(req *http.Request, ns runtime.NegotiatedSerializer) (runtime.SerializerInfo, error) { + mediaType, ok := NegotiateMediaTypeOptions(req.Header.Get("Accept"), AcceptedMediaTypesForEndpoint(ns), DefaultEndpointRestrictions) + if !ok || mediaType.Accepted.Serializer.StreamSerializer == nil { _, supported := MediaTypesForSerializer(ns) return runtime.SerializerInfo{}, NewNotAcceptableError(supported) } - return mediaType.Accepted, nil + return mediaType.Accepted.Serializer, nil } // NegotiateInputSerializer returns the input serializer for the provided request. @@ -79,7 +85,10 @@ func NegotiateInputSerializerForMediaType(mediaType string, streaming bool, ns r mediaType = mediaTypes[0].MediaType } if mediaType, _, err := mime.ParseMediaType(mediaType); err == nil { - if info, ok := runtime.SerializerInfoForMediaType(mediaTypes, mediaType); ok { + for _, info := range mediaTypes { + if info.MediaType != mediaType { + continue + } return info, nil } } @@ -96,13 +105,10 @@ func NegotiateInputSerializerForMediaType(mediaType string, streaming bool, ns r func isPrettyPrint(req *http.Request) bool { // DEPRECATED: should be part of the content type if req.URL != nil { - // avoid an allocation caused by parsing the URL query - if strings.Contains(req.URL.RawQuery, "pretty") { - pp := req.URL.Query().Get("pretty") - if len(pp) > 0 { - pretty, _ := strconv.ParseBool(pp) - return pretty - } + pp := req.URL.Query().Get("pretty") + if len(pp) > 0 { + pretty, _ := strconv.ParseBool(pp) + return pretty } } userAgent := req.UserAgent() @@ -116,10 +122,9 @@ func isPrettyPrint(req *http.Request) bool { // EndpointRestrictions is an interface that allows content-type negotiation // to verify server support for specific options type EndpointRestrictions interface { - // AllowsMediaTypeTransform returns true if the endpoint allows either the requested mime type - // or the requested transformation. If false, the caller should ignore this mime type. If the - // target is nil, the client is not requesting a transformation. - AllowsMediaTypeTransform(mimeType, mimeSubType string, target *schema.GroupVersionKind) bool + // AllowsConversion should return true if the specified group version kind + // is an allowed target object. + AllowsConversion(schema.GroupVersionKind) bool // AllowsServerVersion should return true if the specified version is valid // for the server group. AllowsServerVersion(version string) bool @@ -128,17 +133,24 @@ type EndpointRestrictions interface { AllowsStreamSchema(schema string) bool } -// DefaultEndpointRestrictions is the default EndpointRestrictions which allows -// content-type negotiation to verify server support for specific options var DefaultEndpointRestrictions = emptyEndpointRestrictions{} type emptyEndpointRestrictions struct{} -func (emptyEndpointRestrictions) AllowsMediaTypeTransform(mimeType string, mimeSubType string, gvk *schema.GroupVersionKind) bool { - return gvk == nil +func (emptyEndpointRestrictions) AllowsConversion(schema.GroupVersionKind) bool { return false } +func (emptyEndpointRestrictions) AllowsServerVersion(string) bool { return false } +func (emptyEndpointRestrictions) AllowsStreamSchema(s string) bool { return s == "watch" } + +// AcceptedMediaType contains information about a valid media type that the +// server can serialize. +type AcceptedMediaType struct { + // Type is the first part of the media type ("application") + Type string + // SubType is the second part of the media type ("json") + SubType string + // Serializer is the serialization info this object accepts + Serializer runtime.SerializerInfo } -func (emptyEndpointRestrictions) AllowsServerVersion(string) bool { return false } -func (emptyEndpointRestrictions) AllowsStreamSchema(s string) bool { return s == "watch" } // MediaTypeOptions describes information for a given media type that may alter // the server response @@ -166,13 +178,13 @@ type MediaTypeOptions struct { Unrecognized []string // the accepted media type from the client - Accepted runtime.SerializerInfo + Accepted *AcceptedMediaType } // acceptMediaTypeOptions returns an options object that matches the provided media type params. If // it returns false, the provided options are not allowed and the media type must be skipped. These // parameters are unversioned and may not be changed. -func acceptMediaTypeOptions(params map[string]string, accepts *runtime.SerializerInfo, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { +func acceptMediaTypeOptions(params map[string]string, accepts *AcceptedMediaType, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { var options MediaTypeOptions // extract all known parameters @@ -198,7 +210,7 @@ func acceptMediaTypeOptions(params map[string]string, accepts *runtime.Serialize // controls the streaming schema case "stream": - if len(v) > 0 && (accepts.StreamSerializer == nil || !endpoint.AllowsStreamSchema(v)) { + if len(v) > 0 && (accepts.Serializer.StreamSerializer == nil || !endpoint.AllowsStreamSchema(v)) { return MediaTypeOptions{}, false } options.Stream = v @@ -226,38 +238,68 @@ func acceptMediaTypeOptions(params map[string]string, accepts *runtime.Serialize } } - if !endpoint.AllowsMediaTypeTransform(accepts.MediaTypeType, accepts.MediaTypeSubType, options.Convert) { + if options.Convert != nil && !endpoint.AllowsConversion(*options.Convert) { return MediaTypeOptions{}, false } - options.Accepted = *accepts + options.Accepted = accepts return options, true } +type candidateMediaType struct { + accepted *AcceptedMediaType + clauses goautoneg.Accept +} + +type candidateMediaTypeSlice []candidateMediaType + // NegotiateMediaTypeOptions returns the most appropriate content type given the accept header and // a list of alternatives along with the accepted media type parameters. -func NegotiateMediaTypeOptions(header string, accepted []runtime.SerializerInfo, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { +func NegotiateMediaTypeOptions(header string, accepted []AcceptedMediaType, endpoint EndpointRestrictions) (MediaTypeOptions, bool) { if len(header) == 0 && len(accepted) > 0 { return MediaTypeOptions{ - Accepted: accepted[0], + Accepted: &accepted[0], }, true } + var candidates candidateMediaTypeSlice clauses := goautoneg.ParseAccept(header) - for i := range clauses { - clause := &clauses[i] + for _, clause := range clauses { for i := range accepted { accepts := &accepted[i] switch { - case clause.Type == accepts.MediaTypeType && clause.SubType == accepts.MediaTypeSubType, - clause.Type == accepts.MediaTypeType && clause.SubType == "*", + case clause.Type == accepts.Type && clause.SubType == accepts.SubType, + clause.Type == accepts.Type && clause.SubType == "*", clause.Type == "*" && clause.SubType == "*": - if retVal, ret := acceptMediaTypeOptions(clause.Params, accepts, endpoint); ret { - return retVal, true - } + candidates = append(candidates, candidateMediaType{accepted: accepts, clauses: clause}) } } } + for _, v := range candidates { + if retVal, ret := acceptMediaTypeOptions(v.clauses.Params, v.accepted, endpoint); ret { + return retVal, true + } + } + return MediaTypeOptions{}, false } + +// AcceptedMediaTypesForEndpoint returns an array of structs that are used to efficiently check which +// allowed media types the server exposes. +func AcceptedMediaTypesForEndpoint(ns runtime.NegotiatedSerializer) []AcceptedMediaType { + var acceptedMediaTypes []AcceptedMediaType + for _, info := range ns.SupportedMediaTypes() { + segments := strings.SplitN(info.MediaType, "/", 2) + if len(segments) == 1 { + segments = append(segments, "*") + } + t := AcceptedMediaType{ + Type: segments[0], + SubType: segments[1], + Serializer: info, + } + acceptedMediaTypes = append(acceptedMediaTypes, t) + } + return acceptedMediaTypes +} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go index e2c164b1525..e69ba02af03 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/negotiation/negotiate_test.go @@ -17,10 +17,8 @@ limitations under the License. package negotiation import ( - "mime" "net/http" "net/url" - "strings" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -41,23 +39,7 @@ type fakeNegotiater struct { func (n *fakeNegotiater) SupportedMediaTypes() []runtime.SerializerInfo { var out []runtime.SerializerInfo for _, s := range n.types { - mediaType, _, err := mime.ParseMediaType(s) - if err != nil { - panic(err) - } - parts := strings.SplitN(mediaType, "/", 2) - if len(parts) == 1 { - // this is an error on the server side - parts = append(parts, "") - } - - info := runtime.SerializerInfo{ - Serializer: n.serializer, - MediaType: s, - MediaTypeType: parts[0], - MediaTypeSubType: parts[1], - EncodesAsText: true, - } + info := runtime.SerializerInfo{Serializer: n.serializer, MediaType: s, EncodesAsText: true} for _, t := range n.streamTypes { if t == s { info.StreamSerializer = &runtime.StreamSerializerInfo{ @@ -249,7 +231,7 @@ func TestNegotiate(t *testing.T) { req = &http.Request{Header: http.Header{}} req.Header.Set("Accept", test.accept) } - _, s, err := NegotiateOutputMediaType(req, test.ns, DefaultEndpointRestrictions) + s, err := NegotiateOutputSerializer(req, test.ns) switch { case err == nil && test.errFn != nil: t.Errorf("%d: failed: expected error", i) @@ -280,30 +262,3 @@ func TestNegotiate(t *testing.T) { } } } - -func fakeSerializerInfoSlice() []runtime.SerializerInfo { - result := make([]runtime.SerializerInfo, 2) - result[0] = runtime.SerializerInfo{ - MediaType: "application/json", - MediaTypeType: "application", - MediaTypeSubType: "json", - } - result[1] = runtime.SerializerInfo{ - MediaType: "application/vnd.kubernetes.protobuf", - MediaTypeType: "application", - MediaTypeSubType: "vnd.kubernetes.protobuf", - } - return result -} - -func BenchmarkNegotiateMediaTypeOptions(b *testing.B) { - accepted := fakeSerializerInfoSlice() - header := "application/vnd.kubernetes.protobuf,*/*" - - for i := 0; i < b.N; i++ { - options, _ := NegotiateMediaTypeOptions(header, accepted, DefaultEndpointRestrictions) - if options.Accepted != accepted[1] { - b.Errorf("Unexpected result") - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go index e9d11001758..e06dcdcf5c7 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/patch.go @@ -23,12 +23,11 @@ import ( "strings" "time" - jsonpatch "github.com/evanphx/json-patch" + "github.com/evanphx/json-patch" + "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -37,19 +36,15 @@ import ( "k8s.io/apimachinery/pkg/util/mergepatch" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/strategicpatch" - "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/audit" - "k8s.io/apiserver/pkg/authorization/authorizer" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/util/dryrun" utilfeature "k8s.io/apiserver/pkg/util/feature" - utiltrace "k8s.io/utils/trace" - "sigs.k8s.io/yaml" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) const ( @@ -58,14 +53,14 @@ const ( ) // PatchResource returns a function that will handle a resource patch. -func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interface, patchTypes []string) http.HandlerFunc { +func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface, patchTypes []string) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { // For performance tracking purposes. - trace := utiltrace.New("Patch", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("Patch " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) if isDryRun(req.URL) && !utilfeature.DefaultFeatureGate.Enabled(features.DryRun) { - scope.err(errors.NewBadRequest("the dryRun feature is disabled"), w, req) + scope.err(errors.NewBadRequest("the dryRun alpha feature is disabled"), w, req) return } @@ -95,48 +90,36 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac return } - ctx, cancel := context.WithTimeout(req.Context(), timeout) - defer cancel() + ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) - if err != nil { - scope.err(err, w, req) - return - } - - patchBytes, err := limitedReadBody(req, scope.MaxRequestBodyBytes) + patchJS, err := limitedReadBody(req, scope.MaxRequestBodyBytes) if err != nil { scope.err(err, w, req) return } - options := &metav1.PatchOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { + options := &metav1.UpdateOptions{} + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return } - if errs := validation.ValidatePatchOptions(options, patchType); len(errs) > 0 { - err := errors.NewInvalid(schema.GroupKind{Group: metav1.GroupName, Kind: "PatchOptions"}, "", errs) + if errs := validation.ValidateUpdateOptions(options); len(errs) > 0 { + err := errors.NewInvalid(schema.GroupKind{Group: metav1.GroupName, Kind: "UpdateOptions"}, "", errs) scope.err(err, w, req) return } - options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("PatchOptions")) ae := request.AuditEventFrom(ctx) admit = admission.WithAudit(admit, ae) - audit.LogRequestPatch(ae, patchBytes) + audit.LogRequestPatch(ae, patchJS) trace.Step("Recorded the audit event") - baseContentType := runtime.ContentTypeJSON - if patchType == types.ApplyPatchType { - baseContentType = runtime.ContentTypeYAML - } - s, ok := runtime.SerializerInfoForMediaType(scope.Serializer.SupportedMediaTypes(), baseContentType) + s, ok := runtime.SerializerInfoForMediaType(scope.Serializer.SupportedMediaTypes(), runtime.ContentTypeJSON) if !ok { - scope.err(fmt.Errorf("no serializer defined for %v", baseContentType), w, req) + scope.err(fmt.Errorf("no serializer defined for JSON"), w, req) return } gv := scope.Kind.GroupVersion() @@ -147,19 +130,7 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac ) userInfo, _ := request.UserFrom(ctx) - staticCreateAttributes := admission.NewAttributesRecord( - nil, - nil, - scope.Kind, - namespace, - name, - scope.Resource, - scope.Subresource, - admission.Create, - patchToCreateOptions(options), - dryrun.IsDryRun(options.DryRun), - userInfo) - staticUpdateAttributes := admission.NewAttributesRecord( + staticAdmissionAttributes := admission.NewAttributesRecord( nil, nil, scope.Kind, @@ -168,43 +139,41 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac scope.Resource, scope.Subresource, admission.Update, - patchToUpdateOptions(options), dryrun.IsDryRun(options.DryRun), userInfo, ) - - mutatingAdmission, _ := admit.(admission.MutationInterface) - createAuthorizerAttributes := authorizer.AttributesRecord{ - User: userInfo, - ResourceRequest: true, - Path: req.URL.Path, - Verb: "create", - APIGroup: scope.Resource.Group, - APIVersion: scope.Resource.Version, - Resource: scope.Resource.Resource, - Subresource: scope.Subresource, - Namespace: namespace, - Name: name, + admissionCheck := func(updatedObject runtime.Object, currentObject runtime.Object) error { + // if we allow create-on-patch, we have this TODO: call the mutating admission chain with the CREATE verb instead of UPDATE + if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && admit.Handles(admission.Update) { + return mutatingAdmission.Admit(admission.NewAttributesRecord( + updatedObject, + currentObject, + scope.Kind, + namespace, + name, + scope.Resource, + scope.Subresource, + admission.Update, + dryrun.IsDryRun(options.DryRun), + userInfo, + )) + } + return nil } p := patcher{ namer: scope.Namer, creater: scope.Creater, defaulter: scope.Defaulter, - typer: scope.Typer, unsafeConvertor: scope.UnsafeConvertor, kind: scope.Kind, resource: scope.Resource, - subresource: scope.Subresource, - dryRun: dryrun.IsDryRun(options.DryRun), - - objectInterfaces: scope, hubGroupVersion: scope.HubGroupVersion, - createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, scope), scope.Authorizer, createAuthorizerAttributes), - updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, scope), - admissionCheck: mutatingAdmission, + createValidation: rest.AdmissionToValidateObjectFunc(admit, staticAdmissionAttributes), + updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticAdmissionAttributes), + admissionCheck: admissionCheck, codec: codec, @@ -214,34 +183,35 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac restPatcher: r, name: name, patchType: patchType, - patchBytes: patchBytes, - userAgent: req.UserAgent(), + patchJS: patchJS, trace: trace, } - result, wasCreated, err := p.patchResource(ctx, scope) + result, err := p.patchResource(ctx) if err != nil { scope.err(err, w, req) return } trace.Step("Object stored in database") - if err := setObjectSelfLink(ctx, result, req, scope.Namer); err != nil { + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } + if err := setSelfLink(result, requestInfo, scope.Namer); err != nil { scope.err(err, w, req) return } trace.Step("Self-link added") - status := http.StatusOK - if wasCreated { - status = http.StatusCreated - } - transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, http.StatusOK, result) } } -type mutateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error +type mutateObjectUpdateFunc func(obj, old runtime.Object) error // patcher breaks the process of patch application and retries into smaller // pieces of functionality. @@ -253,33 +223,27 @@ type patcher struct { namer ScopeNamer creater runtime.ObjectCreater defaulter runtime.ObjectDefaulter - typer runtime.ObjectTyper unsafeConvertor runtime.ObjectConvertor resource schema.GroupVersionResource kind schema.GroupVersionKind - subresource string - dryRun bool - - objectInterfaces admission.ObjectInterfaces hubGroupVersion schema.GroupVersion // Validation functions createValidation rest.ValidateObjectFunc updateValidation rest.ValidateObjectUpdateFunc - admissionCheck admission.MutationInterface + admissionCheck mutateObjectUpdateFunc codec runtime.Codec timeout time.Duration - options *metav1.PatchOptions + options *metav1.UpdateOptions // Operation information restPatcher rest.Patcher name string patchType types.PatchType - patchBytes []byte - userAgent string + patchJS []byte trace *utiltrace.Trace @@ -287,18 +251,14 @@ type patcher struct { namespace string updatedObjectInfo rest.UpdatedObjectInfo mechanism patchMechanism - forceAllowCreate bool } type patchMechanism interface { applyPatchToCurrentObject(currentObject runtime.Object) (runtime.Object, error) - createNewObject() (runtime.Object, error) } type jsonPatcher struct { *patcher - - fieldManager *fieldmanager.FieldManager } func (p *jsonPatcher) applyPatchToCurrentObject(currentObject runtime.Object) (runtime.Object, error) { @@ -317,38 +277,18 @@ func (p *jsonPatcher) applyPatchToCurrentObject(currentObject runtime.Object) (r // Construct the resulting typed, unversioned object. objToUpdate := p.restPatcher.New() if err := runtime.DecodeInto(p.codec, patchedObjJS, objToUpdate); err != nil { - return nil, errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{ - field.Invalid(field.NewPath("patch"), string(patchedObjJS), err.Error()), - }) + return nil, err } - if p.fieldManager != nil { - if objToUpdate, err = p.fieldManager.Update(currentObject, objToUpdate, managerOrUserAgent(p.options.FieldManager, p.userAgent)); err != nil { - return nil, fmt.Errorf("failed to update object (json PATCH for %v) managed fields: %v", p.kind, err) - } - } return objToUpdate, nil } -func (p *jsonPatcher) createNewObject() (runtime.Object, error) { - return nil, errors.NewNotFound(p.resource.GroupResource(), p.name) -} - -// applyJSPatch applies the patch. Input and output objects must both have +// patchJS applies the patch. Input and output objects must both have // the external version, since that is what the patch must have been constructed against. func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, retErr error) { switch p.patchType { case types.JSONPatchType: - // sanity check potentially abusive patches - // TODO(liggitt): drop this once golang json parser limits stack depth (https://github.com/golang/go/issues/31789) - if len(p.patchBytes) > 1024*1024 { - v := []interface{}{} - if err := json.Unmarshal(p.patchBytes, &v); err != nil { - return nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err)) - } - } - - patchObj, err := jsonpatch.DecodePatch(p.patchBytes) + patchObj, err := jsonpatch.DecodePatch(p.patchJS) if err != nil { return nil, errors.NewBadRequest(err.Error()) } @@ -363,16 +303,7 @@ func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, retErr } return patchedJS, nil case types.MergePatchType: - // sanity check potentially abusive patches - // TODO(liggitt): drop this once golang json parser limits stack depth (https://github.com/golang/go/issues/31789) - if len(p.patchBytes) > 1024*1024 { - v := map[string]interface{}{} - if err := json.Unmarshal(p.patchBytes, &v); err != nil { - return nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err)) - } - } - - return jsonpatch.MergePatch(versionedJS, p.patchBytes) + return jsonpatch.MergePatch(versionedJS, p.patchJS) default: // only here as a safety net - go-restful filters content-type return nil, fmt.Errorf("unknown Content-Type header for patch: %v", p.patchType) @@ -384,7 +315,6 @@ type smpPatcher struct { // Schema schemaReferenceObj runtime.Object - fieldManager *fieldmanager.FieldManager } func (p *smpPatcher) applyPatchToCurrentObject(currentObject runtime.Object) (runtime.Object, error) { @@ -398,69 +328,22 @@ func (p *smpPatcher) applyPatchToCurrentObject(currentObject runtime.Object) (ru if err != nil { return nil, err } - if err := strategicPatchObject(p.defaulter, currentVersionedObject, p.patchBytes, versionedObjToUpdate, p.schemaReferenceObj); err != nil { + if err := strategicPatchObject(p.defaulter, currentVersionedObject, p.patchJS, versionedObjToUpdate, p.schemaReferenceObj); err != nil { return nil, err } // Convert the object back to the hub version - newObj, err := p.unsafeConvertor.ConvertToVersion(versionedObjToUpdate, p.hubGroupVersion) - if err != nil { - return nil, err - } - - if p.fieldManager != nil { - if newObj, err = p.fieldManager.Update(currentObject, newObj, managerOrUserAgent(p.options.FieldManager, p.userAgent)); err != nil { - return nil, fmt.Errorf("failed to update object (smp PATCH for %v) managed fields: %v", p.kind, err) - } - } - return newObj, nil -} - -func (p *smpPatcher) createNewObject() (runtime.Object, error) { - return nil, errors.NewNotFound(p.resource.GroupResource(), p.name) -} - -type applyPatcher struct { - patch []byte - options *metav1.PatchOptions - creater runtime.ObjectCreater - kind schema.GroupVersionKind - fieldManager *fieldmanager.FieldManager + return p.unsafeConvertor.ConvertToVersion(versionedObjToUpdate, p.hubGroupVersion) } -func (p *applyPatcher) applyPatchToCurrentObject(obj runtime.Object) (runtime.Object, error) { - force := false - if p.options.Force != nil { - force = *p.options.Force - } - if p.fieldManager == nil { - panic("FieldManager must be installed to run apply") - } - - patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}} - if err := yaml.Unmarshal(p.patch, &patchObj.Object); err != nil { - return nil, errors.NewBadRequest(fmt.Sprintf("error decoding YAML: %v", err)) - } - - return p.fieldManager.Apply(obj, patchObj, p.options.FieldManager, force) -} - -func (p *applyPatcher) createNewObject() (runtime.Object, error) { - obj, err := p.creater.New(p.kind) - if err != nil { - return nil, fmt.Errorf("failed to create new object: %v", err) - } - return p.applyPatchToCurrentObject(obj) -} - -// strategicPatchObject applies a strategic merge patch of to +// strategicPatchObject applies a strategic merge patch of to // and stores the result in . // It additionally returns the map[string]interface{} representation of the -// and . +// and . // NOTE: Both and are supposed to be versioned. func strategicPatchObject( defaulter runtime.ObjectDefaulter, originalObject runtime.Object, - patchBytes []byte, + patchJS []byte, objToUpdate runtime.Object, schemaReferenceObj runtime.Object, ) error { @@ -470,7 +353,7 @@ func strategicPatchObject( } patchMap := make(map[string]interface{}) - if err := json.Unmarshal(patchBytes, &patchMap); err != nil { + if err := json.Unmarshal(patchJS, &patchMap); err != nil { return errors.NewBadRequest(err.Error()) } @@ -482,129 +365,52 @@ func strategicPatchObject( // applyPatch is called every time GuaranteedUpdate asks for the updated object, // and is given the currently persisted object as input. -// TODO: rename this function because the name implies it is related to applyPatcher -func (p *patcher) applyPatch(_ context.Context, _, currentObject runtime.Object) (objToUpdate runtime.Object, patchErr error) { +func (p *patcher) applyPatch(_ context.Context, _, currentObject runtime.Object) (runtime.Object, error) { // Make sure we actually have a persisted currentObject p.trace.Step("About to apply patch") - currentObjectHasUID, err := hasUID(currentObject) - if err != nil { + if hasUID, err := hasUID(currentObject); err != nil { return nil, err - } else if !currentObjectHasUID { - objToUpdate, patchErr = p.mechanism.createNewObject() - } else { - objToUpdate, patchErr = p.mechanism.applyPatchToCurrentObject(currentObject) - } - - if patchErr != nil { - return nil, patchErr + } else if !hasUID { + return nil, errors.NewNotFound(p.resource.GroupResource(), p.name) } - objToUpdateHasUID, err := hasUID(objToUpdate) + objToUpdate, err := p.mechanism.applyPatchToCurrentObject(currentObject) if err != nil { return nil, err } - if objToUpdateHasUID && !currentObjectHasUID { - accessor, err := meta.Accessor(objToUpdate) - if err != nil { - return nil, err - } - return nil, errors.NewConflict(p.resource.GroupResource(), p.name, fmt.Errorf("uid mismatch: the provided object specified uid %s, and no existing object was found", accessor.GetUID())) - } - if err := checkName(objToUpdate, p.name, p.namespace, p.namer); err != nil { return nil, err } return objToUpdate, nil } -func (p *patcher) admissionAttributes(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object, operation admission.Operation, operationOptions runtime.Object) admission.Attributes { - userInfo, _ := request.UserFrom(ctx) - return admission.NewAttributesRecord(updatedObject, currentObject, p.kind, p.namespace, p.name, p.resource, p.subresource, operation, operationOptions, p.dryRun, userInfo) -} - // applyAdmission is called every time GuaranteedUpdate asks for the updated object, // and is given the currently persisted object and the patched object as input. -// TODO: rename this function because the name implies it is related to applyPatcher func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) { p.trace.Step("About to check admission control") - var operation admission.Operation - var options runtime.Object - if hasUID, err := hasUID(currentObject); err != nil { - return nil, err - } else if !hasUID { - operation = admission.Create - currentObject = nil - options = patchToCreateOptions(p.options) - } else { - operation = admission.Update - options = patchToUpdateOptions(p.options) - } - if p.admissionCheck != nil && p.admissionCheck.Handles(operation) { - attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation, options) - return patchedObject, p.admissionCheck.Admit(ctx, attributes, p.objectInterfaces) - } - return patchedObject, nil + return patchedObject, p.admissionCheck(patchedObject, currentObject) } // patchResource divides PatchResource for easier unit testing -func (p *patcher) patchResource(ctx context.Context, scope *RequestScope) (runtime.Object, bool, error) { +func (p *patcher) patchResource(ctx context.Context) (runtime.Object, error) { p.namespace = request.NamespaceValue(ctx) switch p.patchType { case types.JSONPatchType, types.MergePatchType: - p.mechanism = &jsonPatcher{ - patcher: p, - fieldManager: scope.FieldManager, - } + p.mechanism = &jsonPatcher{patcher: p} case types.StrategicMergePatchType: schemaReferenceObj, err := p.unsafeConvertor.ConvertToVersion(p.restPatcher.New(), p.kind.GroupVersion()) if err != nil { - return nil, false, err - } - p.mechanism = &smpPatcher{ - patcher: p, - schemaReferenceObj: schemaReferenceObj, - fieldManager: scope.FieldManager, - } - // this case is unreachable if ServerSideApply is not enabled because we will have already rejected the content type - case types.ApplyPatchType: - p.mechanism = &applyPatcher{ - fieldManager: scope.FieldManager, - patch: p.patchBytes, - options: p.options, - creater: p.creater, - kind: p.kind, + return nil, err } - p.forceAllowCreate = true + p.mechanism = &smpPatcher{patcher: p, schemaReferenceObj: schemaReferenceObj} default: - return nil, false, fmt.Errorf("%v: unimplemented patch type", p.patchType) + return nil, fmt.Errorf("%v: unimplemented patch type", p.patchType) } - - wasCreated := false p.updatedObjectInfo = rest.DefaultUpdatedObjectInfo(nil, p.applyPatch, p.applyAdmission) - requestFunc := func() (runtime.Object, error) { - // Pass in UpdateOptions to override UpdateStrategy.AllowUpdateOnCreate - options := patchToUpdateOptions(p.options) - updateObject, created, updateErr := p.restPatcher.Update(ctx, p.name, p.updatedObjectInfo, p.createValidation, p.updateValidation, p.forceAllowCreate, options) - wasCreated = created + return finishRequest(p.timeout, func() (runtime.Object, error) { + updateObject, _, updateErr := p.restPatcher.Update(ctx, p.name, p.updatedObjectInfo, p.createValidation, p.updateValidation, false, p.options) return updateObject, updateErr - } - result, err := finishRequest(p.timeout, func() (runtime.Object, error) { - result, err := requestFunc() - // If the object wasn't committed to storage because it's serialized size was too large, - // it is safe to remove managedFields (which can be large) and try again. - if isTooLargeError(err) && p.patchType != types.ApplyPatchType { - if _, accessorErr := meta.Accessor(p.restPatcher.New()); accessorErr == nil { - p.updatedObjectInfo = rest.DefaultUpdatedObjectInfo(nil, p.applyPatch, p.applyAdmission, func(_ context.Context, obj, _ runtime.Object) (runtime.Object, error) { - accessor, _ := meta.Accessor(obj) - accessor.SetManagedFields(nil) - return obj, nil - }) - result, err = requestFunc() - } - } - return result, err }) - return result, wasCreated, err } // applyPatchToObject applies a strategic merge patch of to @@ -624,9 +430,7 @@ func applyPatchToObject( // Rather than serialize the patched map to JSON, then decode it to an object, we go directly from a map to an object if err := runtime.DefaultUnstructuredConverter.FromUnstructured(patchedObjMap, objToUpdate); err != nil { - return errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{ - field.Invalid(field.NewPath("patch"), fmt.Sprintf("%+v", patchMap), err.Error()), - }) + return err } // Decoding from JSON to a versioned object would apply defaults, so we do the same here defaulter.Default(objToUpdate) @@ -645,29 +449,3 @@ func interpretStrategicMergePatchError(err error) error { return err } } - -// patchToUpdateOptions creates an UpdateOptions with the same field values as the provided PatchOptions. -func patchToUpdateOptions(po *metav1.PatchOptions) *metav1.UpdateOptions { - if po == nil { - return nil - } - uo := &metav1.UpdateOptions{ - DryRun: po.DryRun, - FieldManager: po.FieldManager, - } - uo.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("UpdateOptions")) - return uo -} - -// patchToCreateOptions creates an CreateOptions with the same field values as the provided PatchOptions. -func patchToCreateOptions(po *metav1.PatchOptions) *metav1.CreateOptions { - if po == nil { - return nil - } - co := &metav1.CreateOptions{ - DryRun: po.DryRun, - FieldManager: po.FieldManager, - } - co.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("CreateOptions")) - return co -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response.go index f9b38e07d37..e140c081746 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response.go @@ -23,118 +23,164 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" - "k8s.io/apimachinery/pkg/apis/meta/v1beta1/validation" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" - utiltrace "k8s.io/utils/trace" ) -// transformObject takes the object as returned by storage and ensures it is in -// the client's desired form, as well as ensuring any API level fields like self-link -// are properly set. -func transformObject(ctx context.Context, obj runtime.Object, opts interface{}, mediaType negotiation.MediaTypeOptions, scope *RequestScope, req *http.Request) (runtime.Object, error) { - if co, ok := obj.(runtime.CacheableObject); ok { - if mediaType.Convert != nil { - // Non-nil mediaType.Convert means that some conversion of the object - // has to happen. Currently conversion may potentially modify the - // object or assume something about it (e.g. asTable operates on - // reflection, which won't work for any wrapper). - // To ensure it will work correctly, let's operate on base objects - // and not cache it for now. - // - // TODO: Long-term, transformObject should be changed so that it - // implements runtime.Encoder interface. - return doTransformObject(ctx, co.GetObject(), opts, mediaType, scope, req) - } +// transformResponseObject takes an object loaded from storage and performs any necessary transformations. +// Will write the complete response object. +func transformResponseObject(ctx context.Context, scope RequestScope, req *http.Request, w http.ResponseWriter, statusCode int, result runtime.Object) { + // TODO: fetch the media type much earlier in request processing and pass it into this method. + trace := scope.Trace + mediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope) + if err != nil { + status := responsewriters.ErrorToAPIStatus(err) + trace.Step("Writing raw JSON response") + responsewriters.WriteRawJSON(int(status.Code), status, w) + return } - return doTransformObject(ctx, obj, opts, mediaType, scope, req) -} -func doTransformObject(ctx context.Context, obj runtime.Object, opts interface{}, mediaType negotiation.MediaTypeOptions, scope *RequestScope, req *http.Request) (runtime.Object, error) { - if _, ok := obj.(*metav1.Status); ok { - return obj, nil - } - if err := setObjectSelfLink(ctx, obj, req, scope.Namer); err != nil { - return nil, err - } + // If conversion was allowed by the scope, perform it before writing the response + if target := mediaType.Convert; target != nil { + switch { + + case target.Kind == "PartialObjectMetadata" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: + if meta.IsListType(result) { + // TODO: this should be calculated earlier + err = newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result)) + scope.err(err, w, req) + return + } + m, err := meta.Accessor(result) + if err != nil { + scope.err(err, w, req) + return + } + partial := meta.AsPartialObjectMetadata(m) + partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) - switch target := mediaType.Convert; { - case target == nil: - return obj, nil + // renegotiate under the internal version + _, info, err := negotiation.NegotiateOutputMediaType(req, metainternalversion.Codecs, &scope) + if err != nil { + scope.err(err, w, req) + return + } + encoder := metainternalversion.Codecs.EncoderForVersion(info.Serializer, metav1beta1.SchemeGroupVersion) + trace.Step(fmt.Sprintf("Serializing response as type %s", info.MediaType)) + responsewriters.SerializeObject(info.MediaType, encoder, w, req, statusCode, partial) + return + + case target.Kind == "PartialObjectMetadataList" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: + if !meta.IsListType(result) { + // TODO: this should be calculated earlier + err = newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result)) + scope.err(err, w, req) + return + } + list := &metav1beta1.PartialObjectMetadataList{} + trace.Step("Processing list items") + err := meta.EachListItem(result, func(obj runtime.Object) error { + m, err := meta.Accessor(obj) + if err != nil { + return err + } + partial := meta.AsPartialObjectMetadata(m) + partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) + list.Items = append(list.Items, partial) + return nil + }) + if err != nil { + scope.err(err, w, req) + return + } - case target.Kind == "PartialObjectMetadata": - return asPartialObjectMetadata(obj, target.GroupVersion()) + // renegotiate under the internal version + _, info, err := negotiation.NegotiateOutputMediaType(req, metainternalversion.Codecs, &scope) + if err != nil { + scope.err(err, w, req) + return + } + encoder := metainternalversion.Codecs.EncoderForVersion(info.Serializer, metav1beta1.SchemeGroupVersion) + trace.Step(fmt.Sprintf("Serializing response as type %s", info.MediaType)) + responsewriters.SerializeObject(info.MediaType, encoder, w, req, statusCode, list) + return + + case target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: + // TODO: relax the version abstraction + // TODO: skip if this is a status response (delete without body)? + + opts := &metav1beta1.TableOptions{} + trace.Step("Decoding parameters") + if err := metav1beta1.ParameterCodec.DecodeParameters(req.URL.Query(), metav1beta1.SchemeGroupVersion, opts); err != nil { + scope.err(err, w, req) + return + } - case target.Kind == "PartialObjectMetadataList": - return asPartialObjectMetadataList(obj, target.GroupVersion()) + trace.Step("Converting to table") + table, err := scope.TableConvertor.ConvertToTable(ctx, result, opts) + if err != nil { + scope.err(err, w, req) + return + } - case target.Kind == "Table": - options, ok := opts.(*metav1.TableOptions) - if !ok { - return nil, fmt.Errorf("unexpected TableOptions, got %T", opts) - } - return asTable(ctx, obj, options, scope, target.GroupVersion()) + trace.Step("Processing rows") + for i := range table.Rows { + item := &table.Rows[i] + switch opts.IncludeObject { + case metav1beta1.IncludeObject: + item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion()) + if err != nil { + scope.err(err, w, req) + return + } + // TODO: rely on defaulting for the value here? + case metav1beta1.IncludeMetadata, "": + m, err := meta.Accessor(item.Object.Object) + if err != nil { + scope.err(err, w, req) + return + } + // TODO: turn this into an internal type and do conversion in order to get object kind automatically set? + partial := meta.AsPartialObjectMetadata(m) + partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) + item.Object.Object = partial + case metav1beta1.IncludeNone: + item.Object.Object = nil + default: + // TODO: move this to validation on the table options? + err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject)) + scope.err(err, w, req) + } + } - default: - accepted, _ := negotiation.MediaTypesForSerializer(metainternalversionscheme.Codecs) - err := negotiation.NewNotAcceptableError(accepted) - return nil, err - } -} + // renegotiate under the internal version + _, info, err := negotiation.NegotiateOutputMediaType(req, metainternalversion.Codecs, &scope) + if err != nil { + scope.err(err, w, req) + return + } + encoder := metainternalversion.Codecs.EncoderForVersion(info.Serializer, metav1beta1.SchemeGroupVersion) + trace.Step(fmt.Sprintf("Serializing response as type %s", info.MediaType)) + responsewriters.SerializeObject(info.MediaType, encoder, w, req, statusCode, table) + return -// optionsForTransform will load and validate any additional query parameter options for -// a conversion or return an error. -func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Request) (interface{}, error) { - switch target := mediaType.Convert; { - case target == nil: - case target.Kind == "Table" && (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion): - opts := &metav1.TableOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), metav1.SchemeGroupVersion, opts); err != nil { - return nil, err - } - switch errs := validation.ValidateTableOptions(opts); len(errs) { - case 0: - return opts, nil - case 1: - return nil, errors.NewBadRequest(fmt.Sprintf("Unable to convert to Table as requested: %v", errs[0].Error())) default: - return nil, errors.NewBadRequest(fmt.Sprintf("Unable to convert to Table as requested: %v", errs)) + // this block should only be hit if scope AllowsConversion is incorrect + accepted, _ := negotiation.MediaTypesForSerializer(metainternalversion.Codecs) + err := negotiation.NewNotAcceptableError(accepted) + status := responsewriters.ErrorToAPIStatus(err) + trace.Step("Writing raw JSON response") + responsewriters.WriteRawJSON(int(status.Code), status, w) + return } } - return nil, nil -} -// targetEncodingForTransform returns the appropriate serializer for the input media type -func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.MediaTypeOptions, req *http.Request) (schema.GroupVersionKind, runtime.NegotiatedSerializer, bool) { - switch target := mediaType.Convert; { - case target == nil: - case (target.Kind == "PartialObjectMetadata" || target.Kind == "PartialObjectMetadataList" || target.Kind == "Table") && - (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion): - return *target, metainternalversionscheme.Codecs, true - } - return scope.Kind, scope.Serializer, false -} - -// transformResponseObject takes an object loaded from storage and performs any necessary transformations. -// Will write the complete response object. -func transformResponseObject(ctx context.Context, scope *RequestScope, trace *utiltrace.Trace, req *http.Request, w http.ResponseWriter, statusCode int, mediaType negotiation.MediaTypeOptions, result runtime.Object) { - options, err := optionsForTransform(mediaType, req) - if err != nil { - scope.err(err, w, req) - return - } - obj, err := transformObject(ctx, result, options, mediaType, scope, req) - if err != nil { - scope.err(err, w, req) - return - } - kind, serializer, _ := targetEncodingForTransform(scope, mediaType, req) - responsewriters.WriteObjectNegotiated(serializer, scope, kind.GroupVersion(), w, req, statusCode, obj) + trace.Step("Writing response") + responsewriters.WriteObject(statusCode, scope.Kind.GroupVersion(), scope.Serializer, result, w, req) } // errNotAcceptable indicates Accept negotiation has failed @@ -158,118 +204,3 @@ func (e errNotAcceptable) Status() metav1.Status { Message: e.Error(), } } - -func asTable(ctx context.Context, result runtime.Object, opts *metav1.TableOptions, scope *RequestScope, groupVersion schema.GroupVersion) (runtime.Object, error) { - switch groupVersion { - case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion: - default: - return nil, newNotAcceptableError(fmt.Sprintf("no Table exists in group version %s", groupVersion)) - } - - obj, err := scope.TableConvertor.ConvertToTable(ctx, result, opts) - if err != nil { - return nil, err - } - - table := (*metav1.Table)(obj) - - for i := range table.Rows { - item := &table.Rows[i] - switch opts.IncludeObject { - case metav1.IncludeObject: - item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion()) - if err != nil { - return nil, err - } - // TODO: rely on defaulting for the value here? - case metav1.IncludeMetadata, "": - m, err := meta.Accessor(item.Object.Object) - if err != nil { - return nil, err - } - // TODO: turn this into an internal type and do conversion in order to get object kind automatically set? - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata")) - item.Object.Object = partial - case metav1.IncludeNone: - item.Object.Object = nil - default: - err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject)) - return nil, err - } - } - - return table, nil -} - -func asPartialObjectMetadata(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) { - if meta.IsListType(result) { - err := newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result)) - return nil, err - } - switch groupVersion { - case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion: - default: - return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion)) - } - m, err := meta.Accessor(result) - if err != nil { - return nil, err - } - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata")) - return partial, nil -} - -func asPartialObjectMetadataList(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) { - li, ok := result.(metav1.ListInterface) - if !ok { - return nil, newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result)) - } - - gvk := groupVersion.WithKind("PartialObjectMetadata") - switch { - case groupVersion == metav1beta1.SchemeGroupVersion: - list := &metav1beta1.PartialObjectMetadataList{} - err := meta.EachListItem(result, func(obj runtime.Object) error { - m, err := meta.Accessor(obj) - if err != nil { - return err - } - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(gvk) - list.Items = append(list.Items, *partial) - return nil - }) - if err != nil { - return nil, err - } - list.SelfLink = li.GetSelfLink() - list.ResourceVersion = li.GetResourceVersion() - list.Continue = li.GetContinue() - return list, nil - - case groupVersion == metav1.SchemeGroupVersion: - list := &metav1.PartialObjectMetadataList{} - err := meta.EachListItem(result, func(obj runtime.Object) error { - m, err := meta.Accessor(obj) - if err != nil { - return err - } - partial := meta.AsPartialObjectMetadata(m) - partial.GetObjectKind().SetGroupVersionKind(gvk) - list.Items = append(list.Items, *partial) - return nil - }) - if err != nil { - return nil, err - } - list.SelfLink = li.GetSelfLink() - list.ResourceVersion = li.GetResourceVersion() - list.Continue = li.GetContinue() - return list, nil - - default: - return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion)) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response_test.go deleted file mode 100644 index d47a81e0c91..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/response_test.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2019 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 handlers - -import ( - "context" - "fmt" - "io" - "net/http" - "reflect" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - examplev1 "k8s.io/apiserver/pkg/apis/example/v1" - "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" - "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" -) - -var _ runtime.CacheableObject = &mockCacheableObject{} - -type mockCacheableObject struct { - gvk schema.GroupVersionKind - obj runtime.Object -} - -// DeepCopyObject implements runtime.Object interface. -func (m *mockCacheableObject) DeepCopyObject() runtime.Object { - panic("DeepCopy unimplemented for mockCacheableObject") -} - -// GetObjectKind implements runtime.Object interface. -func (m *mockCacheableObject) GetObjectKind() schema.ObjectKind { - return m -} - -// GroupVersionKind implements schema.ObjectKind interface. -func (m *mockCacheableObject) GroupVersionKind() schema.GroupVersionKind { - return m.gvk -} - -// SetGroupVersionKind implements schema.ObjectKind interface. -func (m *mockCacheableObject) SetGroupVersionKind(gvk schema.GroupVersionKind) { - m.gvk = gvk -} - -// CacheEncode implements runtime.CacheableObject interface. -func (m *mockCacheableObject) CacheEncode(id runtime.Identifier, encode func(runtime.Object, io.Writer) error, w io.Writer) error { - return fmt.Errorf("unimplemented") -} - -// GetObject implements runtime.CacheableObject interface. -func (m *mockCacheableObject) GetObject() runtime.Object { - return m.obj -} - -type mockNamer struct{} - -func (*mockNamer) Namespace(_ *http.Request) (string, error) { return "", nil } -func (*mockNamer) Name(_ *http.Request) (string, string, error) { return "", "", nil } -func (*mockNamer) ObjectName(_ runtime.Object) (string, string, error) { return "", "", nil } -func (*mockNamer) SetSelfLink(_ runtime.Object, _ string) error { return nil } -func (*mockNamer) GenerateLink(_ *request.RequestInfo, _ runtime.Object) (string, error) { - return "", nil -} -func (*mockNamer) GenerateListLink(_ *http.Request) (string, error) { return "", nil } - -func TestCacheableObject(t *testing.T) { - pomGVK := metav1.SchemeGroupVersion.WithKind("PartialObjectMetadata") - tableGVK := metav1.SchemeGroupVersion.WithKind("Table") - - status := &metav1.Status{Status: "status"} - pod := &examplev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", - }, - } - podMeta := &metav1.PartialObjectMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", - }, - } - podMeta.GetObjectKind().SetGroupVersionKind(pomGVK) - podTable := &metav1.Table{ - Rows: []metav1.TableRow{ - { - Cells: []interface{}{pod.Name, pod.CreationTimestamp.Time.UTC().Format(time.RFC3339)}, - }, - }, - } - - tableConvertor := rest.NewDefaultTableConvertor(examplev1.Resource("Pod")) - - testCases := []struct { - desc string - object runtime.Object - opts *metav1beta1.TableOptions - mediaType negotiation.MediaTypeOptions - - expectedUnwrap bool - expectedObj runtime.Object - expectedErr error - }{ - { - desc: "metav1.Status", - object: status, - expectedObj: status, - expectedErr: nil, - }, - { - desc: "cacheableObject nil convert", - object: &mockCacheableObject{obj: pod}, - mediaType: negotiation.MediaTypeOptions{}, - expectedObj: &mockCacheableObject{obj: pod}, - expectedErr: nil, - }, - { - desc: "cacheableObject as PartialObjectMeta", - object: &mockCacheableObject{obj: pod}, - mediaType: negotiation.MediaTypeOptions{Convert: &pomGVK}, - expectedObj: podMeta, - expectedErr: nil, - }, - { - desc: "cacheableObject as Table", - object: &mockCacheableObject{obj: pod}, - opts: &metav1beta1.TableOptions{NoHeaders: true, IncludeObject: metav1.IncludeNone}, - mediaType: negotiation.MediaTypeOptions{Convert: &tableGVK}, - expectedObj: podTable, - expectedErr: nil, - }, - } - - for _, test := range testCases { - t.Run(test.desc, func(t *testing.T) { - result, err := transformObject( - request.WithRequestInfo(context.TODO(), &request.RequestInfo{}), - test.object, test.opts, test.mediaType, - &RequestScope{ - Namer: &mockNamer{}, - TableConvertor: tableConvertor, - }, - nil) - - if err != test.expectedErr { - t.Errorf("unexpected error: %v, expected: %v", err, test.expectedErr) - } - if a, e := result, test.expectedObj; !reflect.DeepEqual(a, e) { - t.Errorf("unexpected result: %v, expected: %v", a, e) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/errors_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/errors_test.go index 457a5553290..52a56cab506 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/errors_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/errors_test.go @@ -76,7 +76,7 @@ func TestForbidden(t *testing.T) { for _, test := range cases { observer := httptest.NewRecorder() scheme := runtime.NewScheme() - negotiatedSerializer := serializer.NewCodecFactory(scheme).WithoutConversion() + negotiatedSerializer := serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)} Forbidden(request.NewDefaultContext(), test.attributes, observer, &http.Request{}, test.reason, negotiatedSerializer) result := string(observer.Body.Bytes()) if result != test.expected { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status.go old mode 100644 new mode 100755 index 5a845435033..99673077b2b --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status.go @@ -38,18 +38,11 @@ func ErrorToAPIStatus(err error) *metav1.Status { if len(status.Status) == 0 { status.Status = metav1.StatusFailure } - switch status.Status { - case metav1.StatusSuccess: - if status.Code == 0 { + if status.Code == 0 { + switch status.Status { + case metav1.StatusSuccess: status.Code = http.StatusOK - } - case metav1.StatusFailure: - if status.Code == 0 { - status.Code = http.StatusInternalServerError - } - default: - runtime.HandleError(fmt.Errorf("apiserver received an error with wrong status field : %#+v", err)) - if status.Code == 0 { + case metav1.StatusFailure: status.Code = http.StatusInternalServerError } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status_test.go index 9e1d37bd2b2..b4a8bf42c78 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/status_test.go @@ -27,19 +27,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -func TestBadStatusErrorToAPIStatus(t *testing.T) { - err := errors.StatusError{} - actual := ErrorToAPIStatus(&err) - expected := &metav1.Status{ - TypeMeta: metav1.TypeMeta{Kind: "Status", APIVersion: "v1"}, - Status: metav1.StatusFailure, - Code: 500, - } - if !reflect.DeepEqual(actual, expected) { - t.Errorf("%s: Expected %#v, Got %#v", actual, expected, actual) - } -} - func TestAPIStatus(t *testing.T) { cases := map[error]metav1.Status{ errors.NewNotFound(schema.GroupResource{Group: "legacy.kubernetes.io", Resource: "foos"}, "bar"): { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go index b7c59cfc54d..fd335b5d7e5 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go @@ -17,17 +17,11 @@ limitations under the License. package responsewriters import ( - "compress/gzip" "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "strconv" - "strings" - "sync" - - "k8s.io/apiserver/pkg/features" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -37,11 +31,47 @@ import ( "k8s.io/apiserver/pkg/endpoints/metrics" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/pkg/util/flushwriter" "k8s.io/apiserver/pkg/util/wsstream" ) +// httpResponseWriterWithInit wraps http.ResponseWriter, and implements the io.Writer interface to be used +// with encoding. The purpose is to allow for encoding to a stream, while accommodating a custom HTTP status code +// if encoding fails, and meeting the encoder's io.Writer interface requirement. +type httpResponseWriterWithInit struct { + hasWritten bool + mediaType string + statusCode int + innerW http.ResponseWriter +} + +func (w httpResponseWriterWithInit) Write(b []byte) (n int, err error) { + if !w.hasWritten { + w.innerW.Header().Set("Content-Type", w.mediaType) + w.innerW.WriteHeader(w.statusCode) + w.hasWritten = true + } + + return w.innerW.Write(b) +} + +// WriteObject renders a returned runtime.Object to the response as a stream or an encoded object. If the object +// returned by the response implements rest.ResourceStreamer that interface will be used to render the +// response. The Accept header and current API version will be passed in, and the output will be copied +// directly to the response body. If content type is returned it is used, otherwise the content type will +// be "application/octet-stream". All other objects are sent to standard JSON serialization. +func WriteObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSerializer, object runtime.Object, w http.ResponseWriter, req *http.Request) { + stream, ok := object.(rest.ResourceStreamer) + if ok { + requestInfo, _ := request.RequestInfoFrom(req.Context()) + metrics.RecordLongRunning(req, requestInfo, func() { + StreamObject(statusCode, gv, s, stream, w, req) + }) + return + } + WriteObjectNegotiated(s, gv, w, req, statusCode, object) +} + // StreamObject performs input stream negotiation from a ResourceStreamer and writes that to the response. // If the client requests a websocket upgrade, negotiate for a websocket reader protocol (because many // browser clients cannot easily handle binary streaming protocols). @@ -71,10 +101,6 @@ func StreamObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSe } w.Header().Set("Content-Type", contentType) w.WriteHeader(statusCode) - // Flush headers, if possible - if flusher, ok := w.(http.Flusher); ok { - flusher.Flush() - } writer := w.(io.Writer) if flush { writer = flushwriter.Wrap(w) @@ -83,154 +109,19 @@ func StreamObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSe } // SerializeObject renders an object in the content type negotiated by the client using the provided encoder. -// The context is optional and can be nil. This method will perform optional content compression if requested by -// a client and the feature gate for APIResponseCompression is enabled. -func SerializeObject(mediaType string, encoder runtime.Encoder, hw http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) { - w := &deferredResponseWriter{ - mediaType: mediaType, - statusCode: statusCode, - contentEncoding: negotiateContentEncoding(req), - hw: hw, - } - - err := encoder.Encode(object, w) - if err == nil { - err = w.Close() - if err == nil { - return - } - } +// The context is optional and can be nil. +func SerializeObject(mediaType string, encoder runtime.Encoder, innerW http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) { + w := httpResponseWriterWithInit{mediaType: mediaType, innerW: innerW, statusCode: statusCode} - // make a best effort to write the object if a failure is detected - utilruntime.HandleError(fmt.Errorf("apiserver was unable to write a JSON response: %v", err)) - status := ErrorToAPIStatus(err) - candidateStatusCode := int(status.Code) - // if the current status code is successful, allow the error's status code to overwrite it - if statusCode >= http.StatusOK && statusCode < http.StatusBadRequest { - w.statusCode = candidateStatusCode - } - output, err := runtime.Encode(encoder, status) - if err != nil { - w.mediaType = "text/plain" - output = []byte(fmt.Sprintf("%s: %s", status.Reason, status.Message)) + if err := encoder.Encode(object, w); err != nil { + errSerializationFatal(err, encoder, w) } - if _, err := w.Write(output); err != nil { - utilruntime.HandleError(fmt.Errorf("apiserver was unable to write a fallback JSON response: %v", err)) - } - w.Close() } -var gzipPool = &sync.Pool{ - New: func() interface{} { - gw, err := gzip.NewWriterLevel(nil, defaultGzipContentEncodingLevel) - if err != nil { - panic(err) - } - return gw - }, -} - -const ( - // defaultGzipContentEncodingLevel is set to 4 which uses less CPU than the default level - defaultGzipContentEncodingLevel = 4 - // defaultGzipThresholdBytes is compared to the size of the first write from the stream - // (usually the entire object), and if the size is smaller no gzipping will be performed - // if the client requests it. - defaultGzipThresholdBytes = 128 * 1024 -) - -// negotiateContentEncoding returns a supported client-requested content encoding for the -// provided request. It will return the empty string if no supported content encoding was -// found or if response compression is disabled. -func negotiateContentEncoding(req *http.Request) string { - encoding := req.Header.Get("Accept-Encoding") - if len(encoding) == 0 { - return "" - } - if !utilfeature.DefaultFeatureGate.Enabled(features.APIResponseCompression) { - return "" - } - for len(encoding) > 0 { - var token string - if next := strings.Index(encoding, ","); next != -1 { - token = encoding[:next] - encoding = encoding[next+1:] - } else { - token = encoding - encoding = "" - } - switch strings.TrimSpace(token) { - case "gzip": - return "gzip" - } - } - return "" -} - -type deferredResponseWriter struct { - mediaType string - statusCode int - contentEncoding string - - hasWritten bool - hw http.ResponseWriter - w io.Writer -} - -func (w *deferredResponseWriter) Write(p []byte) (n int, err error) { - if w.hasWritten { - return w.w.Write(p) - } - w.hasWritten = true - - hw := w.hw - header := hw.Header() - switch { - case w.contentEncoding == "gzip" && len(p) > defaultGzipThresholdBytes: - header.Set("Content-Encoding", "gzip") - header.Add("Vary", "Accept-Encoding") - - gw := gzipPool.Get().(*gzip.Writer) - gw.Reset(hw) - - w.w = gw - default: - w.w = hw - } - - header.Set("Content-Type", w.mediaType) - hw.WriteHeader(w.statusCode) - return w.w.Write(p) -} - -func (w *deferredResponseWriter) Close() error { - if !w.hasWritten { - return nil - } - var err error - switch t := w.w.(type) { - case *gzip.Writer: - err = t.Close() - t.Reset(nil) - gzipPool.Put(t) - } - return err -} - -var nopCloser = ioutil.NopCloser(nil) - // WriteObjectNegotiated renders an object in the content type negotiated by the client. -func WriteObjectNegotiated(s runtime.NegotiatedSerializer, restrictions negotiation.EndpointRestrictions, gv schema.GroupVersion, w http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) { - stream, ok := object.(rest.ResourceStreamer) - if ok { - requestInfo, _ := request.RequestInfoFrom(req.Context()) - metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() { - StreamObject(statusCode, gv, s, stream, w, req) - }) - return - } - - _, serializer, err := negotiation.NegotiateOutputMediaType(req, s, restrictions) +// The context is optional and can be nil. +func WriteObjectNegotiated(s runtime.NegotiatedSerializer, gv schema.GroupVersion, w http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) { + serializer, err := negotiation.NegotiateOutputSerializer(req, s) if err != nil { // if original statusCode was not successful we need to return the original error // we cannot hide it behind negotiation problems @@ -267,10 +158,29 @@ func ErrorNegotiated(err error, s runtime.NegotiatedSerializer, gv schema.GroupV return code } - WriteObjectNegotiated(s, negotiation.DefaultEndpointRestrictions, gv, w, req, code, status) + WriteObjectNegotiated(s, gv, w, req, code, status) return code } +// errSerializationFatal renders an error to the response, and if codec fails will render plaintext. +// Returns the HTTP status code of the error. +func errSerializationFatal(err error, codec runtime.Encoder, w httpResponseWriterWithInit) { + utilruntime.HandleError(fmt.Errorf("apiserver was unable to write a JSON response: %v", err)) + status := ErrorToAPIStatus(err) + candidateStatusCode := int(status.Code) + // If original statusCode was not successful, we need to return the original error. + // We cannot hide it behind serialization problems + if w.statusCode >= http.StatusOK && w.statusCode < http.StatusBadRequest { + w.statusCode = candidateStatusCode + } + output, err := runtime.Encode(codec, status) + if err != nil { + w.mediaType = "text/plain" + output = []byte(fmt.Sprintf("%s: %s", status.Reason, status.Message)) + } + w.Write(output) +} + // WriteRawJSON writes a non-API object in JSON. func WriteRawJSON(statusCode int, object interface{}, w http.ResponseWriter) { output, err := json.MarshalIndent(object, "", " ") diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go deleted file mode 100644 index 624b6becdff..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go +++ /dev/null @@ -1,307 +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 responsewriters - -import ( - "bytes" - "compress/gzip" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/http/httptest" - "reflect" - "testing" - - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/diff" - "k8s.io/apiserver/pkg/features" - utilfeature "k8s.io/apiserver/pkg/util/feature" - featuregatetesting "k8s.io/component-base/featuregate/testing" -) - -func TestSerializeObject(t *testing.T) { - smallPayload := []byte("{test-object,test-object}") - largePayload := bytes.Repeat([]byte("0123456789abcdef"), defaultGzipThresholdBytes/16+1) - tests := []struct { - name string - - compressionEnabled bool - - mediaType string - out []byte - outErrs []error - req *http.Request - statusCode int - object runtime.Object - - wantCode int - wantHeaders http.Header - wantBody []byte - }{ - { - name: "serialize object", - out: smallPayload, - req: &http.Request{Header: http.Header{}}, - wantCode: http.StatusOK, - wantHeaders: http.Header{"Content-Type": []string{""}}, - wantBody: smallPayload, - }, - - { - name: "return content type", - out: smallPayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - wantCode: http.StatusOK, - wantHeaders: http.Header{"Content-Type": []string{"application/json"}}, - wantBody: smallPayload, - }, - - { - name: "return status code", - statusCode: http.StatusBadRequest, - out: smallPayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - wantCode: http.StatusBadRequest, - wantHeaders: http.Header{"Content-Type": []string{"application/json"}}, - wantBody: smallPayload, - }, - - { - name: "fail to encode object", - out: smallPayload, - outErrs: []error{fmt.Errorf("bad")}, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - wantCode: http.StatusInternalServerError, - wantHeaders: http.Header{"Content-Type": []string{"application/json"}}, - wantBody: smallPayload, - }, - - { - name: "fail to encode object or status", - out: smallPayload, - outErrs: []error{fmt.Errorf("bad"), fmt.Errorf("bad2")}, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - wantCode: http.StatusInternalServerError, - wantHeaders: http.Header{"Content-Type": []string{"text/plain"}}, - wantBody: []byte(": bad"), - }, - - { - name: "fail to encode object or status with status code", - out: smallPayload, - outErrs: []error{errors.NewNotFound(schema.GroupResource{}, "test"), fmt.Errorf("bad2")}, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - statusCode: http.StatusOK, - wantCode: http.StatusNotFound, - wantHeaders: http.Header{"Content-Type": []string{"text/plain"}}, - wantBody: []byte("NotFound: \"test\" not found"), - }, - - { - name: "fail to encode object or status with status code and keeps previous error", - out: smallPayload, - outErrs: []error{errors.NewNotFound(schema.GroupResource{}, "test"), fmt.Errorf("bad2")}, - mediaType: "application/json", - req: &http.Request{Header: http.Header{}}, - statusCode: http.StatusNotAcceptable, - wantCode: http.StatusNotAcceptable, - wantHeaders: http.Header{"Content-Type": []string{"text/plain"}}, - wantBody: []byte("NotFound: \"test\" not found"), - }, - - { - name: "compression requires feature gate", - out: largePayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"gzip"}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{"Content-Type": []string{"application/json"}}, - wantBody: largePayload, - }, - - { - name: "compress on gzip", - compressionEnabled: true, - out: largePayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"gzip"}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{ - "Content-Type": []string{"application/json"}, - "Content-Encoding": []string{"gzip"}, - "Vary": []string{"Accept-Encoding"}, - }, - wantBody: gzipContent(largePayload, defaultGzipContentEncodingLevel), - }, - - { - name: "compression is not performed on small objects", - compressionEnabled: true, - out: smallPayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"gzip"}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{ - "Content-Type": []string{"application/json"}, - }, - wantBody: smallPayload, - }, - - { - name: "compress when multiple encodings are requested", - compressionEnabled: true, - out: largePayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"deflate, , gzip,"}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{ - "Content-Type": []string{"application/json"}, - "Content-Encoding": []string{"gzip"}, - "Vary": []string{"Accept-Encoding"}, - }, - wantBody: gzipContent(largePayload, defaultGzipContentEncodingLevel), - }, - - { - name: "ignore compression on deflate", - compressionEnabled: true, - out: largePayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"deflate"}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{ - "Content-Type": []string{"application/json"}, - }, - wantBody: largePayload, - }, - - { - name: "ignore compression on unrecognized types", - compressionEnabled: true, - out: largePayload, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{", , other, nothing, what, "}, - }}, - wantCode: http.StatusOK, - wantHeaders: http.Header{ - "Content-Type": []string{"application/json"}, - }, - wantBody: largePayload, - }, - - { - name: "errors are compressed", - compressionEnabled: true, - statusCode: http.StatusInternalServerError, - out: smallPayload, - outErrs: []error{fmt.Errorf(string(largePayload)), fmt.Errorf("bad2")}, - mediaType: "application/json", - req: &http.Request{Header: http.Header{ - "Accept-Encoding": []string{"gzip"}, - }}, - wantCode: http.StatusInternalServerError, - wantHeaders: http.Header{ - "Content-Type": []string{"text/plain"}, - "Content-Encoding": []string{"gzip"}, - "Vary": []string{"Accept-Encoding"}, - }, - wantBody: gzipContent([]byte(": "+string(largePayload)), defaultGzipContentEncodingLevel), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.APIResponseCompression, tt.compressionEnabled)() - - encoder := &fakeEncoder{ - buf: tt.out, - errs: tt.outErrs, - } - if tt.statusCode == 0 { - tt.statusCode = http.StatusOK - } - recorder := httptest.NewRecorder() - SerializeObject(tt.mediaType, encoder, recorder, tt.req, tt.statusCode, tt.object) - result := recorder.Result() - if result.StatusCode != tt.wantCode { - t.Fatalf("unexpected code: %v", result.StatusCode) - } - if !reflect.DeepEqual(result.Header, tt.wantHeaders) { - t.Fatal(diff.ObjectReflectDiff(tt.wantHeaders, result.Header)) - } - body, _ := ioutil.ReadAll(result.Body) - if !bytes.Equal(tt.wantBody, body) { - t.Fatalf("wanted:\n%s\ngot:\n%s", hex.Dump(tt.wantBody), hex.Dump(body)) - } - }) - } -} - -type fakeEncoder struct { - obj runtime.Object - buf []byte - errs []error -} - -func (e *fakeEncoder) Encode(obj runtime.Object, w io.Writer) error { - e.obj = obj - if len(e.errs) > 0 { - err := e.errs[0] - e.errs = e.errs[1:] - return err - } - _, err := w.Write(e.buf) - return err -} - -func (e *fakeEncoder) Identifier() runtime.Identifier { - return runtime.Identifier("fake") -} - -func gzipContent(data []byte, level int) []byte { - buf := &bytes.Buffer{} - gw, err := gzip.NewWriterLevel(buf, level) - if err != nil { - panic(err) - } - if _, err := gw.Write(data); err != nil { - panic(err) - } - if err := gw.Close(); err != nil { - panic(err) - } - return buf.Bytes() -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest.go index 97471637e56..3a0456cabc3 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest.go @@ -28,8 +28,7 @@ import ( "strings" "time" - grpccodes "google.golang.org/grpc/codes" - grpcstatus "google.golang.org/grpc/status" + "k8s.io/klog" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -39,14 +38,12 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/metrics" "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/rest" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/klog" + utiltrace "k8s.io/apiserver/pkg/util/trace" + openapiproto "k8s.io/kube-openapi/pkg/util/proto" ) // RequestScope encapsulates common fields across all RESTful handler methods. @@ -56,22 +53,16 @@ type RequestScope struct { Serializer runtime.NegotiatedSerializer runtime.ParameterCodec - // StandardSerializers, if set, restricts which serializers can be used when - // we aren't transforming the output (into Table or PartialObjectMetadata). - // Used only by CRDs which do not yet support Protobuf. - StandardSerializers []runtime.SerializerInfo - Creater runtime.ObjectCreater Convertor runtime.ObjectConvertor Defaulter runtime.ObjectDefaulter Typer runtime.ObjectTyper UnsafeConvertor runtime.ObjectConvertor Authorizer authorizer.Authorizer - - EquivalentResourceMapper runtime.EquivalentResourceMapper + Trace *utiltrace.Trace TableConvertor rest.TableConvertor - FieldManager *fieldmanager.FieldManager + OpenAPIModels openapiproto.Models Resource schema.GroupVersionResource Kind schema.GroupVersionKind @@ -89,28 +80,12 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque responsewriters.ErrorNegotiated(err, scope.Serializer, scope.Kind.GroupVersion(), w, req) } -func (scope *RequestScope) AllowsMediaTypeTransform(mimeType, mimeSubType string, gvk *schema.GroupVersionKind) bool { - // some handlers like CRDs can't serve all the mime types that PartialObjectMetadata or Table can - if - // gvk is nil (no conversion) allow StandardSerializers to further restrict the set of mime types. - if gvk == nil { - if len(scope.StandardSerializers) == 0 { - return true - } - for _, info := range scope.StandardSerializers { - if info.MediaTypeType == mimeType && info.MediaTypeSubType == mimeSubType { - return true - } - } - return false - } - +func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind) bool { // TODO: this is temporary, replace with an abstraction calculated at endpoint installation time - if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion || gvk.GroupVersion() == metav1.SchemeGroupVersion { + if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion { switch gvk.Kind { case "Table": - return scope.TableConvertor != nil && - mimeType == "application" && - (mimeSubType == "json" || mimeSubType == "yaml") + return scope.TableConvertor != nil case "PartialObjectMetadata", "PartialObjectMetadataList": // TODO: should delineate between lists and non-list endpoints return true @@ -129,18 +104,8 @@ func (scope *RequestScope) AllowsStreamSchema(s string) bool { return s == "watch" } -var _ admission.ObjectInterfaces = &RequestScope{} - -func (r *RequestScope) GetObjectCreater() runtime.ObjectCreater { return r.Creater } -func (r *RequestScope) GetObjectTyper() runtime.ObjectTyper { return r.Typer } -func (r *RequestScope) GetObjectDefaulter() runtime.ObjectDefaulter { return r.Defaulter } -func (r *RequestScope) GetObjectConvertor() runtime.ObjectConvertor { return r.Convertor } -func (r *RequestScope) GetEquivalentResourceMapper() runtime.EquivalentResourceMapper { - return r.EquivalentResourceMapper -} - // ConnectResource returns a function that handles a connect request on a rest.Storage object. -func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc { +func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { if isDryRun(req.URL) { scope.err(errors.NewBadRequest("dryRun is not supported"), w, req) @@ -167,14 +132,14 @@ func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admiss userInfo, _ := request.UserFrom(ctx) // TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { - err = mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) + err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo)) if err != nil { scope.err(err, w, req) return } } if validatingAdmission, ok := admit.(admission.ValidationInterface); ok { - err = validatingAdmission.Validate(ctx, admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, nil, false, userInfo), scope) + err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo)) if err != nil { scope.err(err, w, req) return @@ -182,7 +147,7 @@ func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admiss } } requestInfo, _ := request.RequestInfoFrom(ctx) - metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() { + metrics.RecordLongRunning(req, requestInfo, func() { handler, err := connecter.Connect(ctx, name, opts, &responder{scope: scope, req: req, w: w}) if err != nil { scope.err(err, w, req) @@ -195,13 +160,13 @@ func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admiss // responder implements rest.Responder for assisting a connector in writing objects or errors. type responder struct { - scope *RequestScope + scope RequestScope req *http.Request w http.ResponseWriter } func (r *responder) Object(statusCode int, obj runtime.Object) { - responsewriters.WriteObjectNegotiated(r.scope.Serializer, r.scope, r.scope.Kind.GroupVersion(), r.w, r.req, statusCode, obj) + responsewriters.WriteObject(statusCode, r.scope.Kind.GroupVersion(), r.scope.Serializer, obj, r.w, r.req) } func (r *responder) Error(err error) { @@ -224,15 +189,10 @@ func finishRequest(timeout time.Duration, fn resultFunc) (result runtime.Object, defer func() { panicReason := recover() if panicReason != nil { - // do not wrap the sentinel ErrAbortHandler panic value - if panicReason != http.ErrAbortHandler { - // Same as stdlib http server code. Manually allocate stack - // trace buffer size to prevent excessively large logs - const size = 64 << 10 - buf := make([]byte, size) - buf = buf[:goruntime.Stack(buf, false)] - panicReason = fmt.Sprintf("%v\n%s", panicReason, buf) - } + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:goruntime.Stack(buf, false)] + panicReason = strings.TrimSuffix(fmt.Sprintf("%v\n%s", panicReason, string(buf)), "\n") // Propagate to parent goroutine panicCh <- panicReason } @@ -262,11 +222,11 @@ func finishRequest(timeout time.Duration, fn resultFunc) (result runtime.Object, } } -// transformDecodeError adds additional information into a bad-request api error when a decode fails. +// transformDecodeError adds additional information when a decode fails. func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, gvk *schema.GroupVersionKind, body []byte) error { objGVKs, _, err := typer.ObjectKinds(into) if err != nil { - return errors.NewBadRequest(err.Error()) + return err } objGVK := objGVKs[0] if gvk != nil && len(gvk.Kind) > 0 { @@ -323,35 +283,23 @@ func checkName(obj runtime.Object, name, namespace string, namer ScopeNamer) err return nil } -// setObjectSelfLink sets the self link of an object as needed. -// TODO: remove the need for the namer LinkSetters by requiring objects implement either Object or List -// interfaces -func setObjectSelfLink(ctx context.Context, obj runtime.Object, req *http.Request, namer ScopeNamer) error { - if utilfeature.DefaultFeatureGate.Enabled(features.RemoveSelfLink) { - return nil - } - - // We only generate list links on objects that implement ListInterface - historically we duck typed this - // check via reflection, but as we move away from reflection we require that you not only carry Items but - // ListMeta into order to be identified as a list. +// setListSelfLink sets the self link of a list to the base URL, then sets the self links +// on all child objects returned. Returns the number of items in the list. +func setListSelfLink(obj runtime.Object, ctx context.Context, req *http.Request, namer ScopeNamer) (int, error) { if !meta.IsListType(obj) { - requestInfo, ok := request.RequestInfoFrom(ctx) - if !ok { - return fmt.Errorf("missing requestInfo") - } - return setSelfLink(obj, requestInfo, namer) + return 0, nil } uri, err := namer.GenerateListLink(req) if err != nil { - return err + return 0, err } if err := namer.SetSelfLink(obj, uri); err != nil { klog.V(4).Infof("Unable to set self link on object: %v", err) } requestInfo, ok := request.RequestInfoFrom(ctx) if !ok { - return fmt.Errorf("missing requestInfo") + return 0, fmt.Errorf("missing requestInfo") } count := 0 @@ -359,14 +307,7 @@ func setObjectSelfLink(ctx context.Context, obj runtime.Object, req *http.Reques count++ return setSelfLink(obj, requestInfo, namer) }) - - if count == 0 { - if err := meta.SetList(obj, []runtime.Object{}); err != nil { - return err - } - } - - return err + return count, err } func summarizeData(data []byte, maxLength int) string { @@ -413,35 +354,9 @@ func parseTimeout(str string) time.Duration { } klog.Errorf("Failed to parse %q: %v", str, err) } - // 34 chose as a number close to 30 that is likely to be unique enough to jump out at me the next time I see a timeout. Everyone chooses 30. - return 34 * time.Second + return 30 * time.Second } func isDryRun(url *url.URL) bool { return len(url.Query()["dryRun"]) != 0 } - -type etcdError interface { - Code() grpccodes.Code - Error() string -} - -type grpcError interface { - GRPCStatus() *grpcstatus.Status -} - -func isTooLargeError(err error) bool { - if err != nil { - if etcdErr, ok := err.(etcdError); ok { - if etcdErr.Code() == grpccodes.InvalidArgument && etcdErr.Error() == "etcdserver: request is too large" { - return true - } - } - if grpcErr, ok := err.(grpcError); ok { - if grpcErr.GRPCStatus().Code() == grpccodes.ResourceExhausted && strings.Contains(grpcErr.GRPCStatus().Message(), "trying to send message larger than max") { - return true - } - } - } - return false -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest_test.go index d1d46e89c9a..47b198704a0 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/rest_test.go @@ -26,28 +26,24 @@ import ( "testing" "time" - jsonpatch "github.com/evanphx/json-patch" - fuzz "github.com/google/gofuzz" + "github.com/evanphx/json-patch" + apiequality "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - testapigroupv1 "k8s.io/apimachinery/pkg/apis/testapigroup/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/diff" - "k8s.io/apimachinery/pkg/util/json" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/strategicpatch" - "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/apis/example" examplev1 "k8s.io/apiserver/pkg/apis/example/v1" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - utiltrace "k8s.io/utils/trace" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) var ( @@ -153,10 +149,10 @@ func TestJSONPatch(t *testing.T) { }, } { p := &patcher{ - patchType: types.JSONPatchType, - patchBytes: []byte(test.patch), + patchType: types.JSONPatchType, + patchJS: []byte(test.patch), } - jp := jsonPatcher{patcher: p} + jp := jsonPatcher{p} codec := codecs.LegacyCodec(examplev1.SchemeGroupVersion) pod := &examplev1.Pod{} pod.Name = "podA" @@ -260,11 +256,11 @@ func (p *testPatcher) Update(ctx context.Context, name string, objInfo rest.Upda } if currentPod == nil { - if err := createValidation(ctx, currentPod); err != nil { + if err := createValidation(currentPod); err != nil { return nil, false, err } } else { - if err := updateValidation(ctx, currentPod, inPod); err != nil { + if err := updateValidation(currentPod, inPod); err != nil { return nil, false, err } } @@ -351,13 +347,13 @@ func (tc *patchTestCase) Run(t *testing.T) { admissionMutation := tc.admissionMutation if admissionMutation == nil { - admissionMutation = func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation = func(updatedObject runtime.Object, currentObject runtime.Object) error { return nil } } admissionValidation := tc.admissionValidation if admissionValidation == nil { - admissionValidation = func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation = func(updatedObject runtime.Object, currentObject runtime.Object) error { return nil } } @@ -369,7 +365,6 @@ func (tc *patchTestCase) Run(t *testing.T) { creater := runtime.ObjectCreater(scheme) defaulter := runtime.ObjectDefaulter(scheme) convertor := runtime.UnsafeObjectConvertor(scheme) - objectInterfaces := admission.NewObjectInterfacesFromScheme(scheme) kind := examplev1.SchemeGroupVersion.WithKind("Pod") resource := examplev1.SchemeGroupVersion.WithResource("pods") schemaReferenceObj := &examplev1.Pod{} @@ -446,8 +441,6 @@ func (tc *patchTestCase) Run(t *testing.T) { kind: kind, resource: resource, - objectInterfaces: objectInterfaces, - hubGroupVersion: hubVersion, createValidation: rest.ValidateAllObjectFunc, @@ -461,12 +454,12 @@ func (tc *patchTestCase) Run(t *testing.T) { restPatcher: testPatcher, name: name, patchType: patchType, - patchBytes: patch, + patchJS: patch, - trace: utiltrace.New("Patch", utiltrace.Field{"name", name}), + trace: utiltrace.New("Patch" + name), } - resultObj, _, err := p.patchResource(ctx, &RequestScope{}) + resultObj, err := p.patchResource(ctx) if len(tc.expectedError) != 0 { if err == nil || err.Error() != tc.expectedError { t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err) @@ -718,7 +711,7 @@ func TestPatchWithAdmissionRejection(t *testing.T) { for _, test := range []Test{ { name: "TestPatchWithMutatingAdmissionRejection", - admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("mutating admission failure") }, admissionValidation: rest.ValidateAllObjectUpdateFunc, @@ -727,17 +720,17 @@ func TestPatchWithAdmissionRejection(t *testing.T) { { name: "TestPatchWithValidatingAdmissionRejection", admissionMutation: rest.ValidateAllObjectUpdateFunc, - admissionValidation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation: func(updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("validating admission failure") }, expectedError: "validating admission failure", }, { name: "TestPatchWithBothAdmissionRejections", - admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("mutating admission failure") }, - admissionValidation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionValidation: func(updatedObject runtime.Object, currentObject runtime.Object) error { return errors.New("validating admission failure") }, expectedError: "mutating admission failure", @@ -777,7 +770,7 @@ func TestPatchWithVersionConflictThenAdmissionFailure(t *testing.T) { tc := &patchTestCase{ name: "TestPatchWithVersionConflictThenAdmissionFailure", - admissionMutation: func(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object) error { + admissionMutation: func(updatedObject runtime.Object, currentObject runtime.Object) error { if seen { return errors.New("admission failure") } @@ -826,10 +819,10 @@ func TestHasUID(t *testing.T) { } func TestParseTimeout(t *testing.T) { - if d := parseTimeout(""); d != 34*time.Second { + if d := parseTimeout(""); d != 30*time.Second { t.Errorf("blank timeout produces %v", d) } - if d := parseTimeout("not a timeout"); d != 34*time.Second { + if d := parseTimeout("not a timeout"); d != 30*time.Second { t.Errorf("bad timeout produces %v", d) } if d := parseTimeout("10s"); d != 10*time.Second { @@ -849,8 +842,6 @@ func TestFinishRequest(t *testing.T) { expectedObj runtime.Object expectedErr error expectedPanic string - - expectedPanicObj interface{} }{ { name: "Expected obj is returned", @@ -893,6 +884,7 @@ func TestFinishRequest(t *testing.T) { timeout: time.Second, fn: func() (runtime.Object, error) { panic("my panic") + return nil, nil }, expectedObj: nil, expectedErr: nil, @@ -903,22 +895,12 @@ func TestFinishRequest(t *testing.T) { timeout: time.Second, fn: func() (runtime.Object, error) { panic("my panic") + return nil, nil }, expectedObj: nil, expectedErr: nil, expectedPanic: "rest_test.go", }, - { - name: "http.ErrAbortHandler panic is propagated without wrapping with stack", - timeout: time.Second, - fn: func() (runtime.Object, error) { - panic(http.ErrAbortHandler) - }, - expectedObj: nil, - expectedErr: nil, - expectedPanic: http.ErrAbortHandler.Error(), - expectedPanicObj: http.ErrAbortHandler, - }, } for i, tc := range testcases { t.Run(tc.name, func(t *testing.T) { @@ -932,10 +914,6 @@ func TestFinishRequest(t *testing.T) { case r != nil && len(tc.expectedPanic) > 0 && !strings.Contains(fmt.Sprintf("%v", r), tc.expectedPanic): t.Errorf("expected panic containing '%s', got '%v'", tc.expectedPanic, r) } - - if tc.expectedPanicObj != nil && !reflect.DeepEqual(tc.expectedPanicObj, r) { - t.Errorf("expected panic obj %#v, got %#v", tc.expectedPanicObj, r) - } }() obj, err := finishRequest(tc.timeout, tc.fn) if (err == nil && tc.expectedErr != nil) || (err != nil && tc.expectedErr == nil) || (err != nil && tc.expectedErr != nil && err.Error() != tc.expectedErr.Error()) { @@ -963,145 +941,3 @@ func setTcPod(tcPod *example.Pod, name string, namespace string, uid types.UID, tcPod.Spec.NodeName = nodeName } } - -func (f mutateObjectUpdateFunc) Handles(operation admission.Operation) bool { - return true -} - -func (f mutateObjectUpdateFunc) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) { - return f(ctx, a.GetObject(), a.GetOldObject()) -} - -func TestTransformDecodeErrorEnsuresBadRequestError(t *testing.T) { - testCases := []struct { - name string - typer runtime.ObjectTyper - decodedGVK *schema.GroupVersionKind - decodeIntoObject runtime.Object - baseErr error - expectedErr error - }{ - { - name: "decoding normal objects fails and returns a bad-request error", - typer: clientgoscheme.Scheme, - decodedGVK: &schema.GroupVersionKind{ - Group: testapigroupv1.GroupName, - Version: "v1", - Kind: "Carp", - }, - decodeIntoObject: &testapigroupv1.Carp{}, // which client-go's scheme doesn't recognize - baseErr: fmt.Errorf("plain error"), - }, - { - name: "decoding objects with unknown GVK fails and returns a bad-request error", - typer: alwaysErrorTyper{}, - decodedGVK: nil, - decodeIntoObject: &testapigroupv1.Carp{}, // which client-go's scheme doesn't recognize - baseErr: nil, - }, - } - for _, testCase := range testCases { - err := transformDecodeError(testCase.typer, testCase.baseErr, testCase.decodeIntoObject, testCase.decodedGVK, []byte(``)) - if apiStatus, ok := err.(apierrors.APIStatus); !ok || apiStatus.Status().Code != http.StatusBadRequest { - t.Errorf("expected bad request error but got: %v", err) - } - } -} - -var _ runtime.ObjectTyper = alwaysErrorTyper{} - -type alwaysErrorTyper struct{} - -func (alwaysErrorTyper) ObjectKinds(runtime.Object) ([]schema.GroupVersionKind, bool, error) { - return nil, false, fmt.Errorf("always error") -} - -func (alwaysErrorTyper) Recognizes(gvk schema.GroupVersionKind) bool { - return false -} - -func TestUpdateToCreateOptions(t *testing.T) { - f := fuzz.New() - for i := 0; i < 100; i++ { - t.Run(fmt.Sprintf("Run %d/100", i), func(t *testing.T) { - update := &metav1.UpdateOptions{} - f.Fuzz(update) - create := updateToCreateOptions(update) - - b, err := json.Marshal(create) - if err != nil { - t.Fatalf("failed to marshal CreateOptions (%v): %v", err, create) - } - got := &metav1.UpdateOptions{} - err = json.Unmarshal(b, &got) - if err != nil { - t.Fatalf("failed to unmarshal UpdateOptions: %v", err) - } - got.TypeMeta = metav1.TypeMeta{} - update.TypeMeta = metav1.TypeMeta{} - if !reflect.DeepEqual(*update, *got) { - t.Fatalf(`updateToCreateOptions round-trip failed: -got: %#+v -want: %#+v`, got, update) - } - - }) - } -} - -func TestPatchToUpdateOptions(t *testing.T) { - tests := []struct { - name string - converterFn func(po *metav1.PatchOptions) interface{} - }{ - { - name: "patchToUpdateOptions", - converterFn: func(patch *metav1.PatchOptions) interface{} { - return patchToUpdateOptions(patch) - }, - }, - { - name: "patchToCreateOptions", - converterFn: func(patch *metav1.PatchOptions) interface{} { - return patchToCreateOptions(patch) - }, - }, - } - - f := fuzz.New() - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - for i := 0; i < 100; i++ { - t.Run(fmt.Sprintf("Run %d/100", i), func(t *testing.T) { - patch := &metav1.PatchOptions{} - f.Fuzz(patch) - converted := test.converterFn(patch) - - b, err := json.Marshal(converted) - if err != nil { - t.Fatalf("failed to marshal converted object (%v): %v", err, converted) - } - got := &metav1.PatchOptions{} - err = json.Unmarshal(b, &got) - if err != nil { - t.Fatalf("failed to unmarshal converted object: %v", err) - } - - // Clear TypeMeta because we expect it to be different between the original and converted type - got.TypeMeta = metav1.TypeMeta{} - patch.TypeMeta = metav1.TypeMeta{} - - // clear fields that we know belong in PatchOptions only - patch.Force = nil - - if !reflect.DeepEqual(*patch, *got) { - t.Fatalf(`round-trip failed: -got: %#+v -want: %#+v`, got, converted) - } - - }) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/update.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/update.go index c58fe9d5792..f6bbd061a6b 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/update.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/update.go @@ -24,8 +24,7 @@ import ( "time" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" @@ -39,18 +38,18 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/util/dryrun" utilfeature "k8s.io/apiserver/pkg/util/feature" - utiltrace "k8s.io/utils/trace" + utiltrace "k8s.io/apiserver/pkg/util/trace" ) // UpdateResource returns a function that will handle a resource update -func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interface) http.HandlerFunc { +func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interface) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { // For performance tracking purposes. - trace := utiltrace.New("Update", utiltrace.Field{Key: "url", Value: req.URL.Path}, utiltrace.Field{Key: "user-agent", Value: &lazyTruncatedUserAgent{req}}, utiltrace.Field{Key: "client", Value: &lazyClientIP{req}}) + trace := utiltrace.New("Update " + req.URL.Path) defer trace.LogIfLong(500 * time.Millisecond) if isDryRun(req.URL) && !utilfeature.DefaultFeatureGate.Enabled(features.DryRun) { - scope.err(errors.NewBadRequest("the dryRun feature is disabled"), w, req) + scope.err(errors.NewBadRequest("the dryRun alpha feature is disabled"), w, req) return } @@ -62,16 +61,9 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa scope.err(err, w, req) return } - ctx, cancel := context.WithTimeout(req.Context(), timeout) - defer cancel() + ctx := req.Context() ctx = request.WithNamespace(ctx, namespace) - outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope) - if err != nil { - scope.err(err, w, req) - return - } - body, err := limitedReadBody(req, scope.MaxRequestBodyBytes) if err != nil { scope.err(err, w, req) @@ -79,7 +71,7 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa } options := &metav1.UpdateOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil { err = errors.NewBadRequest(err.Error()) scope.err(err, w, req) return @@ -89,7 +81,6 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa scope.err(err, w, req) return } - options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("UpdateOptions")) s, err := negotiation.NegotiateInputSerializer(req, false, scope.Serializer) if err != nil { @@ -124,23 +115,7 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa } userInfo, _ := request.UserFrom(ctx) - transformers := []rest.TransformFunc{} - - // allows skipping managedFields update if the resulting object is too big - shouldUpdateManagedFields := true - if scope.FieldManager != nil { - transformers = append(transformers, func(_ context.Context, newObj, liveObj runtime.Object) (runtime.Object, error) { - if shouldUpdateManagedFields { - obj, err := scope.FieldManager.Update(liveObj, newObj, managerOrUserAgent(options.FieldManager, req.UserAgent())) - if err != nil { - return nil, fmt.Errorf("failed to update object (Update for %v) managed fields: %v", scope.Kind, err) - } - return obj, nil - } - return newObj, nil - }) - } - + var transformers []rest.TransformFunc if mutatingAdmission, ok := admit.(admission.MutationInterface); ok { transformers = append(transformers, func(ctx context.Context, newObj, oldObj runtime.Object) (runtime.Object, error) { isNotZeroObject, err := hasUID(oldObj) @@ -148,15 +123,16 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa return nil, fmt.Errorf("unexpected error when extracting UID from oldObj: %v", err.Error()) } else if !isNotZeroObject { if mutatingAdmission.Handles(admission.Create) { - return newObj, mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, updateToCreateOptions(options), dryrun.IsDryRun(options.DryRun), userInfo), scope) + return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)) } } else { if mutatingAdmission.Handles(admission.Update) { - return newObj, mutatingAdmission.Admit(ctx, admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, options, dryrun.IsDryRun(options.DryRun), userInfo), scope) + return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)) } } return newObj, nil }) + } createAuthorizerAttributes := authorizer.AttributesRecord{ @@ -174,36 +150,23 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa trace.Step("About to store object in database") wasCreated := false - requestFunc := func() (runtime.Object, error) { + result, err := finishRequest(timeout, func() (runtime.Object, error) { obj, created, err := r.Update( ctx, name, rest.DefaultUpdatedObjectInfo(obj, transformers...), withAuthorization(rest.AdmissionToValidateObjectFunc( admit, - admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, updateToCreateOptions(options), dryrun.IsDryRun(options.DryRun), userInfo), scope), + admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)), scope.Authorizer, createAuthorizerAttributes), rest.AdmissionToValidateObjectUpdateFunc( admit, - admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, options, dryrun.IsDryRun(options.DryRun), userInfo), scope), + admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo)), false, options, ) wasCreated = created return obj, err - } - result, err := finishRequest(timeout, func() (runtime.Object, error) { - result, err := requestFunc() - // If the object wasn't committed to storage because it's serialized size was too large, - // it is safe to remove managedFields (which can be large) and try again. - if isTooLargeError(err) && scope.FieldManager != nil { - if accessor, accessorErr := meta.Accessor(obj); accessorErr == nil { - accessor.SetManagedFields(nil) - shouldUpdateManagedFields = false - result, err = requestFunc() - } - } - return result, err }) if err != nil { scope.err(err, w, req) @@ -211,12 +174,24 @@ func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interfa } trace.Step("Object stored in database") + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } + if err := setSelfLink(result, requestInfo, scope.Namer); err != nil { + scope.err(err, w, req) + return + } + trace.Step("Self-link added") + status := http.StatusOK if wasCreated { status = http.StatusCreated } - transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result) + scope.Trace = trace + transformResponseObject(ctx, scope, req, w, status, result) } } @@ -225,17 +200,17 @@ func withAuthorization(validate rest.ValidateObjectFunc, a authorizer.Authorizer var authorizerDecision authorizer.Decision var authorizerReason string var authorizerErr error - return func(ctx context.Context, obj runtime.Object) error { + return func(obj runtime.Object) error { if a == nil { return errors.NewInternalError(fmt.Errorf("no authorizer provided, unable to authorize a create on update")) } once.Do(func() { - authorizerDecision, authorizerReason, authorizerErr = a.Authorize(ctx, attributes) + authorizerDecision, authorizerReason, authorizerErr = a.Authorize(attributes) }) // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here. if authorizerDecision == authorizer.DecisionAllow { // Continue to validating admission - return validate(ctx, obj) + return validate(obj) } if authorizerErr != nil { return errors.NewInternalError(authorizerErr) @@ -251,16 +226,3 @@ func withAuthorization(validate rest.ValidateObjectFunc, a authorizer.Authorizer return errors.NewForbidden(gr, name, err) } } - -// updateToCreateOptions creates a CreateOptions with the same field values as the provided UpdateOptions. -func updateToCreateOptions(uo *metav1.UpdateOptions) *metav1.CreateOptions { - if uo == nil { - return nil - } - co := &metav1.CreateOptions{ - DryRun: uo.DryRun, - FieldManager: uo.FieldManager, - } - co.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("CreateOptions")) - return co -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go old mode 100644 new mode 100755 index 22945ccf6b8..0b4e7355621 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/watch.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/metrics" + "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/server/httplog" "k8s.io/apiserver/pkg/util/wsstream" @@ -60,52 +61,41 @@ func (w *realTimeoutFactory) TimeoutCh() (<-chan time.Time, func() bool) { return t.C, t.Stop } -// serveWatch will serve a watch response. +// serveWatch handles serving requests to the server // TODO: the functionality in this method and in WatchServer.Serve is not cleanly decoupled. -func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions negotiation.MediaTypeOptions, req *http.Request, w http.ResponseWriter, timeout time.Duration) { - defer watcher.Stop() - - options, err := optionsForTransform(mediaTypeOptions, req) - if err != nil { - scope.err(err, w, req) - return - } - - // negotiate for the stream serializer from the scope's serializer - serializer, err := negotiation.NegotiateOutputMediaTypeStream(req, scope.Serializer, scope) +func serveWatch(watcher watch.Interface, scope RequestScope, req *http.Request, w http.ResponseWriter, timeout time.Duration) { + // negotiate for the stream serializer + serializer, err := negotiation.NegotiateOutputStreamSerializer(req, scope.Serializer) if err != nil { scope.err(err, w, req) return } framer := serializer.StreamSerializer.Framer streamSerializer := serializer.StreamSerializer.Serializer - encoder := scope.Serializer.EncoderForVersion(streamSerializer, scope.Kind.GroupVersion()) - useTextFraming := serializer.EncodesAsText + embedded := serializer.Serializer if framer == nil { scope.err(fmt.Errorf("no framer defined for %q available for embedded encoding", serializer.MediaType), w, req) return } + encoder := scope.Serializer.EncoderForVersion(streamSerializer, scope.Kind.GroupVersion()) + + useTextFraming := serializer.EncodesAsText + + // find the embedded serializer matching the media type + embeddedEncoder := scope.Serializer.EncoderForVersion(embedded, scope.Kind.GroupVersion()) + // TODO: next step, get back mediaTypeOptions from negotiate and return the exact value here mediaType := serializer.MediaType if mediaType != runtime.ContentTypeJSON { mediaType += ";stream=watch" } - // locate the appropriate embedded encoder based on the transform - var embeddedEncoder runtime.Encoder - contentKind, contentSerializer, transform := targetEncodingForTransform(scope, mediaTypeOptions, req) - if transform { - info, ok := runtime.SerializerInfoForMediaType(contentSerializer.SupportedMediaTypes(), serializer.MediaType) - if !ok { - scope.err(fmt.Errorf("no encoder for %q exists in the requested target %#v", serializer.MediaType, contentSerializer), w, req) - return - } - embeddedEncoder = contentSerializer.EncoderForVersion(info.Serializer, contentKind.GroupVersion()) - } else { - embeddedEncoder = scope.Serializer.EncoderForVersion(serializer.Serializer, contentKind.GroupVersion()) - } - ctx := req.Context() + requestInfo, ok := request.RequestInfoFrom(ctx) + if !ok { + scope.err(fmt.Errorf("missing requestInfo"), w, req) + return + } server := &WatchServer{ Watching: watcher, @@ -116,20 +106,10 @@ func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions n Framer: framer, Encoder: encoder, EmbeddedEncoder: embeddedEncoder, - - Fixup: func(obj runtime.Object) runtime.Object { - result, err := transformObject(ctx, obj, options, mediaTypeOptions, scope, req) - if err != nil { - utilruntime.HandleError(fmt.Errorf("failed to transform object %v: %v", reflect.TypeOf(obj), err)) - return obj - } - // When we are transformed to a table, use the table options as the state for whether we - // should print headers - on watch, we only want to print table headers on the first object - // and omit them on subsequent events. - if tableOptions, ok := options.(*metav1.TableOptions); ok { - tableOptions.NoHeaders = true + Fixup: func(obj runtime.Object) { + if err := setSelfLink(obj, requestInfo, scope.Namer); err != nil { + utilruntime.HandleError(fmt.Errorf("failed to set link for object %v: %v", reflect.TypeOf(obj), err)) } - return result }, TimeoutFactory: &realTimeoutFactory{timeout}, @@ -141,7 +121,7 @@ func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions n // WatchServer serves a watch.Interface over a websocket or vanilla HTTP. type WatchServer struct { Watching watch.Interface - Scope *RequestScope + Scope RequestScope // true if websocket messages should use text framing (as opposed to binary framing) UseTextFraming bool @@ -153,8 +133,7 @@ type WatchServer struct { Encoder runtime.Encoder // used to encode the nested object in the watch stream EmbeddedEncoder runtime.Encoder - // used to correct the object before we send it to the serializer - Fixup func(runtime.Object) runtime.Object + Fixup func(runtime.Object) TimeoutFactory TimeoutFactory } @@ -166,7 +145,7 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { metrics.RegisteredWatchers.WithLabelValues(kind.Group, kind.Version, kind.Kind).Inc() defer metrics.RegisteredWatchers.WithLabelValues(kind.Group, kind.Version, kind.Kind).Dec() - w = httplog.Unlogged(req, w) + w = httplog.Unlogged(w) if wsstream.IsWebSocketRequest(req) { w.Header().Set("Content-Type", s.MediaType) @@ -174,6 +153,13 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } + cn, ok := w.(http.CloseNotifier) + if !ok { + err := fmt.Errorf("unable to start watch - can't get http.CloseNotifier: %#v", w) + utilruntime.HandleError(err) + s.Scope.err(errors.NewInternalError(err), w, req) + return + } flusher, ok := w.(http.Flusher) if !ok { err := fmt.Errorf("unable to start watch - can't get http.Flusher: %#v", w) @@ -195,6 +181,7 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { // ensure the connection times out timeoutCh, cleanup := s.TimeoutFactory.TimeoutCh() defer cleanup() + defer s.Watching.Stop() // begin the stream w.Header().Set("Content-Type", s.MediaType) @@ -204,14 +191,11 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { var unknown runtime.Unknown internalEvent := &metav1.InternalEvent{} - outEvent := &metav1.WatchEvent{} buf := &bytes.Buffer{} ch := s.Watching.ResultChan() - done := req.Context().Done() - for { select { - case <-done: + case <-cn.CloseNotify(): return case <-timeoutCh: return @@ -220,9 +204,9 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { // End of results. return } - metrics.WatchEvents.WithLabelValues(kind.Group, kind.Version, kind.Kind).Inc() - obj := s.Fixup(event.Object) + obj := event.Object + s.Fixup(obj) if err := s.EmbeddedEncoder.Encode(obj, buf); err != nil { // unexpected error utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v", obj, err)) @@ -233,13 +217,11 @@ func (s *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { // type unknown.Raw = buf.Bytes() event.Object = &unknown - metrics.WatchEventsSizes.WithLabelValues(kind.Group, kind.Version, kind.Kind).Observe(float64(len(unknown.Raw))) - - *outEvent = metav1.WatchEvent{} // create the external type directly and encode it. Clients will only recognize the serialization we provide. // The internal event is being reused, not reallocated so its just a few extra assignments to do it this way // and we get the benefit of using conversion functions which already have to stay in sync + outEvent := &metav1.WatchEvent{} *internalEvent = metav1.InternalEvent(event) err := metav1.Convert_v1_InternalEvent_To_v1_WatchEvent(internalEvent, outEvent, nil) if err != nil { @@ -280,17 +262,18 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) { buf := &bytes.Buffer{} streamBuf := &bytes.Buffer{} ch := s.Watching.ResultChan() - for { select { case <-done: + s.Watching.Stop() return case event, ok := <-ch: if !ok { // End of results. return } - obj := s.Fixup(event.Object) + obj := event.Object + s.Fixup(obj) if err := s.EmbeddedEncoder.Encode(obj, buf); err != nil { // unexpected error utilruntime.HandleError(fmt.Errorf("unable to encode watch object %T: %v", obj, err)) @@ -312,21 +295,25 @@ func (s *WatchServer) HandleWS(ws *websocket.Conn) { if err != nil { utilruntime.HandleError(fmt.Errorf("unable to convert watch object: %v", err)) // client disconnect. + s.Watching.Stop() return } if err := s.Encoder.Encode(outEvent, streamBuf); err != nil { // encoding error utilruntime.HandleError(fmt.Errorf("unable to encode event: %v", err)) + s.Watching.Stop() return } if s.UseTextFraming { if err := websocket.Message.Send(ws, streamBuf.String()); err != nil { // Client disconnect. + s.Watching.Stop() return } } else { if err := websocket.Message.Send(ws, streamBuf.Bytes()); err != nil { // Client disconnect. + s.Watching.Stop() return } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/installer.go b/vendor/k8s.io/apiserver/pkg/endpoints/installer.go index 06e0b211897..31234c82f63 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/installer.go @@ -27,20 +27,18 @@ import ( "unicode" restful "github.com/emicklei/go-restful" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/endpoints/discovery" "k8s.io/apiserver/pkg/endpoints/handlers" - "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager" "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/metrics" - "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/rest" - utilfeature "k8s.io/apiserver/pkg/util/feature" + genericfilters "k8s.io/apiserver/pkg/server/filters" ) const ( @@ -49,9 +47,10 @@ const ( ) type APIInstaller struct { - group *APIGroupVersion - prefix string // Path prefix where API resources are to be registered. - minRequestTimeout time.Duration + group *APIGroupVersion + prefix string // Path prefix where API resources are to be registered. + minRequestTimeout time.Duration + enableAPIResponseCompression bool } // Struct capturing information about an action ("GET", "POST", "WATCH", "PROXY", etc). @@ -132,20 +131,6 @@ func (a *APIInstaller) newWebService() *restful.WebService { return ws } -// calculate the storage gvk, the gvk objects are converted to before persisted to the etcd. -func getStorageVersionKind(storageVersioner runtime.GroupVersioner, storage rest.Storage, typer runtime.ObjectTyper) (schema.GroupVersionKind, error) { - object := storage.New() - fqKinds, _, err := typer.ObjectKinds(object) - if err != nil { - return schema.GroupVersionKind{}, err - } - gvk, ok := storageVersioner.KindForGroupVersionKinds(fqKinds) - if !ok { - return schema.GroupVersionKind{}, fmt.Errorf("cannot find the storage version kind for %v", reflect.TypeOf(object)) - } - return gvk, nil -} - // GetResourceKind returns the external group version kind registered for the given storage // object. If the storage object is a subresource and has an override supplied for it, it returns // the group version kind supplied in the override. @@ -191,8 +176,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag return nil, err } - group, version := a.group.GroupVersion.Group, a.group.GroupVersion.Version - fqKindToRegister, err := GetResourceKind(a.group.GroupVersion, storage, a.group.Typer) if err != nil { return nil, err @@ -240,7 +223,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag watcher, isWatcher := storage.(rest.Watcher) connecter, isConnecter := storage.(rest.Connecter) storageMeta, isMetadata := storage.(rest.StorageMetadata) - storageVersionProvider, isStorageVersionProvider := storage.(rest.StorageVersionProvider) if !isMetadata { storageMeta = defaultStorageMetadata{} } @@ -280,10 +262,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if err != nil { return nil, err } - versionedPatchOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("PatchOptions")) - if err != nil { - return nil, err - } versionedUpdateOptions, err := a.group.Creater.New(optionsExternalVersion.WithKind("UpdateOptions")) if err != nil { return nil, err @@ -291,17 +269,12 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag var versionedDeleteOptions runtime.Object var versionedDeleterObject interface{} - deleteReturnsDeletedObject := false if isGracefulDeleter { versionedDeleteOptions, err = a.group.Creater.New(optionsExternalVersion.WithKind("DeleteOptions")) if err != nil { return nil, err } versionedDeleterObject = indirectArbitraryPointer(versionedDeleteOptions) - - if mayReturnFullObjectDeleter, ok := storage.(rest.MayReturnFullObjectDeleter); ok { - deleteReturnsDeletedObject = mayReturnFullObjectDeleter.DeleteReturnsDeletedObject() - } } versionedStatusPtr, err := a.group.Creater.New(optionsExternalVersion.WithKind("Status")) @@ -381,24 +354,9 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag resourceKind = kind } - tableProvider, isTableProvider := storage.(rest.TableConvertor) - if isLister && !isTableProvider { - // All listers must implement TableProvider - return nil, fmt.Errorf("%q must implement TableConvertor", resource) - } + tableProvider, _ := storage.(rest.TableConvertor) var apiResource metav1.APIResource - if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionHash) && - isStorageVersionProvider && - storageVersionProvider.StorageVersion() != nil { - versioner := storageVersionProvider.StorageVersion() - gvk, err := getStorageVersionKind(versioner, storage, a.group.Typer) - if err != nil { - return nil, err - } - apiResource.StorageVersionHash = discovery.StorageVersionHash(gvk.Group, gvk.Version, gvk.Kind) - } - // Get the list of actions for the given scope. switch { case !namespaceScoped: @@ -445,6 +403,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag actions = appendIf(actions, action{"WATCH", "watch/" + itemPath, nameParams, namer, false}, isWatcher) actions = appendIf(actions, action{"CONNECT", itemPath, nameParams, namer, false}, isConnecter) actions = appendIf(actions, action{"CONNECT", itemPath + "/{path:*}", proxyParams, namer, false}, isConnecter && connectSubpath) + break default: namespaceParamName := "namespaces" // Handler for standard REST verbs (GET, PUT, POST and DELETE). @@ -500,6 +459,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag // DEPRECATED in 1.11 actions = appendIf(actions, action{"WATCHLIST", "watch/" + resource, params, namer, true}, allowWatchList) } + break } // Create Routes for the actions. @@ -519,11 +479,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag // // test/integration/auth_test.go is currently the most comprehensive status code test - for _, s := range a.group.Serializer.SupportedMediaTypes() { - if len(s.MediaTypeSubType) == 0 || len(s.MediaTypeType) == 0 { - return nil, fmt.Errorf("all serializers in the group Serializer must have MediaTypeType and MediaTypeSubType set: %s", s.MediaType) - } - } mediaTypes, streamMediaTypes := negotiation.MediaTypesForSerializer(a.group.Serializer) allMediaTypes := append(mediaTypes, streamMediaTypes...) ws.Produces(allMediaTypes...) @@ -539,8 +494,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag UnsafeConvertor: a.group.UnsafeConvertor, Authorizer: a.group.Authorizer, - EquivalentResourceMapper: a.group.EquivalentResourceRegistry, - // TODO: Check for the interface on storage TableConvertor: tableProvider, @@ -558,19 +511,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if a.group.MetaGroupVersion != nil { reqScope.MetaGroupVersion = *a.group.MetaGroupVersion } - if a.group.OpenAPIModels != nil && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) { - reqScope.FieldManager, err = fieldmanager.NewDefaultFieldManager( - a.group.OpenAPIModels, - a.group.UnsafeConvertor, - a.group.Defaulter, - a.group.Creater, - fqKindToRegister, - reqScope.HubGroupVersion, - ) - if err != nil { - return nil, fmt.Errorf("failed to create field manager: %v", err) - } - } + reqScope.OpenAPIModels = a.group.OpenAPIModels for _, action := range actions { producedObject := storageMeta.ProducesObject(action.Verb) if producedObject == nil { @@ -632,11 +573,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if needOverride { // need change the reported verb - handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler) + handler = metrics.InstrumentRouteFunc(verbOverrider.OverrideMetricsVerb(action.Verb), resource, subresource, requestScope, handler) } else { - handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler) + handler = metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, handler) } + if a.enableAPIResponseCompression { + handler = genericfilters.RestfulWithCompression(handler) + } doc := "read the specified " + kind if isSubresource { doc = "read " + subresource + " of the specified " + kind @@ -649,12 +593,12 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Returns(http.StatusOK, "OK", producedObject). Writes(producedObject) if isGetterWithOptions { - if err := AddObjectParams(ws, route, versionedGetOptions); err != nil { + if err := addObjectParams(ws, route, versionedGetOptions); err != nil { return nil, err } } if isExporter { - if err := AddObjectParams(ws, route, versionedExportOptions); err != nil { + if err := addObjectParams(ws, route, versionedExportOptions); err != nil { return nil, err } } @@ -665,7 +609,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isSubresource { doc = "list " + subresource + " of objects of kind " + kind } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout)) + if a.enableAPIResponseCompression { + handler = genericfilters.RestfulWithCompression(handler) + } route := ws.GET(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). @@ -673,7 +620,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Produces(append(storageMeta.ProducesMIMETypes(action.Verb), allMediaTypes...)...). Returns(http.StatusOK, "OK", versionedList). Writes(versionedList) - if err := AddObjectParams(ws, route, versionedListOptions); err != nil { + if err := addObjectParams(ws, route, versionedListOptions); err != nil { return nil, err } switch { @@ -697,7 +644,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isSubresource { doc = "replace " + subresource + " of the specified " + kind } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulUpdateResource(updater, reqScope, admit)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulUpdateResource(updater, reqScope, admit)) route := ws.PUT(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). @@ -709,7 +656,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Returns(http.StatusCreated, "Created", producedObject). Reads(defaultVersionedObject). Writes(producedObject) - if err := AddObjectParams(ws, route, versionedUpdateOptions); err != nil { + if err := addObjectParams(ws, route, versionedUpdateOptions); err != nil { return nil, err } addParams(route, action.Params) @@ -724,20 +671,17 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag string(types.MergePatchType), string(types.StrategicMergePatchType), } - if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) { - supportedTypes = append(supportedTypes, string(types.ApplyPatchType)) - } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulPatchResource(patcher, reqScope, admit, supportedTypes)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulPatchResource(patcher, reqScope, admit, supportedTypes)) route := ws.PATCH(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). - Consumes(supportedTypes...). + Consumes(string(types.JSONPatchType), string(types.MergePatchType), string(types.StrategicMergePatchType)). Operation("patch"+namespaced+kind+strings.Title(subresource)+operationSuffix). Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...). Returns(http.StatusOK, "OK", producedObject). Reads(metav1.Patch{}). Writes(producedObject) - if err := AddObjectParams(ws, route, versionedPatchOptions); err != nil { + if err := addObjectParams(ws, route, versionedUpdateOptions); err != nil { return nil, err } addParams(route, action.Params) @@ -749,8 +693,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag } else { handler = restfulCreateResource(creater, reqScope, admit) } - handler = metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, handler) - article := GetArticleForNoun(kind, " ") + handler = metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, handler) + article := getArticleForNoun(kind, " ") doc := "create" + article + kind if isSubresource { doc = "create " + subresource + " of" + article + kind @@ -767,34 +711,30 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Returns(http.StatusAccepted, "Accepted", producedObject). Reads(defaultVersionedObject). Writes(producedObject) - if err := AddObjectParams(ws, route, versionedCreateOptions); err != nil { + if err := addObjectParams(ws, route, versionedCreateOptions); err != nil { return nil, err } addParams(route, action.Params) routes = append(routes, route) case "DELETE": // Delete a resource. - article := GetArticleForNoun(kind, " ") + article := getArticleForNoun(kind, " ") doc := "delete" + article + kind if isSubresource { doc = "delete " + subresource + " of" + article + kind } - deleteReturnType := versionedStatus - if deleteReturnsDeletedObject { - deleteReturnType = producedObject - } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit)) route := ws.DELETE(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). Operation("delete"+namespaced+kind+strings.Title(subresource)+operationSuffix). Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...). - Writes(deleteReturnType). - Returns(http.StatusOK, "OK", deleteReturnType). - Returns(http.StatusAccepted, "Accepted", deleteReturnType) + Writes(versionedStatus). + Returns(http.StatusOK, "OK", versionedStatus). + Returns(http.StatusAccepted, "Accepted", versionedStatus) if isGracefulDeleter { route.Reads(versionedDeleterObject) route.ParameterNamed("body").Required(false) - if err := AddObjectParams(ws, route, versionedDeleteOptions); err != nil { + if err := addObjectParams(ws, route, versionedDeleteOptions); err != nil { return nil, err } } @@ -805,7 +745,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isSubresource { doc = "delete collection of " + subresource + " of a " + kind } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit)) route := ws.DELETE(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). @@ -813,14 +753,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...). Writes(versionedStatus). Returns(http.StatusOK, "OK", versionedStatus) - if isCollectionDeleter { - route.Reads(versionedDeleterObject) - route.ParameterNamed("body").Required(false) - if err := AddObjectParams(ws, route, versionedDeleteOptions); err != nil { - return nil, err - } - } - if err := AddObjectParams(ws, route, versionedListOptions); err != nil { + if err := addObjectParams(ws, route, versionedListOptions); err != nil { return nil, err } addParams(route, action.Params) @@ -832,7 +765,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag doc = "watch changes to " + subresource + " of an object of kind " + kind } doc += ". deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter." - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout)) route := ws.GET(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). @@ -840,7 +773,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Produces(allMediaTypes...). Returns(http.StatusOK, "OK", versionedWatchEvent). Writes(versionedWatchEvent) - if err := AddObjectParams(ws, route, versionedListOptions); err != nil { + if err := addObjectParams(ws, route, versionedListOptions); err != nil { return nil, err } addParams(route, action.Params) @@ -852,7 +785,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag doc = "watch individual changes to a list of " + subresource + " of " + kind } doc += ". deprecated: use the 'watch' parameter with a list operation instead." - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout)) route := ws.GET(action.Path).To(handler). Doc(doc). Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")). @@ -860,7 +793,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Produces(allMediaTypes...). Returns(http.StatusOK, "OK", versionedWatchEvent). Writes(versionedWatchEvent) - if err := AddObjectParams(ws, route, versionedListOptions); err != nil { + if err := addObjectParams(ws, route, versionedListOptions); err != nil { return nil, err } addParams(route, action.Params) @@ -875,7 +808,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag if isSubresource { doc = "connect " + method + " requests to " + subresource + " of " + kind } - handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, restfulConnectResource(connecter, reqScope, admit, path, isSubresource)) + handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulConnectResource(connecter, reqScope, admit, path, isSubresource)) route := ws.Method(method).Path(action.Path). To(handler). Doc(doc). @@ -884,7 +817,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag Consumes("*/*"). Writes(connectProducedObject) if versionedConnectOptions != nil { - if err := AddObjectParams(ws, route, versionedConnectOptions); err != nil { + if err := addObjectParams(ws, route, versionedConnectOptions); err != nil { return nil, err } } @@ -932,9 +865,6 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag apiResource.Kind = gvk.Kind } - // Record the existence of the GVR and the corresponding GVK - a.group.EquivalentResourceRegistry.RegisterKindFor(reqScope.Resource, reqScope.Subresource, fqKindToRegister) - return &apiResource, nil } @@ -956,13 +886,13 @@ func addParams(route *restful.RouteBuilder, params []*restful.Parameter) { } } -// AddObjectParams converts a runtime.Object into a set of go-restful Param() definitions on the route. +// addObjectParams converts a runtime.Object into a set of go-restful Param() definitions on the route. // The object must be a pointer to a struct; only fields at the top level of the struct that are not // themselves interfaces or structs are used; only fields with a json tag that is non empty (the standard // Go JSON behavior for omitting a field) become query parameters. The name of the query parameter is // the JSON field name. If a description struct tag is set on the field, that description is used on the // query parameter. In essence, it converts a standard JSON top level object into a query param schema. -func AddObjectParams(ws *restful.WebService, route *restful.RouteBuilder, obj interface{}) error { +func addObjectParams(ws *restful.WebService, route *restful.RouteBuilder, obj interface{}) error { sv, err := conversion.EnforcePtr(obj) if err != nil { return err @@ -1064,8 +994,8 @@ func splitSubresource(path string) (string, string, error) { return resource, subresource, nil } -// GetArticleForNoun returns the article needed for the given noun. -func GetArticleForNoun(noun string, padding string) string { +// getArticleForNoun returns the article needed for the given noun. +func getArticleForNoun(noun string, padding string) string { if noun[len(noun)-2:] != "ss" && noun[len(noun)-1:] == "s" { // Plurals don't have an article. // Don't catch words like class @@ -1093,60 +1023,60 @@ func isVowel(c rune) bool { func restfulListResource(r rest.Lister, rw rest.Watcher, scope handlers.RequestScope, forceWatch bool, minRequestTimeout time.Duration) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.ListResource(r, rw, &scope, forceWatch, minRequestTimeout)(res.ResponseWriter, req.Request) + handlers.ListResource(r, rw, scope, forceWatch, minRequestTimeout)(res.ResponseWriter, req.Request) } } func restfulCreateNamedResource(r rest.NamedCreater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.CreateNamedResource(r, &scope, admit)(res.ResponseWriter, req.Request) + handlers.CreateNamedResource(r, scope, admit)(res.ResponseWriter, req.Request) } } func restfulCreateResource(r rest.Creater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.CreateResource(r, &scope, admit)(res.ResponseWriter, req.Request) + handlers.CreateResource(r, scope, admit)(res.ResponseWriter, req.Request) } } func restfulDeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.DeleteResource(r, allowsOptions, &scope, admit)(res.ResponseWriter, req.Request) + handlers.DeleteResource(r, allowsOptions, scope, admit)(res.ResponseWriter, req.Request) } } func restfulDeleteCollection(r rest.CollectionDeleter, checkBody bool, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.DeleteCollection(r, checkBody, &scope, admit)(res.ResponseWriter, req.Request) + handlers.DeleteCollection(r, checkBody, scope, admit)(res.ResponseWriter, req.Request) } } func restfulUpdateResource(r rest.Updater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.UpdateResource(r, &scope, admit)(res.ResponseWriter, req.Request) + handlers.UpdateResource(r, scope, admit)(res.ResponseWriter, req.Request) } } func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit admission.Interface, supportedTypes []string) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.PatchResource(r, &scope, admit, supportedTypes)(res.ResponseWriter, req.Request) + handlers.PatchResource(r, scope, admit, supportedTypes)(res.ResponseWriter, req.Request) } } func restfulGetResource(r rest.Getter, e rest.Exporter, scope handlers.RequestScope) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.GetResource(r, e, &scope)(res.ResponseWriter, req.Request) + handlers.GetResource(r, e, scope)(res.ResponseWriter, req.Request) } } func restfulGetResourceWithOptions(r rest.GetterWithOptions, scope handlers.RequestScope, isSubresource bool) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.GetResourceWithOptions(r, &scope, isSubresource)(res.ResponseWriter, req.Request) + handlers.GetResourceWithOptions(r, scope, isSubresource)(res.ResponseWriter, req.Request) } } func restfulConnectResource(connecter rest.Connecter, scope handlers.RequestScope, admit admission.Interface, restPath string, isSubresource bool) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { - handlers.ConnectResource(connecter, &scope, admit, restPath, isSubresource)(res.ResponseWriter, req.Request) + handlers.ConnectResource(connecter, scope, admit, restPath, isSubresource)(res.ResponseWriter, req.Request) } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/installer_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/installer_test.go index c661bd6fc01..898d3b38584 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/installer_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/installer_test.go @@ -82,7 +82,7 @@ func TestGetArticleForNoun(t *testing.T) { }, } for _, tt := range tests { - if got := GetArticleForNoun(tt.noun, tt.padding); got != tt.want { + if got := getArticleForNoun(tt.noun, tt.padding); got != tt.want { t.Errorf("%q. GetArticleForNoun() = %v, want %v", tt.noun, got, tt.want) } } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/OWNERS old mode 100644 new mode 100755 index 33c780d7a6d..f0706b3f104 --- a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - wojtek-t - jimmidyson diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go index c79efdef4e3..ae16d43bb1e 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go @@ -20,157 +20,107 @@ import ( "bufio" "net" "net/http" - "net/url" "regexp" "strconv" "strings" "sync" "time" - restful "github.com/emicklei/go-restful" - - "k8s.io/apimachinery/pkg/apis/meta/v1/validation" - "k8s.io/apimachinery/pkg/types" - utilsets "k8s.io/apimachinery/pkg/util/sets" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/features" - utilfeature "k8s.io/apiserver/pkg/util/feature" - compbasemetrics "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" + + "github.com/emicklei/go-restful" + "github.com/prometheus/client_golang/prometheus" ) // resettableCollector is the interface implemented by prometheus.MetricVec // that can be used by Prometheus to collect metrics and reset their values. type resettableCollector interface { - compbasemetrics.Registerable + prometheus.Collector Reset() } -const ( - APIServerComponent string = "apiserver" -) - -/* - * By default, all the following metrics are defined as falling under - * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes) - * - * Promoting the stability level of the metric is a responsibility of the component owner, since it - * involves explicitly acknowledging support for the metric across multiple releases, in accordance with - * the metric stability policy. - */ var ( // TODO(a-robinson): Add unit tests for the handling of these metrics once // the upstream library supports it. - requestCounter = compbasemetrics.NewCounterVec( - &compbasemetrics.CounterOpts{ - Name: "apiserver_request_total", - Help: "Counter of apiserver requests broken out for each verb, dry run value, group, version, resource, scope, component, and HTTP response contentType and code.", - StabilityLevel: compbasemetrics.ALPHA, + requestCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "apiserver_request_count", + Help: "Counter of apiserver requests broken out for each verb, API resource, client, and HTTP response contentType and code.", }, - // The label_name contentType doesn't follow the label_name convention defined here: - // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/instrumentation.md - // But changing it would break backwards compatibility. Future label_names - // should be all lowercase and separated by underscores. - []string{"verb", "dry_run", "group", "version", "resource", "subresource", "scope", "component", "contentType", "code"}, + []string{"verb", "resource", "subresource", "scope", "client", "contentType", "code"}, ) - longRunningRequestGauge = compbasemetrics.NewGaugeVec( - &compbasemetrics.GaugeOpts{ - Name: "apiserver_longrunning_gauge", - Help: "Gauge of all active long-running apiserver requests broken out by verb, group, version, resource, scope and component. Not all requests are tracked this way.", - StabilityLevel: compbasemetrics.ALPHA, + longRunningRequestGauge = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "apiserver_longrunning_gauge", + Help: "Gauge of all active long-running apiserver requests broken out by verb, API resource, and scope. Not all requests are tracked this way.", }, - []string{"verb", "group", "version", "resource", "subresource", "scope", "component"}, + []string{"verb", "resource", "subresource", "scope"}, ) - requestLatencies = compbasemetrics.NewHistogramVec( - &compbasemetrics.HistogramOpts{ - Name: "apiserver_request_duration_seconds", - Help: "Response latency distribution in seconds for each verb, dry run value, group, version, resource, subresource, scope and component.", - // This metric is used for verifying api call latencies SLO, - // as well as tracking regressions in this aspects. - // Thus we customize buckets significantly, to empower both usecases. - Buckets: []float64{0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, - 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60}, - StabilityLevel: compbasemetrics.ALPHA, + requestLatencies = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "apiserver_request_latencies", + Help: "Response latency distribution in microseconds for each verb, resource and subresource.", + // Use buckets ranging from 125 ms to 8 seconds. + Buckets: prometheus.ExponentialBuckets(125000, 2.0, 7), }, - []string{"verb", "dry_run", "group", "version", "resource", "subresource", "scope", "component"}, + []string{"verb", "resource", "subresource", "scope"}, ) - responseSizes = compbasemetrics.NewHistogramVec( - &compbasemetrics.HistogramOpts{ + requestLatenciesSummary = prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Name: "apiserver_request_latencies_summary", + Help: "Response latency summary in microseconds for each verb, resource and subresource.", + // Make the sliding window of 5h. + // TODO: The value for this should be based on our SLI definition (medium term). + MaxAge: 5 * time.Hour, + }, + []string{"verb", "resource", "subresource", "scope"}, + ) + responseSizes = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ Name: "apiserver_response_sizes", - Help: "Response size distribution in bytes for each group, version, verb, resource, subresource, scope and component.", + Help: "Response size distribution in bytes for each verb, resource, subresource and scope (namespace/cluster).", // Use buckets ranging from 1000 bytes (1KB) to 10^9 bytes (1GB). - Buckets: compbasemetrics.ExponentialBuckets(1000, 10.0, 7), - StabilityLevel: compbasemetrics.ALPHA, + Buckets: prometheus.ExponentialBuckets(1000, 10.0, 7), }, - []string{"verb", "group", "version", "resource", "subresource", "scope", "component"}, + []string{"verb", "resource", "subresource", "scope"}, ) // DroppedRequests is a number of requests dropped with 'Try again later' response" - DroppedRequests = compbasemetrics.NewCounterVec( - &compbasemetrics.CounterOpts{ - Name: "apiserver_dropped_requests_total", - Help: "Number of requests dropped with 'Try again later' response", - StabilityLevel: compbasemetrics.ALPHA, + DroppedRequests = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "apiserver_dropped_requests", + Help: "Number of requests dropped with 'Try again later' response", }, []string{"requestKind"}, ) // RegisteredWatchers is a number of currently registered watchers splitted by resource. - RegisteredWatchers = compbasemetrics.NewGaugeVec( - &compbasemetrics.GaugeOpts{ - Name: "apiserver_registered_watchers", - Help: "Number of currently registered watchers for a given resources", - StabilityLevel: compbasemetrics.ALPHA, - }, - []string{"group", "version", "kind"}, - ) - WatchEvents = compbasemetrics.NewCounterVec( - &compbasemetrics.CounterOpts{ - Name: "apiserver_watch_events_total", - Help: "Number of events sent in watch clients", - StabilityLevel: compbasemetrics.ALPHA, - }, - []string{"group", "version", "kind"}, - ) - WatchEventsSizes = compbasemetrics.NewHistogramVec( - &compbasemetrics.HistogramOpts{ - Name: "apiserver_watch_events_sizes", - Help: "Watch event size distribution in bytes", - Buckets: compbasemetrics.ExponentialBuckets(1024, 2.0, 8), // 1K, 2K, 4K, 8K, ..., 128K. - StabilityLevel: compbasemetrics.ALPHA, + RegisteredWatchers = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "apiserver_registered_watchers", + Help: "Number of currently registered watchers for a given resources", }, []string{"group", "version", "kind"}, ) - // Because of volatility of the base metric this is pre-aggregated one. Instead of reporting current usage all the time + // Because of volatality of the base metric this is pre-aggregated one. Instead of reporing current usage all the time // it reports maximal usage during the last second. - currentInflightRequests = compbasemetrics.NewGaugeVec( - &compbasemetrics.GaugeOpts{ - Name: "apiserver_current_inflight_requests", - Help: "Maximal number of currently used inflight request limit of this apiserver per request kind in last second.", - StabilityLevel: compbasemetrics.ALPHA, + currentInflightRequests = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "apiserver_current_inflight_requests", + Help: "Maximal mumber of currently used inflight request limit of this apiserver per request kind in last second.", }, []string{"requestKind"}, ) - - requestTerminationsTotal = compbasemetrics.NewCounterVec( - &compbasemetrics.CounterOpts{ - Name: "apiserver_request_terminations_total", - Help: "Number of requests which apiserver terminated in self-defense.", - StabilityLevel: compbasemetrics.ALPHA, - }, - []string{"verb", "group", "version", "resource", "subresource", "scope", "component", "code"}, - ) kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`) metrics = []resettableCollector{ requestCounter, longRunningRequestGauge, requestLatencies, + requestLatenciesSummary, responseSizes, DroppedRequests, RegisteredWatchers, - WatchEvents, - WatchEventsSizes, currentInflightRequests, - requestTerminationsTotal, } ) @@ -187,7 +137,7 @@ var registerMetrics sync.Once func Register() { registerMetrics.Do(func() { for _, metric := range metrics { - legacyregistry.MustRegister(metric) + prometheus.MustRegister(metric) } }) } @@ -204,46 +154,34 @@ func UpdateInflightRequestMetrics(nonmutating, mutating int) { currentInflightRequests.WithLabelValues(MutatingKind).Set(float64(mutating)) } -// RecordRequestTermination records that the request was terminated early as part of a resource -// preservation or apiserver self-defense mechanism (e.g. timeouts, maxinflight throttling, -// proxyHandler errors). RecordRequestTermination should only be called zero or one times -// per request. -func RecordRequestTermination(req *http.Request, requestInfo *request.RequestInfo, component string, code int) { +// Record records a single request to the standard metrics endpoints. For use by handlers that perform their own +// processing. All API paths should use InstrumentRouteFunc implicitly. Use this instead of MonitorRequest if +// you already have a RequestInfo object. +func Record(req *http.Request, requestInfo *request.RequestInfo, contentType string, code int, responseSizeInBytes int, elapsed time.Duration) { if requestInfo == nil { requestInfo = &request.RequestInfo{Verb: req.Method, Path: req.URL.Path} } scope := CleanScope(requestInfo) - // We don't use verb from , as for the healthy path - // MonitorRequest is called from InstrumentRouteFunc which is registered - // in installer.go with predefined list of verbs (different than those - // translated to RequestInfo). - // However, we need to tweak it e.g. to differentiate GET from LIST. - verb := canonicalVerb(strings.ToUpper(req.Method), scope) if requestInfo.IsResourceRequest { - requestTerminationsTotal.WithLabelValues(cleanVerb(verb, req), requestInfo.APIGroup, requestInfo.APIVersion, requestInfo.Resource, requestInfo.Subresource, scope, component, codeToString(code)).Inc() + MonitorRequest(req, strings.ToUpper(requestInfo.Verb), requestInfo.Resource, requestInfo.Subresource, scope, contentType, code, responseSizeInBytes, elapsed) } else { - requestTerminationsTotal.WithLabelValues(cleanVerb(verb, req), "", "", "", requestInfo.Path, scope, component, codeToString(code)).Inc() + MonitorRequest(req, strings.ToUpper(requestInfo.Verb), "", requestInfo.Path, scope, contentType, code, responseSizeInBytes, elapsed) } } // RecordLongRunning tracks the execution of a long running request against the API server. It provides an accurate count // of the total number of open long running requests. requestInfo may be nil if the caller is not in the normal request flow. -func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, component string, fn func()) { +func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, fn func()) { if requestInfo == nil { requestInfo = &request.RequestInfo{Verb: req.Method, Path: req.URL.Path} } - var g compbasemetrics.GaugeMetric + var g prometheus.Gauge scope := CleanScope(requestInfo) - // We don't use verb from , as for the healthy path - // MonitorRequest is called from InstrumentRouteFunc which is registered - // in installer.go with predefined list of verbs (different than those - // translated to RequestInfo). - // However, we need to tweak it e.g. to differentiate GET from LIST. - reportedVerb := cleanVerb(canonicalVerb(strings.ToUpper(req.Method), scope), req) + reportedVerb := cleanVerb(strings.ToUpper(requestInfo.Verb), req) if requestInfo.IsResourceRequest { - g = longRunningRequestGauge.WithLabelValues(reportedVerb, requestInfo.APIGroup, requestInfo.APIVersion, requestInfo.Resource, requestInfo.Subresource, scope, component) + g = longRunningRequestGauge.WithLabelValues(reportedVerb, requestInfo.Resource, requestInfo.Subresource, scope) } else { - g = longRunningRequestGauge.WithLabelValues(reportedVerb, "", "", "", requestInfo.Path, scope, component) + g = longRunningRequestGauge.WithLabelValues(reportedVerb, "", requestInfo.Path, scope) } g.Inc() defer g.Dec() @@ -252,21 +190,22 @@ func RecordLongRunning(req *http.Request, requestInfo *request.RequestInfo, comp // MonitorRequest handles standard transformations for client and the reported verb and then invokes Monitor to record // a request. verb must be uppercase to be backwards compatible with existing monitoring tooling. -func MonitorRequest(req *http.Request, verb, group, version, resource, subresource, scope, component, contentType string, httpCode, respSize int, elapsed time.Duration) { +func MonitorRequest(req *http.Request, verb, resource, subresource, scope, contentType string, httpCode, respSize int, elapsed time.Duration) { reportedVerb := cleanVerb(verb, req) - dryRun := cleanDryRun(req.URL) - elapsedSeconds := elapsed.Seconds() - requestCounter.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component, contentType, codeToString(httpCode)).Inc() - requestLatencies.WithLabelValues(reportedVerb, dryRun, group, version, resource, subresource, scope, component).Observe(elapsedSeconds) + client := cleanUserAgent(utilnet.GetHTTPClient(req)) + elapsedMicroseconds := float64(elapsed / time.Microsecond) + requestCounter.WithLabelValues(reportedVerb, resource, subresource, scope, client, contentType, codeToString(httpCode)).Inc() + requestLatencies.WithLabelValues(reportedVerb, resource, subresource, scope).Observe(elapsedMicroseconds) + requestLatenciesSummary.WithLabelValues(reportedVerb, resource, subresource, scope).Observe(elapsedMicroseconds) // We are only interested in response sizes of read requests. if verb == "GET" || verb == "LIST" { - responseSizes.WithLabelValues(reportedVerb, group, version, resource, subresource, scope, component).Observe(float64(respSize)) + responseSizes.WithLabelValues(reportedVerb, resource, subresource, scope).Observe(float64(respSize)) } } // InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps // the go-restful RouteFunction instead of a HandlerFunc plus some Kubernetes endpoint specific information. -func InstrumentRouteFunc(verb, group, version, resource, subresource, scope, component string, routeFunc restful.RouteFunction) restful.RouteFunction { +func InstrumentRouteFunc(verb, resource, subresource, scope string, routeFunc restful.RouteFunction) restful.RouteFunction { return restful.RouteFunction(func(request *restful.Request, response *restful.Response) { now := time.Now() @@ -285,12 +224,12 @@ func InstrumentRouteFunc(verb, group, version, resource, subresource, scope, com routeFunc(request, response) - MonitorRequest(request.Request, verb, group, version, resource, subresource, scope, component, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now)) + MonitorRequest(request.Request, verb, resource, subresource, scope, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now)) }) } // InstrumentHandlerFunc works like Prometheus' InstrumentHandlerFunc but adds some Kubernetes endpoint specific information. -func InstrumentHandlerFunc(verb, group, version, resource, subresource, scope, component string, handler http.HandlerFunc) http.HandlerFunc { +func InstrumentHandlerFunc(verb, resource, subresource, scope string, handler http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { now := time.Now() @@ -307,7 +246,7 @@ func InstrumentHandlerFunc(verb, group, version, resource, subresource, scope, c handler(w, req) - MonitorRequest(req, verb, group, version, resource, subresource, scope, component, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now)) + MonitorRequest(req, verb, resource, subresource, scope, delegate.Header().Get("Content-Type"), delegate.Status(), delegate.ContentLength(), time.Since(now)) } } @@ -326,18 +265,6 @@ func CleanScope(requestInfo *request.RequestInfo) string { return "" } -func canonicalVerb(verb string, scope string) string { - switch verb { - case "GET", "HEAD": - if scope != "resource" { - return "LIST" - } - return "GET" - default: - return verb - } -} - func cleanVerb(verb string, request *http.Request) string { reportedVerb := verb if verb == "LIST" { @@ -352,26 +279,17 @@ func cleanVerb(verb string, request *http.Request) string { if verb == "WATCHLIST" { reportedVerb = "WATCH" } - if verb == "PATCH" && request.Header.Get("Content-Type") == string(types.ApplyPatchType) && utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) { - reportedVerb = "APPLY" - } return reportedVerb } -func cleanDryRun(u *url.URL) string { - // avoid allocating when we don't see dryRun in the query - if !strings.Contains(u.RawQuery, "dryRun") { - return "" - } - dryRun := u.Query()["dryRun"] - if errs := validation.ValidateDryRun(nil, dryRun); len(errs) > 0 { - return "invalid" +func cleanUserAgent(ua string) string { + // We collapse all "web browser"-type user agents into one "browser" to reduce metric cardinality. + if strings.HasPrefix(ua, "Mozilla/") { + return "Browser" } - // Since dryRun could be valid with any arbitrarily long length - // we have to dedup and sort the elements before joining them together - // TODO: this is a fairly large allocation for what it does, consider - // a sort and dedup in a single pass - return strings.Join(utilsets.NewString(dryRun...).List(), ",") + // If an old "kubectl.exe" has passed us its full path, we discard the path portion. + ua = kubectlExeRegexp.ReplaceAllString(ua, "$1") + return ua } // ResponseWriterDelegator interface wraps http.ResponseWriter to additionally record content-length, status-code, etc. diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics_test.go new file mode 100644 index 00000000000..4c0a8aa5d27 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics_test.go @@ -0,0 +1,54 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package metrics + +import "testing" + +func TestCleanUserAgent(t *testing.T) { + panicBuf := []byte{198, 73, 129, 133, 90, 216, 104, 29, 13, 134, 209, 233, 30, 0, 22} + + for _, tc := range []struct { + In string + Out string + }{ + { + In: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", + Out: "Browser", + }, + { + In: "kubectl/v1.2.4", + Out: "kubectl/v1.2.4", + }, + { + In: `C:\Users\Kubernetes\kubectl.exe/v1.5.4`, + Out: "kubectl.exe/v1.5.4", + }, + { + In: `C:\Program Files\kubectl.exe/v1.5.4`, + Out: "kubectl.exe/v1.5.4", + }, + { + // This malicious input courtesy of enisoc. + In: string(panicBuf) + "kubectl.exe", + Out: "kubectl.exe", + }, + } { + if cleanUserAgent(tc.In) != tc.Out { + t.Errorf("Failed to clean User-Agent: %s", tc.In) + } + } +} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/OWNERS old mode 100644 new mode 100755 index 006f0125e18..4126a6be36b --- a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/OWNERS @@ -1,4 +1,2 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - mbohlool diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go index e3bd028bbf9..e512f29b38c 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi.go @@ -108,18 +108,6 @@ func (s groupVersionKinds) Less(i, j int) bool { return s[i].Group < s[j].Group } -func (s groupVersionKinds) JSON() []interface{} { - j := []interface{}{} - for _, gvk := range s { - j = append(j, map[string]interface{}{ - "group": gvk.Group, - "version": gvk.Version, - "kind": gvk.Kind, - }) - } - return j -} - // DefinitionNamer is the type to customize OpenAPI definition name. type DefinitionNamer struct { typeGroupVersionKinds map[string]groupVersionKinds @@ -184,7 +172,7 @@ func NewDefinitionNamer(schemes ...*runtime.Scheme) *DefinitionNamer { func (d *DefinitionNamer) GetDefinitionName(name string) (string, spec.Extensions) { if groupVersionKinds, ok := d.typeGroupVersionKinds[name]; ok { return friendlyName(name), spec.Extensions{ - extensionGVK: groupVersionKinds.JSON(), + extensionGVK: []v1.GroupVersionKind(groupVersionKinds), } } return friendlyName(name), nil diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi_test.go index 0ebfedeaeba..fb188fed0c7 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/openapi/openapi_test.go @@ -23,6 +23,7 @@ import ( "github.com/go-openapi/spec" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" openapitesting "k8s.io/apiserver/pkg/endpoints/openapi/testing" ) @@ -57,13 +58,13 @@ func TestGetDefinitionName(t *testing.T) { namer := NewDefinitionNamer(s) n, e := namer.GetDefinitionName(typePkgName) assertEqual(t, typeFriendlyName, n) - assertEqual(t, []interface{}{ - map[string]interface{}{ - "group": "test", - "version": "v1", - "kind": "TestType", + assertEqual(t, e["x-kubernetes-group-version-kind"], []v1.GroupVersionKind{ + { + Group: "test", + Version: "v1", + Kind: "TestType", }, - }, e["x-kubernetes-group-version-kind"]) + }) n, e2 := namer.GetDefinitionName("test.com/another.Type") assertEqual(t, "com.test.another.Type", n) assertEqual(t, e2, spec.Extensions(nil)) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/patchhandler_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/patchhandler_test.go index d3e198f1fed..6d0475c773d 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/patchhandler_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/patchhandler_test.go @@ -53,9 +53,6 @@ func TestPatch(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) - if err != nil { - t.Errorf("unexpected error: %v", err) - } request.Header.Set("Content-Type", "application/merge-patch+json; charset=UTF-8") response, err := client.Do(request) if err != nil { @@ -72,67 +69,6 @@ func TestPatch(t *testing.T) { } } -func TestForbiddenForceOnNonApply(t *testing.T) { - storage := map[string]rest.Storage{} - ID := "id" - item := &genericapitesting.Simple{ - ObjectMeta: metav1.ObjectMeta{ - Name: ID, - Namespace: "", // update should allow the client to send an empty namespace - UID: "uid", - }, - Other: "bar", - } - simpleStorage := SimpleRESTStorage{item: *item} - storage["simple"] = &simpleStorage - selfLinker := &setTestSelfLinker{ - t: t, - expectedSet: "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/namespaces/default/simple/" + ID, - name: ID, - namespace: metav1.NamespaceDefault, - } - handler := handleLinker(storage, selfLinker) - server := httptest.NewServer(handler) - defer server.Close() - - client := http.Client{} - request, err := http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - request.Header.Set("Content-Type", "application/merge-patch+json; charset=UTF-8") - _, err = client.Do(request) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - request, err = http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID+"?force=true", bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - request.Header.Set("Content-Type", "application/merge-patch+json; charset=UTF-8") - response, err := client.Do(request) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if response.StatusCode != http.StatusUnprocessableEntity { - t.Errorf("Unexpected response %#v", response) - } - - request, err = http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID+"?force=false", bytes.NewReader([]byte(`{"labels":{"foo":"bar"}}`))) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - request.Header.Set("Content-Type", "application/merge-patch+json; charset=UTF-8") - response, err = client.Do(request) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if response.StatusCode != http.StatusUnprocessableEntity { - t.Errorf("Unexpected response %#v", response) - } -} - func TestPatchRequiresMatchingName(t *testing.T) { storage := map[string]rest.Storage{} ID := "id" @@ -152,9 +88,6 @@ func TestPatchRequiresMatchingName(t *testing.T) { client := http.Client{} request, err := http.NewRequest("PATCH", server.URL+"/"+prefix+"/"+testGroupVersion.Group+"/"+testGroupVersion.Version+"/namespaces/default/simple/"+ID, bytes.NewReader([]byte(`{"metadata":{"name":"idbar"}}`))) - if err != nil { - t.Errorf("unexpected error: %v", err) - } request.Header.Set("Content-Type", "application/merge-patch+json") response, err := client.Do(request) if err != nil { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS old mode 100644 new mode 100755 index 4da107c8c38..9d268c4d148 --- a/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/endpoints/request/OWNERS @@ -1,4 +1,2 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - sttts diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/request/context_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/request/context_test.go index d606c63c884..72b3124b44e 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/request/context_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/request/context_test.go @@ -35,7 +35,7 @@ func TestNamespaceContext(t *testing.T) { } ctx = NewContext() - _, ok = NamespaceFrom(ctx) + result, ok = NamespaceFrom(ctx) if ok { t.Fatalf("Should not be ok because there is no namespace on the context") } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go b/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go index 8eb1a8500c4..cc8ae39fa2c 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/request/requestinfo.go @@ -24,7 +24,6 @@ import ( "k8s.io/apimachinery/pkg/api/validation/path" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" @@ -209,7 +208,7 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er // if there's no name on the request and we thought it was a get before, then the actual verb is a list or a watch if len(requestInfo.Name) == 0 && requestInfo.Verb == "get" { opts := metainternalversion.ListOptions{} - if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), metav1.SchemeGroupVersion, &opts); err != nil { + if err := metainternalversion.ParameterCodec.DecodeParameters(req.URL.Query(), metav1.SchemeGroupVersion, &opts); err != nil { // An error in parsing request will result in default to "list" and not setting "name" field. klog.Errorf("Couldn't parse request %#v: %v", req.URL.Query(), err) // Reset opts to not rely on partial results from parsing. diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/testing/OWNERS b/vendor/k8s.io/apiserver/pkg/endpoints/testing/OWNERS old mode 100644 new mode 100755 index 90be719cc2b..8ee0deffdab --- a/vendor/k8s.io/apiserver/pkg/endpoints/testing/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/endpoints/testing/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - smarterclayton - wojtek-t diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/testing/conversion.go b/vendor/k8s.io/apiserver/pkg/endpoints/testing/conversion.go deleted file mode 100644 index 446264439c5..00000000000 --- a/vendor/k8s.io/apiserver/pkg/endpoints/testing/conversion.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2020 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 testing - -import ( - "net/url" - - "k8s.io/apimachinery/pkg/conversion" - "k8s.io/apimachinery/pkg/runtime" -) - -func convertUrlValuesToSimpleGetOptions(in *url.Values, out *SimpleGetOptions, s conversion.Scope) error { - // Skip TypeMeta field. - - if values, ok := map[string][]string(*in)["param1"]; ok && len(values) > 0 { - if err := runtime.Convert_Slice_string_To_string(&values, &out.Param1, s); err != nil { - return err - } - } else { - out.Param1 = "" - } - if values, ok := map[string][]string(*in)["param2"]; ok && len(values) > 0 { - if err := runtime.Convert_Slice_string_To_string(&values, &out.Param2, s); err != nil { - return err - } - } else { - out.Param2 = "" - } - if values, ok := map[string][]string(*in)["atAPath"]; ok && len(values) > 0 { - if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil { - return err - } - } else { - out.Path = "" - } - return nil -} - -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddConversionFunc((*url.Values)(nil), (*SimpleGetOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { - return convertUrlValuesToSimpleGetOptions(a.(*url.Values), b.(*SimpleGetOptions), scope) - }); err != nil { - return err - } - return nil -} diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/testing/doc.go b/vendor/k8s.io/apiserver/pkg/endpoints/testing/doc.go index 2e801ab5f5f..0ea50660981 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/testing/doc.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/testing/doc.go @@ -16,4 +16,4 @@ limitations under the License. // +k8s:deepcopy-gen=package -package testing // import "k8s.io/apiserver/pkg/endpoints/testing" +package testing diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/testing/zz_generated.deepcopy.go b/vendor/k8s.io/apiserver/pkg/endpoints/testing/zz_generated.deepcopy.go index 9a8a80ba196..ff3e3951415 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/testing/zz_generated.deepcopy.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/testing/zz_generated.deepcopy.go @@ -86,7 +86,7 @@ func (in *SimpleGetOptions) DeepCopyObject() runtime.Object { func (in *SimpleList) DeepCopyInto(out *SimpleList) { *out = *in out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) + out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]Simple, len(*in)) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/watch_test.go b/vendor/k8s.io/apiserver/pkg/endpoints/watch_test.go index e588bfb0560..81d141fa753 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/watch_test.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/watch_test.go @@ -17,7 +17,6 @@ limitations under the License. package endpoints import ( - "context" "encoding/json" "fmt" "io" @@ -35,6 +34,7 @@ import ( apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -44,7 +44,6 @@ import ( "k8s.io/apimachinery/pkg/watch" example "k8s.io/apiserver/pkg/apis/example" "k8s.io/apiserver/pkg/endpoints/handlers" - "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" apitesting "k8s.io/apiserver/pkg/endpoints/testing" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/client-go/dynamic" @@ -214,48 +213,6 @@ func TestWatchWebsocketClientClose(t *testing.T) { } } -func TestWatchClientClose(t *testing.T) { - simpleStorage := &SimpleRESTStorage{} - _ = rest.Watcher(simpleStorage) // Give compile error if this doesn't work. - handler := handle(map[string]rest.Storage{"simples": simpleStorage}) - server := httptest.NewServer(handler) - defer server.Close() - - dest, _ := url.Parse(server.URL) - dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simples" - dest.RawQuery = "watch=1" - - request, err := http.NewRequest("GET", dest.String(), nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - request.Header.Add("Accept", "application/json") - - response, err := http.DefaultClient.Do(request) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if response.StatusCode != http.StatusOK { - b, _ := ioutil.ReadAll(response.Body) - t.Fatalf("Unexpected response: %#v\n%s", response, string(b)) - } - - // Close response to cause a cancel on the server - if err := response.Body.Close(); err != nil { - t.Fatalf("Unexpected close client err: %v", err) - } - - select { - case data, ok := <-simpleStorage.fakeWatch.ResultChan(): - if ok { - t.Errorf("expected a closed result channel, but got watch result %#v", data) - } - case <-time.After(5 * time.Second): - t.Errorf("watcher did not close when client closed") - } -} - func TestWatchRead(t *testing.T) { simpleStorage := &SimpleRESTStorage{} _ = rest.Watcher(simpleStorage) // Give compile error if this doesn't work. @@ -609,21 +566,6 @@ func (t *fakeTimeoutFactory) TimeoutCh() (<-chan time.Time, func() bool) { } } -// serveWatch will serve a watch response according to the watcher and watchServer. -// Before watchServer.ServeHTTP, an error may occur like k8s.io/apiserver/pkg/endpoints/handlers/watch.go#serveWatch does. -func serveWatch(watcher watch.Interface, watchServer *handlers.WatchServer, preServeErr error) http.HandlerFunc { - return func(w http.ResponseWriter, req *http.Request) { - defer watcher.Stop() - - if preServeErr != nil { - responsewriters.ErrorNegotiated(preServeErr, watchServer.Scope.Serializer, watchServer.Scope.Kind.GroupVersion(), w, req) - return - } - - watchServer.ServeHTTP(w, req) - } -} - func TestWatchHTTPErrors(t *testing.T) { watcher := watch.NewFake() timeoutCh := make(chan time.Time) @@ -637,7 +579,6 @@ func TestWatchHTTPErrors(t *testing.T) { // Setup a new watchserver watchServer := &handlers.WatchServer{ - Scope: &handlers.RequestScope{}, Watching: watcher, MediaType: "testcase/json", @@ -645,11 +586,13 @@ func TestWatchHTTPErrors(t *testing.T) { Encoder: newCodec, EmbeddedEncoder: newCodec, - Fixup: func(obj runtime.Object) runtime.Object { return obj }, + Fixup: func(obj runtime.Object) {}, TimeoutFactory: &fakeTimeoutFactory{timeoutCh, done}, } - s := httptest.NewServer(serveWatch(watcher, watchServer, nil)) + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + watchServer.ServeHTTP(w, req) + })) defer s.Close() // Setup a client @@ -660,9 +603,6 @@ func TestWatchHTTPErrors(t *testing.T) { req, _ := http.NewRequest("GET", dest.String(), nil) client := http.Client{} resp, err := client.Do(req) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } errStatus := errors.NewInternalError(fmt.Errorf("we got an error")).Status() watcher.Error(&errStatus) watcher.Stop() @@ -686,7 +626,7 @@ func TestWatchHTTPErrors(t *testing.T) { } } -func TestWatchHTTPErrorsBeforeServe(t *testing.T) { +func TestWatchHTTPDynamicClientErrors(t *testing.T) { watcher := watch.NewFake() timeoutCh := make(chan time.Time) done := make(chan struct{}) @@ -699,10 +639,6 @@ func TestWatchHTTPErrorsBeforeServe(t *testing.T) { // Setup a new watchserver watchServer := &handlers.WatchServer{ - Scope: &handlers.RequestScope{ - Serializer: runtime.NewSimpleNegotiatedSerializer(info), - Kind: testGroupVersion.WithKind("test"), - }, Watching: watcher, MediaType: "testcase/json", @@ -710,85 +646,46 @@ func TestWatchHTTPErrorsBeforeServe(t *testing.T) { Encoder: newCodec, EmbeddedEncoder: newCodec, - Fixup: func(obj runtime.Object) runtime.Object { return obj }, + Fixup: func(obj runtime.Object) {}, TimeoutFactory: &fakeTimeoutFactory{timeoutCh, done}, } - errStatus := errors.NewInternalError(fmt.Errorf("we got an error")) - - s := httptest.NewServer(serveWatch(watcher, watchServer, errStatus)) + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + watchServer.ServeHTTP(w, req) + })) defer s.Close() - // Setup a client - dest, _ := url.Parse(s.URL) - dest.Path = "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/simple" - dest.RawQuery = "watch=true" - - req, _ := http.NewRequest("GET", dest.String(), nil) - client := http.Client{} - resp, err := client.Do(req) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + client := dynamic.NewForConfigOrDie(&restclient.Config{ + Host: s.URL, + APIPath: "/" + prefix, + }).Resource(newGroupVersion.WithResource("simple")) - // We had already got an error before watch serve started - decoder := json.NewDecoder(resp.Body) - var status *metav1.Status - err = decoder.Decode(&status) + w, err := client.Watch(metav1.ListOptions{}) if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if status.Kind != "Status" || status.APIVersion != "v1" || status.Code != 500 || status.Status != "Failure" || !strings.Contains(status.Message, "we got an error") { - t.Fatalf("error: %#v", status) - } - - // check for leaks - if !watcher.IsStopped() { - t.Errorf("Leaked watcher goruntine after request done") + t.Fatal(err) } -} -func TestWatchHTTPDynamicClientErrors(t *testing.T) { - watcher := watch.NewFake() - timeoutCh := make(chan time.Time) - done := make(chan struct{}) + errStatus := errors.NewInternalError(fmt.Errorf("we got an error")).Status() + watcher.Error(&errStatus) + watcher.Stop() - info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) - if !ok || info.StreamSerializer == nil { - t.Fatal(info) + got := <-w.ResultChan() + if got.Type != watch.Error { + t.Fatalf("unexpected watch type: %#v", got) } - serializer := info.StreamSerializer - - // Setup a new watchserver - watchServer := &handlers.WatchServer{ - Scope: &handlers.RequestScope{}, - Watching: watcher, - - MediaType: "testcase/json", - Framer: serializer.Framer, - Encoder: newCodec, - EmbeddedEncoder: newCodec, - - Fixup: func(obj runtime.Object) runtime.Object { return obj }, - TimeoutFactory: &fakeTimeoutFactory{timeoutCh, done}, + obj, ok := got.Object.(*unstructured.Unstructured) + if !ok { + t.Fatalf("not the correct object type: %#v", got) } - s := httptest.NewServer(serveWatch(watcher, watchServer, nil)) - defer s.Close() - defer s.CloseClientConnections() - - client := dynamic.NewForConfigOrDie(&restclient.Config{ - Host: s.URL, - APIPath: "/" + prefix, - }).Resource(newGroupVersion.WithResource("simple")) - - _, err := client.Watch(context.TODO(), metav1.ListOptions{}) - if err == nil { + status := &metav1.Status{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), status); err != nil { t.Fatal(err) } - if err.Error() != "no stream serializers registered for testcase/json" { - t.Fatalf("unexpected error: %v", err) + if status.Kind != "Status" || status.APIVersion != "v1" || status.Code != 500 || status.Status != "Failure" || !strings.Contains(status.Message, "we got an error") { + t.Fatalf("error: %#v", status) } + t.Logf("status: %#v", status) } func TestWatchHTTPTimeout(t *testing.T) { @@ -804,7 +701,6 @@ func TestWatchHTTPTimeout(t *testing.T) { // Setup a new watchserver watchServer := &handlers.WatchServer{ - Scope: &handlers.RequestScope{}, Watching: watcher, MediaType: "testcase/json", @@ -812,11 +708,13 @@ func TestWatchHTTPTimeout(t *testing.T) { Encoder: newCodec, EmbeddedEncoder: newCodec, - Fixup: func(obj runtime.Object) runtime.Object { return obj }, + Fixup: func(obj runtime.Object) {}, TimeoutFactory: &fakeTimeoutFactory{timeoutCh, done}, } - s := httptest.NewServer(serveWatch(watcher, watchServer, nil)) + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + watchServer.ServeHTTP(w, req) + })) defer s.Close() // Setup a client @@ -827,9 +725,6 @@ func TestWatchHTTPTimeout(t *testing.T) { req, _ := http.NewRequest("GET", dest.String(), nil) client := http.Client{} resp, err := client.Do(req) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } watcher.Add(&apitesting.Simple{TypeMeta: metav1.TypeMeta{APIVersion: newGroupVersion.String()}}) // Make sure we can actually watch an endpoint @@ -844,7 +739,7 @@ func TestWatchHTTPTimeout(t *testing.T) { close(timeoutCh) select { case <-done: - if !watcher.IsStopped() { + if !watcher.Stopped { t.Errorf("Leaked watch on timeout") } case <-time.After(wait.ForeverTestTimeout): @@ -862,30 +757,6 @@ func TestWatchHTTPTimeout(t *testing.T) { func BenchmarkWatchHTTP(b *testing.B) { items := benchmarkItems(b) - // use ASCII names to capture the cost of handling ASCII only self-links - for i := range items { - item := &items[i] - item.Namespace = fmt.Sprintf("namespace-%d", i) - item.Name = fmt.Sprintf("reasonable-name-%d", i) - } - - runWatchHTTPBenchmark(b, items) -} - -func BenchmarkWatchHTTP_UTF8(b *testing.B) { - items := benchmarkItems(b) - - // use UTF names to capture the cost of handling UTF-8 escaping in self-links - for i := range items { - item := &items[i] - item.Namespace = fmt.Sprintf("躀痢疈蜧í柢-%d", i) - item.Name = fmt.Sprintf("翏Ŏ熡韐-%d", i) - } - - runWatchHTTPBenchmark(b, items) -} - -func runWatchHTTPBenchmark(b *testing.B, items []example.Pod) { simpleStorage := &SimpleRESTStorage{} handler := handle(map[string]rest.Storage{"simples": simpleStorage}) server := httptest.NewServer(handler) diff --git a/vendor/k8s.io/apiserver/pkg/features/OWNERS b/vendor/k8s.io/apiserver/pkg/features/OWNERS index 05b08249aed..fe7b0144e0c 100644 --- a/vendor/k8s.io/apiserver/pkg/features/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/features/OWNERS @@ -1,4 +1,2 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - feature-approvers diff --git a/vendor/k8s.io/apiserver/pkg/features/kube_features.go b/vendor/k8s.io/apiserver/pkg/features/kube_features.go index f0b5308e83a..92418256814 100644 --- a/vendor/k8s.io/apiserver/pkg/features/kube_features.go +++ b/vendor/k8s.io/apiserver/pkg/features/kube_features.go @@ -17,10 +17,7 @@ limitations under the License. package features import ( - "k8s.io/apimachinery/pkg/util/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/component-base/featuregate" ) const ( @@ -33,21 +30,17 @@ const ( // owner: @tallclair // alpha: v1.5 // beta: v1.6 - // deprecated: v1.18 // // StreamingProxyRedirects controls whether the apiserver should intercept (and follow) // redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward). - // - // This feature is deprecated, and will be removed in v1.22. - StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects" + StreamingProxyRedirects utilfeature.Feature = "StreamingProxyRedirects" // owner: @tallclair - // alpha: v1.12 - // beta: v1.14 + // alpha: v1.10 // // ValidateProxyRedirects controls whether the apiserver should validate that redirects are only // followed to the same host. Only used if StreamingProxyRedirects is enabled. - ValidateProxyRedirects featuregate.Feature = "ValidateProxyRedirects" + ValidateProxyRedirects utilfeature.Feature = "ValidateProxyRedirects" // owner: @tallclair // alpha: v1.7 @@ -57,20 +50,27 @@ const ( // AdvancedAuditing enables a much more general API auditing pipeline, which includes support for // pluggable output backends and an audit policy specifying how different requests should be // audited. - AdvancedAuditing featuregate.Feature = "AdvancedAuditing" + AdvancedAuditing utilfeature.Feature = "AdvancedAuditing" // owner: @pbarker // alpha: v1.13 // // DynamicAuditing enables configuration of audit policy and webhook backends through an // AuditSink API object. - DynamicAuditing featuregate.Feature = "DynamicAuditing" + DynamicAuditing utilfeature.Feature = "DynamicAuditing" // owner: @ilackams // alpha: v1.7 // // Enables compression of REST responses (GET and LIST only) - APIResponseCompression featuregate.Feature = "APIResponseCompression" + APIResponseCompression utilfeature.Feature = "APIResponseCompression" + + // owner: @smarterclayton + // alpha: v1.7 + // + // Allow asynchronous coordination of object creation. + // Auto-enabled by the Initializers admission plugin. + Initializers utilfeature.Feature = "Initializers" // owner: @smarterclayton // alpha: v1.8 @@ -78,7 +78,7 @@ const ( // // Allow API clients to retrieve resource lists in chunks rather than // all at once. - APIListChunking featuregate.Feature = "APIListChunking" + APIListChunking utilfeature.Feature = "APIListChunking" // owner: @apelisse // alpha: v1.12 @@ -87,92 +87,23 @@ const ( // Allow requests to be processed but not stored, so that // validation, merging, mutation can be tested without // committing. - DryRun featuregate.Feature = "DryRun" - - // owner: @caesarxuchao - // alpha: v1.15 - // - // Allow apiservers to show a count of remaining items in the response - // to a chunking list request. - RemainingItemCount featuregate.Feature = "RemainingItemCount" - - // owner: @apelisse, @lavalamp - // alpha: v1.14 - // beta: v1.16 - // - // Server-side apply. Merging happens on the server. - ServerSideApply featuregate.Feature = "ServerSideApply" - - // owner: @caesarxuchao - // alpha: v1.14 - // beta: v1.15 - // - // Allow apiservers to expose the storage version hash in the discovery - // document. - StorageVersionHash featuregate.Feature = "StorageVersionHash" - - // owner: @ksubrmnn - // alpha: v1.14 - // - // Allows kube-proxy to run in Overlay mode for Windows - WinOverlay featuregate.Feature = "WinOverlay" - - // owner: @ksubrmnn - // alpha: v1.14 - // - // Allows kube-proxy to create DSR loadbalancers for Windows - WinDSR featuregate.Feature = "WinDSR" - - // owner: @wojtek-t - // alpha: v1.15 - // beta: v1.16 - // GA: v1.17 - // - // Enables support for watch bookmark events. - WatchBookmark featuregate.Feature = "WatchBookmark" - - // owner: @MikeSpreitzer @yue9944882 - // alpha: v1.15 - // - // - // Enables managing request concurrency with prioritization and fairness at each server - APIPriorityAndFairness featuregate.Feature = "APIPriorityAndFairness" - - // owner: @wojtek-t - // alpha: v1.16 - // - // Deprecates and removes SelfLink from ObjectMeta and ListMeta. - RemoveSelfLink featuregate.Feature = "RemoveSelfLink" - - // owner: @shaloulcy - // alpha: v1.18 - // - // Allows label and field based indexes in apiserver watch cache to accelerate list operations. - SelectorIndex featuregate.Feature = "SelectorIndex" + DryRun utilfeature.Feature = "DryRun" ) func init() { - runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates)) + utilfeature.DefaultFeatureGate.Add(defaultKubernetesFeatureGates) } // defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys. // To add a new feature, define a key for it above and add it here. The features will be // available throughout Kubernetes binaries. -var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ - StreamingProxyRedirects: {Default: true, PreRelease: featuregate.Deprecated}, - ValidateProxyRedirects: {Default: true, PreRelease: featuregate.Beta}, - AdvancedAuditing: {Default: true, PreRelease: featuregate.GA}, - DynamicAuditing: {Default: false, PreRelease: featuregate.Alpha}, - APIResponseCompression: {Default: true, PreRelease: featuregate.Beta}, - APIListChunking: {Default: true, PreRelease: featuregate.Beta}, - DryRun: {Default: true, PreRelease: featuregate.Beta}, - RemainingItemCount: {Default: true, PreRelease: featuregate.Beta}, - ServerSideApply: {Default: true, PreRelease: featuregate.Beta}, - StorageVersionHash: {Default: true, PreRelease: featuregate.Beta}, - WinOverlay: {Default: false, PreRelease: featuregate.Alpha}, - WinDSR: {Default: false, PreRelease: featuregate.Alpha}, - WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, - APIPriorityAndFairness: {Default: false, PreRelease: featuregate.Alpha}, - RemoveSelfLink: {Default: false, PreRelease: featuregate.Alpha}, - SelectorIndex: {Default: false, PreRelease: featuregate.Alpha}, +var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureSpec{ + StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta}, + ValidateProxyRedirects: {Default: false, PreRelease: utilfeature.Alpha}, + AdvancedAuditing: {Default: true, PreRelease: utilfeature.GA}, + DynamicAuditing: {Default: false, PreRelease: utilfeature.Alpha}, + APIResponseCompression: {Default: false, PreRelease: utilfeature.Alpha}, + Initializers: {Default: false, PreRelease: utilfeature.Alpha}, + APIListChunking: {Default: true, PreRelease: utilfeature.Beta}, + DryRun: {Default: true, PreRelease: utilfeature.Beta}, } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS b/vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS old mode 100644 new mode 100755 index 59bdd352d7a..75e139342b7 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - thockin - lavalamp @@ -17,14 +15,20 @@ reviewers: - saad-ali - janetkuo - pwittrock +- roberthbailey - ncdc - eparis +- jlowdermilk - piosz - dims - hongchaodeng - krousey +- markturansky +- fgrzadkowski - xiang90 - resouer - mqliang +- feihujiang - sdminonne +- goltermann - enj diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/options.go b/vendor/k8s.io/apiserver/pkg/registry/generic/options.go index 577192b626e..af651371f09 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/options.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/options.go @@ -22,7 +22,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/storagebackend" - "k8s.io/client-go/tools/cache" ) // RESTOptions is set of configuration options to generic registries. @@ -48,7 +47,6 @@ type RESTOptionsGetter interface { // StoreOptions is set of configuration options used to complete generic registries. type StoreOptions struct { RESTOptions RESTOptionsGetter - TriggerFunc storage.IndexerFuncs + TriggerFunc storage.TriggerPublisherFunc AttrFunc storage.AttrFunc - Indexers *cache.Indexers } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go index 005a376d404..f589dd1ec48 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go @@ -45,17 +45,11 @@ func newDecoratedWatcher(w watch.Interface, decorator ObjectFunc) *decoratedWatc func (d *decoratedWatcher) run(ctx context.Context) { var recv, send watch.Event - var ok bool for { select { - case recv, ok = <-d.w.ResultChan(): - // The underlying channel may be closed after timeout. - if !ok { - d.cancel() - return - } + case recv = <-d.w.ResultChan(): switch recv.Type { - case watch.Added, watch.Modified, watch.Deleted, watch.Bookmark: + case watch.Added, watch.Modified, watch.Deleted: err := d.decorator(recv.Object) if err != nil { send = makeStatusErrorEvent(err) diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go index c32de6f8ff9..08046fa22cc 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go @@ -38,22 +38,20 @@ func (s *DryRunnableStorage) Create(ctx context.Context, key string, obj, out ru if err := s.Storage.Get(ctx, key, "", out, false); err == nil { return storage.NewKeyExistsError(key, 0) } - return s.copyInto(obj, out) + s.copyInto(obj, out) + return nil } return s.Storage.Create(ctx, key, obj, out, ttl) } -func (s *DryRunnableStorage) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions, deleteValidation storage.ValidateObjectFunc, dryRun bool) error { +func (s *DryRunnableStorage) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions, dryRun bool) error { if dryRun { if err := s.Storage.Get(ctx, key, "", out, false); err != nil { return err } - if err := preconditions.Check(key, out); err != nil { - return err - } - return deleteValidation(ctx, out) + return preconditions.Check(key, out) } - return s.Storage.Delete(ctx, key, out, preconditions, deleteValidation) + return s.Storage.Delete(ctx, key, out, preconditions) } func (s *DryRunnableStorage) Watch(ctx context.Context, key string, resourceVersion string, p storage.SelectionPredicate) (watch.Interface, error) { @@ -89,14 +87,12 @@ func (s *DryRunnableStorage) GuaranteedUpdate( return err } rev, err := s.Versioner().ObjectResourceVersion(ptrToType) - if err != nil { - return err - } out, _, err := tryUpdate(ptrToType, storage.ResponseMeta{ResourceVersion: rev}) if err != nil { return err } - return s.copyInto(out, ptrToType) + s.copyInto(out, ptrToType) + return nil } return s.Storage.GuaranteedUpdate(ctx, key, ptrToType, ignoreNotFound, preconditions, tryUpdate, suggestion...) } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun_test.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun_test.go index 7a04ec03b87..8fbf219cfdb 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun_test.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun_test.go @@ -29,14 +29,13 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" examplev1 "k8s.io/apiserver/pkg/apis/example/v1" - "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" - etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" "k8s.io/apiserver/pkg/storage/storagebackend/factory" ) func NewDryRunnableTestStorage(t *testing.T) (DryRunnableStorage, func()) { - server, sc := etcd3testing.NewUnsecuredEtcd3TestClientServer(t) + server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) sc.Codec = apitesting.TestStorageCodec(codecs, examplev1.SchemeGroupVersion) s, destroy, err := factory.Create(*sc) if err != nil { @@ -234,7 +233,7 @@ func TestDryRunDeleteDoesntDelete(t *testing.T) { t.Fatalf("Failed to create new object: %v", err) } - err = s.Delete(context.Background(), "key", out, nil, rest.ValidateAllObjectFunc, true) + err = s.Delete(context.Background(), "key", out, nil, true) if err != nil { t.Fatalf("Failed to dry-run delete the object: %v", err) } @@ -250,7 +249,7 @@ func TestDryRunDeleteMissingObjectFails(t *testing.T) { defer destroy() out := UnstructuredOrDie(`{}`) - err := s.Delete(context.Background(), "key", out, nil, rest.ValidateAllObjectFunc, true) + err := s.Delete(context.Background(), "key", out, nil, true) if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeKeyNotFound { t.Errorf("Expected key to be not found, error: %v", err) } @@ -270,7 +269,7 @@ func TestDryRunDeleteReturnsObject(t *testing.T) { out = UnstructuredOrDie(`{}`) expected := UnstructuredOrDie(`{"kind": "Pod", "metadata": {"resourceVersion": "2"}}`) - err = s.Delete(context.Background(), "key", out, nil, rest.ValidateAllObjectFunc, true) + err = s.Delete(context.Background(), "key", out, nil, true) if err != nil { t.Fatalf("Failed to delete with valid precondition: %v", err) } @@ -293,12 +292,12 @@ func TestDryRunDeletePreconditions(t *testing.T) { wrongID := types.UID("wrong-uid") myID := types.UID("my-uid") - err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &wrongID}, rest.ValidateAllObjectFunc, true) + err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &wrongID}, true) if e, ok := err.(*storage.StorageError); !ok || e.Code != storage.ErrCodeInvalidObj { t.Errorf("Expected invalid object, error: %v", err) } - err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &myID}, rest.ValidateAllObjectFunc, true) + err = s.Delete(context.Background(), "key", out, &storage.Preconditions{UID: &myID}, true) if err != nil { t.Fatalf("Failed to delete with valid precondition: %v", err) } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go index 945a388b886..45524750705 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go @@ -17,65 +17,52 @@ limitations under the License. package registry import ( - "fmt" "sync" "k8s.io/klog" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/storage" cacherstorage "k8s.io/apiserver/pkg/storage/cacher" - "k8s.io/apiserver/pkg/storage/etcd3" + etcdstorage "k8s.io/apiserver/pkg/storage/etcd" "k8s.io/apiserver/pkg/storage/storagebackend" "k8s.io/apiserver/pkg/storage/storagebackend/factory" - "k8s.io/client-go/tools/cache" ) // Creates a cacher based given storageConfig. func StorageWithCacher(capacity int) generic.StorageDecorator { return func( storageConfig *storagebackend.Config, + objectType runtime.Object, resourcePrefix string, keyFunc func(obj runtime.Object) (string, error), - newFunc func() runtime.Object, newListFunc func() runtime.Object, getAttrsFunc storage.AttrFunc, - triggerFuncs storage.IndexerFuncs, - indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error) { + triggerFunc storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) { - s, d, err := generic.NewRawStorage(storageConfig) - if err != nil { - return s, d, err - } - if capacity <= 0 { - klog.V(5).Infof("Storage caching is disabled for %s", objectTypeToString(newFunc())) - return s, d, nil - } - if klog.V(5) { - klog.Infof("Storage caching is enabled for %s with capacity %v", objectTypeToString(newFunc()), capacity) + s, d := generic.NewRawStorage(storageConfig) + if capacity == 0 { + klog.V(5).Infof("Storage caching is disabled for %T", objectType) + return s, d } + klog.V(5).Infof("Storage caching is enabled for %T with capacity %v", objectType, capacity) // TODO: we would change this later to make storage always have cacher and hide low level KV layer inside. // Currently it has two layers of same storage interface -- cacher and low level kv. cacherConfig := cacherstorage.Config{ - CacheCapacity: capacity, - Storage: s, - Versioner: etcd3.APIObjectVersioner{}, - ResourcePrefix: resourcePrefix, - KeyFunc: keyFunc, - NewFunc: newFunc, - NewListFunc: newListFunc, - GetAttrsFunc: getAttrsFunc, - IndexerFuncs: triggerFuncs, - Indexers: indexers, - Codec: storageConfig.Codec, - } - cacher, err := cacherstorage.NewCacherFromConfig(cacherConfig) - if err != nil { - return nil, func() {}, err + CacheCapacity: capacity, + Storage: s, + Versioner: etcdstorage.APIObjectVersioner{}, + Type: objectType, + ResourcePrefix: resourcePrefix, + KeyFunc: keyFunc, + NewListFunc: newListFunc, + GetAttrsFunc: getAttrsFunc, + TriggerPublisherFunc: triggerFunc, + Codec: storageConfig.Codec, } + cacher := cacherstorage.NewCacherFromConfig(cacherConfig) destroyFunc := func() { cacher.Stop() d() @@ -86,19 +73,8 @@ func StorageWithCacher(capacity int) generic.StorageDecorator { // merges as that shuts down storage properly RegisterStorageCleanup(destroyFunc) - return cacher, destroyFunc, nil - } -} - -func objectTypeToString(obj runtime.Object) string { - // special-case unstructured objects that tell us their apiVersion/kind - if u, isUnstructured := obj.(*unstructured.Unstructured); isUnstructured { - if apiVersion, kind := u.GetAPIVersion(), u.GetKind(); len(apiVersion) > 0 && len(kind) > 0 { - return fmt.Sprintf("apiVersion=%s, kind=%s", apiVersion, kind) - } + return cacher, destroyFunc } - // otherwise just return the type - return fmt.Sprintf("%T", obj) } // TODO : Remove all the code below when PR diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go index edd75bc2af6..2dcf99eae52 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go @@ -24,11 +24,12 @@ import ( "sync" "time" - apierrors "k8s.io/apimachinery/pkg/api/errors" + kubeerr "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/validation/path" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -43,9 +44,8 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" storeerr "k8s.io/apiserver/pkg/storage/errors" - "k8s.io/apiserver/pkg/storage/etcd3/metrics" + "k8s.io/apiserver/pkg/storage/etcd/metrics" "k8s.io/apiserver/pkg/util/dryrun" - "k8s.io/client-go/tools/cache" "k8s.io/klog" ) @@ -166,11 +166,6 @@ type Store struct { // ReturnDeletedObject determines whether the Store returns the object // that was deleted. Otherwise, return a generic success status response. ReturnDeletedObject bool - // ShouldDeleteDuringUpdate is an optional function to determine whether - // an update from existing to obj should result in a delete. - // If specified, this is checked in addition to standard finalizer, - // deletionTimestamp, and deletionGracePeriodSeconds checks. - ShouldDeleteDuringUpdate func(ctx context.Context, key string, obj, existing runtime.Object) bool // ExportStrategy implements resource-specific behavior during export, // optional. Exported objects are not decorated. ExportStrategy rest.RESTExportStrategy @@ -182,12 +177,6 @@ type Store struct { // resource. It is wrapped into a "DryRunnableStorage" that will // either pass-through or simply dry-run. Storage DryRunnableStorage - // StorageVersioner outputs the an object will be - // converted to before persisted in etcd, given a list of possible - // kinds of the object. - // If the StorageVersioner is nil, apiserver will leave the - // storageVersionHash as empty in the discovery document. - StorageVersioner runtime.GroupVersioner // Called to cleanup clients used by the underlying Storage; optional. DestroyFunc func() } @@ -221,13 +210,13 @@ func NamespaceKeyFunc(ctx context.Context, prefix string, name string) (string, key := NamespaceKeyRootFunc(ctx, prefix) ns, ok := genericapirequest.NamespaceFrom(ctx) if !ok || len(ns) == 0 { - return "", apierrors.NewBadRequest("Namespace parameter required.") + return "", kubeerr.NewBadRequest("Namespace parameter required.") } if len(name) == 0 { - return "", apierrors.NewBadRequest("Name parameter required.") + return "", kubeerr.NewBadRequest("Name parameter required.") } if msgs := path.IsValidPathSegmentName(name); len(msgs) != 0 { - return "", apierrors.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) + return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) } key = key + "/" + name return key, nil @@ -237,10 +226,10 @@ func NamespaceKeyFunc(ctx context.Context, prefix string, name string) (string, // to a resource relative to the given prefix without a namespace. func NoNamespaceKeyFunc(ctx context.Context, prefix string, name string) (string, error) { if len(name) == 0 { - return "", apierrors.NewBadRequest("Name parameter required.") + return "", kubeerr.NewBadRequest("Name parameter required.") } if msgs := path.IsValidPathSegmentName(name); len(msgs) != 0 { - return "", apierrors.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) + return "", kubeerr.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";"))) } key := prefix + "/" + name return key, nil @@ -318,6 +307,7 @@ func (e *Store) ListPredicate(ctx context.Context, p storage.SelectionPredicate, // By default we should serve the request from etcd. options = &metainternalversion.ListOptions{ResourceVersion: ""} } + p.IncludeUninitialized = options.IncludeUninitialized p.Limit = options.Limit p.Continue = options.Continue list := e.NewListFunc() @@ -342,7 +332,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if createValidation != nil { - if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { + if err := createValidation(obj.DeepCopyObject()); err != nil { return nil, err } } @@ -364,7 +354,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation if err := e.Storage.Create(ctx, key, obj, out, ttl, dryrun.IsDryRun(options.DryRun)); err != nil { err = storeerr.InterpretCreateError(err, qualifiedResource, name) err = rest.CheckGeneratedNameError(e.CreateStrategy, err, obj) - if !apierrors.IsAlreadyExists(err) { + if !kubeerr.IsAlreadyExists(err) { return nil, err } if errGet := e.Storage.Get(ctx, key, "", out, false); errGet != nil { @@ -375,7 +365,7 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation return nil, err } if accessor.GetDeletionTimestamp() != nil { - msg := &err.(*apierrors.StatusError).ErrStatus.Message + msg := &err.(*kubeerr.StatusError).ErrStatus.Message *msg = fmt.Sprintf("object is being deleted: %s", *msg) } return nil, err @@ -390,15 +380,96 @@ func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation return nil, err } } + if !options.IncludeUninitialized { + return e.WaitForInitialized(ctx, out) + } return out, nil } -// ShouldDeleteDuringUpdate is the default function for -// checking if an object should be deleted during an update. -// It checks if the new object has no finalizers, -// the existing object's deletionTimestamp is set, and -// the existing object's deletionGracePeriodSeconds is 0 or nil -func ShouldDeleteDuringUpdate(ctx context.Context, key string, obj, existing runtime.Object) bool { +// WaitForInitialized holds until the object is initialized, or returns an error if the default limit expires. +// This method is exposed publicly for consumers of generic rest tooling. +func (e *Store) WaitForInitialized(ctx context.Context, obj runtime.Object) (runtime.Object, error) { + // return early if we don't have initializers, or if they've completed already + accessor, err := meta.Accessor(obj) + if err != nil { + return obj, nil + } + initializers := accessor.GetInitializers() + if initializers == nil { + return obj, nil + } + if result := initializers.Result; result != nil { + return nil, kubeerr.FromObject(result) + } + + key, err := e.KeyFunc(ctx, accessor.GetName()) + if err != nil { + return nil, err + } + qualifiedResource := e.qualifiedResourceFromContext(ctx) + w, err := e.Storage.Watch(ctx, key, accessor.GetResourceVersion(), storage.SelectionPredicate{ + Label: labels.Everything(), + Field: fields.Everything(), + + IncludeUninitialized: true, + }) + if err != nil { + return nil, err + } + defer w.Stop() + + latest := obj + ch := w.ResultChan() + for { + select { + case event, ok := <-ch: + if !ok { + msg := fmt.Sprintf("server has timed out waiting for the initialization of %s %s", + qualifiedResource.String(), accessor.GetName()) + return nil, kubeerr.NewTimeoutError(msg, 0) + } + switch event.Type { + case watch.Deleted: + if latest = event.Object; latest != nil { + if accessor, err := meta.Accessor(latest); err == nil { + if initializers := accessor.GetInitializers(); initializers != nil && initializers.Result != nil { + // initialization failed, but we missed the modification event + return nil, kubeerr.FromObject(initializers.Result) + } + } + } + return nil, kubeerr.NewInternalError(fmt.Errorf("object deleted while waiting for creation")) + case watch.Error: + if status, ok := event.Object.(*metav1.Status); ok { + return nil, &kubeerr.StatusError{ErrStatus: *status} + } + return nil, kubeerr.NewInternalError(fmt.Errorf("unexpected object in watch stream, can't complete initialization %T", event.Object)) + case watch.Modified: + latest = event.Object + accessor, err = meta.Accessor(latest) + if err != nil { + return nil, kubeerr.NewInternalError(fmt.Errorf("object no longer has access to metadata %T: %v", latest, err)) + } + initializers := accessor.GetInitializers() + if initializers == nil { + // completed initialization + return latest, nil + } + if result := initializers.Result; result != nil { + // initialization failed + return nil, kubeerr.FromObject(result) + } + } + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +// shouldDeleteDuringUpdate checks if a Update is removing all the object's +// finalizers. If so, it further checks if the object's +// DeletionGracePeriodSeconds is 0. +func (e *Store) shouldDeleteDuringUpdate(ctx context.Context, key string, obj, existing runtime.Object) bool { newMeta, err := meta.Accessor(obj) if err != nil { utilruntime.HandleError(err) @@ -409,16 +480,21 @@ func ShouldDeleteDuringUpdate(ctx context.Context, key string, obj, existing run utilruntime.HandleError(err) return false } - if len(newMeta.GetFinalizers()) > 0 { - // don't delete with finalizers remaining in the new object + return len(newMeta.GetFinalizers()) == 0 && oldMeta.GetDeletionGracePeriodSeconds() != nil && *oldMeta.GetDeletionGracePeriodSeconds() == 0 +} + +// shouldDeleteForFailedInitialization returns true if the provided object is initializing and has +// a failure recorded. +func (e *Store) shouldDeleteForFailedInitialization(ctx context.Context, obj runtime.Object) bool { + m, err := meta.Accessor(obj) + if err != nil { + utilruntime.HandleError(err) return false } - if oldMeta.GetDeletionTimestamp() == nil { - // don't delete if the existing object hasn't had a delete request made - return false + if initializers := m.GetInitializers(); initializers != nil && initializers.Result != nil { + return true } - // delete if the existing object has no grace period or a grace period of 0 - return oldMeta.GetDeletionGracePeriodSeconds() == nil || *oldMeta.GetDeletionGracePeriodSeconds() == 0 + return false } // deleteWithoutFinalizers handles deleting an object ignoring its finalizer list. @@ -426,8 +502,7 @@ func ShouldDeleteDuringUpdate(ctx context.Context, key string, obj, existing run func (e *Store) deleteWithoutFinalizers(ctx context.Context, name, key string, obj runtime.Object, preconditions *storage.Preconditions, dryRun bool) (runtime.Object, bool, error) { out := e.NewFunc() klog.V(6).Infof("going to delete %s from registry, triggered by update", name) - // Using the rest.ValidateAllObjectFunc because the request is an UPDATE request and has already passed the admission for the UPDATE verb. - if err := e.Storage.Delete(ctx, key, out, preconditions, rest.ValidateAllObjectFunc, dryRun); err != nil { + if err := e.Storage.Delete(ctx, key, out, preconditions, dryRun); err != nil { // Deletion is racy, i.e., there could be multiple update // requests to remove all finalizers from the object, so we // ignore the NotFound error. @@ -465,7 +540,6 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj storagePreconditions := &storage.Preconditions{} if preconditions := objInfo.Preconditions(); preconditions != nil { storagePreconditions.UID = preconditions.UID - storagePreconditions.ResourceVersion = preconditions.ResourceVersion } out := e.NewFunc() @@ -494,7 +568,7 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj } if version == 0 { if !e.UpdateStrategy.AllowCreateOnUpdate() && !forceAllowCreate { - return nil, nil, apierrors.NewNotFound(qualifiedResource, name) + return nil, nil, kubeerr.NewNotFound(qualifiedResource, name) } creating = true creatingObj = obj @@ -504,7 +578,7 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if createValidation != nil { - if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { + if err := createValidation(obj.DeepCopyObject()); err != nil { return nil, nil, err } } @@ -534,10 +608,10 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj // leave the Kind field empty. See the discussion in #18526. qualifiedKind := schema.GroupKind{Group: qualifiedResource.Group, Kind: qualifiedResource.Resource} fieldErrList := field.ErrorList{field.Invalid(field.NewPath("metadata").Child("resourceVersion"), resourceVersion, "must be specified for an update")} - return nil, nil, apierrors.NewInvalid(qualifiedKind, name, fieldErrList) + return nil, nil, kubeerr.NewInvalid(qualifiedKind, name, fieldErrList) } if resourceVersion != version { - return nil, nil, apierrors.NewConflict(qualifiedResource, name, fmt.Errorf(OptimisticLockErrorMsg)) + return nil, nil, kubeerr.NewConflict(qualifiedResource, name, fmt.Errorf(OptimisticLockErrorMsg)) } } if err := rest.BeforeUpdate(e.UpdateStrategy, ctx, obj, existing); err != nil { @@ -546,13 +620,11 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj // at this point we have a fully formed object. It is time to call the validators that the apiserver // handling chain wants to enforce. if updateValidation != nil { - if err := updateValidation(ctx, obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil { + if err := updateValidation(obj.DeepCopyObject(), existing.DeepCopyObject()); err != nil { return nil, nil, err } } - // Check the default delete-during-update conditions, and store-specific conditions if provided - if ShouldDeleteDuringUpdate(ctx, key, obj, existing) && - (e.ShouldDeleteDuringUpdate == nil || e.ShouldDeleteDuringUpdate(ctx, key, obj, existing)) { + if e.shouldDeleteDuringUpdate(ctx, key, obj, existing) { deleteObj = obj return nil, nil, errEmptiedFinalizers } @@ -580,6 +652,10 @@ func (e *Store) Update(ctx context.Context, name string, objInfo rest.UpdatedObj return nil, false, err } + if e.shouldDeleteForFailedInitialization(ctx, out) { + return e.deleteWithoutFinalizers(ctx, name, key, out, storagePreconditions, dryrun.IsDryRun(options.DryRun)) + } + if creating { if e.AfterCreate != nil { if err := e.AfterCreate(out); err != nil { @@ -765,25 +841,21 @@ func deletionFinalizersForGarbageCollection(ctx context.Context, e *Store, acces } // markAsDeleting sets the obj's DeletionGracePeriodSeconds to 0, and sets the -// DeletionTimestamp to "now" if there is no existing deletionTimestamp or if the existing -// deletionTimestamp is further in future. Finalizers are watching for such updates and will +// DeletionTimestamp to "now". Finalizers are watching for such updates and will // finalize the object if their IDs are present in the object's Finalizers list. -func markAsDeleting(obj runtime.Object, now time.Time) (err error) { +func markAsDeleting(obj runtime.Object) (err error) { objectMeta, kerr := meta.Accessor(obj) if kerr != nil { return kerr } + now := metav1.NewTime(time.Now()) // This handles Generation bump for resources that don't support graceful // deletion. For resources that support graceful deletion is handle in // pkg/api/rest/delete.go if objectMeta.GetDeletionTimestamp() == nil && objectMeta.GetGeneration() > 0 { objectMeta.SetGeneration(objectMeta.GetGeneration() + 1) } - existingDeletionTimestamp := objectMeta.GetDeletionTimestamp() - if existingDeletionTimestamp == nil || existingDeletionTimestamp.After(now) { - metaNow := metav1.NewTime(now) - objectMeta.SetDeletionTimestamp(&metaNow) - } + objectMeta.SetDeletionTimestamp(&now) var zero int64 = 0 objectMeta.SetDeletionGracePeriodSeconds(&zero) return nil @@ -801,7 +873,7 @@ func markAsDeleting(obj runtime.Object, now time.Time) (err error) { // 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) updateForGracefulDeletionAndFinalizers(ctx context.Context, name, key string, options *metav1.DeleteOptions, preconditions storage.Preconditions, deleteValidation rest.ValidateObjectFunc, in runtime.Object) (err error, ignoreNotFound, deleteImmediately bool, out, lastExisting runtime.Object) { +func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.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) var pendingFinalizers bool out = e.NewFunc() @@ -812,9 +884,6 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name false, /* ignoreNotFound */ &preconditions, storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) { - if err := deleteValidation(ctx, existing); err != nil { - return nil, err - } graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, existing, options) if err != nil { return nil, err @@ -841,7 +910,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name // set the DeleteGracePeriods to 0 if the object has pendingFinalizers but not supporting graceful deletion if pendingFinalizers { klog.V(6).Infof("update the DeletionTimestamp to \"now\" and GracePeriodSeconds to 0 for object %s, because it has pending finalizers", name) - err = markAsDeleting(existing, time.Now()) + err = markAsDeleting(existing) if err != nil { return nil, err } @@ -885,17 +954,16 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx context.Context, name } // Delete removes the item from storage. -func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { +func (e *Store) Delete(ctx context.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { key, err := e.KeyFunc(ctx, name) if err != nil { return nil, false, err } obj := e.NewFunc() qualifiedResource := e.qualifiedResourceFromContext(ctx) - if err = e.Storage.Get(ctx, key, "", obj, false); err != nil { + if err := e.Storage.Get(ctx, key, "", obj, false); err != nil { return nil, false, storeerr.InterpretDeleteError(err, qualifiedResource, name) } - // support older consumers of delete by treating "nil" as delete immediately if options == nil { options = metav1.NewDeleteOptions(0) @@ -903,7 +971,6 @@ func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.V var preconditions storage.Preconditions if options.Preconditions != nil { preconditions.UID = options.Preconditions.UID - preconditions.ResourceVersion = options.Preconditions.ResourceVersion } graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, obj, options) if err != nil { @@ -917,7 +984,7 @@ func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.V // check if obj has pending finalizers accessor, err := meta.Accessor(obj) if err != nil { - return nil, false, apierrors.NewInternalError(err) + return nil, false, kubeerr.NewInternalError(err) } pendingFinalizers := len(accessor.GetFinalizers()) != 0 var ignoreNotFound bool @@ -929,16 +996,7 @@ func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.V shouldUpdateFinalizers, _ := deletionFinalizersForGarbageCollection(ctx, 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, deleteValidation, obj) - // Update the preconditions.ResourceVersion if set since we updated the object. - if err == nil && deleteImmediately && preconditions.ResourceVersion != nil { - accessor, err = meta.Accessor(out) - if err != nil { - return out, false, apierrors.NewInternalError(err) - } - resourceVersion := accessor.GetResourceVersion() - preconditions.ResourceVersion = &resourceVersion - } + 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. @@ -961,7 +1019,7 @@ func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.V // delete immediately, or no graceful deletion supported klog.V(6).Infof("going to delete %s from registry: ", name) out = e.NewFunc() - if err := e.Storage.Delete(ctx, key, out, &preconditions, storage.ValidateObjectFunc(deleteValidation), dryrun.IsDryRun(options.DryRun)); err != nil { + if err := e.Storage.Delete(ctx, key, out, &preconditions, dryrun.IsDryRun(options.DryRun)); err != nil { // Please refer to the place where we set ignoreNotFound for the reason // why we ignore the NotFound error . if storage.IsNotFound(err) && ignoreNotFound && lastExisting != nil { @@ -976,11 +1034,6 @@ func (e *Store) Delete(ctx context.Context, name string, deleteValidation rest.V return out, true, err } -// DeleteReturnsDeletedObject implements the rest.MayReturnFullObjectDeleter interface -func (e *Store) DeleteReturnsDeletedObject() bool { - return e.ReturnDeletedObject -} - // DeleteCollection removes all items returned by List with a given ListOptions from storage. // // DeleteCollection is currently NOT atomic. It can happen that only subset of objects @@ -991,13 +1044,18 @@ func (e *Store) DeleteReturnsDeletedObject() bool { // are removing all objects of a given type) with the current API (it's technically // possibly with storage API, but watch is not delivered correctly then). // It will be possible to fix it with v3 etcd API. -func (e *Store) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { +func (e *Store) DeleteCollection(ctx context.Context, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { if listOptions == nil { listOptions = &metainternalversion.ListOptions{} } else { listOptions = listOptions.DeepCopy() } + // DeleteCollection must remain backwards compatible with old clients that expect it to + // remove all resources, initialized or not, within the type. It is also consistent with + // Delete which does not require IncludeUninitialized + listOptions.IncludeUninitialized = true + listObj, err := e.List(ctx, listOptions) if err != nil { return nil, err @@ -1044,7 +1102,7 @@ func (e *Store) DeleteCollection(ctx context.Context, deleteValidation rest.Vali errs <- err return } - if _, _, err := e.Delete(ctx, accessor.GetName(), deleteValidation, options); err != nil && !apierrors.IsNotFound(err) { + if _, _, err := e.Delete(ctx, accessor.GetName(), options); err != nil && !kubeerr.IsNotFound(err) { klog.V(4).Infof("Delete %s in DeleteCollection failed: %v", accessor.GetName(), err) errs <- err return @@ -1112,7 +1170,7 @@ func (e *Store) Watch(ctx context.Context, options *metainternalversion.ListOpti resourceVersion := "" if options != nil { resourceVersion = options.ResourceVersion - predicate.AllowWatchBookmarks = options.AllowWatchBookmarks + predicate.IncludeUninitialized = options.IncludeUninitialized } return e.WatchPredicate(ctx, predicate, resourceVersion) } @@ -1217,10 +1275,6 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { return fmt.Errorf("store for %s must set both KeyRootFunc and KeyFunc or neither", e.DefaultQualifiedResource.String()) } - if e.TableConvertor == nil { - return fmt.Errorf("store for %s must set TableConvertor; rest.NewDefaultTableConvertor(e.DefaultQualifiedResource) can be used to output just name/creation time", e.DefaultQualifiedResource.String()) - } - var isNamespaced bool switch { case e.CreateStrategy != nil: @@ -1257,11 +1311,6 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { } } - err := validateIndexers(options.Indexers) - if err != nil { - return err - } - opts, err := options.RESTOptions.GetRESTOptions(e.DefaultQualifiedResource) if err != nil { return err @@ -1310,6 +1359,11 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { return e.KeyFunc(genericapirequest.NewContext(), accessor.GetName()) } + triggerFunc := options.TriggerFunc + if triggerFunc == nil { + triggerFunc = storage.NoTriggerPublisher + } + if e.DeleteCollectionWorkers == 0 { e.DeleteCollectionWorkers = opts.DeleteCollectionWorkers } @@ -1328,21 +1382,15 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { if e.Storage.Storage == nil { e.Storage.Codec = opts.StorageConfig.Codec - var err error - e.Storage.Storage, e.DestroyFunc, err = opts.Decorator( + e.Storage.Storage, e.DestroyFunc = opts.Decorator( opts.StorageConfig, + e.NewFunc(), prefix, keyFunc, - e.NewFunc, e.NewListFunc, attrFunc, - options.TriggerFunc, - options.Indexers, + triggerFunc, ) - if err != nil { - return err - } - e.StorageVersioner = opts.StorageConfig.EncodeVersioner if opts.CountMetricPollPeriod > 0 { stopFunc := e.startObservingCount(opts.CountMetricPollPeriod) @@ -1377,26 +1425,9 @@ func (e *Store) startObservingCount(period time.Duration) func() { return func() { close(stopCh) } } -func (e *Store) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { +func (e *Store) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) { if e.TableConvertor != nil { return e.TableConvertor.ConvertToTable(ctx, object, tableOptions) } - return rest.NewDefaultTableConvertor(e.DefaultQualifiedResource).ConvertToTable(ctx, object, tableOptions) -} - -func (e *Store) StorageVersion() runtime.GroupVersioner { - return e.StorageVersioner -} - -// validateIndexers will check the prefix of indexers. -func validateIndexers(indexers *cache.Indexers) error { - if indexers == nil { - return nil - } - for indexName := range *indexers { - if len(indexName) <= 2 || (indexName[:2] != "l:" && indexName[:2] != "f:") { - return fmt.Errorf("index must prefix with \"l:\" or \"f:\"") - } - } - return nil + return rest.NewDefaultTableConvertor(e.qualifiedResourceFromContext(ctx)).ConvertToTable(ctx, object, tableOptions) } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go index 00e6017f0ec..bdc06164d3d 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/registry/store_test.go @@ -42,19 +42,22 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/apis/example" examplev1 "k8s.io/apiserver/pkg/apis/example/v1" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" cacherstorage "k8s.io/apiserver/pkg/storage/cacher" - "k8s.io/apiserver/pkg/storage/etcd3" - etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" + etcdstorage "k8s.io/apiserver/pkg/storage/etcd" + etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" "k8s.io/apiserver/pkg/storage/names" "k8s.io/apiserver/pkg/storage/storagebackend/factory" storagetesting "k8s.io/apiserver/pkg/storage/testing" - "k8s.io/client-go/tools/cache" + utilfeature "k8s.io/apiserver/pkg/util/feature" + utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" ) var scheme = runtime.NewScheme() @@ -124,9 +127,9 @@ func NewTestGenericStoreRegistry(t *testing.T) (factory.DestroyFunc, *Store) { return newTestGenericStoreRegistry(t, scheme, false) } -func getPodAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { +func getPodAttrs(obj runtime.Object) (labels.Set, fields.Set, bool, error) { pod := obj.(*example.Pod) - return labels.Set{"name": pod.ObjectMeta.Name}, nil, nil + return labels.Set{"name": pod.ObjectMeta.Name}, nil, pod.Initializers != nil, nil } // matchPodName returns selection predicate that matches any pod with name in the set. @@ -149,8 +152,8 @@ func matchEverything() storage.SelectionPredicate { return storage.SelectionPredicate{ Label: labels.Everything(), Field: fields.Everything(), - GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, err error) { - return nil, nil, nil + GetAttrs: func(obj runtime.Object) (label labels.Set, field fields.Set, uninitialized bool, err error) { + return nil, nil, false, nil }, } } @@ -250,7 +253,7 @@ func TestStoreListResourceVersion(t *testing.T) { t.Fatal(err) } - versioner := etcd3.APIObjectVersioner{} + versioner := etcdstorage.APIObjectVersioner{} rev, err := versioner.ObjectResourceVersion(obj) if err != nil { t.Fatal(err) @@ -317,13 +320,13 @@ func TestStoreCreate(t *testing.T) { } // create the object with denying admission - _, err := registry.Create(testContext, podA, denyCreateValidation, &metav1.CreateOptions{}) + objA, err := registry.Create(testContext, podA, denyCreateValidation, &metav1.CreateOptions{}) if err == nil { t.Errorf("Expected admission error: %v", err) } // create the object - objA, err := registry.Create(testContext, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + objA, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -358,7 +361,7 @@ func TestStoreCreate(t *testing.T) { // now delete pod with graceful period set delOpts := &metav1.DeleteOptions{GracePeriodSeconds: &gracefulPeriod} - _, _, err = registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, delOpts) + _, _, err = registry.Delete(testContext, podA.Name, delOpts) if err != nil { t.Fatalf("Failed to delete pod gracefully. Unexpected error: %v", err) } @@ -376,6 +379,33 @@ func TestStoreCreate(t *testing.T) { } } +func isPendingInitialization(obj metav1.Object) bool { + return obj.GetInitializers() != nil && obj.GetInitializers().Result == nil && len(obj.GetInitializers().Pending) > 0 +} + +func hasInitializers(obj metav1.Object, expected ...string) bool { + if !isPendingInitialization(obj) { + return false + } + if len(expected) != len(obj.GetInitializers().Pending) { + return false + } + for i, init := range obj.GetInitializers().Pending { + if init.Name != expected[i] { + return false + } + } + return true +} + +func isFailedInitialization(obj metav1.Object) bool { + return obj.GetInitializers() != nil && obj.GetInitializers().Result != nil && obj.GetInitializers().Result.Status == metav1.StatusFailure +} + +func isInitialized(obj metav1.Object) bool { + return obj.GetInitializers() == nil +} + func isQualifiedResource(err error, kind, group string) bool { if err.(errors.APIStatus).Status().Details.Kind != kind || err.(errors.APIStatus).Status().Details.Group != group { return false @@ -383,6 +413,185 @@ func isQualifiedResource(err error, kind, group string) bool { return true } +func TestStoreCreateInitialized(t *testing.T) { + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.Initializers, true)() + + podA := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", Namespace: "test", + Initializers: &metav1.Initializers{ + Pending: []metav1.Initializer{{Name: validInitializerName}}, + }, + }, + Spec: example.PodSpec{NodeName: "machine"}, + } + + ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") + destroyFunc, registry := NewTestGenericStoreRegistry(t) + defer destroyFunc() + + ch := make(chan struct{}) + chObserver := make(chan struct{}) + + // simulate a background initializer that initializes the object + early := make(chan struct{}, 1) + go func() { + defer close(ch) + w, err := registry.Watch(ctx, &metainternalversion.ListOptions{ + IncludeUninitialized: true, + Watch: true, + FieldSelector: fields.OneTermEqualSelector("metadata.name", "foo"), + }) + if err != nil { + t.Fatal(err) + } + defer w.Stop() + event := <-w.ResultChan() + pod := event.Object.(*example.Pod) + if event.Type != watch.Added || !hasInitializers(pod, validInitializerName) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + + select { + case <-early: + t.Fatalf("CreateInitialized should not have returned") + default: + } + + pod.Initializers = nil + updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + if err != nil { + t.Fatal(err) + } + pod = updated.(*example.Pod) + if !isInitialized(pod) { + t.Fatalf("unexpected update: %#v", pod.Initializers) + } + + event = <-w.ResultChan() + if event.Type != watch.Modified || !isInitialized(event.Object.(*example.Pod)) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + }() + + // create a background worker that should only observe the final creation + go func() { + defer close(chObserver) + w, err := registry.Watch(ctx, &metainternalversion.ListOptions{ + IncludeUninitialized: false, + Watch: true, + FieldSelector: fields.OneTermEqualSelector("metadata.name", "foo"), + }) + if err != nil { + t.Fatal(err) + } + defer w.Stop() + + event := <-w.ResultChan() + pod := event.Object.(*example.Pod) + if event.Type != watch.Added || !isInitialized(pod) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + }() + + // create the object + objA, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // signal that we're now waiting, then wait for both observers to see + // the result of the create. + early <- struct{}{} + <-ch + <-chObserver + + // get the object + checkobj, err := registry.Get(ctx, podA.Name, &metav1.GetOptions{}) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // verify objects are equal + if e, a := objA, checkobj; !reflect.DeepEqual(e, a) { + t.Errorf("Expected %#v, got %#v", e, a) + } +} + +func TestStoreCreateInitializedFailed(t *testing.T) { + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.Initializers, true)() + + podA := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", Namespace: "test", + Initializers: &metav1.Initializers{ + Pending: []metav1.Initializer{{Name: validInitializerName}}, + }, + }, + Spec: example.PodSpec{NodeName: "machine"}, + } + + ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") + destroyFunc, registry := NewTestGenericStoreRegistry(t) + defer destroyFunc() + + ch := make(chan struct{}) + go func() { + w, err := registry.Watch(ctx, &metainternalversion.ListOptions{ + IncludeUninitialized: true, + Watch: true, + FieldSelector: fields.OneTermEqualSelector("metadata.name", "foo"), + }) + if err != nil { + t.Fatal(err) + } + event := <-w.ResultChan() + pod := event.Object.(*example.Pod) + if event.Type != watch.Added || !hasInitializers(pod, validInitializerName) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + pod.Initializers.Pending = nil + pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure, Code: 403, Reason: metav1.StatusReasonForbidden, Message: "induced failure"} + updated, _, err := registry.Update(ctx, podA.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + if err != nil { + t.Fatal(err) + } + pod = updated.(*example.Pod) + if !isFailedInitialization(pod) { + t.Fatalf("unexpected update: %#v", pod.Initializers) + } + + event = <-w.ResultChan() + if event.Type != watch.Modified || !isFailedInitialization(event.Object.(*example.Pod)) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + + event = <-w.ResultChan() + if event.Type != watch.Deleted || !isFailedInitialization(event.Object.(*example.Pod)) { + t.Fatalf("unexpected event: %s %#v", event.Type, event.Object) + } + w.Stop() + close(ch) + }() + + // create the object + _, err := registry.Create(ctx, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if !errors.IsForbidden(err) { + t.Fatalf("unexpected error: %#v", err.(errors.APIStatus).Status()) + } + if err.(errors.APIStatus).Status().Message != "induced failure" { + t.Fatalf("unexpected error: %#v", err) + } + + <-ch + + // get the object + _, err = registry.Get(ctx, podA.Name, &metav1.GetOptions{}) + if !errors.IsNotFound(err) { + t.Fatalf("Unexpected error: %v", err) + } +} + func updateAndVerify(t *testing.T, ctx context.Context, registry *Store, pod *example.Pod) bool { obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) if err != nil { @@ -661,7 +870,7 @@ func TestStoreDelete(t *testing.T) { defer destroyFunc() // test failure condition - _, _, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, nil) + _, _, err := registry.Delete(testContext, podA.Name, nil) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } @@ -673,7 +882,7 @@ func TestStoreDelete(t *testing.T) { } // delete object - _, wasDeleted, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, nil) + _, wasDeleted, err := registry.Delete(testContext, podA.Name, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -688,9 +897,9 @@ func TestStoreDelete(t *testing.T) { } } -func TestStoreGracefulDeleteWithResourceVersion(t *testing.T) { +func TestStoreDeleteUninitialized(t *testing.T) { podA := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, + ObjectMeta: metav1.ObjectMeta{Name: "foo", Initializers: &metav1.Initializers{Pending: []metav1.Initializer{{Name: validInitializerName}}}}, Spec: example.PodSpec{NodeName: "machine"}, } @@ -698,39 +907,20 @@ func TestStoreGracefulDeleteWithResourceVersion(t *testing.T) { destroyFunc, registry := NewTestGenericStoreRegistry(t) defer destroyFunc() - defaultDeleteStrategy := testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true} - registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} - // test failure condition - _, _, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, nil) + _, _, err := registry.Delete(testContext, podA.Name, nil) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } // create pod - _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - - // try to get a item which should be deleted - obj, err := registry.Get(testContext, podA.Name, &metav1.GetOptions{}) - if errors.IsNotFound(err) { - t.Errorf("Unexpected error: %v", err) - } - - accessor, err := meta.Accessor(obj) + _, err = registry.Create(testContext, podA, rest.ValidateAllObjectFunc, &metav1.CreateOptions{IncludeUninitialized: true}) if err != nil { t.Errorf("Unexpected error: %v", err) } - resourceVersion := accessor.GetResourceVersion() - - options := metav1.NewDeleteOptions(0) - options.Preconditions = &metav1.Preconditions{ResourceVersion: &resourceVersion} - // delete object - _, wasDeleted, err := registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, options) + _, wasDeleted, err := registry.Delete(testContext, podA.Name, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -807,7 +997,7 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { } // delete the pod with grace period=0, the pod should still exist because it has a finalizer - _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(0)) + _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, metav1.NewDeleteOptions(0)) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -850,6 +1040,45 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) { } } +func TestFailedInitializationStoreUpdate(t *testing.T) { + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.Initializers, true)() + + initialGeneration := int64(1) + podInitializing := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Initializers: &metav1.Initializers{Pending: []metav1.Initializer{{Name: validInitializerName}}}, Generation: initialGeneration}, + Spec: example.PodSpec{NodeName: "machine"}, + } + + 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, view initializing + obj, err := registry.Create(testContext, podInitializing, rest.ValidateAllObjectFunc, &metav1.CreateOptions{IncludeUninitialized: true}) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod := obj.(*example.Pod) + + // update the pod with initialization failure, the pod should be deleted + pod.Initializers.Result = &metav1.Status{Status: metav1.StatusFailure} + result, _, err := registry.Update(testContext, podInitializing.Name, rest.DefaultUpdatedObjectInfo(pod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + _, err = registry.Get(testContext, podInitializing.Name, &metav1.GetOptions{}) + if err == nil || !errors.IsNotFound(err) { + t.Fatalf("Unexpected error: %v", err) + } + pod = result.(*example.Pod) + if pod.Initializers == nil || pod.Initializers.Result == nil || pod.Initializers.Result.Status != metav1.StatusFailure { + t.Fatalf("Pod returned from update was not correct: %#v", pod) + } +} + func TestNonGracefulStoreHandleFinalizers(t *testing.T) { initialGeneration := int64(1) podWithFinalizer := &example.Pod{ @@ -873,7 +1102,7 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) { } // delete object with nil delete options doesn't delete the object - _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, rest.ValidateAllObjectFunc, nil) + _, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1173,7 +1402,7 @@ func TestStoreDeleteWithOrphanDependents(t *testing.T) { if err != nil { t.Fatalf("Unexpected error: %v", err) } - _, _, err = registry.Delete(testContext, tc.pod.Name, rest.ValidateAllObjectFunc, tc.options) + _, _, err = registry.Delete(testContext, tc.pod.Name, tc.options) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1392,10 +1621,7 @@ func TestStoreDeletionPropagation(t *testing.T) { if err != nil { t.Fatalf("Unexpected error: %v", err) } - _, _, err = registry.Delete(testContext, pod.Name, rest.ValidateAllObjectFunc, tc.options) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } + _, _, err = registry.Delete(testContext, pod.Name, tc.options) obj, err := registry.Get(testContext, pod.Name, &metav1.GetOptions{}) if tc.expectedNotFound { if err == nil || !errors.IsNotFound(err) { @@ -1430,6 +1656,14 @@ func TestStoreDeletionPropagation(t *testing.T) { func TestStoreDeleteCollection(t *testing.T) { podA := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} podB := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}} + podC := &example.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "baz", + Initializers: &metav1.Initializers{ + Pending: []metav1.Initializer{{Name: validInitializerName}}, + }, + }, + } testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) @@ -1441,14 +1675,17 @@ func TestStoreDeleteCollection(t *testing.T) { if _, err := registry.Create(testContext, podB, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { t.Errorf("Unexpected error: %v", err) } + if _, err := registry.Create(testContext, podC, rest.ValidateAllObjectFunc, &metav1.CreateOptions{IncludeUninitialized: true}); err != nil { + t.Errorf("Unexpected error: %v", err) + } // Delete all pods. - deleted, err := registry.DeleteCollection(testContext, rest.ValidateAllObjectFunc, nil, &metainternalversion.ListOptions{}) + deleted, err := registry.DeleteCollection(testContext, nil, &metainternalversion.ListOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } deletedPods := deleted.(*example.PodList) - if len(deletedPods.Items) != 2 { + if len(deletedPods.Items) != 3 { t.Errorf("Unexpected number of pods deleted: %d, expected: 3", len(deletedPods.Items)) } @@ -1458,6 +1695,9 @@ func TestStoreDeleteCollection(t *testing.T) { if _, err := registry.Get(testContext, podB.Name, &metav1.GetOptions{}); !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } + if _, err := registry.Get(testContext, podC.Name, &metav1.GetOptions{}); !errors.IsNotFound(err) { + t.Errorf("Unexpected error: %v", err) + } } func TestStoreDeleteCollectionNotFound(t *testing.T) { @@ -1484,7 +1724,7 @@ func TestStoreDeleteCollectionNotFound(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - _, err := registry.DeleteCollection(testContext, rest.ValidateAllObjectFunc, nil, &metainternalversion.ListOptions{}) + _, err := registry.DeleteCollection(testContext, nil, &metainternalversion.ListOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1522,7 +1762,7 @@ func TestStoreDeleteCollectionWithWatch(t *testing.T) { } defer watcher.Stop() - if _, err := registry.DeleteCollection(testContext, rest.ValidateAllObjectFunc, nil, &metainternalversion.ListOptions{}); err != nil { + if _, err := registry.DeleteCollection(testContext, nil, &metainternalversion.ListOptions{}); err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -1598,7 +1838,7 @@ func TestStoreWatch(t *testing.T) { func newTestGenericStoreRegistry(t *testing.T, scheme *runtime.Scheme, hasCacheEnabled bool) (factory.DestroyFunc, *Store) { podPrefix := "/pods" - server, sc := etcd3testing.NewUnsecuredEtcd3TestClientServer(t) + server, sc := etcdtesting.NewUnsecuredEtcd3TestClientServer(t) strategy := &testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true} sc.Codec = apitesting.TestStorageCodec(codecs, examplev1.SchemeGroupVersion) @@ -1614,18 +1854,15 @@ func newTestGenericStoreRegistry(t *testing.T, scheme *runtime.Scheme, hasCacheE config := cacherstorage.Config{ CacheCapacity: 10, Storage: s, - Versioner: etcd3.APIObjectVersioner{}, + Versioner: etcdstorage.APIObjectVersioner{}, + Type: &example.Pod{}, ResourcePrefix: podPrefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NoNamespaceKeyFunc(podPrefix, obj) }, GetAttrsFunc: getPodAttrs, - NewFunc: func() runtime.Object { return &example.Pod{} }, NewListFunc: func() runtime.Object { return &example.PodList{} }, Codec: sc.Codec, } - cacher, err := cacherstorage.NewCacherFromConfig(config) - if err != nil { - t.Fatalf("Couldn't create cacher: %v", err) - } + cacher := cacherstorage.NewCacherFromConfig(config) d := destroyFunc s = cacher destroyFunc = func() { @@ -1655,12 +1892,12 @@ func newTestGenericStoreRegistry(t *testing.T, scheme *runtime.Scheme, hasCacheE return storage.SelectionPredicate{ Label: label, Field: field, - GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, bool, error) { pod, ok := obj.(*example.Pod) if !ok { - return nil, nil, fmt.Errorf("not a pod") + return nil, nil, false, fmt.Errorf("not a pod") } - return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(&pod.ObjectMeta, true), nil + return labels.Set(pod.ObjectMeta.Labels), generic.ObjectMetaFieldsSet(&pod.ObjectMeta, true), pod.Initializers != nil, nil }, } }, @@ -1747,7 +1984,7 @@ func TestQualifiedResource(t *testing.T) { } // delete a non-exist object - _, _, err = registry.Delete(testContext, podA.Name, rest.ValidateAllObjectFunc, nil) + _, _, err = registry.Delete(testContext, podA.Name, nil) if !errors.IsNotFound(err) { t.Fatalf("Unexpected error: %v", err) @@ -1774,11 +2011,11 @@ func TestQualifiedResource(t *testing.T) { } } -func denyCreateValidation(ctx context.Context, obj runtime.Object) error { +func denyCreateValidation(obj runtime.Object) error { return fmt.Errorf("admission denied") } -func denyUpdateValidation(ctx context.Context, obj, old runtime.Object) error { +func denyUpdateValidation(obj, old runtime.Object) error { return fmt.Errorf("admission denied") } @@ -1871,273 +2108,3 @@ func TestDeletionFinalizersForGarbageCollection(t *testing.T) { } } } - -func TestMarkAsDeleting(t *testing.T) { - now := time.Now() - soon := now.Add(time.Second) - past := now.Add(-time.Second) - - newTimePointer := func(t time.Time) *metav1.Time { - metaTime := metav1.NewTime(t) - return &metaTime - } - testcases := []struct { - name string - deletionTimestamp *metav1.Time - expectDeletionTimestamp *metav1.Time - }{ - { - name: "unset", - deletionTimestamp: nil, - expectDeletionTimestamp: newTimePointer(now), - }, - { - name: "set to future", - deletionTimestamp: newTimePointer(soon), - expectDeletionTimestamp: newTimePointer(now), - }, - { - name: "set to past", - deletionTimestamp: newTimePointer(past), - expectDeletionTimestamp: newTimePointer(past), - }, - } - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - rs := &example.ReplicaSet{} - rs.DeletionTimestamp = tc.deletionTimestamp - if err := markAsDeleting(rs, now); err != nil { - t.Error(err) - } - if reflect.DeepEqual(*rs.DeletionTimestamp, tc.expectDeletionTimestamp) { - t.Errorf("expected %v, got %v", tc.expectDeletionTimestamp, *rs.DeletionTimestamp) - } - }) - } -} - -type staleGuaranteedUpdateStorage struct { - storage.Interface - cachedObj runtime.Object -} - -// GuaranteedUpdate overwrites the method with one that always suggests the cachedObj. -func (s *staleGuaranteedUpdateStorage) GuaranteedUpdate( - ctx context.Context, key string, ptrToType runtime.Object, ignoreNotFound bool, - preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, _ ...runtime.Object) error { - return s.Interface.GuaranteedUpdate(ctx, key, ptrToType, ignoreNotFound, preconditions, tryUpdate, s.cachedObj) -} - -func TestDeleteWithCachedObject(t *testing.T) { - podName := "foo" - podWithFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: podName, Finalizers: []string{"foo.com/x"}}, - Spec: example.PodSpec{NodeName: "machine"}, - } - podWithNoFinalizer := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: podName}, - Spec: example.PodSpec{NodeName: "machine"}, - } - ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") - destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, false) - defer destroyFunc() - // cached object does not have any finalizer. - registry.Storage.Storage = &staleGuaranteedUpdateStorage{Interface: registry.Storage.Storage, cachedObj: podWithNoFinalizer} - // created object with pending finalizer. - _, err := registry.Create(ctx, podWithFinalizer, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if err != nil { - t.Fatal(err) - } - // The object shouldn't be deleted, because the persisted object has pending finalizers. - _, _, err = registry.Delete(ctx, podName, rest.ValidateAllObjectFunc, nil) - if err != nil { - t.Fatal(err) - } - // The object should still be there - _, err = registry.Get(ctx, podName, &metav1.GetOptions{}) - if err != nil { - t.Fatal(err) - } -} - -func TestPreconditionalUpdateWithCachedObject(t *testing.T) { - podName := "foo" - pod := &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: podName}, - Spec: example.PodSpec{NodeName: "machine"}, - } - ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") - destroyFunc, registry := newTestGenericStoreRegistry(t, scheme, false) - defer destroyFunc() - - // cached object has old UID - oldPod, err := registry.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if err != nil { - t.Fatal(err) - } - registry.Storage.Storage = &staleGuaranteedUpdateStorage{Interface: registry.Storage.Storage, cachedObj: oldPod} - - // delete and re-create the same object with new UID - _, _, err = registry.Delete(ctx, podName, rest.ValidateAllObjectFunc, nil) - if err != nil { - t.Fatal(err) - } - obj, err := registry.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if err != nil { - t.Fatal(err) - } - newPod, ok := obj.(*example.Pod) - if !ok { - t.Fatalf("unexpected object: %#v", obj) - } - - // update the object should not fail precondition - newPod.Spec.NodeName = "machine2" - res, _, err := registry.Update(ctx, podName, rest.DefaultUpdatedObjectInfo(newPod), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) - if err != nil { - t.Fatal(err) - } - - // the update should have succeeded - r, ok := res.(*example.Pod) - if !ok { - t.Fatalf("unexpected update result: %#v", res) - } - if r.Spec.NodeName != "machine2" { - t.Fatalf("unexpected, update didn't take effect: %#v", r) - } -} - -// TestRetryDeleteValidation checks if the deleteValidation is called again if -// the GuaranteedUpdate in the Delete handler conflicts with a simultaneous -// Update. -func TestRetryDeleteValidation(t *testing.T) { - testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") - destroyFunc, registry := NewTestGenericStoreRegistry(t) - defer destroyFunc() - - tests := []struct { - pod *example.Pod - deleted bool - }{ - { - pod: &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", Finalizers: []string{"pending"}}, - Spec: example.PodSpec{NodeName: "machine"}, - }, - deleted: false, - }, - - { - pod: &example.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "test"}, - Spec: example.PodSpec{NodeName: "machine"}, - }, - deleted: true, - }, - } - - for _, test := range tests { - ready := make(chan struct{}) - updated := make(chan struct{}) - var readyOnce, updatedOnce sync.Once - var called int - deleteValidation := func(ctx context.Context, obj runtime.Object) error { - readyOnce.Do(func() { - close(ready) - }) - // wait for the update completes - <-updated - called++ - return nil - } - - if _, err := registry.Create(testContext, test.pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - transformer := func(ctx context.Context, newObj runtime.Object, oldObj runtime.Object) (transformedNewObj runtime.Object, err error) { - <-ready - pod, ok := newObj.(*example.Pod) - if !ok { - t.Fatalf("unexpected object %v", newObj) - } - pod.Labels = map[string]string{ - "modified": "true", - } - return pod, nil - } - - go func() { - // This update will cause the Delete to retry due to conflict. - _, _, err := registry.Update(testContext, test.pod.Name, rest.DefaultUpdatedObjectInfo(test.pod, transformer), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) - if err != nil { - t.Fatal(err) - } - updatedOnce.Do(func() { - close(updated) - }) - }() - - _, deleted, err := registry.Delete(testContext, test.pod.Name, deleteValidation, &metav1.DeleteOptions{}) - if err != nil { - t.Fatal(err) - } - if a, e := deleted, test.deleted; a != e { - t.Fatalf("expected deleted to be %v, got %v", e, a) - } - if called != 2 { - t.Fatalf("expected deleteValidation to be called twice") - } - } -} - -func emptyIndexFunc(obj interface{}) ([]string, error) { - return []string{}, nil -} - -func TestValidateIndexers(t *testing.T) { - testcases := []struct { - name string - indexers *cache.Indexers - expectedError bool - }{ - { - name: "nil indexers", - indexers: nil, - expectedError: false, - }, - { - name: "normal indexers", - indexers: &cache.Indexers{ - "f:spec.nodeName": emptyIndexFunc, - "l:controller-revision-hash": emptyIndexFunc, - }, - expectedError: false, - }, - { - name: "too short indexers", - indexers: &cache.Indexers{ - "f": emptyIndexFunc, - }, - expectedError: true, - }, - { - name: "invalid indexers", - indexers: &cache.Indexers{ - "spec.nodeName": emptyIndexFunc, - }, - expectedError: true, - }, - } - - for _, tc := range testcases { - err := validateIndexers(tc.indexers) - if tc.expectedError && err == nil { - t.Errorf("%v: expected error, but got nil", tc.name) - } - if !tc.expectedError && err != nil { - t.Errorf("%v: expected no error, but got %v", tc.name, err) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer.go b/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer.go index be911fab2f1..8bd9d9c9f11 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer.go @@ -19,7 +19,6 @@ package rest import ( "context" "errors" - "fmt" "io" "net/http" "net/url" @@ -62,15 +61,11 @@ func (s *LocationStreamer) InputStream(ctx context.Context, apiVersion, acceptHe if transport == nil { transport = http.DefaultTransport } - client := &http.Client{ Transport: transport, CheckRedirect: s.RedirectChecker, } req, err := http.NewRequest("GET", s.Location.String(), nil) - if err != nil { - return nil, false, "", fmt.Errorf("failed to construct request for %s, got %v", s.Location.String(), err) - } // Pass the parent context down to the request to ensure that the resources // will be release properly. req = req.WithContext(ctx) diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer_test.go b/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer_test.go index fbf83632d3e..4d9cd154339 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer_test.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/rest/streamer_test.go @@ -54,7 +54,7 @@ func TestInputStreamReader(t *testing.T) { return } defer readCloser.Close() - result, _ := ioutil.ReadAll(readCloser) + result, err := ioutil.ReadAll(readCloser) if string(result) != resultString { t.Errorf("Stream content does not match. Got: %s. Expected: %s.", string(result), resultString) } @@ -118,7 +118,7 @@ func TestInputStreamTransport(t *testing.T) { return } defer readCloser.Close() - result, _ := ioutil.ReadAll(readCloser) + result, err := ioutil.ReadAll(readCloser) if string(result) != message { t.Errorf("Stream content does not match. Got: %s. Expected: %s.", string(result), message) } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go b/vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go index 223b630fc53..858ad922af4 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go @@ -21,38 +21,40 @@ import ( "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/storagebackend" "k8s.io/apiserver/pkg/storage/storagebackend/factory" - "k8s.io/client-go/tools/cache" + "k8s.io/klog" ) // StorageDecorator is a function signature for producing a storage.Interface // and an associated DestroyFunc from given parameters. type StorageDecorator func( config *storagebackend.Config, + objectType runtime.Object, resourcePrefix string, keyFunc func(obj runtime.Object) (string, error), - newFunc func() runtime.Object, newListFunc func() runtime.Object, getAttrsFunc storage.AttrFunc, - trigger storage.IndexerFuncs, - indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error) + trigger storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) // UndecoratedStorage returns the given a new storage from the given config // without any decoration. func UndecoratedStorage( config *storagebackend.Config, + objectType runtime.Object, resourcePrefix string, keyFunc func(obj runtime.Object) (string, error), - newFunc func() runtime.Object, newListFunc func() runtime.Object, getAttrsFunc storage.AttrFunc, - trigger storage.IndexerFuncs, - indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error) { + trigger storage.TriggerPublisherFunc) (storage.Interface, factory.DestroyFunc) { return NewRawStorage(config) } // NewRawStorage creates the low level kv storage. This is a work-around for current // two layer of same storage interface. // TODO: Once cacher is enabled on all registries (event registry is special), we will remove this method. -func NewRawStorage(config *storagebackend.Config) (storage.Interface, factory.DestroyFunc, error) { - return factory.Create(*config) +func NewRawStorage(config *storagebackend.Config) (storage.Interface, factory.DestroyFunc) { + s, d, err := factory.Create(*config) + if err != nil { + klog.Fatalf("Unable to create storage backend: config (%v), err (%v)", config, err) + } + return s, d } diff --git a/vendor/k8s.io/apiserver/pkg/registry/generic/testing/tester.go b/vendor/k8s.io/apiserver/pkg/registry/generic/testing/tester.go index 78cc15bf151..5db5c49d3f0 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/generic/testing/tester.go +++ b/vendor/k8s.io/apiserver/pkg/registry/generic/testing/tester.go @@ -28,7 +28,6 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" - "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/registry/rest/resttest" storagetesting "k8s.io/apiserver/pkg/storage/testing" ) @@ -169,7 +168,7 @@ func (t *Tester) createObject(ctx context.Context, obj runtime.Object) error { func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object { key := t.storage.KeyRootFunc(t.tester.TestContext()) - if _, err := t.storage.DeleteCollection(t.tester.TestContext(), rest.ValidateAllObjectFunc, nil, nil); err != nil { + if _, err := t.storage.DeleteCollection(t.tester.TestContext(), nil, nil); err != nil { t.tester.Errorf("unable to clear collection: %v", err) return nil } @@ -193,7 +192,7 @@ func (t *Tester) emitObject(obj runtime.Object, action string) error { if err != nil { return err } - _, _, err = t.storage.Delete(ctx, accessor.GetName(), rest.ValidateAllObjectFunc, nil) + _, _, err = t.storage.Delete(ctx, accessor.GetName(), nil) default: err = fmt.Errorf("unexpected action: %v", action) } diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS b/vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS old mode 100644 new mode 100755 index 9ee8b8a53a3..6427750a9e9 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - thockin - smarterclayton @@ -13,14 +11,22 @@ reviewers: - nikhiljindal - gmarek - justinsb +- roberthbailey - ncdc - eparis - dims - hongchaodeng - krousey +- jszczepkowski - euank +- markturansky +- fgrzadkowski +- fabioy - ingvagabund - david-mcmahon - jianhuiz +- nhlfr +- feihujiang - sdminonne +- goltermann - enj diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/create.go b/vendor/k8s.io/apiserver/pkg/registry/rest/create.go index dd70a4eb780..388ca523394 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/create.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/create.go @@ -92,9 +92,9 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx context.Context, obj runtime. objectMeta.SetName(strategy.GenerateName(objectMeta.GetGenerateName())) } - // Ensure managedFields is not set unless the feature is enabled - if !utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) { - objectMeta.SetManagedFields(nil) + // Ensure Initializers are not set unless the feature is enabled + if !utilfeature.DefaultFeatureGate.Enabled(features.Initializers) { + objectMeta.SetInitializers(nil) } // ClusterName is ignored and should not be saved @@ -157,36 +157,27 @@ type NamespaceScopedStrategy interface { } // AdmissionToValidateObjectFunc converts validating admission to a rest validate object func -func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectFunc { +func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectFunc { validatingAdmission, ok := admit.(admission.ValidationInterface) if !ok { - return func(ctx context.Context, obj runtime.Object) error { return nil } + return func(obj runtime.Object) error { return nil } } - return func(ctx context.Context, obj runtime.Object) error { - name := staticAttributes.GetName() - // in case the generated name is populated - if len(name) == 0 { - if metadata, err := meta.Accessor(obj); err == nil { - name = metadata.GetName() - } - } - + return func(obj runtime.Object) error { finalAttributes := admission.NewAttributesRecord( obj, staticAttributes.GetOldObject(), staticAttributes.GetKind(), staticAttributes.GetNamespace(), - name, + staticAttributes.GetName(), staticAttributes.GetResource(), staticAttributes.GetSubresource(), staticAttributes.GetOperation(), - staticAttributes.GetOperationOptions(), staticAttributes.IsDryRun(), staticAttributes.GetUserInfo(), ) if !validatingAdmission.Handles(finalAttributes.GetOperation()) { return nil } - return validatingAdmission.Validate(ctx, finalAttributes, o) + return validatingAdmission.Validate(finalAttributes) } } diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/create_update.go b/vendor/k8s.io/apiserver/pkg/registry/rest/create_update.go deleted file mode 100644 index 37d6c8f8ada..00000000000 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/create_update.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2019 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 rest - -import ( - "context" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -// RESTCreateUpdateStrategy is a union of RESTUpdateStrategy and RESTCreateStrategy, -// and it defines the minimum validation, accepted input, and name generation -// behavior to create and update an object that follows Kubernetes API conventions. -type RESTCreateUpdateStrategy interface { - RESTCreateStrategy - // AllowCreateOnUpdate returns true if the object can be created by a PUT. - AllowCreateOnUpdate() bool - // PrepareForUpdate is invoked on update before validation to normalize - // the object. For example: remove fields that are not to be persisted, - // sort order-insensitive list fields, etc. This should not remove fields - // whose presence would be considered a validation error. - PrepareForUpdate(ctx context.Context, obj, old runtime.Object) - // ValidateUpdate is invoked after default fields in the object have been - // filled in before the object is persisted. This method should not mutate - // the object. - ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList - // AllowUnconditionalUpdate returns true if the object can be updated - // unconditionally (irrespective of the latest resource version), when - // there is no resource version specified in the object. - AllowUnconditionalUpdate() bool -} - -// Ensure that RESTCreateUpdateStrategy extends RESTCreateStrategy -var _ RESTCreateStrategy = (RESTCreateUpdateStrategy)(nil) - -// Ensure that RESTCreateUpdateStrategy extends RESTUpdateStrategy -var _ RESTUpdateStrategy = (RESTCreateUpdateStrategy)(nil) diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/delete.go b/vendor/k8s.io/apiserver/pkg/registry/rest/delete.go index 3e7ca85b761..7c39f6be10f 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/delete.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/delete.go @@ -26,7 +26,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/admission" ) // RESTDeleteStrategy defines deletion behavior on an object that follows Kubernetes @@ -78,13 +77,8 @@ func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime. return false, false, errors.NewInvalid(schema.GroupKind{Group: metav1.GroupName, Kind: "DeleteOptions"}, "", errs) } // Checking the Preconditions here to fail early. They'll be enforced later on when we actually do the deletion, too. - if options.Preconditions != nil { - if options.Preconditions.UID != nil && *options.Preconditions.UID != objectMeta.GetUID() { - return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the UID in the precondition (%s) does not match the UID in record (%s). The object might have been deleted and then recreated", *options.Preconditions.UID, objectMeta.GetUID())) - } - if options.Preconditions.ResourceVersion != nil && *options.Preconditions.ResourceVersion != objectMeta.GetResourceVersion() { - return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the ResourceVersion in the precondition (%s) does not match the ResourceVersion in record (%s). The object might have been modified", *options.Preconditions.ResourceVersion, objectMeta.GetResourceVersion())) - } + if options.Preconditions != nil && options.Preconditions.UID != nil && *options.Preconditions.UID != objectMeta.GetUID() { + return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the UID in the precondition (%s) does not match the UID in record (%s). The object might have been deleted and then recreated", *options.Preconditions.UID, objectMeta.GetUID())) } gracefulStrategy, ok := strategy.(RESTGracefulDeleteStrategy) if !ok { @@ -141,43 +135,3 @@ func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime. } return true, false, nil } - -// AdmissionToValidateObjectDeleteFunc returns a admission validate func for object deletion -func AdmissionToValidateObjectDeleteFunc(admit admission.Interface, staticAttributes admission.Attributes, objInterfaces admission.ObjectInterfaces) ValidateObjectFunc { - mutatingAdmission, isMutatingAdmission := admit.(admission.MutationInterface) - validatingAdmission, isValidatingAdmission := admit.(admission.ValidationInterface) - - mutating := isMutatingAdmission && mutatingAdmission.Handles(staticAttributes.GetOperation()) - validating := isValidatingAdmission && validatingAdmission.Handles(staticAttributes.GetOperation()) - - return func(ctx context.Context, old runtime.Object) error { - if !mutating && !validating { - return nil - } - finalAttributes := admission.NewAttributesRecord( - nil, - // Deep copy the object to avoid accidentally changing the object. - old.DeepCopyObject(), - staticAttributes.GetKind(), - staticAttributes.GetNamespace(), - staticAttributes.GetName(), - staticAttributes.GetResource(), - staticAttributes.GetSubresource(), - staticAttributes.GetOperation(), - staticAttributes.GetOperationOptions(), - staticAttributes.IsDryRun(), - staticAttributes.GetUserInfo(), - ) - if mutating { - if err := mutatingAdmission.Admit(ctx, finalAttributes, objInterfaces); err != nil { - return err - } - } - if validating { - if err := validatingAdmission.Validate(ctx, finalAttributes, objInterfaces); err != nil { - return err - } - } - return nil - } -} diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/rest.go b/vendor/k8s.io/apiserver/pkg/registry/rest/rest.go index 8f9c981dd85..572f924e73b 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/rest.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/rest.go @@ -24,6 +24,7 @@ import ( metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" @@ -98,8 +99,6 @@ type Lister interface { NewList() runtime.Object // List selects resources in the storage which match to the selector. 'options' can be nil. List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) - // TableConvertor ensures all list implementers also implement table conversion - TableConvertor } // Exporter is an object that knows how to strip a RESTful resource for export. A store should implement this interface @@ -142,14 +141,13 @@ type GetterWithOptions interface { } type TableConvertor interface { - ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) + ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) } // GracefulDeleter knows how to pass deletion options to allow delayed deletion of a // RESTful object. type GracefulDeleter interface { // Delete finds a resource in the storage and deletes it. - // The delete attempt is validated by the deleteValidation first. // If options are provided, the resource will attempt to honor them or return an invalid // request error. // Although it can return an arbitrary error value, IsNotFound(err) is true for the @@ -158,24 +156,18 @@ type GracefulDeleter interface { // information about deletion. // It also returns a boolean which is set to true if the resource was instantly // deleted or false if it will be deleted asynchronously. - Delete(ctx context.Context, name string, deleteValidation ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) -} - -// MayReturnFullObjectDeleter may return deleted object (instead of a simple status) on deletion. -type MayReturnFullObjectDeleter interface { - DeleteReturnsDeletedObject() bool + Delete(ctx context.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) } // CollectionDeleter is an object that can delete a collection // of RESTful resources. type CollectionDeleter interface { // DeleteCollection selects all resources in the storage matching given 'listOptions' - // and deletes them. The delete attempt is validated by the deleteValidation first. - // If 'options' are provided, the resource will attempt to honor them or return an - // invalid request error. + // and deletes them. If 'options' are provided, the resource will attempt to honor + // them or return an invalid request error. // DeleteCollection may not be atomic - i.e. it may delete some objects and still // return an error after it. On success, returns a list of deleted objects. - DeleteCollection(ctx context.Context, deleteValidation ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) + DeleteCollection(ctx context.Context, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) } // Creater is an object that can create an instance of a RESTful object. @@ -184,7 +176,8 @@ type Creater interface { // This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object) New() runtime.Object - // Create creates a new version of a resource. + // Create creates a new version of a resource. If includeUninitialized is set, the object may be returned + // without completing initialization. Create(ctx context.Context, obj runtime.Object, createValidation ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) } @@ -196,7 +189,8 @@ type NamedCreater interface { // Create creates a new version of a resource. It expects a name parameter from the path. // This is needed for create operations on subresources which include the name of the parent - // resource in the path. + // resource in the path. If includeUninitialized is set, the object may be returned without + // completing initialization. Create(ctx context.Context, name string, obj runtime.Object, createValidation ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) } @@ -216,20 +210,20 @@ type UpdatedObjectInfo interface { // ValidateObjectFunc is a function to act on a given object. An error may be returned // if the hook cannot be completed. An ObjectFunc may NOT transform the provided // object. -type ValidateObjectFunc func(ctx context.Context, obj runtime.Object) error +type ValidateObjectFunc func(obj runtime.Object) error // ValidateAllObjectFunc is a "admit everything" instance of ValidateObjectFunc. -func ValidateAllObjectFunc(ctx context.Context, obj runtime.Object) error { +func ValidateAllObjectFunc(obj runtime.Object) error { return nil } // ValidateObjectUpdateFunc is a function to act on a given object and its predecessor. // An error may be returned if the hook cannot be completed. An UpdateObjectFunc // may NOT transform the provided object. -type ValidateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error +type ValidateObjectUpdateFunc func(obj, old runtime.Object) error // ValidateAllObjectUpdateFunc is a "admit everything" instance of ValidateObjectUpdateFunc. -func ValidateAllObjectUpdateFunc(ctx context.Context, obj, old runtime.Object) error { +func ValidateAllObjectUpdateFunc(obj, old runtime.Object) error { return nil } @@ -340,12 +334,3 @@ type StorageMetadata interface { // it is not nil. Only the type of the return object matters, the value will be ignored. ProducesObject(verb string) interface{} } - -// StorageVersionProvider is an optional interface that a storage object can -// implement if it wishes to disclose its storage version. -type StorageVersionProvider interface { - // StorageVersion returns a group versioner, which will outputs the gvk - // an object will be converted to before persisted in etcd, given a - // list of kinds the object might belong to. - StorageVersion() runtime.GroupVersioner -} diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/resttest/resttest.go b/vendor/k8s.io/apiserver/pkg/registry/rest/resttest/resttest.go index ccf6c74b91d..8e6b555426e 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/resttest/resttest.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/resttest/resttest.go @@ -18,7 +18,6 @@ package resttest import ( "context" - "encoding/json" "fmt" "reflect" "strings" @@ -257,7 +256,7 @@ func (t *Tester) delete(ctx context.Context, obj runtime.Object) error { if !ok { return fmt.Errorf("Expected deleting storage, got %v", t.storage) } - _, _, err = deleter.Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, nil) + _, _, err = deleter.Delete(ctx, objectMeta.GetName(), nil) return err } @@ -840,7 +839,7 @@ func (t *Tester) testDeleteNoGraceful(obj runtime.Object, createFn CreateFunc, g if dryRun { opts.DryRun = []string{metav1.DryRunAll} } - obj, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, opts) + obj, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), opts) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -866,7 +865,7 @@ func (t *Tester) testDeleteNoGraceful(obj runtime.Object, createFn CreateFunc, g func (t *Tester) testDeleteNonExist(obj runtime.Object, opts metav1.DeleteOptions) { objectMeta := t.getObjectMetaOrFail(obj) - _, _, err := t.storage.(rest.GracefulDeleter).Delete(t.TestContext(), objectMeta.GetName(), rest.ValidateAllObjectFunc, &opts) + _, _, err := t.storage.(rest.GracefulDeleter).Delete(t.TestContext(), objectMeta.GetName(), &opts) if err == nil || !errors.IsNotFound(err) { t.Errorf("unexpected error: %v", err) } @@ -886,51 +885,12 @@ func (t *Tester) testDeleteWithUID(obj runtime.Object, createFn CreateFunc, getF t.Errorf("unexpected error: %v", err) } opts.Preconditions = metav1.NewPreconditionDeleteOptions("UID1111").Preconditions - obj, _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, &opts) + obj, _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), &opts) if err == nil || !errors.IsConflict(err) { t.Errorf("unexpected error: %v", err) } - obj, _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewPreconditionDeleteOptions("UID0000")) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if !t.returnDeletedObject { - if status, ok := obj.(*metav1.Status); !ok { - t.Errorf("expected status of delete, got %v", status) - } else if status.Status != metav1.StatusSuccess { - t.Errorf("expected success, got: %v", status.Status) - } - } - - _, err = getFn(ctx, foo) - if err == nil || !isNotFoundFn(err) { - t.Errorf("unexpected error: %v", err) - } -} - -// This test the fast-fail path. We test that the precondition gets verified -// again before deleting the object in tests of pkg/storage/etcd. -func (t *Tester) testDeleteWithResourceVersion(obj runtime.Object, createFn CreateFunc, getFn GetFunc, isNotFoundFn IsErrorFunc, opts metav1.DeleteOptions) { - ctx := t.TestContext() - - foo := obj.DeepCopyObject() - t.setObjectMeta(foo, t.namer(1)) - objectMeta := t.getObjectMetaOrFail(foo) - objectMeta.SetResourceVersion("RV0000") - if err := createFn(ctx, foo); err != nil { - t.Errorf("unexpected error: %v", err) - } - opts.Preconditions = metav1.NewRVDeletionPrecondition("RV1111").Preconditions - obj, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, &opts) - if err == nil || !errors.IsConflict(err) { - t.Errorf("unexpected error: %v", err) - } - if wasDeleted { - t.Errorf("unexpected, object %s should not have been deleted immediately", objectMeta.GetName()) - } - obj, _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewRVDeletionPrecondition("RV0000")) + obj, _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewPreconditionDeleteOptions("UID0000")) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -962,7 +922,7 @@ func (t *Tester) testDeleteDryRunGracefulHasdefault(obj runtime.Object, createFn t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) - object, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}) + object, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -973,7 +933,7 @@ func (t *Tester) testDeleteDryRunGracefulHasdefault(obj runtime.Object, createFn if objectMeta.GetDeletionTimestamp() == nil || objectMeta.GetDeletionGracePeriodSeconds() == nil || *objectMeta.GetDeletionGracePeriodSeconds() != expectedGrace { t.Errorf("unexpected deleted meta: %#v", objectMeta) } - _, _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) + _, _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), &metav1.DeleteOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -989,7 +949,7 @@ func (t *Tester) testDeleteGracefulHasDefault(obj runtime.Object, createFn Creat } objectMeta := t.getObjectMetaOrFail(foo) generation := objectMeta.GetGeneration() - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), &metav1.DeleteOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1023,7 +983,7 @@ func (t *Tester) testDeleteGracefulWithValue(obj runtime.Object, createFn Create } objectMeta := t.getObjectMetaOrFail(foo) generation := objectMeta.GetGeneration() - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(expectedGrace+2)) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1057,7 +1017,7 @@ func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, createFn CreateFun } objectMeta := t.getObjectMetaOrFail(foo) generation := objectMeta.GetGeneration() - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(expectedGrace)) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1069,7 +1029,7 @@ func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, createFn CreateFun } // second delete duration is ignored - _, wasDeleted, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(expectedGrace+2)) + _, wasDeleted, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1099,7 +1059,7 @@ func (t *Tester) testDeleteGracefulImmediate(obj runtime.Object, createFn Create } objectMeta := t.getObjectMetaOrFail(foo) generation := objectMeta.GetGeneration() - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(expectedGrace)) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1111,7 +1071,7 @@ func (t *Tester) testDeleteGracefulImmediate(obj runtime.Object, createFn Create } // second delete is immediate, resource is deleted - out, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(0)) + out, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(0)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1141,7 +1101,7 @@ func (t *Tester) testDeleteGracefulUsesZeroOnNil(obj runtime.Object, createFn Cr t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(foo) - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, nil) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), nil) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1167,7 +1127,7 @@ func (t *Tester) testDeleteGracefulShorten(obj runtime.Object, createFn CreateFu bigGrace = 2 * expectedGrace } objectMeta := t.getObjectMetaOrFail(foo) - _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(bigGrace)) + _, wasDeleted, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(bigGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1182,7 +1142,7 @@ func (t *Tester) testDeleteGracefulShorten(obj runtime.Object, createFn CreateFu deletionTimestamp := *objectMeta.GetDeletionTimestamp() // second delete duration is ignored - _, wasDeleted, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), rest.ValidateAllObjectFunc, metav1.NewDeleteOptions(expectedGrace)) + _, wasDeleted, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.GetName(), metav1.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -1461,7 +1421,7 @@ func (t *Tester) testListTableConversion(obj runtime.Object, assignFn AssignFunc } columns := table.ColumnDefinitions if len(columns) == 0 { - t.Fatalf("unexpected number of columns: %v\n%#v", len(columns), columns) + t.Errorf("unexpected number of columns: %v", len(columns)) } if !strings.EqualFold(columns[0].Name, "Name") || columns[0].Type != "string" || columns[0].Format != "name" { t.Errorf("expect column 0 to be the name column: %#v", columns[0]) @@ -1506,11 +1466,8 @@ func (t *Tester) testListTableConversion(obj runtime.Object, assignFn AssignFunc } } if len(row.Cells) != len(table.ColumnDefinitions) { - t.Fatalf("unmatched row length on row %d: %#v", i, row.Cells) } } - data, _ := json.MarshalIndent(table, "", " ") - t.Logf("%s", string(data)) } // ============================================================================= diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/table.go b/vendor/k8s.io/apiserver/pkg/registry/rest/table.go index d90ae70762b..bfcdcf58b13 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/table.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/table.go @@ -24,35 +24,30 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - genericapirequest "k8s.io/apiserver/pkg/endpoints/request" ) type defaultTableConvertor struct { - defaultQualifiedResource schema.GroupResource + qualifiedResource schema.GroupResource } -// NewDefaultTableConvertor creates a default convertor; the provided resource is used for error messages -// if no resource info can be determined from the context passed to ConvertToTable. -func NewDefaultTableConvertor(defaultQualifiedResource schema.GroupResource) TableConvertor { - return defaultTableConvertor{defaultQualifiedResource: defaultQualifiedResource} +// NewDefaultTableConvertor creates a default convertor for the provided resource. +func NewDefaultTableConvertor(resource schema.GroupResource) TableConvertor { + return defaultTableConvertor{qualifiedResource: resource} } var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc() -func (c defaultTableConvertor) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - var table metav1.Table +func (c defaultTableConvertor) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) { + var table metav1beta1.Table fn := func(obj runtime.Object) error { m, err := meta.Accessor(obj) if err != nil { - resource := c.defaultQualifiedResource - if info, ok := genericapirequest.RequestInfoFrom(ctx); ok { - resource = schema.GroupResource{Group: info.APIGroup, Resource: info.Resource} - } - return errNotAcceptable{resource: resource} + return errNotAcceptable{resource: c.qualifiedResource} } - table.Rows = append(table.Rows, metav1.TableRow{ + table.Rows = append(table.Rows, metav1beta1.TableRow{ Cells: []interface{}{m.GetName(), m.GetCreationTimestamp().Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Object: obj}, }) @@ -72,18 +67,15 @@ func (c defaultTableConvertor) ConvertToTable(ctx context.Context, object runtim table.ResourceVersion = m.GetResourceVersion() table.SelfLink = m.GetSelfLink() table.Continue = m.GetContinue() - table.RemainingItemCount = m.GetRemainingItemCount() } else { if m, err := meta.CommonAccessor(object); err == nil { table.ResourceVersion = m.GetResourceVersion() table.SelfLink = m.GetSelfLink() } } - if opt, ok := tableOptions.(*metav1.TableOptions); !ok || !opt.NoHeaders { - table.ColumnDefinitions = []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]}, - {Name: "Created At", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"]}, - } + table.ColumnDefinitions = []metav1beta1.TableColumnDefinition{ + {Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]}, + {Name: "Created At", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"]}, } return &table, nil } diff --git a/vendor/k8s.io/apiserver/pkg/registry/rest/update.go b/vendor/k8s.io/apiserver/pkg/registry/rest/update.go index 0741b84ec29..147541bcfd3 100644 --- a/vendor/k8s.io/apiserver/pkg/registry/rest/update.go +++ b/vendor/k8s.io/apiserver/pkg/registry/rest/update.go @@ -104,10 +104,10 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx context.Context, obj, old run } objectMeta.SetGeneration(oldMeta.GetGeneration()) - // Ensure managedFields state is removed unless ServerSideApply is enabled - if !utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) { - oldMeta.SetManagedFields(nil) - objectMeta.SetManagedFields(nil) + // Ensure Initializers are not set unless the feature is enabled + if !utilfeature.DefaultFeatureGate.Enabled(features.Initializers) { + oldMeta.SetInitializers(nil) + objectMeta.SetInitializers(nil) } strategy.PrepareForUpdate(ctx, obj, old) @@ -252,12 +252,12 @@ func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj run } // AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func -func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectUpdateFunc { +func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes) ValidateObjectUpdateFunc { validatingAdmission, ok := admit.(admission.ValidationInterface) if !ok { - return func(ctx context.Context, obj, old runtime.Object) error { return nil } + return func(obj, old runtime.Object) error { return nil } } - return func(ctx context.Context, obj, old runtime.Object) error { + return func(obj, old runtime.Object) error { finalAttributes := admission.NewAttributesRecord( obj, old, @@ -267,13 +267,12 @@ func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttrib staticAttributes.GetResource(), staticAttributes.GetSubresource(), staticAttributes.GetOperation(), - staticAttributes.GetOperationOptions(), staticAttributes.IsDryRun(), staticAttributes.GetUserInfo(), ) if !validatingAdmission.Handles(finalAttributes.GetOperation()) { return nil } - return validatingAdmission.Validate(ctx, finalAttributes, o) + return validatingAdmission.Validate(finalAttributes) } } diff --git a/vendor/k8s.io/apiserver/pkg/server/config.go b/vendor/k8s.io/apiserver/pkg/server/config.go index ccbc31462a9..0299f63f68a 100644 --- a/vendor/k8s.io/apiserver/pkg/server/config.go +++ b/vendor/k8s.io/apiserver/pkg/server/config.go @@ -17,25 +17,26 @@ limitations under the License. package server import ( + "crypto/tls" + "crypto/x509" "fmt" "net" "net/http" goruntime "runtime" - "runtime/debug" "sort" "strconv" "strings" "sync/atomic" "time" + "github.com/emicklei/go-restful-swagger12" jsonpatch "github.com/evanphx/json-patch" "github.com/go-openapi/spec" - "github.com/google/uuid" + "github.com/pborman/uuid" + "k8s.io/klog" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/sets" utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup" "k8s.io/apimachinery/pkg/version" @@ -53,20 +54,18 @@ import ( genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" apiopenapi "k8s.io/apiserver/pkg/endpoints/openapi" apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/features" genericregistry "k8s.io/apiserver/pkg/registry/generic" - "k8s.io/apiserver/pkg/server/dynamiccertificates" - "k8s.io/apiserver/pkg/server/egressselector" genericfilters "k8s.io/apiserver/pkg/server/filters" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/server/routes" serverstore "k8s.io/apiserver/pkg/server/storage" - utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/apiserver/pkg/util/logs" "k8s.io/client-go/informers" restclient "k8s.io/client-go/rest" - "k8s.io/component-base/logs" - "k8s.io/klog" + certutil "k8s.io/client-go/util/cert" openapicommon "k8s.io/kube-openapi/pkg/common" - utilsnet "k8s.io/utils/net" // install apis _ "k8s.io/apiserver/pkg/apis/apiserver/install" @@ -96,11 +95,6 @@ type Config struct { // This is required for proper functioning of the PostStartHooks on a GenericAPIServer // TODO: move into SecureServing(WithLoopback) as soon as insecure serving is gone LoopbackClientConfig *restclient.Config - - // EgressSelector provides a lookup mechanism for dialing outbound connections. - // It does so based on a EgressSelectorConfiguration which was read at startup. - EgressSelector *egressselector.EgressSelector - // RuleResolver is required to get the list of rules that apply to a given user // in a given namespace RuleResolver authorizer.RuleResolver @@ -109,9 +103,7 @@ type Config struct { AdmissionControl admission.Interface CorsAllowedOriginList []string - // FlowControl, if not nil, gives priority and fairness to request handling - FlowControl utilflowcontrol.Interface - + EnableSwaggerUI bool EnableIndex bool EnableProfiling bool EnableDiscovery bool @@ -120,8 +112,6 @@ type Config struct { EnableMetrics bool DisabledPostStartHooks sets.String - // done values in this values for this map are ignored. - PostStartHooks map[string]PostStartHookConfigEntry // Version will enable the /version endpoint if non-nil Version *version.Info @@ -144,12 +134,8 @@ type Config struct { // DiscoveryAddresses is used to build the IPs pass to discovery. If nil, the ExternalAddress is // always reported DiscoveryAddresses discovery.Addresses - // The default set of healthz checks. There might be more added via AddHealthChecks dynamically. - HealthzChecks []healthz.HealthChecker - // The default set of livez checks. There might be more added via AddHealthChecks dynamically. - LivezChecks []healthz.HealthChecker - // The default set of readyz-only checks. There might be more added via AddReadyzChecks dynamically. - ReadyzChecks []healthz.HealthChecker + // The default set of healthz checks. There might be more added via AddHealthzChecks dynamically. + HealthzChecks []healthz.HealthzChecker // LegacyAPIGroupPrefixes is used to set up URL parsing for authorization and for validating requests // to InstallLegacyAPIGroup. New API servers don't generally have legacy groups at all. LegacyAPIGroupPrefixes sets.String @@ -161,6 +147,8 @@ type Config struct { Serializer runtime.NegotiatedSerializer // OpenAPIConfig will be used in generating OpenAPI spec. This is nil by default. Use DefaultOpenAPIConfig for "working" defaults. OpenAPIConfig *openapicommon.Config + // SwaggerConfig will be used in generating Swagger spec. This is nil by default. Use DefaultSwaggerConfig for "working" defaults. + SwaggerConfig *swagger.Config // RESTOptionsGetter is used to construct RESTStorage types via the generic registry. RESTOptionsGetter genericregistry.RESTOptionsGetter @@ -171,22 +159,11 @@ type Config struct { // 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 - - // This represents the maximum amount of time it should take for apiserver to complete its startup - // sequence and become healthy. From apiserver's start time to when this amount of time has - // elapsed, /livez will assume that unfinished post-start hooks will complete successfully and - // therefore return true. - LivezGracePeriod time.Duration - // ShutdownDelayDuration allows to block shutdown for some time, e.g. until endpoints pointing to this API server - // have converged on all node. During this time, the API server keeps serving, /healthz will return 200, - // but /readyz will return failure. - ShutdownDelayDuration time.Duration - // The limit on the total size increase all "copy" operations in a json // patch may cause. // This affects all places that applies json patch in the binary. JSONPatchMaxCopyBytes int64 - // The limit on the request size that would be accepted and decoded in a write request + // The limit on the request body size that would be accepted and decoded in a write request. // 0 means no limit. MaxRequestBodyBytes int64 // MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further @@ -198,11 +175,9 @@ type Config struct { // Predicate which is true for paths of long-running http requests LongRunningFunc apirequest.LongRunningRequestCheck - // GoawayChance is the probability that send a GOAWAY to HTTP/2 clients. When client received - // GOAWAY, the in-flight requests will not be affected and new requests will use - // a new TCP connection to triggering re-balancing to another server behind the load balance. - // Default to 0, means never send GOAWAY. Max is 0.02 to prevent break the apiserver. - GoawayChance float64 + // EnableAPIResponseCompression indicates whether API Responses should support compression + // if the client requests it via Accept-Encoding + EnableAPIResponseCompression bool // MergedResourceConfig indicates which groupVersion enabled and its resources enabled/disabled. // This is composed of genericapiserver defaultAPIResourceConfig and those parsed from flags. @@ -217,10 +192,6 @@ type Config struct { // kube-proxy, services, etc.) can reach the GenericAPIServer. // If nil or 0.0.0.0, the host's default interface will be used. PublicAddress net.IP - - // EquivalentResourceRegistry provides information about resources equivalent to a given resource, - // and the kind associated with a given resource. As resources are installed, they are registered here. - EquivalentResourceRegistry runtime.EquivalentResourceRegistry } type RecommendedConfig struct { @@ -243,13 +214,13 @@ type SecureServingInfo struct { // Cert is the main server cert which is used if SNI does not match. Cert must be non-nil and is // allowed to be in SNICerts. - Cert dynamiccertificates.CertKeyContentProvider + Cert *tls.Certificate - // SNICerts are the TLS certificates used for SNI. - SNICerts []dynamiccertificates.SNICertKeyContentProvider + // SNICerts are the TLS certificates by name used for SNI. + SNICerts map[string]*tls.Certificate // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates - ClientCA dynamiccertificates.CAContentProvider + ClientCA *x509.CertPool // MinTLSVersion optionally overrides the minimum TLS version supported. // Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). @@ -262,9 +233,6 @@ type SecureServingInfo struct { // HTTP2MaxStreamsPerConnection is the limit that the api server imposes on each client. // A value of zero means to use the default provided by golang's HTTP/2 support. HTTP2MaxStreamsPerConnection int - - // DisableHTTP2 indicates that http2 should not be enabled. - DisableHTTP2 bool } type AuthenticationInfo struct { @@ -273,6 +241,10 @@ type AuthenticationInfo struct { APIAudiences authenticator.Audiences // Authenticator determines which subject is making the request Authenticator authenticator.Request + // SupportsBasicAuth indicates that's at least one Authenticator supports basic auth + // If this is true, a basic auth challenge is returned on authentication failure + // TODO(roberthbailey): Remove once the server no longer supports http basic auth. + SupportsBasicAuth bool } type AuthorizationInfo struct { @@ -283,17 +255,13 @@ type AuthorizationInfo struct { // NewConfig returns a Config struct with the default values func NewConfig(codecs serializer.CodecFactory) *Config { - defaultHealthChecks := []healthz.HealthChecker{healthz.PingHealthz, healthz.LogHealthz} return &Config{ Serializer: codecs, BuildHandlerChainFunc: DefaultBuildHandlerChain, HandlerChainWaitGroup: new(utilwaitgroup.SafeWaitGroup), LegacyAPIGroupPrefixes: sets.NewString(DefaultLegacyAPIPrefix), DisabledPostStartHooks: sets.NewString(), - PostStartHooks: map[string]PostStartHookConfigEntry{}, - HealthzChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), - ReadyzChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), - LivezChecks: append([]healthz.HealthChecker{}, defaultHealthChecks...), + HealthzChecks: []healthz.HealthzChecker{healthz.PingHealthz, healthz.LogHealthz}, EnableIndex: true, EnableDiscovery: true, EnableProfiling: true, @@ -302,22 +270,23 @@ func NewConfig(codecs serializer.CodecFactory) *Config { MaxMutatingRequestsInFlight: 200, RequestTimeout: time.Duration(60) * time.Second, MinRequestTimeout: 1800, - LivezGracePeriod: time.Duration(0), - ShutdownDelayDuration: time.Duration(0), - // 1.5MB is the default client request size in bytes + // 10MB is the recommended maximum client request size in bytes // the etcd server should accept. See - // https://github.com/etcd-io/etcd/blob/release-3.4/embed/config.go#L56. + // https://github.com/etcd-io/etcd/blob/release-3.3/etcdserver/server.go#L90. // A request body might be encoded in json, and is converted to - // proto when persisted in etcd, so we allow 2x as the largest size + // proto when persisted in etcd. Assuming the upper bound of + // the size ratio is 10:1, we set 100MB as the largest size // increase the "copy" operations in a json patch may cause. - JSONPatchMaxCopyBytes: int64(3 * 1024 * 1024), - // 1.5MB is the recommended client request size in byte + JSONPatchMaxCopyBytes: int64(100 * 1024 * 1024), + // 10MB is the recommended maximum client request size in bytes // the etcd server should accept. See - // https://github.com/etcd-io/etcd/blob/release-3.4/embed/config.go#L56. + // https://github.com/etcd-io/etcd/blob/release-3.3/etcdserver/server.go#L90. // A request body might be encoded in json, and is converted to - // proto when persisted in etcd, so we allow 2x as the largest request + // proto when persisted in etcd. Assuming the upper bound of + // the size ratio is 10:1, we set 100MB as the largest request // body size to be accepted and decoded in a write request. - MaxRequestBodyBytes: int64(3 * 1024 * 1024), + MaxRequestBodyBytes: int64(100 * 1024 * 1024), + EnableAPIResponseCompression: utilfeature.DefaultFeatureGate.Enabled(features.APIResponseCompression), // Default to treating watch as a long-running operation // Generic API servers have no inherent long-running subresources @@ -335,7 +304,7 @@ func NewRecommendedConfig(codecs serializer.CodecFactory) *RecommendedConfig { func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, defNamer *apiopenapi.DefinitionNamer) *openapicommon.Config { return &openapicommon.Config{ ProtocolList: []string{"https"}, - IgnorePrefixes: []string{}, + IgnorePrefixes: []string{"/swaggerapi"}, Info: &spec.Info{ InfoProps: spec.InfoProps{ Title: "Generic API Server", @@ -352,19 +321,39 @@ func DefaultOpenAPIConfig(getDefinitions openapicommon.GetOpenAPIDefinitions, de } } -func (c *AuthenticationInfo) ApplyClientCert(clientCA dynamiccertificates.CAContentProvider, servingInfo *SecureServingInfo) error { - if servingInfo == nil { - return nil - } - if clientCA == nil { - return nil +// DefaultSwaggerConfig returns a default configuration without WebServiceURL and +// WebServices set. +func DefaultSwaggerConfig() *swagger.Config { + return &swagger.Config{ + ApiPath: "/swaggerapi", + SwaggerPath: "/swaggerui/", + SwaggerFilePath: "/swagger-ui/", + SchemaFormatHandler: func(typeName string) string { + switch typeName { + case "metav1.Time", "*metav1.Time": + return "date-time" + } + return "" + }, } - if servingInfo.ClientCA == nil { - servingInfo.ClientCA = clientCA - return nil +} + +func (c *AuthenticationInfo) ApplyClientCert(clientCAFile string, servingInfo *SecureServingInfo) error { + if servingInfo != nil { + if len(clientCAFile) > 0 { + clientCAs, err := certutil.CertsFromFile(clientCAFile) + if err != nil { + return fmt.Errorf("unable to load client CA file: %v", err) + } + if servingInfo.ClientCA == nil { + servingInfo.ClientCA = x509.NewCertPool() + } + for _, cert := range clientCAs { + servingInfo.ClientCA.AddCert(cert) + } + } } - servingInfo.ClientCA = dynamiccertificates.NewUnionCAContentProvider(servingInfo.ClientCA, clientCA) return nil } @@ -384,47 +373,6 @@ type CompletedConfig struct { *completedConfig } -// AddHealthChecks adds a health check to our config to be exposed by the health endpoints -// of our configured apiserver. We should prefer this to adding healthChecks directly to -// the config unless we explicitly want to add a healthcheck only to a specific health endpoint. -func (c *Config) AddHealthChecks(healthChecks ...healthz.HealthChecker) { - for _, check := range healthChecks { - c.HealthzChecks = append(c.HealthzChecks, check) - c.LivezChecks = append(c.LivezChecks, check) - c.ReadyzChecks = append(c.ReadyzChecks, check) - } -} - -// AddPostStartHook allows you to add a PostStartHook that will later be added to the server itself in a New call. -// Name conflicts will cause an error. -func (c *Config) AddPostStartHook(name string, hook PostStartHookFunc) error { - if len(name) == 0 { - return fmt.Errorf("missing name") - } - if hook == nil { - return fmt.Errorf("hook func may not be nil: %q", name) - } - if c.DisabledPostStartHooks.Has(name) { - klog.V(1).Infof("skipping %q because it was explicitly disabled", name) - return nil - } - - if postStartHook, exists := c.PostStartHooks[name]; exists { - // this is programmer error, but it can be hard to debug - return fmt.Errorf("unable to add %q because it was already registered by: %s", name, postStartHook.originatingStack) - } - c.PostStartHooks[name] = PostStartHookConfigEntry{hook: hook, originatingStack: string(debug.Stack())} - - return nil -} - -// AddPostStartHookOrDie allows you to add a PostStartHook, but dies on failure. -func (c *Config) AddPostStartHookOrDie(name string, hook PostStartHookFunc) { - if err := c.AddPostStartHook(name, hook); err != nil { - klog.Fatalf("Error registering PostStartHook %q: %v", name, err) - } -} - // Complete fills in any fields not set that are required to have valid data and can be derived // from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver. func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig { @@ -480,6 +428,13 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo } } } + if c.SwaggerConfig != nil && len(c.SwaggerConfig.WebServicesUrl) == 0 { + if c.SecureServing != nil { + c.SwaggerConfig.WebServicesUrl = "https://" + c.ExternalAddress + } else { + c.SwaggerConfig.WebServicesUrl = "http://" + c.ExternalAddress + } + } if c.DiscoveryAddresses == nil { c.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: c.ExternalAddress} } @@ -490,21 +445,6 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo c.RequestInfoResolver = NewRequestInfoResolver(c) } - if c.EquivalentResourceRegistry == nil { - if c.RESTOptionsGetter == nil { - c.EquivalentResourceRegistry = runtime.NewEquivalentResourceRegistry() - } else { - c.EquivalentResourceRegistry = runtime.NewEquivalentResourceRegistryWithIdentity(func(groupResource schema.GroupResource) string { - // use the storage prefix as the key if possible - if opts, err := c.RESTOptionsGetter.GetRESTOptions(groupResource); err == nil { - return opts.ResourcePrefix - } - // otherwise return "" to use the default key (parent GV name) - return "" - }) - } - } - return CompletedConfig{&completedConfig{c, informers}} } @@ -524,9 +464,6 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G if c.LoopbackClientConfig == nil { return nil, fmt.Errorf("Genericapiserver.New() called with config.LoopbackClientConfig == nil") } - if c.EquivalentResourceRegistry == nil { - return nil, fmt.Errorf("Genericapiserver.New() called with config.EquivalentResourceRegistry == nil") - } handlerChainBuilder := func(handler http.Handler) http.Handler { return c.BuildHandlerChainFunc(handler, c.Config) @@ -534,43 +471,39 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G apiServerHandler := NewAPIServerHandler(name, c.Serializer, handlerChainBuilder, delegationTarget.UnprotectedHandler()) s := &GenericAPIServer{ - discoveryAddresses: c.DiscoveryAddresses, - LoopbackClientConfig: c.LoopbackClientConfig, - legacyAPIGroupPrefixes: c.LegacyAPIGroupPrefixes, - admissionControl: c.AdmissionControl, - Serializer: c.Serializer, - AuditBackend: c.AuditBackend, - Authorizer: c.Authorization.Authorizer, - delegationTarget: delegationTarget, - EquivalentResourceRegistry: c.EquivalentResourceRegistry, - HandlerChainWaitGroup: c.HandlerChainWaitGroup, - - minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second, - ShutdownTimeout: c.RequestTimeout, - ShutdownDelayDuration: c.ShutdownDelayDuration, - SecureServingInfo: c.SecureServing, - ExternalAddress: c.ExternalAddress, + discoveryAddresses: c.DiscoveryAddresses, + LoopbackClientConfig: c.LoopbackClientConfig, + legacyAPIGroupPrefixes: c.LegacyAPIGroupPrefixes, + admissionControl: c.AdmissionControl, + Serializer: c.Serializer, + AuditBackend: c.AuditBackend, + Authorizer: c.Authorization.Authorizer, + delegationTarget: delegationTarget, + HandlerChainWaitGroup: c.HandlerChainWaitGroup, + + minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second, + ShutdownTimeout: c.RequestTimeout, + + SecureServingInfo: c.SecureServing, + ExternalAddress: c.ExternalAddress, Handler: apiServerHandler, listedPathProvider: apiServerHandler, + swaggerConfig: c.SwaggerConfig, openAPIConfig: c.OpenAPIConfig, postStartHooks: map[string]postStartHookEntry{}, preShutdownHooks: map[string]preShutdownHookEntry{}, disabledPostStartHooks: c.DisabledPostStartHooks, - healthzChecks: c.HealthzChecks, - livezChecks: c.LivezChecks, - readyzChecks: c.ReadyzChecks, - readinessStopCh: make(chan struct{}), - livezGracePeriod: c.LivezGracePeriod, + healthzChecks: c.HealthzChecks, DiscoveryGroupManager: discovery.NewRootAPIsHandler(c.DiscoveryAddresses, c.Serializer), - maxRequestBodyBytes: c.MaxRequestBodyBytes, - livezClock: clock.RealClock{}, + enableAPIResponseCompression: c.EnableAPIResponseCompression, + maxRequestBodyBytes: c.MaxRequestBodyBytes, } for { @@ -586,7 +519,6 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G } } - // first add poststarthooks from delegated targets for k, v := range delegationTarget.PostStartHooks() { s.postStartHooks[k] = v } @@ -595,13 +527,6 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G s.preShutdownHooks[k] = v } - // add poststarthooks that were preconfigured. Using the add method will give us an error if the same name has already been registered. - for name, preconfiguredPostStartHook := range c.PostStartHooks { - if err := s.AddPostStartHook(name, preconfiguredPostStartHook.hook); err != nil { - return nil, err - } - } - genericApiServerHookName := "generic-apiserver-start-informers" if c.SharedInformerFactory != nil && !s.isPostStartHookRegistered(genericApiServerHookName) { err := s.AddPostStartHook(genericApiServerHookName, func(context PostStartHookContext) error { @@ -613,21 +538,6 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G } } - const priorityAndFairnessConfigConsumerHookName = "priority-and-fairness-config-consumer" - if s.isPostStartHookRegistered(priorityAndFairnessConfigConsumerHookName) { - } else if c.FlowControl != nil { - err := s.AddPostStartHook(priorityAndFairnessConfigConsumerHookName, func(context PostStartHookContext) error { - go c.FlowControl.Run(context.StopCh) - return nil - }) - if err != nil { - return nil, err - } - // TODO(yue9944882): plumb pre-shutdown-hook for request-management system? - } else { - klog.V(3).Infof("Not requested to run hook %s", priorityAndFairnessConfigConsumerHookName) - } - for _, delegateCheck := range delegationTarget.HealthzChecks() { skip := false for _, existingCheck := range c.HealthzChecks { @@ -639,7 +549,8 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G if skip { continue } - s.AddHealthChecks(delegateCheck) + + s.healthzChecks = append(s.healthzChecks, delegateCheck) } s.listedPathProvider = routes.ListedPathProviders{s.listedPathProvider, delegationTarget} @@ -660,25 +571,16 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler := genericapifilters.WithAuthorization(apiHandler, c.Authorization.Authorizer, c.Serializer) - if c.FlowControl != nil { - handler = genericfilters.WithPriorityAndFairness(handler, c.LongRunningFunc, c.FlowControl) - } else { - handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc) - } + handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc) handler = genericapifilters.WithImpersonation(handler, c.Authorization.Authorizer, c.Serializer) handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc) - failedHandler := genericapifilters.Unauthorized(c.Serializer) + failedHandler := genericapifilters.Unauthorized(c.Serializer, c.Authentication.SupportsBasicAuth) failedHandler = genericapifilters.WithFailedAuthenticationAudit(failedHandler, c.AuditBackend, c.AuditPolicyChecker) handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences) handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup) handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver) - if c.SecureServing != nil && !c.SecureServing.DisableHTTP2 && c.GoawayChance > 0 { - handler = genericfilters.WithProbabilisticGoaway(handler, c.GoawayChance) - } - handler = genericapifilters.WithAuditAnnotations(handler, c.AuditBackend, c.AuditPolicyChecker) - handler = genericapifilters.WithCacheControl(handler) handler = genericfilters.WithPanicRecovery(handler) return handler } @@ -687,6 +589,9 @@ func installAPI(s *GenericAPIServer, c *Config) { if c.EnableIndex { routes.Index{}.Install(s.listedPathProvider, s.Handler.NonGoRestfulMux) } + if c.SwaggerConfig != nil && c.EnableSwaggerUI { + routes.SwaggerUI{}.Install(s.Handler.NonGoRestfulMux) + } if c.EnableProfiling { routes.Profiling{}.Install(s.Handler.NonGoRestfulMux) if c.EnableContentionProfiling { @@ -733,7 +638,7 @@ func (s *SecureServingInfo) HostPort() (string, int, error) { if err != nil { return "", 0, fmt.Errorf("failed to get port from listener address %q: %v", addr, err) } - port, err := utilsnet.ParsePort(portStr, true) + port, err := strconv.Atoi(portStr) if err != nil { return "", 0, fmt.Errorf("invalid non-numeric port %q", portStr) } @@ -741,24 +646,14 @@ func (s *SecureServingInfo) HostPort() (string, int, error) { } // AuthorizeClientBearerToken wraps the authenticator and authorizer in loopback authentication logic -// if the loopback client config is specified AND it has a bearer token. Note that if either authn or -// authz is nil, this function won't add a token authenticator or authorizer. +// if the loopback client config is specified AND it has a bearer token. func AuthorizeClientBearerToken(loopback *restclient.Config, authn *AuthenticationInfo, authz *AuthorizationInfo) { - if loopback == nil || len(loopback.BearerToken) == 0 { - return - } - if authn == nil || authz == nil { - // prevent nil pointer panic - return - } - if authn.Authenticator == nil || authz.Authorizer == nil { - // authenticator or authorizer might be nil if we want to bypass authz/authn - // and we also do nothing in this case. + if loopback == nil || authn == nil || authz == nil || authn.Authenticator == nil && authz.Authorizer == nil || len(loopback.BearerToken) == 0 { return } privilegedLoopbackToken := loopback.BearerToken - var uid = uuid.New().String() + var uid = uuid.NewRandom().String() tokens := make(map[string]*user.DefaultInfo) tokens[privilegedLoopbackToken] = &user.DefaultInfo{ Name: user.APIServerUser, diff --git a/vendor/k8s.io/apiserver/pkg/server/config_selfclient.go b/vendor/k8s.io/apiserver/pkg/server/config_selfclient.go index f2c2de9b324..53f1795275c 100644 --- a/vendor/k8s.io/apiserver/pkg/server/config_selfclient.go +++ b/vendor/k8s.io/apiserver/pkg/server/config_selfclient.go @@ -21,7 +21,6 @@ import ( "net" restclient "k8s.io/client-go/rest" - netutils "k8s.io/utils/net" ) // LoopbackClientServerNameOverride is passed to the apiserver from the loopback client in order to @@ -39,9 +38,12 @@ func (s *SecureServingInfo) NewClientConfig(caCert []byte) (*restclient.Config, } return &restclient.Config{ - // Do not limit loopback client QPS. - QPS: -1, - Host: "https://" + net.JoinHostPort(host, port), + // Increase QPS limits. The client is currently passed to all admission plugins, + // and those can be throttled in case of higher load on apiserver - see #22340 and #22422 + // for more details. Once #22422 is fixed, we may want to remove it. + QPS: 50, + Burst: 100, + Host: "https://" + net.JoinHostPort(host, port), // override the ServerName to select our loopback certificate via SNI. This name is also // used by the client to compare the returns server certificate against. TLSClientConfig: restclient.TLSClientConfig{ @@ -71,27 +73,23 @@ func LoopbackHostPort(bindAddress string) (string, string, error) { return "", "", fmt.Errorf("invalid server bind address: %q", bindAddress) } - isIPv6 := netutils.IsIPv6String(host) + isIPv6 := net.ParseIP(host).To4() == nil // Value is expected to be an IP or DNS name, not "0.0.0.0". if host == "0.0.0.0" || host == "::" { + host = "localhost" // Get ip of local interface, but fall back to "localhost". // Note that "localhost" is resolved with the external nameserver first with Go's stdlib. // So if localhost. resolves, we don't get a 127.0.0.1 as expected. - host = getLoopbackAddress(isIPv6) - } - return host, port, nil -} - -// getLoopbackAddress returns the ip address of local loopback interface. If any error occurs or loopback interface is not found, will fall back to "localhost" -func getLoopbackAddress(wantIPv6 bool) string { - addrs, err := net.InterfaceAddrs() - if err == nil { - for _, address := range addrs { - if ipnet, ok := address.(*net.IPNet); ok && ipnet.IP.IsLoopback() && wantIPv6 == netutils.IsIPv6(ipnet.IP) { - return ipnet.IP.String() + addrs, err := net.InterfaceAddrs() + if err == nil { + for _, address := range addrs { + if ipnet, ok := address.(*net.IPNet); ok && ipnet.IP.IsLoopback() && isIPv6 == (ipnet.IP.To4() == nil) { + host = ipnet.IP.String() + break + } } } } - return "localhost" + return host, port, nil } diff --git a/vendor/k8s.io/apiserver/pkg/server/config_selfclient_test.go b/vendor/k8s.io/apiserver/pkg/server/config_selfclient_test.go index 19e975ffb6a..9374403ff9d 100644 --- a/vendor/k8s.io/apiserver/pkg/server/config_selfclient_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/config_selfclient_test.go @@ -19,19 +19,9 @@ package server import ( "net" "testing" - - netutils "k8s.io/utils/net" ) -func TestLoopbackHostPortIPv4(t *testing.T) { - _, ipv6only, err := isIPv6LoopbackSupported() - if err != nil { - t.Fatalf("fail to enumerate network interface, %s", err) - } - if ipv6only { - t.Fatalf("no ipv4 loopback interface") - } - +func TestLoopbackHostPort(t *testing.T) { host, port, err := LoopbackHostPort("1.2.3.4:443") if err != nil { t.Fatalf("unexpected error: %v", err) @@ -53,17 +43,8 @@ func TestLoopbackHostPortIPv4(t *testing.T) { if port != "443" { t.Fatalf("expected 443 as port, got %q", port) } -} -func TestLoopbackHostPortIPv6(t *testing.T) { - ipv6, _, err := isIPv6LoopbackSupported() - if err != nil { - t.Fatalf("fail to enumerate network interface, %s", err) - } - if !ipv6 { - t.Fatalf("no ipv6 loopback interface") - } - host, port, err := LoopbackHostPort("[ff06:0:0:0:0:0:0:c3]:443") + host, port, err = LoopbackHostPort("[ff06:0:0:0:0:0:0:c3]:443") if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -81,28 +62,8 @@ func TestLoopbackHostPortIPv6(t *testing.T) { if ip := net.ParseIP(host); ip == nil || !ip.IsLoopback() || ip.To4() != nil { t.Fatalf("expected IPv6 host to be loopback, got %q", host) } + if port != "443" { t.Fatalf("expected 443 as port, got %q", port) } } - -func isIPv6LoopbackSupported() (ipv6 bool, ipv6only bool, err error) { - addrs, err := net.InterfaceAddrs() - if err != nil { - return false, false, err - } - ipv4 := false - for _, address := range addrs { - ipnet, ok := address.(*net.IPNet) - if !ok || !ipnet.IP.IsLoopback() { - continue - } - if netutils.IsIPv6(ipnet.IP) { - ipv6 = true - continue - } - ipv4 = true - } - ipv6only = ipv6 && !ipv4 - return ipv6, ipv6only, nil -} diff --git a/vendor/k8s.io/apiserver/pkg/server/config_test.go b/vendor/k8s.io/apiserver/pkg/server/config_test.go index 978f1b9c8c9..07fece4c7ae 100644 --- a/vendor/k8s.io/apiserver/pkg/server/config_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/config_test.go @@ -23,65 +23,22 @@ import ( "net/http" "net/http/httptest" "net/http/httputil" - "reflect" "testing" - "time" - "github.com/google/go-cmp/cmp" - "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/waitgroup" - auditinternal "k8s.io/apiserver/pkg/apis/audit" - "k8s.io/apiserver/pkg/audit" - "k8s.io/apiserver/pkg/audit/policy" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/rest" ) -func TestAuthorizeClientBearerTokenNoops(t *testing.T) { - // All of these should do nothing (not panic, no side-effects) - cfgGens := []func() *rest.Config{ - func() *rest.Config { return nil }, - func() *rest.Config { return &rest.Config{} }, - func() *rest.Config { return &rest.Config{BearerToken: "mu"} }, - } - authcGens := []func() *AuthenticationInfo{ - func() *AuthenticationInfo { return nil }, - func() *AuthenticationInfo { return &AuthenticationInfo{} }, - } - authzGens := []func() *AuthorizationInfo{ - func() *AuthorizationInfo { return nil }, - func() *AuthorizationInfo { return &AuthorizationInfo{} }, - } - for _, cfgGen := range cfgGens { - for _, authcGen := range authcGens { - for _, authzGen := range authzGens { - pConfig := cfgGen() - pAuthc := authcGen() - pAuthz := authzGen() - AuthorizeClientBearerToken(pConfig, pAuthc, pAuthz) - if before, after := authcGen(), pAuthc; !reflect.DeepEqual(before, after) { - t.Errorf("AuthorizeClientBearerToken(%v, %#+v, %v) changed %#+v", pConfig, pAuthc, pAuthz, *before) - } - if before, after := authzGen(), pAuthz; !reflect.DeepEqual(before, after) { - t.Errorf("AuthorizeClientBearerToken(%v, %v, %#+v) changed %#+v", pConfig, pAuthc, pAuthz, *before) - } - } - } - } -} - func TestNewWithDelegate(t *testing.T) { delegateConfig := NewConfig(codecs) delegateConfig.ExternalAddress = "192.168.10.4:443" delegateConfig.PublicAddress = net.ParseIP("192.168.10.4") delegateConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") delegateConfig.LoopbackClientConfig = &rest.Config{} + delegateConfig.SwaggerConfig = DefaultSwaggerConfig() clientset := fake.NewSimpleClientset() if clientset == nil { t.Fatal("unable to create fake client set") @@ -100,9 +57,7 @@ func TestNewWithDelegate(t *testing.T) { w.WriteHeader(http.StatusForbidden) }) - delegatePostStartHookChan := make(chan struct{}) - delegateServer.AddPostStartHookOrDie("delegate-post-start-hook", func(context PostStartHookContext) error { - defer close(delegatePostStartHookChan) + delegateServer.AddPostStartHook("delegate-post-start-hook", func(context PostStartHookContext) error { return nil }) @@ -114,6 +69,7 @@ func TestNewWithDelegate(t *testing.T) { wrappingConfig.PublicAddress = net.ParseIP("192.168.10.4") wrappingConfig.LegacyAPIGroupPrefixes = sets.NewString("/api") wrappingConfig.LoopbackClientConfig = &rest.Config{} + wrappingConfig.SwaggerConfig = DefaultSwaggerConfig() wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error { return fmt.Errorf("wrapping failed healthcheck") @@ -128,9 +84,7 @@ func TestNewWithDelegate(t *testing.T) { w.WriteHeader(http.StatusUnauthorized) }) - wrappingPostStartHookChan := make(chan struct{}) - wrappingServer.AddPostStartHookOrDie("wrapping-post-start-hook", func(context PostStartHookContext) error { - defer close(wrappingPostStartHookChan) + wrappingServer.AddPostStartHook("wrapping-post-start-hook", func(context PostStartHookContext) error { return nil }) @@ -142,39 +96,23 @@ func TestNewWithDelegate(t *testing.T) { server := httptest.NewServer(wrappingServer.Handler) defer server.Close() - // Wait for the hooks to finish before checking the response - <-delegatePostStartHookChan - <-wrappingPostStartHookChan - expectedPaths := []string{ - "/apis", - "/bar", - "/foo", - "/healthz", - "/healthz/delegate-health", - "/healthz/log", - "/healthz/ping", - "/healthz/poststarthook/delegate-post-start-hook", - "/healthz/poststarthook/generic-apiserver-start-informers", - "/healthz/poststarthook/wrapping-post-start-hook", - "/healthz/wrapping-health", - "/livez", - "/livez/delegate-health", - "/livez/log", - "/livez/ping", - "/livez/poststarthook/delegate-post-start-hook", - "/livez/poststarthook/generic-apiserver-start-informers", - "/livez/poststarthook/wrapping-post-start-hook", - "/metrics", - "/readyz", - "/readyz/delegate-health", - "/readyz/log", - "/readyz/ping", - "/readyz/poststarthook/delegate-post-start-hook", - "/readyz/poststarthook/generic-apiserver-start-informers", - "/readyz/poststarthook/wrapping-post-start-hook", - "/readyz/shutdown", - } - checkExpectedPathsAtRoot(server.URL, expectedPaths, t) + checkPath(server.URL, http.StatusOK, `{ + "paths": [ + "/apis", + "/bar", + "/foo", + "/healthz", + "/healthz/delegate-health", + "/healthz/log", + "/healthz/ping", + "/healthz/poststarthook/delegate-post-start-hook", + "/healthz/poststarthook/generic-apiserver-start-informers", + "/healthz/poststarthook/wrapping-post-start-hook", + "/healthz/wrapping-health", + "/metrics", + "/swaggerapi" + ] +}`, t) checkPath(server.URL+"/healthz", http.StatusInternalServerError, `[+]ping ok [+]log ok [-]wrapping-health failed: reason withheld @@ -196,138 +134,22 @@ healthz check failed } func checkPath(url string, expectedStatusCode int, expectedBody string, t *testing.T) { - t.Run(url, func(t *testing.T) { - resp, err := http.Get(url) - if err != nil { - t.Fatal(err) - } - dump, _ := httputil.DumpResponse(resp, true) - t.Log(string(dump)) - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - - if e, a := expectedBody, string(body); e != a { - t.Errorf("%q expected %v, got %v", url, e, a) - } - if e, a := expectedStatusCode, resp.StatusCode; e != a { - t.Errorf("%q expected %v, got %v", url, e, a) - } - }) -} - -func checkExpectedPathsAtRoot(url string, expectedPaths []string, t *testing.T) { - t.Run(url, func(t *testing.T) { - resp, err := http.Get(url) - if err != nil { - t.Fatal(err) - } - dump, _ := httputil.DumpResponse(resp, true) - t.Log(string(dump)) - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - var result map[string]interface{} - json.Unmarshal(body, &result) - paths, ok := result["paths"].([]interface{}) - if !ok { - t.Errorf("paths not found") - } - pathset := sets.NewString() - for _, p := range paths { - pathset.Insert(p.(string)) - } - expectedset := sets.NewString(expectedPaths...) - for _, p := range pathset.Difference(expectedset) { - t.Errorf("Got %v path, which we did not expect", p) - } - for _, p := range expectedset.Difference(pathset) { - t.Errorf(" Expected %v path which we did not get", p) - } - }) -} - -func TestAuthenticationAuditAnnotationsDefaultChain(t *testing.T) { - authn := authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { - // confirm that we can set an audit annotation in a handler before WithAudit - audit.AddAuditAnnotation(req.Context(), "pandas", "are awesome") - - // confirm that trying to use the audit event directly would never work - if ae := request.AuditEventFrom(req.Context()); ae != nil { - t.Errorf("expected nil audit event, got %v", ae) - } - - return &authenticator.Response{User: &user.DefaultInfo{}}, true, nil - }) - backend := &testBackend{} - c := &Config{ - Authentication: AuthenticationInfo{Authenticator: authn}, - AuditBackend: backend, - AuditPolicyChecker: policy.FakeChecker(auditinternal.LevelMetadata, nil), - - // avoid nil panics - HandlerChainWaitGroup: &waitgroup.SafeWaitGroup{}, - RequestInfoResolver: &request.RequestInfoFactory{}, - RequestTimeout: 10 * time.Second, - LongRunningFunc: func(_ *http.Request, _ *request.RequestInfo) bool { return false }, + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) } + dump, _ := httputil.DumpResponse(resp, true) + t.Log(string(dump)) - h := DefaultBuildHandlerChain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // confirm this is a no-op - if r.Context() != audit.WithAuditAnnotations(r.Context()) { - t.Error("unexpected double wrapping of context") - } - - // confirm that we have an audit event - ae := request.AuditEventFrom(r.Context()) - if ae == nil { - t.Error("unexpected nil audit event") - } - - // confirm that the direct way of setting audit annotations later in the chain works as expected - audit.LogAnnotation(ae, "snorlax", "is cool too") - - // confirm that the indirect way of setting audit annotations later in the chain also works - audit.AddAuditAnnotation(r.Context(), "dogs", "are okay") - - if _, err := w.Write([]byte("done")); err != nil { - t.Errorf("failed to write response: %v", err) - } - }), c) - w := httptest.NewRecorder() - - h.ServeHTTP(w, httptest.NewRequest("GET", "https://ignored.com", nil)) - - r := w.Result() - if ok := r.StatusCode == http.StatusOK && w.Body.String() == "done" && len(r.Header.Get(auditinternal.HeaderAuditID)) > 0; !ok { - t.Errorf("invalid response: %#v", w) + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) } - if len(backend.events) == 0 { - t.Error("expected audit events, got none") + + if e, a := expectedBody, string(body); e != a { + t.Errorf("%q expected %v, got %v", url, e, a) } - // these should all be the same because the handler chain mutates the event in place - want := map[string]string{"pandas": "are awesome", "snorlax": "is cool too", "dogs": "are okay"} - for _, event := range backend.events { - if event.Stage != auditinternal.StageResponseComplete { - t.Errorf("expected event stage to be complete, got: %s", event.Stage) - } - if diff := cmp.Diff(want, event.Annotations); diff != "" { - t.Errorf("event has unexpected annotations (-want +got): %s", diff) - } + if e, a := expectedStatusCode, resp.StatusCode; e != a { + t.Errorf("%q expected %v, got %v", url, e, a) } } - -type testBackend struct { - events []*auditinternal.Event - - audit.Backend // nil panic if anything other than ProcessEvents called -} - -func (b *testBackend) ProcessEvents(events ...*auditinternal.Event) bool { - b.events = append(b.events, events...) - return true -} diff --git a/vendor/k8s.io/apiserver/pkg/server/deprecated_insecure_serving.go b/vendor/k8s.io/apiserver/pkg/server/deprecated_insecure_serving.go index 9419af9ed37..a78250edae9 100644 --- a/vendor/k8s.io/apiserver/pkg/server/deprecated_insecure_serving.go +++ b/vendor/k8s.io/apiserver/pkg/server/deprecated_insecure_serving.go @@ -29,8 +29,6 @@ import ( ) // DeprecatedInsecureServingInfo is the main context object for the insecure http server. -// HTTP does NOT include authentication or authorization. -// You shouldn't be using this. It makes sig-auth sad. type DeprecatedInsecureServingInfo struct { // Listener is the secure server network listener. Listener net.Listener @@ -52,9 +50,7 @@ func (s *DeprecatedInsecureServingInfo) Serve(handler http.Handler, shutdownTime } else { klog.Infof("Serving insecurely on %s", s.Listener.Addr()) } - _, err := RunServer(insecureServer, s.Listener, shutdownTimeout, stopCh) - // NOTE: we do not handle stoppedCh returned by RunServer for graceful termination here - return err + return RunServer(insecureServer, s.Listener, shutdownTimeout, stopCh) } func (s *DeprecatedInsecureServingInfo) NewLoopbackClientConfig() (*rest.Config, error) { diff --git a/vendor/k8s.io/apiserver/pkg/server/doc.go b/vendor/k8s.io/apiserver/pkg/server/doc.go index bc671eae844..b5f97c65857 100644 --- a/vendor/k8s.io/apiserver/pkg/server/doc.go +++ b/vendor/k8s.io/apiserver/pkg/server/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package server contains the plumbing to create kubernetes-like API server command. -package server // import "k8s.io/apiserver/pkg/server" +package server diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key.go deleted file mode 100644 index 114002b1a07..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" -) - -// CertKeyContentProvider provides a certificate and matching private key -type CertKeyContentProvider interface { - // Name is just an identifier - Name() string - // CurrentCertKeyContent provides cert and key byte content - CurrentCertKeyContent() ([]byte, []byte) -} - -// SNICertKeyContentProvider provides a certificate and matching private key as well as optional explicit names -type SNICertKeyContentProvider interface { - CertKeyContentProvider - // SNINames provides names used for SNI. May return nil. - SNINames() []string -} - -// certKeyContent holds the content for the cert and key -type certKeyContent struct { - cert []byte - key []byte -} - -func (c *certKeyContent) Equal(rhs *certKeyContent) bool { - if c == nil || rhs == nil { - return c == rhs - } - - return bytes.Equal(c.key, rhs.key) && bytes.Equal(c.cert, rhs.cert) -} - -// sniCertKeyContent holds the content for the cert and key as well as any explicit names -type sniCertKeyContent struct { - certKeyContent - sniNames []string -} - -func (c *sniCertKeyContent) Equal(rhs *sniCertKeyContent) bool { - if c == nil || rhs == nil { - return c == rhs - } - - if len(c.sniNames) != len(rhs.sniNames) { - return false - } - - for i := range c.sniNames { - if c.sniNames[i] != rhs.sniNames[i] { - return false - } - } - - return c.certKeyContent.Equal(&rhs.certKeyContent) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key_test.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key_test.go deleted file mode 100644 index 5c50557050d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/cert_key_test.go +++ /dev/null @@ -1,147 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "testing" -) - -func TestCertKeyContentEquals(t *testing.T) { - tests := []struct { - name string - lhs *certKeyContent - rhs *certKeyContent - expected bool - }{ - { - name: "both nil", - expected: true, - }, - { - name: "lhs nil", - rhs: &certKeyContent{}, - expected: false, - }, - { - name: "rhs nil", - lhs: &certKeyContent{}, - expected: false, - }, - { - name: "same", - lhs: &certKeyContent{cert: []byte("foo"), key: []byte("baz")}, - rhs: &certKeyContent{cert: []byte("foo"), key: []byte("baz")}, - expected: true, - }, - { - name: "different cert", - lhs: &certKeyContent{cert: []byte("foo"), key: []byte("baz")}, - rhs: &certKeyContent{cert: []byte("bar"), key: []byte("baz")}, - expected: false, - }, - { - name: "different key", - lhs: &certKeyContent{cert: []byte("foo"), key: []byte("baz")}, - rhs: &certKeyContent{cert: []byte("foo"), key: []byte("qux")}, - expected: false, - }, - { - name: "different cert and key", - lhs: &certKeyContent{cert: []byte("foo"), key: []byte("baz")}, - rhs: &certKeyContent{cert: []byte("bar"), key: []byte("qux")}, - expected: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := test.lhs.Equal(test.rhs) - if actual != test.expected { - t.Error(actual) - } - }) - } -} - -func TestSNICertKeyContentEquals(t *testing.T) { - tests := []struct { - name string - lhs *sniCertKeyContent - rhs *sniCertKeyContent - expected bool - }{ - { - name: "both nil", - expected: true, - }, - { - name: "lhs nil", - rhs: &sniCertKeyContent{}, - expected: false, - }, - { - name: "rhs nil", - lhs: &sniCertKeyContent{}, - expected: false, - }, - { - name: "same", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - expected: true, - }, - { - name: "different cert", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("bar"), key: []byte("baz")}, sniNames: []string{"a"}}, - expected: false, - }, - { - name: "different key", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("qux")}, sniNames: []string{"a"}}, - expected: false, - }, - { - name: "different cert and key", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("bar"), key: []byte("qux")}, sniNames: []string{"a"}}, - expected: false, - }, - { - name: "different names", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"b"}}, - expected: false, - }, - { - name: "extra names", - lhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a"}}, - rhs: &sniCertKeyContent{certKeyContent: certKeyContent{cert: []byte("foo"), key: []byte("baz")}, sniNames: []string{"a", "b"}}, - expected: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := test.lhs.Equal(test.rhs) - if actual != test.expected { - t.Error(actual) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca.go deleted file mode 100644 index 4348fa38784..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca.go +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/x509" -) - -// CAContentProvider provides ca bundle byte content -type CAContentProvider interface { - // Name is just an identifier - Name() string - // CurrentCABundleContent provides ca bundle byte content. Errors can be contained to the controllers initializing - // the value. By the time you get here, you should always be returning a value that won't fail. - CurrentCABundleContent() []byte - // VerifyOptions provides VerifyOptions for authenticators - VerifyOptions() (x509.VerifyOptions, bool) -} - -// dynamicCertificateContent holds the content that overrides the baseTLSConfig -type dynamicCertificateContent struct { - // clientCA holds the content for the clientCA bundle - clientCA caBundleContent - servingCert certKeyContent - sniCerts []sniCertKeyContent -} - -// caBundleContent holds the content for the clientCA bundle. Wrapping the bytes makes the Equals work nicely with the -// method receiver. -type caBundleContent struct { - caBundle []byte -} - -func (c *dynamicCertificateContent) Equal(rhs *dynamicCertificateContent) bool { - if c == nil || rhs == nil { - return c == rhs - } - - if !c.clientCA.Equal(&rhs.clientCA) { - return false - } - - if !c.servingCert.Equal(&rhs.servingCert) { - return false - } - - if len(c.sniCerts) != len(rhs.sniCerts) { - return false - } - - for i := range c.sniCerts { - if !c.sniCerts[i].Equal(&rhs.sniCerts[i]) { - return false - } - } - - return true -} - -func (c *caBundleContent) Equal(rhs *caBundleContent) bool { - if c == nil || rhs == nil { - return c == rhs - } - - return bytes.Equal(c.caBundle, rhs.caBundle) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca_test.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca_test.go deleted file mode 100644 index b72e3454e23..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/client_ca_test.go +++ /dev/null @@ -1,153 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import "testing" - -func TestDynamicCertificateContentEquals(t *testing.T) { - tests := []struct { - name string - lhs *dynamicCertificateContent - rhs *dynamicCertificateContent - expected bool - }{ - { - name: "both nil", - expected: true, - }, - { - name: "lhs nil", - rhs: &dynamicCertificateContent{}, - expected: false, - }, - { - name: "rhs nil", - lhs: &dynamicCertificateContent{}, - expected: false, - }, - { - name: "same", - lhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - }, - rhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - }, - expected: true, - }, - { - name: "different", - lhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - }, - rhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("bar")}, - }, - expected: false, - }, - { - name: "same with serving", - lhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("foo"), key: []byte("foo")}, - }, - rhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("foo"), key: []byte("foo")}, - }, - expected: true, - }, - { - name: "different serving cert", - lhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("foo"), key: []byte("foo")}, - }, - rhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("bar"), key: []byte("foo")}, - }, - expected: false, - }, - { - name: "different serving key", - lhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("foo"), key: []byte("foo")}, - }, - rhs: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("foo")}, - servingCert: certKeyContent{cert: []byte("foo"), key: []byte("bar")}, - }, - expected: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := test.lhs.Equal(test.rhs) - if actual != test.expected { - t.Error(actual) - } - }) - } -} - -func TestCABundleContentEquals(t *testing.T) { - tests := []struct { - name string - lhs *caBundleContent - rhs *caBundleContent - expected bool - }{ - { - name: "both nil", - expected: true, - }, - { - name: "lhs nil", - rhs: &caBundleContent{}, - expected: false, - }, - { - name: "rhs nil", - lhs: &caBundleContent{}, - expected: false, - }, - { - name: "same", - lhs: &caBundleContent{caBundle: []byte("foo")}, - rhs: &caBundleContent{caBundle: []byte("foo")}, - expected: true, - }, - { - name: "different", - lhs: &caBundleContent{caBundle: []byte("foo")}, - rhs: &caBundleContent{caBundle: []byte("bar")}, - expected: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := test.lhs.Equal(test.rhs) - if actual != test.expected { - t.Error(actual) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/configmap_cafile_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/configmap_cafile_content.go deleted file mode 100644 index 6000941b764..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/configmap_cafile_content.go +++ /dev/null @@ -1,274 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/x509" - "fmt" - "sync/atomic" - "time" - - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - corev1informers "k8s.io/client-go/informers/core/v1" - "k8s.io/client-go/kubernetes" - corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - "k8s.io/klog" -) - -// ConfigMapCAController provies a CAContentProvider that can dynamically react to configmap changes -// It also fulfills the authenticator interface to provide verifyoptions -type ConfigMapCAController struct { - name string - - configmapLister corev1listers.ConfigMapLister - configmapNamespace string - configmapName string - configmapKey string - // configMapInformer is tracked so that we can start these on Run - configMapInformer cache.SharedIndexInformer - - // caBundle is a caBundleAndVerifier that contains the last read, non-zero length content of the file - caBundle atomic.Value - - listeners []Listener - - queue workqueue.RateLimitingInterface - // preRunCaches are the caches to sync before starting the work of this control loop - preRunCaches []cache.InformerSynced -} - -var _ Notifier = &ConfigMapCAController{} -var _ CAContentProvider = &ConfigMapCAController{} -var _ ControllerRunner = &ConfigMapCAController{} - -// NewDynamicCAFromConfigMapController returns a CAContentProvider based on a configmap that automatically reloads content. -// It is near-realtime via an informer. -func NewDynamicCAFromConfigMapController(purpose, namespace, name, key string, kubeClient kubernetes.Interface) (*ConfigMapCAController, error) { - if len(purpose) == 0 { - return nil, fmt.Errorf("missing purpose for ca bundle") - } - if len(namespace) == 0 { - return nil, fmt.Errorf("missing namespace for ca bundle") - } - if len(name) == 0 { - return nil, fmt.Errorf("missing name for ca bundle") - } - if len(key) == 0 { - return nil, fmt.Errorf("missing key for ca bundle") - } - caContentName := fmt.Sprintf("%s::%s::%s::%s", purpose, namespace, name, key) - - // we construct our own informer because we need such a small subset of the information available. Just one namespace. - uncastConfigmapInformer := corev1informers.NewFilteredConfigMapInformer(kubeClient, namespace, 12*time.Hour, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, func(listOptions *v1.ListOptions) { - listOptions.FieldSelector = fields.OneTermEqualSelector("metadata.name", name).String() - }) - - configmapLister := corev1listers.NewConfigMapLister(uncastConfigmapInformer.GetIndexer()) - - c := &ConfigMapCAController{ - name: caContentName, - configmapNamespace: namespace, - configmapName: name, - configmapKey: key, - configmapLister: configmapLister, - configMapInformer: uncastConfigmapInformer, - - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("DynamicConfigMapCABundle-%s", purpose)), - preRunCaches: []cache.InformerSynced{uncastConfigmapInformer.HasSynced}, - } - - uncastConfigmapInformer.AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: func(obj interface{}) bool { - if cast, ok := obj.(*corev1.ConfigMap); ok { - return cast.Name == c.configmapName && cast.Namespace == c.configmapNamespace - } - if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok { - if cast, ok := tombstone.Obj.(*corev1.ConfigMap); ok { - return cast.Name == c.configmapName && cast.Namespace == c.configmapNamespace - } - } - return true // always return true just in case. The checks are fairly cheap - }, - Handler: cache.ResourceEventHandlerFuncs{ - // we have a filter, so any time we're called, we may as well queue. We only ever check one configmap - // so we don't have to be choosy about our key. - AddFunc: func(obj interface{}) { - c.queue.Add(c.keyFn()) - }, - UpdateFunc: func(oldObj, newObj interface{}) { - c.queue.Add(c.keyFn()) - }, - DeleteFunc: func(obj interface{}) { - c.queue.Add(c.keyFn()) - }, - }, - }) - - return c, nil -} - -func (c *ConfigMapCAController) keyFn() string { - // this format matches DeletionHandlingMetaNamespaceKeyFunc for our single key - return c.configmapNamespace + "/" + c.configmapName -} - -// AddListener adds a listener to be notified when the CA content changes. -func (c *ConfigMapCAController) AddListener(listener Listener) { - c.listeners = append(c.listeners, listener) -} - -// loadCABundle determines the next set of content for the file. -func (c *ConfigMapCAController) loadCABundle() error { - configMap, err := c.configmapLister.ConfigMaps(c.configmapNamespace).Get(c.configmapName) - if err != nil { - return err - } - caBundle := configMap.Data[c.configmapKey] - if len(caBundle) == 0 { - return fmt.Errorf("missing content for CA bundle %q", c.Name()) - } - - // check to see if we have a change. If the values are the same, do nothing. - if !c.hasCAChanged([]byte(caBundle)) { - return nil - } - - caBundleAndVerifier, err := newCABundleAndVerifier(c.Name(), []byte(caBundle)) - if err != nil { - return err - } - c.caBundle.Store(caBundleAndVerifier) - - for _, listener := range c.listeners { - listener.Enqueue() - } - - return nil -} - -// hasCAChanged returns true if the caBundle is different than the current. -func (c *ConfigMapCAController) hasCAChanged(caBundle []byte) bool { - uncastExisting := c.caBundle.Load() - if uncastExisting == nil { - return true - } - - // check to see if we have a change. If the values are the same, do nothing. - existing, ok := uncastExisting.(*caBundleAndVerifier) - if !ok { - return true - } - if !bytes.Equal(existing.caBundle, caBundle) { - return true - } - - return false -} - -// RunOnce runs a single sync loop -func (c *ConfigMapCAController) RunOnce() error { - // Ignore the error when running once because when using a dynamically loaded ca file, because we think it's better to have nothing for - // a brief time than completely crash. If crashing is necessary, higher order logic like a healthcheck and cause failures. - _ = c.loadCABundle() - return nil -} - -// Run starts the kube-apiserver and blocks until stopCh is closed. -func (c *ConfigMapCAController) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - - klog.Infof("Starting %s", c.name) - defer klog.Infof("Shutting down %s", c.name) - - // we have a personal informer that is narrowly scoped, start it. - go c.configMapInformer.Run(stopCh) - - // wait for your secondary caches to fill before starting your work - if !cache.WaitForNamedCacheSync(c.name, stopCh, c.preRunCaches...) { - return - } - - // doesn't matter what workers say, only start one. - go wait.Until(c.runWorker, time.Second, stopCh) - - // start timer that rechecks every minute, just in case. this also serves to prime the controller quickly. - go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) { - c.queue.Add(workItemKey) - return false, nil - }, stopCh) - - <-stopCh -} - -func (c *ConfigMapCAController) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *ConfigMapCAController) processNextWorkItem() bool { - dsKey, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(dsKey) - - err := c.loadCABundle() - if err == nil { - c.queue.Forget(dsKey) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) - c.queue.AddRateLimited(dsKey) - - return true -} - -// Name is just an identifier -func (c *ConfigMapCAController) Name() string { - return c.name -} - -// CurrentCABundleContent provides ca bundle byte content -func (c *ConfigMapCAController) CurrentCABundleContent() []byte { - uncastObj := c.caBundle.Load() - if uncastObj == nil { - return nil // this can happen if we've been unable load data from the apiserver for some reason - } - - return c.caBundle.Load().(*caBundleAndVerifier).caBundle -} - -// VerifyOptions provides verifyoptions compatible with authenticators -func (c *ConfigMapCAController) VerifyOptions() (x509.VerifyOptions, bool) { - uncastObj := c.caBundle.Load() - if uncastObj == nil { - // This can happen if we've been unable load data from the apiserver for some reason. - // In this case, we should not accept any connections on the basis of this ca bundle. - return x509.VerifyOptions{}, false - } - - return uncastObj.(*caBundleAndVerifier).verifyOptions, true -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go deleted file mode 100644 index 8a2a5e2b799..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go +++ /dev/null @@ -1,255 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/x509" - "fmt" - "io/ioutil" - "sync/atomic" - "time" - - "k8s.io/client-go/util/cert" - - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/util/workqueue" - "k8s.io/klog" -) - -// FileRefreshDuration is exposed so that integration tests can crank up the reload speed. -var FileRefreshDuration = 1 * time.Minute - -// Listener is an interface to use to notify interested parties of a change. -type Listener interface { - // Enqueue should be called when an input may have changed - Enqueue() -} - -// Notifier is a way to add listeners -type Notifier interface { - // AddListener is adds a listener to be notified of potential input changes - AddListener(listener Listener) -} - -// ControllerRunner is a generic interface for starting a controller -type ControllerRunner interface { - // RunOnce runs the sync loop a single time. This useful for synchronous priming - RunOnce() error - - // Run should be called a go .Run - Run(workers int, stopCh <-chan struct{}) -} - -// DynamicFileCAContent provies a CAContentProvider that can dynamically react to new file content -// It also fulfills the authenticator interface to provide verifyoptions -type DynamicFileCAContent struct { - name string - - // filename is the name the file to read. - filename string - - // caBundle is a caBundleAndVerifier that contains the last read, non-zero length content of the file - caBundle atomic.Value - - listeners []Listener - - // queue only ever has one item, but it has nice error handling backoff/retry semantics - queue workqueue.RateLimitingInterface -} - -var _ Notifier = &DynamicFileCAContent{} -var _ CAContentProvider = &DynamicFileCAContent{} -var _ ControllerRunner = &DynamicFileCAContent{} - -type caBundleAndVerifier struct { - caBundle []byte - verifyOptions x509.VerifyOptions -} - -// NewDynamicCAContentFromFile returns a CAContentProvider based on a filename that automatically reloads content -func NewDynamicCAContentFromFile(purpose, filename string) (*DynamicFileCAContent, error) { - if len(filename) == 0 { - return nil, fmt.Errorf("missing filename for ca bundle") - } - name := fmt.Sprintf("%s::%s", purpose, filename) - - ret := &DynamicFileCAContent{ - name: name, - filename: filename, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("DynamicCABundle-%s", purpose)), - } - if err := ret.loadCABundle(); err != nil { - return nil, err - } - - return ret, nil -} - -// AddListener adds a listener to be notified when the CA content changes. -func (c *DynamicFileCAContent) AddListener(listener Listener) { - c.listeners = append(c.listeners, listener) -} - -// loadCABundle determines the next set of content for the file. -func (c *DynamicFileCAContent) loadCABundle() error { - caBundle, err := ioutil.ReadFile(c.filename) - if err != nil { - return err - } - if len(caBundle) == 0 { - return fmt.Errorf("missing content for CA bundle %q", c.Name()) - } - - // check to see if we have a change. If the values are the same, do nothing. - if !c.hasCAChanged(caBundle) { - return nil - } - - caBundleAndVerifier, err := newCABundleAndVerifier(c.Name(), caBundle) - if err != nil { - return err - } - c.caBundle.Store(caBundleAndVerifier) - klog.V(2).Infof("Loaded a new CA Bundle and Verifier for %q", c.Name()) - - for _, listener := range c.listeners { - listener.Enqueue() - } - - return nil -} - -// hasCAChanged returns true if the caBundle is different than the current. -func (c *DynamicFileCAContent) hasCAChanged(caBundle []byte) bool { - uncastExisting := c.caBundle.Load() - if uncastExisting == nil { - return true - } - - // check to see if we have a change. If the values are the same, do nothing. - existing, ok := uncastExisting.(*caBundleAndVerifier) - if !ok { - return true - } - if !bytes.Equal(existing.caBundle, caBundle) { - return true - } - - return false -} - -// RunOnce runs a single sync loop -func (c *DynamicFileCAContent) RunOnce() error { - return c.loadCABundle() -} - -// Run starts the kube-apiserver and blocks until stopCh is closed. -func (c *DynamicFileCAContent) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - - klog.Infof("Starting %s", c.name) - defer klog.Infof("Shutting down %s", c.name) - - // doesn't matter what workers say, only start one. - go wait.Until(c.runWorker, time.Second, stopCh) - - // start timer that rechecks every minute, just in case. this also serves to prime the controller quickly. - go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) { - c.queue.Add(workItemKey) - return false, nil - }, stopCh) - - // TODO this can be wired to an fsnotifier as well. - - <-stopCh -} - -func (c *DynamicFileCAContent) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *DynamicFileCAContent) processNextWorkItem() bool { - dsKey, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(dsKey) - - err := c.loadCABundle() - if err == nil { - c.queue.Forget(dsKey) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) - c.queue.AddRateLimited(dsKey) - - return true -} - -// Name is just an identifier -func (c *DynamicFileCAContent) Name() string { - return c.name -} - -// CurrentCABundleContent provides ca bundle byte content -func (c *DynamicFileCAContent) CurrentCABundleContent() (cabundle []byte) { - return c.caBundle.Load().(*caBundleAndVerifier).caBundle -} - -// VerifyOptions provides verifyoptions compatible with authenticators -func (c *DynamicFileCAContent) VerifyOptions() (x509.VerifyOptions, bool) { - uncastObj := c.caBundle.Load() - if uncastObj == nil { - return x509.VerifyOptions{}, false - } - - return uncastObj.(*caBundleAndVerifier).verifyOptions, true -} - -// newVerifyOptions creates a new verification func from a file. It reads the content and then fails. -// It will return a nil function if you pass an empty CA file. -func newCABundleAndVerifier(name string, caBundle []byte) (*caBundleAndVerifier, error) { - if len(caBundle) == 0 { - return nil, fmt.Errorf("missing content for CA bundle %q", name) - } - - // Wrap with an x509 verifier - var err error - verifyOptions := defaultVerifyOptions() - verifyOptions.Roots, err = cert.NewPoolFromBytes(caBundle) - if err != nil { - return nil, fmt.Errorf("error loading CA bundle for %q: %v", name, err) - } - - return &caBundleAndVerifier{ - caBundle: caBundle, - verifyOptions: verifyOptions, - }, nil -} - -// defaultVerifyOptions returns VerifyOptions that use the system root certificates, current time, -// and requires certificates to be valid for client auth (x509.ExtKeyUsageClientAuth) -func defaultVerifyOptions() x509.VerifyOptions { - return x509.VerifyOptions{ - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go deleted file mode 100644 index 5b63f708972..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "crypto/tls" - "fmt" - "io/ioutil" - "sync/atomic" - "time" - - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/util/workqueue" - "k8s.io/klog" -) - -// DynamicCertKeyPairContent provides a CertKeyContentProvider that can dynamically react to new file content -type DynamicCertKeyPairContent struct { - name string - - // certFile is the name of the certificate file to read. - certFile string - // keyFile is the name of the key file to read. - keyFile string - - // servingCert is a certKeyContent that contains the last read, non-zero length content of the key and cert - certKeyPair atomic.Value - - listeners []Listener - - // queue only ever has one item, but it has nice error handling backoff/retry semantics - queue workqueue.RateLimitingInterface -} - -var _ Notifier = &DynamicCertKeyPairContent{} -var _ CertKeyContentProvider = &DynamicCertKeyPairContent{} -var _ ControllerRunner = &DynamicCertKeyPairContent{} - -// NewDynamicServingContentFromFiles returns a dynamic CertKeyContentProvider based on a cert and key filename -func NewDynamicServingContentFromFiles(purpose, certFile, keyFile string) (*DynamicCertKeyPairContent, error) { - if len(certFile) == 0 || len(keyFile) == 0 { - return nil, fmt.Errorf("missing filename for serving cert") - } - name := fmt.Sprintf("%s::%s::%s", purpose, certFile, keyFile) - - ret := &DynamicCertKeyPairContent{ - name: name, - certFile: certFile, - keyFile: keyFile, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("DynamicCABundle-%s", purpose)), - } - if err := ret.loadCertKeyPair(); err != nil { - return nil, err - } - - return ret, nil -} - -// AddListener adds a listener to be notified when the serving cert content changes. -func (c *DynamicCertKeyPairContent) AddListener(listener Listener) { - c.listeners = append(c.listeners, listener) -} - -// loadServingCert determines the next set of content for the file. -func (c *DynamicCertKeyPairContent) loadCertKeyPair() error { - cert, err := ioutil.ReadFile(c.certFile) - if err != nil { - return err - } - key, err := ioutil.ReadFile(c.keyFile) - if err != nil { - return err - } - if len(cert) == 0 || len(key) == 0 { - return fmt.Errorf("missing content for serving cert %q", c.Name()) - } - - // Ensure that the key matches the cert and both are valid - _, err = tls.X509KeyPair(cert, key) - if err != nil { - return err - } - - newCertKey := &certKeyContent{ - cert: cert, - key: key, - } - - // check to see if we have a change. If the values are the same, do nothing. - existing, ok := c.certKeyPair.Load().(*certKeyContent) - if ok && existing != nil && existing.Equal(newCertKey) { - return nil - } - - c.certKeyPair.Store(newCertKey) - klog.V(2).Infof("Loaded a new cert/key pair for %q", c.Name()) - - for _, listener := range c.listeners { - listener.Enqueue() - } - - return nil -} - -// RunOnce runs a single sync loop -func (c *DynamicCertKeyPairContent) RunOnce() error { - return c.loadCertKeyPair() -} - -// Run starts the controller and blocks until stopCh is closed. -func (c *DynamicCertKeyPairContent) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - - klog.Infof("Starting %s", c.name) - defer klog.Infof("Shutting down %s", c.name) - - // doesn't matter what workers say, only start one. - go wait.Until(c.runWorker, time.Second, stopCh) - - // start timer that rechecks every minute, just in case. this also serves to prime the controller quickly. - go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) { - c.queue.Add(workItemKey) - return false, nil - }, stopCh) - - // TODO this can be wired to an fsnotifier as well. - - <-stopCh -} - -func (c *DynamicCertKeyPairContent) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *DynamicCertKeyPairContent) processNextWorkItem() bool { - dsKey, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(dsKey) - - err := c.loadCertKeyPair() - if err == nil { - c.queue.Forget(dsKey) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) - c.queue.AddRateLimited(dsKey) - - return true -} - -// Name is just an identifier -func (c *DynamicCertKeyPairContent) Name() string { - return c.name -} - -// CurrentCertKeyContent provides cert and key byte content -func (c *DynamicCertKeyPairContent) CurrentCertKeyContent() ([]byte, []byte) { - certKeyContent := c.certKeyPair.Load().(*certKeyContent) - return certKeyContent.cert, certKeyContent.key -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_sni_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_sni_content.go deleted file mode 100644 index 161fa1ca759..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_sni_content.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -// DynamicFileSNIContent provides a SNICertKeyContentProvider that can dynamically react to new file content -type DynamicFileSNIContent struct { - *DynamicCertKeyPairContent - sniNames []string -} - -var _ Notifier = &DynamicFileSNIContent{} -var _ SNICertKeyContentProvider = &DynamicFileSNIContent{} -var _ ControllerRunner = &DynamicFileSNIContent{} - -// NewDynamicSNIContentFromFiles returns a dynamic SNICertKeyContentProvider based on a cert and key filename and explicit names -func NewDynamicSNIContentFromFiles(purpose, certFile, keyFile string, sniNames ...string) (*DynamicFileSNIContent, error) { - servingContent, err := NewDynamicServingContentFromFiles(purpose, certFile, keyFile) - if err != nil { - return nil, err - } - - ret := &DynamicFileSNIContent{ - DynamicCertKeyPairContent: servingContent, - sniNames: sniNames, - } - if err := ret.loadCertKeyPair(); err != nil { - return nil, err - } - - return ret, nil -} - -// SNINames returns explicitly set SNI names for the certificate. These are not dynamic. -func (c *DynamicFileSNIContent) SNINames() []string { - return c.sniNames -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates.go deleted file mode 100644 index 90a67f7b211..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "net" - "strings" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/klog" -) - -// BuildNamedCertificates returns a map of *tls.Certificate by name. It's -// suitable for use in tls.Config#NamedCertificates. Returns an error if any of the certs -// is invalid. Returns nil if len(certs) == 0 -func (c *DynamicServingCertificateController) BuildNamedCertificates(sniCerts []sniCertKeyContent) (map[string]*tls.Certificate, error) { - nameToCertificate := map[string]*tls.Certificate{} - byNameExplicit := map[string]*tls.Certificate{} - - // Iterate backwards so that earlier certs take precedence in the names map - for i := len(sniCerts) - 1; i >= 0; i-- { - cert, err := tls.X509KeyPair(sniCerts[i].cert, sniCerts[i].key) - if err != nil { - return nil, fmt.Errorf("invalid SNI cert keypair [%d/%q]: %v", i, c.sniCerts[i].Name(), err) - } - - // error is not possible given above call to X509KeyPair - x509Cert, _ := x509.ParseCertificate(cert.Certificate[0]) - - names := sniCerts[i].sniNames - for _, name := range names { - byNameExplicit[name] = &cert - } - - klog.V(2).Infof("loaded SNI cert [%d/%q]: %s", i, c.sniCerts[i].Name(), GetHumanCertDetail(x509Cert)) - if c.eventRecorder != nil { - c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.sniCerts[i].Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "SNICertificateReload", "loaded SNI cert [%d/%q]: %s with explicit names %v", i, c.sniCerts[i].Name(), GetHumanCertDetail(x509Cert), names) - } - - if len(names) == 0 { - names = getCertificateNames(x509Cert) - for _, name := range names { - nameToCertificate[name] = &cert - } - } - } - - // Explicitly set names must override - for k, v := range byNameExplicit { - nameToCertificate[k] = v - } - - return nameToCertificate, nil -} - -// getCertificateNames returns names for an x509.Certificate. The names are -// suitable for use in tls.Config#NamedCertificates. -func getCertificateNames(cert *x509.Certificate) []string { - var names []string - - cn := cert.Subject.CommonName - cnIsIP := net.ParseIP(cn) != nil - cnIsValidDomain := cn == "*" || len(validation.IsDNS1123Subdomain(strings.TrimPrefix(cn, "*."))) == 0 - // don't use the CN if it is a valid IP because our IP serving detection may unexpectedly use it to terminate the connection. - if !cnIsIP && cnIsValidDomain { - names = append(names, cn) - } - for _, san := range cert.DNSNames { - names = append(names, san) - } - // intentionally all IPs in the cert are ignored as SNI forbids passing IPs - // to select a cert. Before go 1.6 the tls happily passed IPs as SNI values. - - return names -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates_test.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates_test.go deleted file mode 100644 index 56848723337..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates_test.go +++ /dev/null @@ -1,332 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/pem" - "fmt" - "math/big" - "net" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -type testCertSpec struct { - host string - names, ips []string // in certificate -} - -type namedtestCertSpec struct { - testCertSpec - explicitNames []string // as --tls-sni-cert-key explicit names -} - -func TestBuiltNamedCertificates(t *testing.T) { - tests := []struct { - certs []namedtestCertSpec - explicitNames []string - expected map[string]int // name to certs[*] index - errorString string - }{ - { - // empty certs - expected: map[string]int{}, - }, - { - // only one cert - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "test.com", - }, - }, - }, - expected: map[string]int{ - "test.com": 0, - }, - }, - { - // ip as cns are ignored - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "1.2.3.4", - names: []string{"test.com"}, - }, - }, - }, - expected: map[string]int{ - "test.com": 0, - }, - }, - { - // ips are ignored - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "test.com", - ips: []string{"1.2.3.4"}, - }, - }, - }, - expected: map[string]int{ - "test.com": 0, - }, - }, - { - // two certs with the same name - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "test.com", - }, - }, - { - testCertSpec: testCertSpec{ - host: "test.com", - }, - }, - }, - expected: map[string]int{ - "test.com": 0, - }, - }, - { - // two certs with different names - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "test2.com", - }, - }, - { - testCertSpec: testCertSpec{ - host: "test1.com", - }, - }, - }, - expected: map[string]int{ - "test1.com": 1, - "test2.com": 0, - }, - }, - { - // two certs with the same name, explicit trumps - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "test.com", - }, - }, - { - testCertSpec: testCertSpec{ - host: "test.com", - }, - explicitNames: []string{"test.com"}, - }, - }, - expected: map[string]int{ - "test.com": 1, - }, - }, - { - // certs with partial overlap; ips are ignored - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "a", - names: []string{"a.test.com", "test.com"}, - }, - }, - { - testCertSpec: testCertSpec{ - host: "b", - names: []string{"b.test.com", "test.com"}, - }, - }, - }, - expected: map[string]int{ - "a": 0, "b": 1, - "a.test.com": 0, "b.test.com": 1, - "test.com": 0, - }, - }, - { - // wildcards - certs: []namedtestCertSpec{ - { - testCertSpec: testCertSpec{ - host: "a", - names: []string{"a.test.com", "test.com"}, - }, - explicitNames: []string{"*.test.com", "test.com"}, - }, - { - testCertSpec: testCertSpec{ - host: "b", - names: []string{"b.test.com", "test.com"}, - }, - explicitNames: []string{"dev.test.com", "test.com"}, - }}, - expected: map[string]int{ - "test.com": 0, - "*.test.com": 0, - "dev.test.com": 1, - }, - }, - } - -NextTest: - for i, test := range tests { - var sniCerts []SNICertKeyContentProvider - bySignature := map[string]int{} // index in test.certs by cert signature - for j, c := range test.certs { - certProvider, err := createTestTLSCerts(c.testCertSpec, c.explicitNames) - if err != nil { - t.Errorf("%d - failed to create cert %d: %v", i, j, err) - continue NextTest - } - - sniCerts = append(sniCerts, certProvider) - - sig, err := certSignature(certProvider) - if err != nil { - t.Errorf("%d - failed to get signature for %d: %v", i, j, err) - continue NextTest - } - bySignature[sig] = j - } - - c := DynamicServingCertificateController{sniCerts: sniCerts} - content, err := c.newTLSContent() - assert.NoError(t, err) - - certMap, err := c.BuildNamedCertificates(content.sniCerts) - if err == nil && len(test.errorString) != 0 { - t.Errorf("%d - expected no error, got: %v", i, err) - } else if err != nil && err.Error() != test.errorString { - t.Errorf("%d - expected error %q, got: %v", i, test.errorString, err) - } else { - got := map[string]int{} - for name, cert := range certMap { - x509Certs, err := x509.ParseCertificates(cert.Certificate[0]) - assert.NoError(t, err, "%d - invalid certificate for %q", i, name) - assert.True(t, len(x509Certs) > 0, "%d - expected at least one x509 cert in tls cert for %q", i, name) - got[name] = bySignature[x509CertSignature(x509Certs[0])] - } - - assert.EqualValues(t, test.expected, got, "%d - wrong certificate map", i) - } - } -} - -func parseIPList(ips []string) []net.IP { - var netIPs []net.IP - for _, ip := range ips { - netIPs = append(netIPs, net.ParseIP(ip)) - } - return netIPs -} - -func createTestTLSCerts(spec testCertSpec, names []string) (certProvider SNICertKeyContentProvider, err error) { - certPem, keyPem, err := generateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names) - if err != nil { - return nil, err - } - - return NewStaticSNICertKeyContent("test-cert", certPem, keyPem, names...) -} - -func x509CertSignature(cert *x509.Certificate) string { - return base64.StdEncoding.EncodeToString(cert.Signature) -} - -func certSignature(certProvider CertKeyContentProvider) (string, error) { - currentCert, currentKey := certProvider.CurrentCertKeyContent() - - tlsCert, err := tls.X509KeyPair(currentCert, currentKey) - if err != nil { - return "", err - } - - x509Certs, err := x509.ParseCertificates(tlsCert.Certificate[0]) - if err != nil { - return "", err - } - return x509CertSignature(x509Certs[0]), nil -} - -// generateSelfSignedCertKey creates a self-signed certificate and key for the given host. -// Host may be an IP or a DNS name -// You may also specify additional subject alt names (either ip or dns names) for the certificate -func generateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) { - priv, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - return nil, nil, err - } - - template := x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), - }, - NotBefore: time.Unix(0, 0), - NotAfter: time.Now().Add(time.Hour * 24 * 365 * 100), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - IsCA: true, - } - - if ip := net.ParseIP(host); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, host) - } - - template.IPAddresses = append(template.IPAddresses, alternateIPs...) - template.DNSNames = append(template.DNSNames, alternateDNS...) - - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - return nil, nil, err - } - - // Generate cert - certBuffer := bytes.Buffer{} - if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { - return nil, nil, err - } - - // Generate key - keyBuffer := bytes.Buffer{} - if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { - return nil, nil, err - } - - return certBuffer.Bytes(), keyBuffer.Bytes(), nil -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/server_test.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/server_test.go deleted file mode 100644 index 4a1a9761040..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/server_test.go +++ /dev/null @@ -1,218 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/tls" - "crypto/x509" - "fmt" - "net" - "net/http" - "strings" - "testing" - "time" - - "k8s.io/client-go/util/cert" -) - -func TestServingCert(t *testing.T) { - tlsConfig := &tls.Config{ - // Can't use SSLv3 because of POODLE and BEAST - // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher - // Can't use TLSv1.1 because of RC4 cipher usage - MinVersion: tls.VersionTLS12, - // enable HTTP2 for go's 1.7 HTTP Server - NextProtos: []string{"h2", "http/1.1"}, - } - - defaultCertProvider, err := createTestTLSCerts(testCertSpec{ - host: "172.30.0.1", - ips: []string{"172.30.0.1"}, - names: []string{"kubernetes", "kubernetes.default.svc.cluster.local"}, - }, nil) - if err != nil { - t.Fatal(err) - } - - var sniCerts []SNICertKeyContentProvider - certSpecs := []testCertSpec{ - { - host: "172.30.0.1", - ips: []string{"172.30.0.1"}, - names: []string{"openshift", "openshift.default.svc.cluster.local"}, - }, - { - host: "127.0.0.1", - ips: []string{"127.0.0.1"}, - names: []string{"localhost"}, - }, - { - host: "2001:abcd:bcda::1", - ips: []string{"2001:abcd:bcda::1"}, - names: []string{"openshiftv6", "openshiftv6.default.svc.cluster.local"}, - }, - } - - for _, certSpec := range certSpecs { - names := append([]string{}, certSpec.ips...) - names = append(names, certSpec.names...) - certProvider, err := createTestTLSCerts(certSpec, names) - if err != nil { - t.Fatal(err) - } - sniCerts = append(sniCerts, certProvider) - } - - dynamicCertificateController := NewDynamicServingCertificateController( - tlsConfig, - &nullCAContent{name: "client-ca"}, - defaultCertProvider, - sniCerts, - nil, // TODO see how to plumb an event recorder down in here. For now this results in simply klog messages. - ) - if err := dynamicCertificateController.RunOnce(); err != nil { - t.Fatal(err) - } - tlsConfig.GetConfigForClient = dynamicCertificateController.GetConfigForClient - tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { return nil, fmt.Errorf("positive failure") } - - stopCh := make(chan struct{}) - defer close(stopCh) - server := &http.Server{ - Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - w.WriteHeader(http.StatusOK) - }), - MaxHeaderBytes: 1 << 20, - TLSConfig: tlsConfig, - } - listener, _, err := createListener("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - apiPort := listener.Addr().String() - go func() { - t.Logf("listening on %s", listener.Addr().String()) - listener = tls.NewListener(listener, server.TLSConfig) - if err := server.ServeTLS(listener, "", ""); err != nil { - t.Error(err) - panic(err) - } - - <-stopCh - server.Close() - t.Logf("stopped listening on %s", listener.Addr().String()) - }() - - time.Sleep(1 * time.Second) - - expectedDefaultCertBytes, _ := defaultCertProvider.CurrentCertKeyContent() - expectedServiceCertBytes, _ := sniCerts[0].CurrentCertKeyContent() - expectedLocalhostCertBytes, _ := sniCerts[1].CurrentCertKeyContent() - expectedServiceV6CertBytes, _ := sniCerts[2].CurrentCertKeyContent() - - tests := []struct { - name string - serverName string - expected []byte - }{ - { - name: "default", // the no server name hits 127.0.0.1, which we hope matches by IP - serverName: "", - expected: []byte(strings.TrimSpace(string(expectedLocalhostCertBytes))), - }, - { - name: "invalid", - serverName: "not-marked", - expected: []byte(strings.TrimSpace(string(expectedDefaultCertBytes))), - }, - { - name: "service by dns", - serverName: "openshift", - expected: []byte(strings.TrimSpace(string(expectedServiceCertBytes))), - }, - { - name: "service v6 by dns", - serverName: "openshiftv6", - expected: []byte(strings.TrimSpace(string(expectedServiceV6CertBytes))), - }, - { - name: "localhost by dns", - serverName: "localhost", - expected: []byte(strings.TrimSpace(string(expectedLocalhostCertBytes))), - }, - { - name: "localhost by IP", - serverName: "127.0.0.1", // this can never actually happen, but let's see - expected: []byte(strings.TrimSpace(string(expectedLocalhostCertBytes))), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - _, actualDefaultCertBytes, err := cert.GetServingCertificates(apiPort, test.serverName) - if err != nil { - t.Fatal(err) - } - if e, a := test.expected, actualDefaultCertBytes[0]; !bytes.Equal(e, a) { - eCert, _ := cert.ParseCertsPEM(e) - aCert, _ := cert.ParseCertsPEM(a) - t.Fatalf("expected %v\n, got %v", GetHumanCertDetail(eCert[0]), GetHumanCertDetail(aCert[0])) - } - }) - } - -} - -func createListener(network, addr string) (net.Listener, int, error) { - if len(network) == 0 { - network = "tcp" - } - ln, err := net.Listen(network, addr) - if err != nil { - return nil, 0, fmt.Errorf("failed to listen on %v: %v", addr, err) - } - - // get port - tcpAddr, ok := ln.Addr().(*net.TCPAddr) - if !ok { - ln.Close() - return nil, 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String()) - } - - return ln, tcpAddr.Port, nil -} - -type nullCAContent struct { - name string -} - -var _ CAContentProvider = &nullCAContent{} - -// Name is just an identifier -func (c *nullCAContent) Name() string { - return c.name -} - -// CurrentCABundleContent provides ca bundle byte content -func (c *nullCAContent) CurrentCABundleContent() (cabundle []byte) { - return nil -} - -func (c *nullCAContent) VerifyOptions() (x509.VerifyOptions, bool) { - return x509.VerifyOptions{}, false -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/static_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/static_content.go deleted file mode 100644 index c877dfe6c6c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/static_content.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "crypto/tls" - "crypto/x509" -) - -type staticCAContent struct { - name string - caBundle *caBundleAndVerifier -} - -var _ CAContentProvider = &staticCAContent{} - -// NewStaticCAContent returns a CAContentProvider that always returns the same value -func NewStaticCAContent(name string, caBundle []byte) (CAContentProvider, error) { - caBundleAndVerifier, err := newCABundleAndVerifier(name, caBundle) - if err != nil { - return nil, err - } - - return &staticCAContent{ - name: name, - caBundle: caBundleAndVerifier, - }, nil -} - -// Name is just an identifier -func (c *staticCAContent) Name() string { - return c.name -} - -// CurrentCABundleContent provides ca bundle byte content -func (c *staticCAContent) CurrentCABundleContent() (cabundle []byte) { - return c.caBundle.caBundle -} - -func (c *staticCAContent) VerifyOptions() (x509.VerifyOptions, bool) { - return c.caBundle.verifyOptions, true -} - -type staticCertKeyContent struct { - name string - cert []byte - key []byte -} - -type staticSNICertKeyContent struct { - staticCertKeyContent - sniNames []string -} - -// NewStaticCertKeyContent returns a CertKeyContentProvider that always returns the same value -func NewStaticCertKeyContent(name string, cert, key []byte) (CertKeyContentProvider, error) { - // Ensure that the key matches the cert and both are valid - _, err := tls.X509KeyPair(cert, key) - if err != nil { - return nil, err - } - - return &staticCertKeyContent{ - name: name, - cert: cert, - key: key, - }, nil -} - -// NewStaticSNICertKeyContent returns a SNICertKeyContentProvider that always returns the same value -func NewStaticSNICertKeyContent(name string, cert, key []byte, sniNames ...string) (SNICertKeyContentProvider, error) { - // Ensure that the key matches the cert and both are valid - _, err := tls.X509KeyPair(cert, key) - if err != nil { - return nil, err - } - - return &staticSNICertKeyContent{ - staticCertKeyContent: staticCertKeyContent{ - name: name, - cert: cert, - key: key, - }, - sniNames: sniNames, - }, nil -} - -// Name is just an identifier -func (c *staticCertKeyContent) Name() string { - return c.name -} - -// CurrentCertKeyContent provides cert and key content -func (c *staticCertKeyContent) CurrentCertKeyContent() ([]byte, []byte) { - return c.cert, c.key -} - -func (c *staticSNICertKeyContent) SNINames() []string { - return c.sniNames -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig.go deleted file mode 100644 index aef0710b5b9..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig.go +++ /dev/null @@ -1,284 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "net" - "sync/atomic" - "time" - - corev1 "k8s.io/api/core/v1" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/tools/events" - "k8s.io/client-go/util/cert" - "k8s.io/client-go/util/workqueue" - "k8s.io/klog" -) - -const workItemKey = "key" - -// DynamicServingCertificateController dynamically loads certificates and provides a golang tls compatible dynamic GetCertificate func. -type DynamicServingCertificateController struct { - // baseTLSConfig is the static portion of the tlsConfig for serving to clients. It is copied and the copy is mutated - // based on the dynamic cert state. - baseTLSConfig *tls.Config - - // clientCA provides the very latest content of the ca bundle - clientCA CAContentProvider - // servingCert provides the very latest content of the default serving certificate - servingCert CertKeyContentProvider - // sniCerts are a list of CertKeyContentProvider with associated names used for SNI - sniCerts []SNICertKeyContentProvider - - // currentlyServedContent holds the original bytes that we are serving. This is used to decide if we need to set a - // new atomic value. The types used for efficient TLSConfig preclude using the processed value. - currentlyServedContent *dynamicCertificateContent - // currentServingTLSConfig holds a *tls.Config that will be used to serve requests - currentServingTLSConfig atomic.Value - - // queue only ever has one item, but it has nice error handling backoff/retry semantics - queue workqueue.RateLimitingInterface - eventRecorder events.EventRecorder -} - -var _ Listener = &DynamicServingCertificateController{} - -// NewDynamicServingCertificateController returns a controller that can be used to keep a TLSConfig up to date. -func NewDynamicServingCertificateController( - baseTLSConfig *tls.Config, - clientCA CAContentProvider, - servingCert CertKeyContentProvider, - sniCerts []SNICertKeyContentProvider, - eventRecorder events.EventRecorder, -) *DynamicServingCertificateController { - c := &DynamicServingCertificateController{ - baseTLSConfig: baseTLSConfig, - clientCA: clientCA, - servingCert: servingCert, - sniCerts: sniCerts, - - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "DynamicServingCertificateController"), - eventRecorder: eventRecorder, - } - - return c -} - -// GetConfigForClient is an implementation of tls.Config.GetConfigForClient -func (c *DynamicServingCertificateController) GetConfigForClient(clientHello *tls.ClientHelloInfo) (*tls.Config, error) { - uncastObj := c.currentServingTLSConfig.Load() - if uncastObj == nil { - return nil, errors.New("dynamiccertificates: configuration not ready") - } - tlsConfig, ok := uncastObj.(*tls.Config) - if !ok { - return nil, errors.New("dynamiccertificates: unexpected config type") - } - - tlsConfigCopy := tlsConfig.Clone() - - // if the client set SNI information, just use our "normal" SNI flow - if len(clientHello.ServerName) > 0 { - return tlsConfigCopy, nil - } - - // if the client didn't set SNI, then we need to inspect the requested IP so that we can choose - // a certificate from our list if we specifically handle that IP. This can happen when an IP is specifically mapped by name. - host, _, err := net.SplitHostPort(clientHello.Conn.LocalAddr().String()) - if err != nil { - return tlsConfigCopy, nil - } - - ipCert, ok := tlsConfigCopy.NameToCertificate[host] - if !ok { - return tlsConfigCopy, nil - } - tlsConfigCopy.Certificates = []tls.Certificate{*ipCert} - tlsConfigCopy.NameToCertificate = nil - - return tlsConfigCopy, nil -} - -// newTLSContent determines the next set of content for overriding the baseTLSConfig. -func (c *DynamicServingCertificateController) newTLSContent() (*dynamicCertificateContent, error) { - newContent := &dynamicCertificateContent{} - - if c.clientCA != nil { - currClientCABundle := c.clientCA.CurrentCABundleContent() - // we allow removing all client ca bundles because the server is still secure when this happens. it just means - // that there isn't a hint to clients about which client-cert to used. this happens when there is no client-ca - // yet known for authentication, which can happen in aggregated apiservers and some kube-apiserver deployment modes. - newContent.clientCA = caBundleContent{caBundle: currClientCABundle} - } - - if c.servingCert != nil { - currServingCert, currServingKey := c.servingCert.CurrentCertKeyContent() - if len(currServingCert) == 0 || len(currServingKey) == 0 { - return nil, fmt.Errorf("not loading an empty serving certificate from %q", c.servingCert.Name()) - } - - newContent.servingCert = certKeyContent{cert: currServingCert, key: currServingKey} - } - - for i, sniCert := range c.sniCerts { - currCert, currKey := sniCert.CurrentCertKeyContent() - if len(currCert) == 0 || len(currKey) == 0 { - return nil, fmt.Errorf("not loading an empty SNI certificate from %d/%q", i, sniCert.Name()) - } - - newContent.sniCerts = append(newContent.sniCerts, sniCertKeyContent{certKeyContent: certKeyContent{cert: currCert, key: currKey}, sniNames: sniCert.SNINames()}) - } - - return newContent, nil -} - -// syncCerts gets newTLSContent, if it has changed from the existing, the content is parsed and stored for usage in -// GetConfigForClient. -func (c *DynamicServingCertificateController) syncCerts() error { - newContent, err := c.newTLSContent() - if err != nil { - return err - } - // if the content is the same as what we currently have, we can simply skip it. This works because we are single - // threaded. If you ever make this multi-threaded, add a lock. - if newContent.Equal(c.currentlyServedContent) { - return nil - } - - // make a shallow copy and override the dynamic pieces which have changed. - newTLSConfigCopy := c.baseTLSConfig.Clone() - - // parse new content to add to TLSConfig - if len(newContent.clientCA.caBundle) > 0 { - newClientCAPool := x509.NewCertPool() - newClientCAs, err := cert.ParseCertsPEM(newContent.clientCA.caBundle) - if err != nil { - return fmt.Errorf("unable to load client CA file %q: %v", string(newContent.clientCA.caBundle), err) - } - for i, cert := range newClientCAs { - klog.V(2).Infof("loaded client CA [%d/%q]: %s", i, c.clientCA.Name(), GetHumanCertDetail(cert)) - if c.eventRecorder != nil { - c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.clientCA.Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "CACertificateReload", "loaded client CA [%d/%q]: %s", i, c.clientCA.Name(), GetHumanCertDetail(cert)) - } - - newClientCAPool.AddCert(cert) - } - - newTLSConfigCopy.ClientCAs = newClientCAPool - } - - if len(newContent.servingCert.cert) > 0 && len(newContent.servingCert.key) > 0 { - cert, err := tls.X509KeyPair(newContent.servingCert.cert, newContent.servingCert.key) - if err != nil { - return fmt.Errorf("invalid serving cert keypair: %v", err) - } - - x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return fmt.Errorf("invalid serving cert: %v", err) - } - - klog.V(2).Infof("loaded serving cert [%q]: %s", c.servingCert.Name(), GetHumanCertDetail(x509Cert)) - if c.eventRecorder != nil { - c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.servingCert.Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "ServingCertificateReload", "loaded serving cert [%q]: %s", c.servingCert.Name(), GetHumanCertDetail(x509Cert)) - } - - newTLSConfigCopy.Certificates = []tls.Certificate{cert} - } - - if len(newContent.sniCerts) > 0 { - newTLSConfigCopy.NameToCertificate, err = c.BuildNamedCertificates(newContent.sniCerts) - if err != nil { - return fmt.Errorf("unable to build named certificate map: %v", err) - } - - // append all named certs. Otherwise, the go tls stack will think no SNI processing - // is necessary because there is only one cert anyway. - // Moreover, if servingCert is not set, the first SNI - // cert will become the default cert. That's what we expect anyway. - for _, sniCert := range newTLSConfigCopy.NameToCertificate { - newTLSConfigCopy.Certificates = append(newTLSConfigCopy.Certificates, *sniCert) - } - } - - // store new values of content for serving. - c.currentServingTLSConfig.Store(newTLSConfigCopy) - c.currentlyServedContent = newContent // this is single threaded, so we have no locking issue - - return nil -} - -// RunOnce runs a single sync step to ensure that we have a valid starting configuration. -func (c *DynamicServingCertificateController) RunOnce() error { - return c.syncCerts() -} - -// Run starts the kube-apiserver and blocks until stopCh is closed. -func (c *DynamicServingCertificateController) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - - klog.Infof("Starting DynamicServingCertificateController") - defer klog.Infof("Shutting down DynamicServingCertificateController") - - // synchronously load once. We will trigger again, so ignoring any error is fine - _ = c.RunOnce() - - // doesn't matter what workers say, only start one. - go wait.Until(c.runWorker, time.Second, stopCh) - - // start timer that rechecks every minute, just in case. this also serves to prime the controller quickly. - go wait.Until(func() { - c.Enqueue() - }, 1*time.Minute, stopCh) - - <-stopCh -} - -func (c *DynamicServingCertificateController) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *DynamicServingCertificateController) processNextWorkItem() bool { - dsKey, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(dsKey) - - err := c.syncCerts() - if err == nil { - c.queue.Forget(dsKey) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) - c.queue.AddRateLimited(dsKey) - - return true -} - -// Enqueue a method to allow separate control loops to cause the certificate controller to trigger and read content. -func (c *DynamicServingCertificateController) Enqueue() { - c.queue.Add(workItemKey) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig_test.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig_test.go deleted file mode 100644 index 6503d197c9d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "reflect" - "testing" - - "github.com/davecgh/go-spew/spew" -) - -var serverKey = []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA13f50PPWuR/InxLIoJjHdNSG+jVUd25CY7ZL2J023X2BAY+1 -M6jkLR6C2nSFZnn58ubiB74/d1g/Fg1Twd419iR615A013f+qOoyFx3LFHxU1S6e -v22fgJ6ntK/+4QD5MwNgOwD8k1jN2WxHqNWn16IF4Tidbv8M9A35YHAdtYDYaOJC -kzjVztzRw1y6bKRakpMXxHylQyWmAKDJ2GSbRTbGtjr7Ji54WBfG43k94tO5X8K4 -VGbz/uxrKe1IFMHNOlrjR438dbOXusksx9EIqDA9a42J3qjr5NKSqzCIbgBFl6qu -45V3A7cdRI/sJ2G1aqlWIXh2fAQiaFQAEBrPfwIDAQABAoIBAAZbxgWCjJ2d8H+x -QDZtC8XI18redAWqPU9P++ECkrHqmDoBkalanJEwS1BDDATAKL4gTh9IX/sXoZT3 -A7e+5PzEitN9r/GD2wIFF0FTYcDTAnXgEFM52vEivXQ5lV3yd2gn+1kCaHG4typp -ZZv34iIc5+uDjjHOWQWCvA86f8XxX5EfYH+GkjfixTtN2xhWWlfi9vzYeESS4Jbt -tqfH0iEaZ1Bm/qvb8vFgKiuSTOoSpaf+ojAdtPtXDjf1bBtQQG+RSQkP59O/taLM -FCVuRrU8EtdB0+9anwmAP+O2UqjL5izA578lQtdIh13jHtGEgOcnfGNUphK11y9r -Mg5V28ECgYEA9fwI6Xy1Rb9b9irp4bU5Ec99QXa4x2bxld5cDdNOZWJQu9OnaIbg -kw/1SyUkZZCGMmibM/BiWGKWoDf8E+rn/ujGOtd70sR9U0A94XMPqEv7iHxhpZmD -rZuSz4/snYbOWCZQYXFoD/nqOwE7Atnz7yh+Jti0qxBQ9bmkb9o0QW8CgYEA4D3d -okzodg5QQ1y9L0J6jIC6YysoDedveYZMd4Un9bKlZEJev4OwiT4xXmSGBYq/7dzo -OJOvN6qgPfibr27mSB8NkAk6jL/VdJf3thWxNYmjF4E3paLJ24X31aSipN1Ta6K3 -KKQUQRvixVoI1q+8WHAubBDEqvFnNYRHD+AjKvECgYBkekjhpvEcxme4DBtw+OeQ -4OJXJTmhKemwwB12AERboWc88d3GEqIVMEWQJmHRotFOMfCDrMNfOxYv5+5t7FxL -gaXHT1Hi7CQNJ4afWrKgmjjqrXPtguGIvq2fXzjVt8T9uNjIlNxe+kS1SXFjXsgH -ftDY6VgTMB0B4ozKq6UAvQKBgQDER8K5buJHe+3rmMCMHn+Qfpkndr4ftYXQ9Kn4 -MFiy6sV0hdfTgRzEdOjXu9vH/BRVy3iFFVhYvIR42iTEIal2VaAUhM94Je5cmSyd -eE1eFHTqfRPNazmPaqttmSc4cfa0D4CNFVoZR6RupIl6Cect7jvkIaVUD+wMXxWo -osOFsQKBgDLwVhZWoQ13RV/jfQxS3veBUnHJwQJ7gKlL1XZ16mpfEOOVnJF7Es8j -TIIXXYhgSy/XshUbsgXQ+YGliye/rXSCTXHBXvWShOqxEMgeMYMRkcm8ZLp/DH7C -kC2pemkLPUJqgSh1PASGcJbDJIvFGUfP69tUCYpHpk3nHzexuAg3 ------END RSA PRIVATE KEY-----`) - -var serverCert = []byte(`-----BEGIN CERTIFICATE----- -MIIDQDCCAiigAwIBAgIJANWw74P5KJk2MA0GCSqGSIb3DQEBCwUAMDQxMjAwBgNV -BAMMKWdlbmVyaWNfd2ViaG9va19hZG1pc3Npb25fcGx1Z2luX3Rlc3RzX2NhMCAX -DTE3MTExNjAwMDUzOVoYDzIyOTEwOTAxMDAwNTM5WjAjMSEwHwYDVQQDExh3ZWJo -b29rLXRlc3QuZGVmYXVsdC5zdmMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDXd/nQ89a5H8ifEsigmMd01Ib6NVR3bkJjtkvYnTbdfYEBj7UzqOQtHoLa -dIVmefny5uIHvj93WD8WDVPB3jX2JHrXkDTXd/6o6jIXHcsUfFTVLp6/bZ+Anqe0 -r/7hAPkzA2A7APyTWM3ZbEeo1afXogXhOJ1u/wz0DflgcB21gNho4kKTONXO3NHD -XLpspFqSkxfEfKVDJaYAoMnYZJtFNsa2OvsmLnhYF8bjeT3i07lfwrhUZvP+7Gsp -7UgUwc06WuNHjfx1s5e6ySzH0QioMD1rjYneqOvk0pKrMIhuAEWXqq7jlXcDtx1E -j+wnYbVqqVYheHZ8BCJoVAAQGs9/AgMBAAGjZDBiMAkGA1UdEwQCMAAwCwYDVR0P -BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATApBgNVHREEIjAg -hwR/AAABghh3ZWJob29rLXRlc3QuZGVmYXVsdC5zdmMwDQYJKoZIhvcNAQELBQAD -ggEBAD/GKSPNyQuAOw/jsYZesb+RMedbkzs18sSwlxAJQMUrrXwlVdHrA8q5WhE6 -ABLqU1b8lQ8AWun07R8k5tqTmNvCARrAPRUqls/ryER+3Y9YEcxEaTc3jKNZFLbc -T6YtcnkdhxsiO136wtiuatpYL91RgCmuSpR8+7jEHhuFU01iaASu7ypFrUzrKHTF -bKwiLRQi1cMzVcLErq5CDEKiKhUkoDucyARFszrGt9vNIl/YCcBOkcNvM3c05Hn3 -M++C29JwS3Hwbubg6WO3wjFjoEhpCwU6qRYUz3MRp4tHO4kxKXx+oQnUiFnR7vW0 -YkNtGc1RUDHwecCTFpJtPb7Yu/E= ------END CERTIFICATE-----`) - -func TestNewStaticCertKeyContent(t *testing.T) { - testCertProvider, err := NewStaticSNICertKeyContent("test-cert", serverCert, serverKey, "foo") - if err != nil { - t.Error(err) - } - - tests := []struct { - name string - clientCA CAContentProvider - servingCert CertKeyContentProvider - sniCerts []SNICertKeyContentProvider - - expected *dynamicCertificateContent - expectedErr string - }{ - { - name: "filled", - clientCA: &staticCAContent{name: "test-ca", caBundle: &caBundleAndVerifier{caBundle: []byte("content-1")}}, - servingCert: testCertProvider, - sniCerts: []SNICertKeyContentProvider{testCertProvider}, - expected: &dynamicCertificateContent{ - clientCA: caBundleContent{caBundle: []byte("content-1")}, - // ignore sni names for serving cert - servingCert: certKeyContent{cert: serverCert, key: serverKey}, - sniCerts: []sniCertKeyContent{{certKeyContent: certKeyContent{cert: serverCert, key: serverKey}, sniNames: []string{"foo"}}}, - }, - }, - { - name: "nil", - expected: &dynamicCertificateContent{clientCA: caBundleContent{}, servingCert: certKeyContent{}}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - c := &DynamicServingCertificateController{ - clientCA: test.clientCA, - servingCert: test.servingCert, - sniCerts: test.sniCerts, - } - actual, err := c.newTLSContent() - if !reflect.DeepEqual(actual, test.expected) { - t.Error(spew.Sdump(actual)) - } - switch { - case err == nil && len(test.expectedErr) == 0: - case err == nil && len(test.expectedErr) != 0: - t.Errorf("missing %q", test.expectedErr) - case err != nil && len(test.expectedErr) == 0: - t.Error(err) - case err != nil && err.Error() != test.expectedErr: - t.Error(err) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/union_content.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/union_content.go deleted file mode 100644 index 89e19ea5a3a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/union_content.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "bytes" - "crypto/x509" - "strings" - - utilerrors "k8s.io/apimachinery/pkg/util/errors" -) - -type unionCAContent []CAContentProvider - -var _ Notifier = &unionCAContent{} -var _ CAContentProvider = &unionCAContent{} -var _ ControllerRunner = &unionCAContent{} - -// NewUnionCAContentProvider returns a CAContentProvider that is a union of other CAContentProviders -func NewUnionCAContentProvider(caContentProviders ...CAContentProvider) CAContentProvider { - return unionCAContent(caContentProviders) -} - -// Name is just an identifier -func (c unionCAContent) Name() string { - names := []string{} - for _, curr := range c { - names = append(names, curr.Name()) - } - return strings.Join(names, ",") -} - -// CurrentCABundleContent provides ca bundle byte content -func (c unionCAContent) CurrentCABundleContent() []byte { - caBundles := [][]byte{} - for _, curr := range c { - if currCABytes := curr.CurrentCABundleContent(); len(currCABytes) > 0 { - caBundles = append(caBundles, []byte(strings.TrimSpace(string(currCABytes)))) - } - } - - return bytes.Join(caBundles, []byte("\n")) -} - -// CurrentCABundleContent provides ca bundle byte content -func (c unionCAContent) VerifyOptions() (x509.VerifyOptions, bool) { - currCABundle := c.CurrentCABundleContent() - if len(currCABundle) == 0 { - return x509.VerifyOptions{}, false - } - - // TODO make more efficient. This isn't actually used in any of our mainline paths. It's called to build the TLSConfig - // TODO on file changes, but the actual authentication runs against the individual items, not the union. - ret, err := newCABundleAndVerifier(c.Name(), c.CurrentCABundleContent()) - if err != nil { - // because we're made up of already vetted values, this indicates some kind of coding error - panic(err) - } - - return ret.verifyOptions, true -} - -// AddListener adds a listener to be notified when the CA content changes. -func (c unionCAContent) AddListener(listener Listener) { - for _, curr := range c { - if notifier, ok := curr.(Notifier); ok { - notifier.AddListener(listener) - } - } -} - -// AddListener adds a listener to be notified when the CA content changes. -func (c unionCAContent) RunOnce() error { - errors := []error{} - for _, curr := range c { - if controller, ok := curr.(ControllerRunner); ok { - if err := controller.RunOnce(); err != nil { - errors = append(errors, err) - } - } - } - - return utilerrors.NewAggregate(errors) -} - -// Run runs the controller -func (c unionCAContent) Run(workers int, stopCh <-chan struct{}) { - for _, curr := range c { - if controller, ok := curr.(ControllerRunner); ok { - go controller.Run(workers, stopCh) - } - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/util.go b/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/util.go deleted file mode 100644 index 6906045cd29..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/util.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright 2019 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 dynamiccertificates - -import ( - "crypto/x509" - "fmt" - "strings" - "time" -) - -// GetHumanCertDetail is a convenient method for printing compact details of certificate that helps when debugging -// kube-apiserver usage of certs. -func GetHumanCertDetail(certificate *x509.Certificate) string { - humanName := certificate.Subject.CommonName - signerHumanName := certificate.Issuer.CommonName - if certificate.Subject.CommonName == certificate.Issuer.CommonName { - signerHumanName = "" - } - - usages := []string{} - for _, curr := range certificate.ExtKeyUsage { - if curr == x509.ExtKeyUsageClientAuth { - usages = append(usages, "client") - continue - } - if curr == x509.ExtKeyUsageServerAuth { - usages = append(usages, "serving") - continue - } - - usages = append(usages, fmt.Sprintf("%d", curr)) - } - - validServingNames := []string{} - for _, ip := range certificate.IPAddresses { - validServingNames = append(validServingNames, ip.String()) - } - for _, dnsName := range certificate.DNSNames { - validServingNames = append(validServingNames, dnsName) - } - servingString := "" - if len(validServingNames) > 0 { - servingString = fmt.Sprintf(" validServingFor=[%s]", strings.Join(validServingNames, ",")) - } - - groupString := "" - if len(certificate.Subject.Organization) > 0 { - groupString = fmt.Sprintf(" groups=[%s]", strings.Join(certificate.Subject.Organization, ",")) - } - - return fmt.Sprintf("%q [%s]%s%s issuer=%q (%v to %v (now=%v))", humanName, strings.Join(usages, ","), groupString, servingString, signerHumanName, certificate.NotBefore.UTC(), certificate.NotAfter.UTC(), - time.Now().UTC()) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/egressselector/config.go b/vendor/k8s.io/apiserver/pkg/server/egressselector/config.go deleted file mode 100644 index b8b1d67a57a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/egressselector/config.go +++ /dev/null @@ -1,232 +0,0 @@ -/* -Copyright 2019 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 egressselector - -import ( - "fmt" - "io/ioutil" - "strings" - - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/validation/field" - "k8s.io/apiserver/pkg/apis/apiserver" - "k8s.io/apiserver/pkg/apis/apiserver/install" - "k8s.io/apiserver/pkg/apis/apiserver/v1beta1" - "k8s.io/utils/path" - "sigs.k8s.io/yaml" -) - -var cfgScheme = runtime.NewScheme() - -func init() { - install.Install(cfgScheme) -} - -// ReadEgressSelectorConfiguration reads the egress selector configuration at the specified path. -// It returns the loaded egress selector configuration if the input file aligns with the required syntax. -// If it does not align with the provided syntax, it returns a default configuration which should function as a no-op. -// It does this by returning a nil configuration, which preserves backward compatibility. -// This works because prior to this there was no egress selector configuration. -// It returns an error if the file did not exist. -func ReadEgressSelectorConfiguration(configFilePath string) (*apiserver.EgressSelectorConfiguration, error) { - if configFilePath == "" { - return nil, nil - } - // a file was provided, so we just read it. - data, err := ioutil.ReadFile(configFilePath) - if err != nil { - return nil, fmt.Errorf("unable to read egress selector configuration from %q [%v]", configFilePath, err) - } - var decodedConfig v1beta1.EgressSelectorConfiguration - err = yaml.Unmarshal(data, &decodedConfig) - if err != nil { - // we got an error where the decode wasn't related to a missing type - return nil, err - } - if decodedConfig.Kind != "EgressSelectorConfiguration" { - return nil, fmt.Errorf("invalid service configuration object %q", decodedConfig.Kind) - } - internalConfig := &apiserver.EgressSelectorConfiguration{} - if err := cfgScheme.Convert(&decodedConfig, internalConfig, nil); err != nil { - // we got an error where the decode wasn't related to a missing type - return nil, err - } - return internalConfig, nil -} - -// ValidateEgressSelectorConfiguration checks the apiserver.EgressSelectorConfiguration for -// common configuration errors. It will return error for problems such as configuring mtls/cert -// settings for protocol which do not support security. It will also try to catch errors such as -// incorrect file paths. It will return nil if it does not find anything wrong. -func ValidateEgressSelectorConfiguration(config *apiserver.EgressSelectorConfiguration) field.ErrorList { - allErrs := field.ErrorList{} - if config == nil { - return allErrs // Treating a nil configuration as valid - } - for _, service := range config.EgressSelections { - fldPath := field.NewPath("service", "connection") - switch service.Connection.ProxyProtocol { - case apiserver.ProtocolDirect: - allErrs = append(allErrs, validateDirectConnection(service.Connection, fldPath)...) - case apiserver.ProtocolHTTPConnect: - allErrs = append(allErrs, validateHTTPConnectTransport(service.Connection.Transport, fldPath)...) - case apiserver.ProtocolGRPC: - allErrs = append(allErrs, validateGRPCTransport(service.Connection.Transport, fldPath)...) - default: - allErrs = append(allErrs, field.NotSupported( - fldPath.Child("protocol"), - service.Connection.ProxyProtocol, - []string{ - string(apiserver.ProtocolDirect), - string(apiserver.ProtocolHTTPConnect), - string(apiserver.ProtocolGRPC), - })) - } - } - return allErrs -} - -func validateHTTPConnectTransport(transport *apiserver.Transport, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if transport == nil { - allErrs = append(allErrs, field.Required( - fldPath.Child("transport"), - "transport must be set for HTTPConnect")) - return allErrs - } - - if transport.TCP != nil && transport.UDS != nil { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tcp"), - transport.TCP, - "TCP and UDS cannot both be set")) - } else if transport.TCP == nil && transport.UDS == nil { - allErrs = append(allErrs, field.Required( - fldPath.Child("tcp"), - "One of TCP or UDS must be set")) - } else if transport.TCP != nil { - allErrs = append(allErrs, validateTCPConnection(transport.TCP, fldPath)...) - } else if transport.UDS != nil { - allErrs = append(allErrs, validateUDSConnection(transport.UDS, fldPath)...) - } - return allErrs -} - -func validateGRPCTransport(transport *apiserver.Transport, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if transport == nil { - allErrs = append(allErrs, field.Required( - fldPath.Child("transport"), - "transport must be set for GRPC")) - return allErrs - } - - if transport.UDS != nil { - allErrs = append(allErrs, validateUDSConnection(transport.UDS, fldPath)...) - } else { - allErrs = append(allErrs, field.Required( - fldPath.Child("uds"), - "UDS must be set with GRPC")) - } - return allErrs -} - -func validateDirectConnection(connection apiserver.Connection, fldPath *field.Path) field.ErrorList { - if connection.Transport != nil { - return field.ErrorList{field.Invalid( - fldPath.Child("transport"), - "direct", - "Transport config should be absent for direct connect"), - } - } - - return nil -} - -func validateUDSConnection(udsConfig *apiserver.UDSTransport, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if udsConfig.UDSName == "" { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("udsName"), - "nil", - "UDSName should be present for UDS connections")) - } - return allErrs -} - -func validateTCPConnection(tcpConfig *apiserver.TCPTransport, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - if strings.HasPrefix(tcpConfig.URL, "http://") { - if tcpConfig.TLSConfig != nil { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig"), - "nil", - "TLSConfig config should not be present when using HTTP")) - } - } else if strings.HasPrefix(tcpConfig.URL, "https://") { - return validateTLSConfig(tcpConfig.TLSConfig, fldPath) - } else { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("url"), - tcpConfig.URL, - "supported connection protocols are http:// and https://")) - } - return allErrs -} - -func validateTLSConfig(tlsConfig *apiserver.TLSConfig, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - if tlsConfig == nil { - allErrs = append(allErrs, field.Required( - fldPath.Child("tlsConfig"), - "TLSConfig must be present when using HTTPS")) - return allErrs - } - if tlsConfig.CABundle != "" { - if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.CABundle); exists == false || err != nil { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig", "caBundle"), - tlsConfig.CABundle, - "TLS config ca bundle does not exist")) - } - } - if tlsConfig.ClientCert == "" { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig", "clientCert"), - "nil", - "Using TLS requires clientCert")) - } else if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.ClientCert); exists == false || err != nil { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig", "clientCert"), - tlsConfig.ClientCert, - "TLS client cert does not exist")) - } - if tlsConfig.ClientKey == "" { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig", "clientKey"), - "nil", - "Using TLS requires requires clientKey")) - } else if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.ClientKey); exists == false || err != nil { - allErrs = append(allErrs, field.Invalid( - fldPath.Child("tlsConfig", "clientKey"), - tlsConfig.ClientKey, - "TLS client key does not exist")) - } - return allErrs -} diff --git a/vendor/k8s.io/apiserver/pkg/server/egressselector/config_test.go b/vendor/k8s.io/apiserver/pkg/server/egressselector/config_test.go deleted file mode 100644 index f01781cf592..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/egressselector/config_test.go +++ /dev/null @@ -1,428 +0,0 @@ -/* -Copyright 2019 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 egressselector - -import ( - "fmt" - "io/ioutil" - "os" - "reflect" - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/apis/apiserver" -) - -func strptr(s string) *string { - return &s -} - -func TestReadEgressSelectorConfiguration(t *testing.T) { - testcases := []struct { - name string - contents string - createFile bool - expectedResult *apiserver.EgressSelectorConfiguration - expectedError *string - }{ - { - name: "empty", - createFile: true, - contents: ``, - expectedResult: nil, - expectedError: strptr("invalid service configuration object \"\""), - }, - { - name: "absent", - createFile: false, - contents: ``, - expectedResult: nil, - expectedError: strptr("unable to read egress selector configuration from \"test-egress-selector-config-absent\" [open test-egress-selector-config-absent: no such file or directory]"), - }, - { - name: "v1beta1", - createFile: true, - contents: ` -apiVersion: apiserver.k8s.io/v1beta1 -kind: EgressSelectorConfiguration -egressSelections: -- name: "cluster" - connection: - proxyProtocol: "HTTPConnect" - transport: - tcp: - url: "https://127.0.0.1:8131" - tlsConfig: - caBundle: "/etc/srv/kubernetes/pki/konnectivity-server/ca.crt" - clientKey: "/etc/srv/kubernetes/pki/konnectivity-server/client.key" - clientCert: "/etc/srv/kubernetes/pki/konnectivity-server/client.crt" -- name: "master" - connection: - proxyProtocol: "HTTPConnect" - transport: - tcp: - url: "https://127.0.0.1:8132" - tlsConfig: - caBundle: "/etc/srv/kubernetes/pki/konnectivity-server-master/ca.crt" - clientKey: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.key" - clientCert: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.crt" -- name: "etcd" - connection: - proxyProtocol: "Direct" -`, - expectedResult: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: "HTTPConnect", - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "https://127.0.0.1:8131", - - TLSConfig: &apiserver.TLSConfig{ - CABundle: "/etc/srv/kubernetes/pki/konnectivity-server/ca.crt", - ClientKey: "/etc/srv/kubernetes/pki/konnectivity-server/client.key", - ClientCert: "/etc/srv/kubernetes/pki/konnectivity-server/client.crt", - }, - }, - }, - }, - }, - { - Name: "master", - Connection: apiserver.Connection{ - ProxyProtocol: "HTTPConnect", - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "https://127.0.0.1:8132", - TLSConfig: &apiserver.TLSConfig{ - CABundle: "/etc/srv/kubernetes/pki/konnectivity-server-master/ca.crt", - ClientKey: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.key", - ClientCert: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.crt", - }, - }, - }, - }, - }, - { - Name: "etcd", - Connection: apiserver.Connection{ - ProxyProtocol: "Direct", - }, - }, - }, - }, - expectedError: nil, - }, - { - name: "wrong_type", - createFile: true, - contents: ` -apiVersion: apps/v1 -kind: DaemonSet -metadata: - labels: - addonmanager.kubernetes.io/mode: Reconcile - k8s-app: konnectivity-agent - namespace: kube-system - name: proxy-agent -spec: - selector: - matchLabels: - k8s-app: konnectivity-agent - updateStrategy: - type: RollingUpdate - template: - metadata: - labels: - k8s-app: proxy-agent - spec: - priorityClassName: system-cluster-critical - # Necessary to reboot node - hostPID: true - volumes: - - name: pki - hostPath: - path: /etc/srv/kubernetes/pki/konnectivity-agent - containers: - - image: gcr.io/google-containers/proxy-agent:v0.0.3 - name: proxy-agent - command: ["/proxy-agent"] - args: ["--caCert=/etc/srv/kubernetes/pki/proxy-agent/ca.crt", "--agentCert=/etc/srv/kubernetes/pki/proxy-agent/client.crt", "--agentKey=/etc/srv/kubernetes/pki/proxy-agent/client.key", "--proxyServerHost=127.0.0.1", "--proxyServerPort=8132"] - securityContext: - capabilities: - add: ["SYS_BOOT"] - env: - - name: wrong-type - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: kube-system - valueFrom: - fieldRef: - fieldPath: metadata.namespace - resources: - limits: - cpu: 50m - memory: 30Mi - volumeMounts: - - name: pki - mountPath: /etc/srv/kubernetes/pki/konnectivity-agent -`, - expectedResult: nil, - expectedError: strptr("invalid service configuration object \"DaemonSet\""), - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - proxyConfig := fmt.Sprintf("test-egress-selector-config-%s", tc.name) - if tc.createFile { - f, err := ioutil.TempFile("", proxyConfig) - if err != nil { - t.Fatal(err) - } - defer os.Remove(f.Name()) - if err := ioutil.WriteFile(f.Name(), []byte(tc.contents), os.FileMode(0755)); err != nil { - t.Fatal(err) - } - proxyConfig = f.Name() - } - config, err := ReadEgressSelectorConfiguration(proxyConfig) - if err == nil && tc.expectedError != nil { - t.Errorf("calling ReadEgressSelectorConfiguration expected error: %s, did not get it", *tc.expectedError) - } - if err != nil && tc.expectedError == nil { - t.Errorf("unexpected error calling ReadEgressSelectorConfiguration got: %#v", err) - } - if err != nil && tc.expectedError != nil && err.Error() != *tc.expectedError { - t.Errorf("calling ReadEgressSelectorConfiguration expected error: %s, got %#v", *tc.expectedError, err) - } - if !reflect.DeepEqual(config, tc.expectedResult) { - t.Errorf("problem with configuration returned from ReadEgressSelectorConfiguration expected: %#v, got: %#v", tc.expectedResult, config) - } - }) - } -} - -func TestValidateEgressSelectorConfiguration(t *testing.T) { - testcases := []struct { - name string - expectError bool - contents *apiserver.EgressSelectorConfiguration - }{ - { - name: "direct-valid", - expectError: false, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "master", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolDirect, - }, - }, - }, - }, - }, - { - name: "direct-invalid-transport", - expectError: true, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "master", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolDirect, - Transport: &apiserver.Transport{}, - }, - }, - }, - }, - }, - { - name: "httpconnect-no-https", - expectError: false, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolHTTPConnect, - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "http://127.0.0.1:8131", - }, - }, - }, - }, - }, - }, - }, - { - name: "httpconnect-https-no-cert-error", - expectError: true, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolHTTPConnect, - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "https://127.0.0.1:8131", - }, - }, - }, - }, - }, - }, - }, - { - name: "httpconnect-tcp-uds-both-set", - expectError: true, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolHTTPConnect, - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "http://127.0.0.1:8131", - }, - UDS: &apiserver.UDSTransport{ - UDSName: "/etc/srv/kubernetes/konnectivity/konnectivity-server.socket", - }, - }, - }, - }, - }, - }, - }, - { - name: "httpconnect-uds", - expectError: false, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolHTTPConnect, - Transport: &apiserver.Transport{ - UDS: &apiserver.UDSTransport{ - UDSName: "/etc/srv/kubernetes/konnectivity/konnectivity-server.socket", - }, - }, - }, - }, - }, - }, - }, - { - name: "grpc-https-invalid", - expectError: true, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolGRPC, - Transport: &apiserver.Transport{ - TCP: &apiserver.TCPTransport{ - URL: "http://127.0.0.1:8131", - TLSConfig: &apiserver.TLSConfig{ - CABundle: "", - ClientKey: "", - ClientCert: "", - }, - }, - }, - }, - }, - }, - }, - }, - { - name: "grpc-uds", - expectError: false, - contents: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolGRPC, - Transport: &apiserver.Transport{ - UDS: &apiserver.UDSTransport{ - UDSName: "/etc/srv/kubernetes/konnectivity/konnectivity-server.socket", - }, - }, - }, - }, - }, - }, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - errs := ValidateEgressSelectorConfiguration(tc.contents) - if tc.expectError == false && len(errs) != 0 { - t.Errorf("Calling ValidateEgressSelectorConfiguration expected no error, got %v", errs) - } else if tc.expectError == true && len(errs) == 0 { - t.Errorf("Calling ValidateEgressSelectorConfiguration expected error, got no error") - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go b/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go deleted file mode 100644 index b8bdec2804c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go +++ /dev/null @@ -1,368 +0,0 @@ -/* -Copyright 2019 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 egressselector - -import ( - "bufio" - "context" - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - "time" - - "google.golang.org/grpc" - - utilnet "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apiserver/pkg/apis/apiserver" - egressmetrics "k8s.io/apiserver/pkg/server/egressselector/metrics" - "k8s.io/klog" - utiltrace "k8s.io/utils/trace" - client "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client" -) - -var directDialer utilnet.DialFunc = http.DefaultTransport.(*http.Transport).DialContext - -// EgressSelector is the map of network context type to context dialer, for network egress. -type EgressSelector struct { - egressToDialer map[EgressType]utilnet.DialFunc -} - -// EgressType is an indicator of which egress selection should be used for sending traffic. -// See https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190226-network-proxy.md#network-context -type EgressType int - -const ( - // Master is the EgressType for traffic intended to go to the control plane. - Master EgressType = iota - // Etcd is the EgressType for traffic intended to go to Kubernetes persistence store. - Etcd - // Cluster is the EgressType for traffic intended to go to the system being managed by Kubernetes. - Cluster -) - -// NetworkContext is the struct used by Kubernetes API Server to indicate where it intends traffic to be sent. -type NetworkContext struct { - // EgressSelectionName is the unique name of the - // EgressSelectorConfiguration which determines - // the network we route the traffic to. - EgressSelectionName EgressType -} - -// Lookup is the interface to get the dialer function for the network context. -type Lookup func(networkContext NetworkContext) (utilnet.DialFunc, error) - -// String returns the canonical string representation of the egress type -func (s EgressType) String() string { - switch s { - case Master: - return "master" - case Etcd: - return "etcd" - case Cluster: - return "cluster" - default: - return "invalid" - } -} - -// AsNetworkContext is a helper function to make it easy to get the basic NetworkContext objects. -func (s EgressType) AsNetworkContext() NetworkContext { - return NetworkContext{EgressSelectionName: s} -} - -func lookupServiceName(name string) (EgressType, error) { - switch strings.ToLower(name) { - case "master": - return Master, nil - case "etcd": - return Etcd, nil - case "cluster": - return Cluster, nil - } - return -1, fmt.Errorf("unrecognized service name %s", name) -} - -func tunnelHTTPConnect(proxyConn net.Conn, proxyAddress, addr string) (net.Conn, error) { - fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", addr, "127.0.0.1") - br := bufio.NewReader(proxyConn) - res, err := http.ReadResponse(br, nil) - if err != nil { - proxyConn.Close() - return nil, fmt.Errorf("reading HTTP response from CONNECT to %s via proxy %s failed: %v", - addr, proxyAddress, err) - } - if res.StatusCode != 200 { - proxyConn.Close() - return nil, fmt.Errorf("proxy error from %s while dialing %s, code %d: %v", - proxyAddress, addr, res.StatusCode, res.Status) - } - - // It's safe to discard the bufio.Reader here and return the - // original TCP conn directly because we only use this for - // TLS, and in TLS the client speaks first, so we know there's - // no unbuffered data. But we can double-check. - if br.Buffered() > 0 { - proxyConn.Close() - return nil, fmt.Errorf("unexpected %d bytes of buffered data from CONNECT proxy %q", - br.Buffered(), proxyAddress) - } - return proxyConn, nil -} - -type proxier interface { - // proxy returns a connection to addr. - proxy(addr string) (net.Conn, error) -} - -var _ proxier = &httpConnectProxier{} - -type httpConnectProxier struct { - conn net.Conn - proxyAddress string -} - -func (t *httpConnectProxier) proxy(addr string) (net.Conn, error) { - return tunnelHTTPConnect(t.conn, t.proxyAddress, addr) -} - -var _ proxier = &grpcProxier{} - -type grpcProxier struct { - tunnel client.Tunnel -} - -func (g *grpcProxier) proxy(addr string) (net.Conn, error) { - return g.tunnel.Dial("tcp", addr) -} - -type proxyServerConnector interface { - // connect establishes connection to the proxy server, and returns a - // proxier based on the connection. - connect() (proxier, error) -} - -type tcpHTTPConnectConnector struct { - proxyAddress string - tlsConfig *tls.Config -} - -func (t *tcpHTTPConnectConnector) connect() (proxier, error) { - conn, err := tls.Dial("tcp", t.proxyAddress, t.tlsConfig) - if err != nil { - return nil, err - } - return &httpConnectProxier{conn: conn, proxyAddress: t.proxyAddress}, nil -} - -type udsHTTPConnectConnector struct { - udsName string -} - -func (u *udsHTTPConnectConnector) connect() (proxier, error) { - conn, err := net.Dial("unix", u.udsName) - if err != nil { - return nil, err - } - return &httpConnectProxier{conn: conn, proxyAddress: u.udsName}, nil -} - -type udsGRPCConnector struct { - udsName string -} - -func (u *udsGRPCConnector) connect() (proxier, error) { - udsName := u.udsName - dialOption := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { - c, err := net.Dial("unix", udsName) - if err != nil { - klog.Errorf("failed to create connection to uds name %s, error: %v", udsName, err) - } - return c, err - }) - - tunnel, err := client.CreateGrpcTunnel(udsName, dialOption, grpc.WithInsecure()) - if err != nil { - return nil, err - } - return &grpcProxier{tunnel: tunnel}, nil -} - -type dialerCreator struct { - connector proxyServerConnector - direct bool - options metricsOptions -} - -type metricsOptions struct { - transport string - protocol string -} - -func (d *dialerCreator) createDialer() utilnet.DialFunc { - if d.direct { - return directDialer - } - return func(ctx context.Context, network, addr string) (net.Conn, error) { - trace := utiltrace.New(fmt.Sprintf("Proxy via HTTP Connect over %s", d.options.transport), utiltrace.Field{Key: "address", Value: addr}) - defer trace.LogIfLong(500 * time.Millisecond) - start := egressmetrics.Metrics.Clock().Now() - proxier, err := d.connector.connect() - if err != nil { - egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageConnect) - return nil, err - } - conn, err := proxier.proxy(addr) - if err != nil { - egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageProxy) - return nil, err - } - egressmetrics.Metrics.ObserveDialLatency(egressmetrics.Metrics.Clock().Now().Sub(start), d.options.protocol, d.options.transport) - return conn, nil - } -} - -func getTLSConfig(t *apiserver.TLSConfig) (*tls.Config, error) { - clientCert := t.ClientCert - clientKey := t.ClientKey - caCert := t.CABundle - clientCerts, err := tls.LoadX509KeyPair(clientCert, clientKey) - if err != nil { - return nil, fmt.Errorf("failed to read key pair %s & %s, got %v", clientCert, clientKey, err) - } - certPool := x509.NewCertPool() - if caCert != "" { - certBytes, err := ioutil.ReadFile(caCert) - if err != nil { - return nil, fmt.Errorf("failed to read cert file %s, got %v", caCert, err) - } - ok := certPool.AppendCertsFromPEM(certBytes) - if !ok { - return nil, fmt.Errorf("failed to append CA cert to the cert pool") - } - } else { - // Use host's root CA set instead of providing our own - certPool = nil - } - return &tls.Config{ - Certificates: []tls.Certificate{clientCerts}, - RootCAs: certPool, - }, nil -} - -func getProxyAddress(urlString string) (string, error) { - proxyURL, err := url.Parse(urlString) - if err != nil { - return "", fmt.Errorf("invalid proxy server url %q: %v", urlString, err) - } - return proxyURL.Host, nil -} - -func connectionToDialerCreator(c apiserver.Connection) (*dialerCreator, error) { - switch c.ProxyProtocol { - - case apiserver.ProtocolHTTPConnect: - if c.Transport.UDS != nil { - return &dialerCreator{ - connector: &udsHTTPConnectConnector{ - udsName: c.Transport.UDS.UDSName, - }, - options: metricsOptions{ - transport: egressmetrics.TransportUDS, - protocol: egressmetrics.ProtocolHTTPConnect, - }, - }, nil - } else if c.Transport.TCP != nil { - tlsConfig, err := getTLSConfig(c.Transport.TCP.TLSConfig) - if err != nil { - return nil, err - } - proxyAddress, err := getProxyAddress(c.Transport.TCP.URL) - if err != nil { - return nil, err - } - return &dialerCreator{ - connector: &tcpHTTPConnectConnector{ - tlsConfig: tlsConfig, - proxyAddress: proxyAddress, - }, - options: metricsOptions{ - transport: egressmetrics.TransportTCP, - protocol: egressmetrics.ProtocolHTTPConnect, - }, - }, nil - } else { - return nil, fmt.Errorf("Either a TCP or UDS transport must be specified") - } - case apiserver.ProtocolGRPC: - if c.Transport.UDS != nil { - return &dialerCreator{ - connector: &udsGRPCConnector{ - udsName: c.Transport.UDS.UDSName, - }, - options: metricsOptions{ - transport: egressmetrics.TransportUDS, - protocol: egressmetrics.ProtocolGRPC, - }, - }, nil - } - return nil, fmt.Errorf("UDS transport must be specified for GRPC") - case apiserver.ProtocolDirect: - return &dialerCreator{direct: true}, nil - default: - return nil, fmt.Errorf("unrecognized service connection protocol %q", c.ProxyProtocol) - } - -} - -// NewEgressSelector configures lookup mechanism for Lookup. -// It does so based on a EgressSelectorConfiguration which was read at startup. -func NewEgressSelector(config *apiserver.EgressSelectorConfiguration) (*EgressSelector, error) { - if config == nil || config.EgressSelections == nil { - // No Connection Services configured, leaving the serviceMap empty, will return default dialer. - return nil, nil - } - cs := &EgressSelector{ - egressToDialer: make(map[EgressType]utilnet.DialFunc), - } - for _, service := range config.EgressSelections { - name, err := lookupServiceName(service.Name) - if err != nil { - return nil, err - } - dialerCreator, err := connectionToDialerCreator(service.Connection) - if err != nil { - return nil, fmt.Errorf("failed to create dialer for egressSelection %q: %v", name, err) - } - cs.egressToDialer[name] = dialerCreator.createDialer() - } - return cs, nil -} - -// Lookup gets the dialer function for the network context. -// This is configured for the Kubernetes API Server at startup. -func (cs *EgressSelector) Lookup(networkContext NetworkContext) (utilnet.DialFunc, error) { - if cs.egressToDialer == nil { - // The round trip wrapper will over-ride the dialContext method appropriately - return nil, nil - } - return cs.egressToDialer[networkContext.EgressSelectionName], nil -} diff --git a/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector_test.go b/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector_test.go deleted file mode 100644 index 8ff72fe8a9e..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector_test.go +++ /dev/null @@ -1,266 +0,0 @@ -/* -Copyright 2019 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 egressselector - -import ( - "context" - "fmt" - "net" - "strings" - "testing" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/clock" - utilnet "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apiserver/pkg/apis/apiserver" - "k8s.io/apiserver/pkg/server/egressselector/metrics" - "k8s.io/component-base/metrics/legacyregistry" - "k8s.io/component-base/metrics/testutil" -) - -type fakeEgressSelection struct { - directDialerCalled bool -} - -func TestEgressSelector(t *testing.T) { - testcases := []struct { - name string - input *apiserver.EgressSelectorConfiguration - services []struct { - egressType EgressType - validateDialer func(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error) - lookupError *string - dialerError *string - } - expectedError *string - }{ - { - name: "direct", - input: &apiserver.EgressSelectorConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "", - APIVersion: "", - }, - EgressSelections: []apiserver.EgressSelection{ - { - Name: "cluster", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolDirect, - }, - }, - { - Name: "master", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolDirect, - }, - }, - { - Name: "etcd", - Connection: apiserver.Connection{ - ProxyProtocol: apiserver.ProtocolDirect, - }, - }, - }, - }, - services: []struct { - egressType EgressType - validateDialer func(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error) - lookupError *string - dialerError *string - }{ - { - Cluster, - validateDirectDialer, - nil, - nil, - }, - { - Master, - validateDirectDialer, - nil, - nil, - }, - { - Etcd, - validateDirectDialer, - nil, - nil, - }, - }, - expectedError: nil, - }, - } - - for _, tc := range testcases { - t.Run(tc.name, func(t *testing.T) { - // Setup the various pieces such as the fake dialer prior to initializing the egress selector. - // Go doesn't allow function pointer comparison, nor does its reflect package - // So overriding the default dialer to detect if it is returned. - fake := &fakeEgressSelection{} - directDialer = fake.fakeDirectDialer - cs, err := NewEgressSelector(tc.input) - if err == nil && tc.expectedError != nil { - t.Errorf("calling NewEgressSelector expected error: %s, did not get it", *tc.expectedError) - } - if err != nil && tc.expectedError == nil { - t.Errorf("unexpected error calling NewEgressSelector got: %#v", err) - } - if err != nil && tc.expectedError != nil && err.Error() != *tc.expectedError { - t.Errorf("calling NewEgressSelector expected error: %s, got %#v", *tc.expectedError, err) - } - - for _, service := range tc.services { - networkContext := NetworkContext{EgressSelectionName: service.egressType} - dialer, lookupErr := cs.Lookup(networkContext) - if lookupErr == nil && service.lookupError != nil { - t.Errorf("calling Lookup expected error: %s, did not get it", *service.lookupError) - } - if lookupErr != nil && service.lookupError == nil { - t.Errorf("unexpected error calling Lookup got: %#v", lookupErr) - } - if lookupErr != nil && service.lookupError != nil && lookupErr.Error() != *service.lookupError { - t.Errorf("calling Lookup expected error: %s, got %#v", *service.lookupError, lookupErr) - } - fake.directDialerCalled = false - ok, dialerErr := service.validateDialer(dialer, fake) - if dialerErr == nil && service.dialerError != nil { - t.Errorf("calling Lookup expected error: %s, did not get it", *service.dialerError) - } - if dialerErr != nil && service.dialerError == nil { - t.Errorf("unexpected error calling Lookup got: %#v", dialerErr) - } - if dialerErr != nil && service.dialerError != nil && dialerErr.Error() != *service.dialerError { - t.Errorf("calling Lookup expected error: %s, got %#v", *service.dialerError, dialerErr) - } - if !ok { - t.Errorf("Could not validate dialer for service %q", service.egressType) - } - } - }) - } -} - -func (s *fakeEgressSelection) fakeDirectDialer(ctx context.Context, network, address string) (net.Conn, error) { - s.directDialerCalled = true - return nil, nil -} - -func validateDirectDialer(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error) { - conn, err := dialer(context.Background(), "tcp", "127.0.0.1:8080") - if err != nil { - return false, err - } - if conn != nil { - return false, nil - } - return s.directDialerCalled, nil -} - -type fakeProxyServerConnector struct { - connectorErr bool - proxierErr bool -} - -func (f *fakeProxyServerConnector) connect() (proxier, error) { - if f.connectorErr { - return nil, fmt.Errorf("fake error") - } - return &fakeProxier{err: f.proxierErr}, nil -} - -type fakeProxier struct { - err bool -} - -func (f *fakeProxier) proxy(_ string) (net.Conn, error) { - if f.err { - return nil, fmt.Errorf("fake error") - } - return nil, nil -} - -func TestMetrics(t *testing.T) { - testcases := map[string]struct { - connectorErr bool - proxierErr bool - metrics []string - want string - }{ - "connect to proxy server error": { - connectorErr: true, - proxierErr: false, - metrics: []string{"apiserver_egress_dialer_dial_failure_count"}, - want: ` - # HELP apiserver_egress_dialer_dial_failure_count [ALPHA] Dial failure count, labeled by the protocol (http-connect or grpc), transport (tcp or uds), and stage (connect or proxy). The stage indicates at which stage the dial failed - # TYPE apiserver_egress_dialer_dial_failure_count counter - apiserver_egress_dialer_dial_failure_count{protocol="fake_protocol",stage="connect",transport="fake_transport"} 1 -`, - }, - "connect succeeded, proxy failed": { - connectorErr: false, - proxierErr: true, - metrics: []string{"apiserver_egress_dialer_dial_failure_count"}, - want: ` - # HELP apiserver_egress_dialer_dial_failure_count [ALPHA] Dial failure count, labeled by the protocol (http-connect or grpc), transport (tcp or uds), and stage (connect or proxy). The stage indicates at which stage the dial failed - # TYPE apiserver_egress_dialer_dial_failure_count counter - apiserver_egress_dialer_dial_failure_count{protocol="fake_protocol",stage="proxy",transport="fake_transport"} 1 -`, - }, - "successful": { - connectorErr: false, - proxierErr: false, - metrics: []string{"apiserver_egress_dialer_dial_duration_seconds"}, - want: ` - # HELP apiserver_egress_dialer_dial_duration_seconds [ALPHA] Dial latency histogram in seconds, labeled by the protocol (http-connect or grpc), transport (tcp or uds) - # TYPE apiserver_egress_dialer_dial_duration_seconds histogram - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="0.005"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="0.025"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="0.1"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="0.5"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="2.5"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="12.5"} 1 - apiserver_egress_dialer_dial_duration_seconds_bucket{protocol="fake_protocol",transport="fake_transport",le="+Inf"} 1 - apiserver_egress_dialer_dial_duration_seconds_sum{protocol="fake_protocol",transport="fake_transport"} 0 - apiserver_egress_dialer_dial_duration_seconds_count{protocol="fake_protocol",transport="fake_transport"} 1 -`, - }, - } - for tn, tc := range testcases { - - t.Run(tn, func(t *testing.T) { - metrics.Metrics.Reset() - metrics.Metrics.SetClock(clock.NewFakeClock(time.Now())) - d := dialerCreator{ - connector: &fakeProxyServerConnector{ - connectorErr: tc.connectorErr, - proxierErr: tc.proxierErr, - }, - options: metricsOptions{ - transport: "fake_transport", - protocol: "fake_protocol", - }, - } - dialer := d.createDialer() - dialer(context.TODO(), "", "") - if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(tc.want), tc.metrics...); err != nil { - t.Errorf("Err in comparing metrics %v", err) - } - }) - } - -} diff --git a/vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go b/vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go deleted file mode 100644 index 04ad61c4fd0..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -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 metrics - -import ( - "time" - - "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" -) - -const ( - namespace = "apiserver" - subsystem = "egress_dialer" - - // ProtocolHTTPConnect means that the proxy protocol is http-connect. - ProtocolHTTPConnect = "http_connect" - // ProtocolGRPC means that the proxy protocol is the GRPC protocol. - ProtocolGRPC = "grpc" - // TransportTCP means that the transport is TCP. - TransportTCP = "tcp" - // TransportUDS means that the transport is UDS. - TransportUDS = "uds" - // StageConnect indicates that the dial failed at establishing connection to the proxy server. - StageConnect = "connect" - // StageProxy indicates that the dial failed at requesting the proxy server to proxy. - StageProxy = "proxy" -) - -var ( - // Use buckets ranging from 5 ms to 12.5 seconds. - latencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 2.5, 12.5} - - // Metrics provides access to all dial metrics. - Metrics = newDialMetrics() -) - -// DialMetrics instruments dials to proxy server with prometheus metrics. -type DialMetrics struct { - clock clock.Clock - latencies *metrics.HistogramVec - failures *metrics.CounterVec -} - -// newDialMetrics create a new DialMetrics, configured with default metric names. -func newDialMetrics() *DialMetrics { - latencies := metrics.NewHistogramVec( - &metrics.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "dial_duration_seconds", - Help: "Dial latency histogram in seconds, labeled by the protocol (http-connect or grpc), transport (tcp or uds)", - Buckets: latencyBuckets, - StabilityLevel: metrics.ALPHA, - }, - []string{"protocol", "transport"}, - ) - - failures := metrics.NewCounterVec( - &metrics.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "dial_failure_count", - Help: "Dial failure count, labeled by the protocol (http-connect or grpc), transport (tcp or uds), and stage (connect or proxy). The stage indicates at which stage the dial failed", - StabilityLevel: metrics.ALPHA, - }, - []string{"protocol", "transport", "stage"}, - ) - - legacyregistry.MustRegister(latencies) - legacyregistry.MustRegister(failures) - return &DialMetrics{latencies: latencies, failures: failures, clock: clock.RealClock{}} -} - -// Clock returns the clock. -func (m *DialMetrics) Clock() clock.Clock { - return m.clock -} - -// SetClock sets the clock. -func (m *DialMetrics) SetClock(c clock.Clock) { - m.clock = c -} - -// Reset resets the metrics. -func (m *DialMetrics) Reset() { - m.latencies.Reset() - m.failures.Reset() -} - -// ObserveDialLatency records the latency of a dial, labeled by protocol, transport. -func (m *DialMetrics) ObserveDialLatency(elapsed time.Duration, protocol, transport string) { - m.latencies.WithLabelValues(protocol, transport).Observe(elapsed.Seconds()) -} - -// ObserveDialFailure records a failed dial, labeled by protocol, transport, and the stage the dial failed at. -func (m *DialMetrics) ObserveDialFailure(protocol, transport, stage string) { - m.failures.WithLabelValues(protocol, transport, stage).Inc() -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/OWNERS b/vendor/k8s.io/apiserver/pkg/server/filters/OWNERS old mode 100644 new mode 100755 index c5f73991a31..121af9571f4 --- a/vendor/k8s.io/apiserver/pkg/server/filters/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/server/filters/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - sttts - dims diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/compression.go b/vendor/k8s.io/apiserver/pkg/server/filters/compression.go new file mode 100644 index 00000000000..625cd5c8d3a --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/server/filters/compression.go @@ -0,0 +1,181 @@ +/* +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 filters + +import ( + "compress/gzip" + "compress/zlib" + "errors" + "fmt" + "io" + "net/http" + "strings" + + "github.com/emicklei/go-restful" + + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/endpoints/request" +) + +// Compressor is an interface to compression writers +type Compressor interface { + io.WriteCloser + Flush() error +} + +const ( + headerAcceptEncoding = "Accept-Encoding" + headerContentEncoding = "Content-Encoding" + + encodingGzip = "gzip" + encodingDeflate = "deflate" +) + +// WithCompression wraps an http.Handler with the Compression Handler +func WithCompression(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + wantsCompression, encoding := wantsCompressedResponse(req) + w.Header().Set("Vary", "Accept-Encoding") + if wantsCompression { + compressionWriter, err := NewCompressionResponseWriter(w, encoding) + if err != nil { + handleError(w, req, err) + runtime.HandleError(fmt.Errorf("failed to compress HTTP response: %v", err)) + return + } + compressionWriter.Header().Set("Content-Encoding", encoding) + handler.ServeHTTP(compressionWriter, req) + compressionWriter.(*compressionResponseWriter).Close() + } else { + handler.ServeHTTP(w, req) + } + }) +} + +// wantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested. +func wantsCompressedResponse(req *http.Request) (bool, string) { + // don't compress watches + ctx := req.Context() + info, ok := request.RequestInfoFrom(ctx) + if !ok { + return false, "" + } + if !info.IsResourceRequest { + return false, "" + } + if info.Verb == "watch" { + return false, "" + } + header := req.Header.Get(headerAcceptEncoding) + gi := strings.Index(header, encodingGzip) + zi := strings.Index(header, encodingDeflate) + // use in order of appearance + switch { + case gi == -1: + return zi != -1, encodingDeflate + case zi == -1: + return gi != -1, encodingGzip + case gi < zi: + return true, encodingGzip + default: + return true, encodingDeflate + } +} + +type compressionResponseWriter struct { + writer http.ResponseWriter + compressor Compressor + encoding string +} + +// NewCompressionResponseWriter returns wraps w with a compression ResponseWriter, using the given encoding +func NewCompressionResponseWriter(w http.ResponseWriter, encoding string) (http.ResponseWriter, error) { + var compressor Compressor + switch encoding { + case encodingGzip: + compressor = gzip.NewWriter(w) + case encodingDeflate: + compressor = zlib.NewWriter(w) + default: + return nil, fmt.Errorf("%s is not a supported encoding type", encoding) + } + return &compressionResponseWriter{ + writer: w, + compressor: compressor, + encoding: encoding, + }, nil +} + +// compressionResponseWriter implements http.Responsewriter Interface +var _ http.ResponseWriter = &compressionResponseWriter{} + +func (c *compressionResponseWriter) Header() http.Header { + return c.writer.Header() +} + +// compress data according to compression method +func (c *compressionResponseWriter) Write(p []byte) (int, error) { + if c.compressorClosed() { + return -1, errors.New("compressing error: tried to write data using closed compressor") + } + c.Header().Set(headerContentEncoding, c.encoding) + defer c.compressor.Flush() + return c.compressor.Write(p) +} + +func (c *compressionResponseWriter) WriteHeader(status int) { + c.writer.WriteHeader(status) +} + +// CloseNotify is part of http.CloseNotifier interface +func (c *compressionResponseWriter) CloseNotify() <-chan bool { + return c.writer.(http.CloseNotifier).CloseNotify() +} + +// Close the underlying compressor +func (c *compressionResponseWriter) Close() error { + if c.compressorClosed() { + return errors.New("Compressing error: tried to close already closed compressor") + } + + c.compressor.Close() + c.compressor = nil + return nil +} + +func (c *compressionResponseWriter) Flush() { + if c.compressorClosed() { + return + } + c.compressor.Flush() +} + +func (c *compressionResponseWriter) compressorClosed() bool { + return nil == c.compressor +} + +// RestfulWithCompression wraps WithCompression to be compatible with go-restful +func RestfulWithCompression(function restful.RouteFunction) restful.RouteFunction { + return restful.RouteFunction(func(request *restful.Request, response *restful.Response) { + handler := WithCompression(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + response.ResponseWriter = w + request.Request = req + function(request, response) + })) + handler.ServeHTTP(response.ResponseWriter, request.Request) + }) +} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/compression_test.go b/vendor/k8s.io/apiserver/pkg/server/filters/compression_test.go new file mode 100644 index 00000000000..b179cff8ee7 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/server/filters/compression_test.go @@ -0,0 +1,106 @@ +/* +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 filters + +import ( + "bytes" + "compress/gzip" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/endpoints/filters" + "k8s.io/apiserver/pkg/endpoints/request" +) + +func TestCompression(t *testing.T) { + tests := []struct { + encoding string + watch bool + }{ + {"", false}, + {"gzip", true}, + {"gzip", false}, + } + + responseData := []byte("1234") + + for _, test := range tests { + handler := WithCompression( + http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write(responseData) + }), + ) + handler = filters.WithRequestInfo(handler, newTestRequestInfoResolver()) + server := httptest.NewServer(handler) + defer server.Close() + client := http.Client{ + Transport: &http.Transport{ + DisableCompression: true, + }, + } + + url := server.URL + "/api/v1/pods" + if test.watch { + url = url + "?watch=1" + } + request, err := http.NewRequest("GET", url, nil) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + request.Header.Set("Accept-Encoding", test.encoding) + response, err := client.Do(request) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + var reader io.Reader + if test.encoding == "gzip" && !test.watch { + if response.Header.Get("Content-Encoding") != "gzip" { + t.Fatal("expected response header Content-Encoding to be set to \"gzip\"") + } + if response.Header.Get("Vary") != "Accept-Encoding" { + t.Fatal("expected response header Vary to be set to \"Accept-Encoding\"") + } + reader, err = gzip.NewReader(response.Body) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + } else { + if response.Header.Get("Content-Encoding") == "gzip" { + t.Fatal("expected response header Content-Encoding not to be set") + } + reader = response.Body + } + body, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !bytes.Equal(body, responseData) { + t.Fatalf("Expected response body %s to equal %s", body, responseData) + } + } +} + +func newTestRequestInfoResolver() *request.RequestInfoFactory { + return &request.RequestInfoFactory{ + APIPrefixes: sets.NewString("api", "apis"), + GrouplessAPIPrefixes: sets.NewString("api"), + } +} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/content_type.go b/vendor/k8s.io/apiserver/pkg/server/filters/content_type.go deleted file mode 100644 index 65c73fcdc46..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/filters/content_type.go +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright 2019 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 filters - -import "net/http" - -// WithContentType sets both the Content-Type and the X-Content-Type-Options (nosniff) header -func WithContentType(handler http.Handler, contentType string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", contentType) - w.Header().Set("X-Content-Type-Options", "nosniff") - handler.ServeHTTP(w, r) - }) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/content_type_test.go b/vendor/k8s.io/apiserver/pkg/server/filters/content_type_test.go deleted file mode 100644 index 3fc163f18cf..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/filters/content_type_test.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Copyright 2019 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 filters - -import ( - "net/http" - "net/http/httptest" - "testing" -) - -func noopHandler() http.HandlerFunc { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // noop - }) -} - -func TestWithContentType(t *testing.T) { - mux := http.NewServeMux() - mux.Handle("/text", WithContentType(noopHandler(), "text/plain")) - mux.Handle("/json", WithContentType(noopHandler(), "application/json")) - tests := []struct { - description string - path string - expectedMimeType string - }{ - {"/text should return a plain text response", "/text", "text/plain"}, - {"/json should return a json response", "/json", "application/json"}, - } - for _, test := range tests { - path := "http://example.com" + test.path - t.Run(path, func(t *testing.T) { - req, err := http.NewRequest("GET", path, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - if nosniffHeader := w.Header().Get("X-Content-Type-Options"); nosniffHeader != "nosniff" { - t.Errorf("expected nosniff header to be set, got %v", nosniffHeader) - } - if mimeTypeHeader := w.Header().Get("Content-Type"); mimeTypeHeader != test.expectedMimeType { - t.Errorf("expected %v, got %v", test.expectedMimeType, mimeTypeHeader) - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/goaway.go b/vendor/k8s.io/apiserver/pkg/server/filters/goaway.go deleted file mode 100644 index 8b1b5e8ea4d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/filters/goaway.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2020 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 filters - -import ( - "math/rand" - "net/http" - "sync" -) - -// GoawayDecider decides if server should send a GOAWAY -type GoawayDecider interface { - Goaway(r *http.Request) bool -} - -var ( - // randPool used to get a rand.Rand and generate a random number thread-safely, - // which improve the performance of using rand.Rand with a locker - randPool = &sync.Pool{ - New: func() interface{} { - return rand.New(rand.NewSource(rand.Int63())) - }, - } -) - -// WithProbabilisticGoaway returns an http.Handler that send GOAWAY probabilistically -// according to the given chance for HTTP2 requests. After client receive GOAWAY, -// the in-flight long-running requests will not be influenced, and the new requests -// will use a new TCP connection to re-balancing to another server behind the load balance. -func WithProbabilisticGoaway(inner http.Handler, chance float64) http.Handler { - return &goaway{ - handler: inner, - decider: &probabilisticGoawayDecider{ - chance: chance, - next: func() float64 { - rnd := randPool.Get().(*rand.Rand) - ret := rnd.Float64() - randPool.Put(rnd) - return ret - }, - }, - } -} - -// goaway send a GOAWAY to client according to decider for HTTP2 requests -type goaway struct { - handler http.Handler - decider GoawayDecider -} - -// ServeHTTP implement HTTP handler -func (h *goaway) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.Proto == "HTTP/2.0" && h.decider.Goaway(r) { - // Send a GOAWAY and tear down the TCP connection when idle. - w.Header().Set("Connection", "close") - } - - h.handler.ServeHTTP(w, r) -} - -// probabilisticGoawayDecider send GOAWAY probabilistically according to chance -type probabilisticGoawayDecider struct { - chance float64 - next func() float64 -} - -// Goaway implement GoawayDecider -func (p *probabilisticGoawayDecider) Goaway(r *http.Request) bool { - if p.next() < p.chance { - return true - } - - return false -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/goaway_test.go b/vendor/k8s.io/apiserver/pkg/server/filters/goaway_test.go deleted file mode 100644 index ff35f30b9c6..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/filters/goaway_test.go +++ /dev/null @@ -1,309 +0,0 @@ -/* -Copyright 2020 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 filters - -import ( - "crypto/tls" - "io" - "math/rand" - "net" - "net/http" - "net/http/httptest" - "testing" - "time" - - "golang.org/x/net/http2" -) - -func TestProbabilisticGoawayDecider(t *testing.T) { - cases := []struct { - name string - chance float64 - nextFn func(chance float64) func() float64 - expectGOAWAY bool - }{ - { - name: "always not GOAWAY", - chance: 0, - nextFn: func(chance float64) func() float64 { - return rand.Float64 - }, - expectGOAWAY: false, - }, - { - name: "always GOAWAY", - chance: 1, - nextFn: func(chance float64) func() float64 { - return rand.Float64 - }, - expectGOAWAY: true, - }, - { - name: "hit GOAWAY", - chance: rand.Float64() + 0.01, - nextFn: func(chance float64) func() float64 { - return func() float64 { - return chance - 0.001 - } - }, - expectGOAWAY: true, - }, - { - name: "does not hit GOAWAY", - chance: rand.Float64() + 0.01, - nextFn: func(chance float64) func() float64 { - return func() float64 { - return chance + 0.001 - } - }, - expectGOAWAY: false, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - d := probabilisticGoawayDecider{chance: tc.chance, next: tc.nextFn(tc.chance)} - result := d.Goaway(nil) - if result != tc.expectGOAWAY { - t.Errorf("expect GOAWAY: %v, got: %v", tc.expectGOAWAY, result) - } - }) - } -} - -// TestClientReceivedGOAWAY tests the in-flight watch requests will not be affected and new requests use a -// connection after client received GOAWAY, and server response watch request with GOAWAY will not break client -// watching body read. -func TestClientReceivedGOAWAY(t *testing.T) { - const ( - urlNormal = "/normal" - urlWatch = "/watch" - urlGoaway = "/goaway" - urlWatchWithGoaway = "/watch-with-goaway" - ) - - const ( - // indicate the bytes watch request will be sent - // used to check if watch request was broke by GOAWAY - watchExpectSendBytes = 5 - ) - - watchHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - timer := time.NewTicker(time.Second) - - w.Header().Set("Transfer-Encoding", "chunked") - w.WriteHeader(200) - - flusher, _ := w.(http.Flusher) - flusher.Flush() - - count := 0 - for { - select { - case <-timer.C: - n, err := w.Write([]byte("w")) - if err != nil { - return - } - flusher.Flush() - count += n - if count == watchExpectSendBytes { - return - } - } - } - }) - - mux := http.NewServeMux() - mux.Handle(urlNormal, WithProbabilisticGoaway(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("hello")) - return - }), 0)) - mux.Handle(urlWatch, WithProbabilisticGoaway(watchHandler, 0)) - mux.Handle(urlGoaway, WithProbabilisticGoaway(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("hello")) - return - }), 1)) - mux.Handle(urlWatchWithGoaway, WithProbabilisticGoaway(watchHandler, 1)) - - s := httptest.NewUnstartedServer(mux) - - http2Options := &http2.Server{} - - if err := http2.ConfigureServer(s.Config, http2Options); err != nil { - t.Fatalf("failed to configure test server to be HTTP2 server, err: %v", err) - } - - s.TLS = s.Config.TLSConfig - s.StartTLS() - defer s.Close() - - tlsConfig := &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{http2.NextProtoTLS}, - } - - cases := []struct { - name string - reqs []string - // expectConnections always equals to GOAWAY requests(urlGoaway or urlWatchWithGoaway) + 1 - expectConnections int - }{ - { - name: "all normal requests use only one connection", - reqs: []string{urlNormal, urlNormal, urlNormal}, - expectConnections: 1, - }, - { - name: "got GOAWAY after set-up watch", - reqs: []string{urlNormal, urlWatch, urlGoaway, urlNormal, urlNormal}, - expectConnections: 2, - }, - { - name: "got GOAWAY after set-up watch, and set-up a new watch", - reqs: []string{urlNormal, urlWatch, urlGoaway, urlWatch, urlNormal, urlNormal}, - expectConnections: 2, - }, - { - name: "got 2 GOAWAY after set-up watch", - reqs: []string{urlNormal, urlWatch, urlGoaway, urlGoaway, urlNormal, urlNormal}, - expectConnections: 3, - }, - { - name: "combine with watch-with-goaway", - reqs: []string{urlNormal, urlWatchWithGoaway, urlNormal, urlWatch, urlGoaway, urlNormal, urlNormal}, - expectConnections: 3, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - // localAddr indicates how many TCP connection set up - localAddr := make([]string, 0) - - // init HTTP2 client - client := http.Client{ - Transport: &http2.Transport{ - TLSClientConfig: tlsConfig, - DialTLS: func(network, addr string, cfg *tls.Config) (conn net.Conn, err error) { - conn, err = tls.Dial(network, addr, cfg) - if err != nil { - t.Fatalf("unexpect connection err: %v", err) - } - localAddr = append(localAddr, conn.LocalAddr().String()) - return - }, - }, - } - - watchChs := make([]chan int, 0) - for _, url := range tc.reqs { - req, err := http.NewRequest(http.MethodGet, s.URL+url, nil) - if err != nil { - t.Fatalf("unexpect new request error: %v", err) - } - resp, err := client.Do(req) - if err != nil { - t.Fatalf("failed request test server, err: %v", err) - } - - // encounter watch bytes received, does not expect to be broken - if url == urlWatch || url == urlWatchWithGoaway { - ch := make(chan int) - watchChs = append(watchChs, ch) - go func() { - count := 0 - for { - buffer := make([]byte, 1) - n, err := resp.Body.Read(buffer) - if err != nil { - // urlWatch will receive io.EOF, - // urlWatchWithGoaway will receive http2.GoAwayError - if err != io.EOF { - if _, ok := err.(http2.GoAwayError); !ok { - t.Errorf("watch received not EOF err: %v", err) - } - } - ch <- count - return - } - count += n - } - }() - } - } - - // check TCP connection count - if tc.expectConnections != len(localAddr) { - t.Fatalf("expect TCP connection: %d, actual: %d", tc.expectConnections, len(localAddr)) - } - - // check if watch request is broken by GOAWAY response - watchTimeout := time.NewTimer(time.Second * 10) - for _, watchCh := range watchChs { - select { - case n := <-watchCh: - if n != watchExpectSendBytes { - t.Fatalf("in-flight watch was broken by GOAWAY response, expect go bytes: %d, actual got: %d", watchExpectSendBytes, n) - } - case <-watchTimeout.C: - t.Error("watch receive timeout") - } - } - }) - } -} - -func TestHTTP1Requests(t *testing.T) { - s := httptest.NewUnstartedServer(WithProbabilisticGoaway(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("hello")) - return - }), 1)) - - http2Options := &http2.Server{} - - if err := http2.ConfigureServer(s.Config, http2Options); err != nil { - t.Fatalf("failed to configure test server to be HTTP2 server, err: %v", err) - } - - s.TLS = s.Config.TLSConfig - s.StartTLS() - defer s.Close() - - tlsConfig := &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{"http/1.1"}, - } - - client := http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConfig, - }, - } - - resp, err := client.Get(s.URL) - if err != nil { - t.Fatalf("failed to request the server, err: %v", err) - } - - if v := resp.Header.Get("Connection"); v != "" { - t.Errorf("expect response HTTP header Connection to be empty, but got: %s", v) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go b/vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go index 13ff3ebbcc3..8818cb5633f 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go @@ -160,6 +160,12 @@ func WithMaxInFlightLimit( handler.ServeHTTP(w, r) default: + // We need to split this data between buckets used for throttling. + if isMutatingRequest { + metrics.DroppedRequests.WithLabelValues(metrics.MutatingKind).Inc() + } else { + metrics.DroppedRequests.WithLabelValues(metrics.ReadOnlyKind).Inc() + } // at this point we're about to return a 429, BUT not all actors should be rate limited. A system:master is so powerful // that they should always get an answer. It's a super-admin or a loopback connection. if currUser, ok := apirequest.UserFrom(ctx); ok { @@ -170,13 +176,7 @@ func WithMaxInFlightLimit( } } } - // We need to split this data between buckets used for throttling. - if isMutatingRequest { - metrics.DroppedRequests.WithLabelValues(metrics.MutatingKind).Inc() - } else { - metrics.DroppedRequests.WithLabelValues(metrics.ReadOnlyKind).Inc() - } - metrics.RecordRequestTermination(r, requestInfo, metrics.APIServerComponent, http.StatusTooManyRequests) + metrics.Record(r, requestInfo, "", http.StatusTooManyRequests, 0, 0) tooManyRequests(r, w) } } diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go b/vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go deleted file mode 100644 index 87bb76aa550..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright 2019 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 filters - -import ( - "context" - "fmt" - "net/http" - "sync/atomic" - - fcv1a1 "k8s.io/api/flowcontrol/v1alpha1" - apitypes "k8s.io/apimachinery/pkg/types" - apirequest "k8s.io/apiserver/pkg/endpoints/request" - utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol" - "k8s.io/klog" -) - -type priorityAndFairnessKeyType int - -const priorityAndFairnessKey priorityAndFairnessKeyType = iota - -const ( - responseHeaderMatchedPriorityLevelConfigurationUID = "X-Kubernetes-PF-PriorityLevel-UID" - responseHeaderMatchedFlowSchemaUID = "X-Kubernetes-PF-FlowSchema-UID" -) - -// PriorityAndFairnessClassification identifies the results of -// classification for API Priority and Fairness -type PriorityAndFairnessClassification struct { - FlowSchemaName string - FlowSchemaUID apitypes.UID - PriorityLevelName string - PriorityLevelUID apitypes.UID -} - -// GetClassification returns the classification associated with the -// given context, if any, otherwise nil -func GetClassification(ctx context.Context) *PriorityAndFairnessClassification { - return ctx.Value(priorityAndFairnessKey).(*PriorityAndFairnessClassification) -} - -var atomicMutatingLen, atomicNonMutatingLen int32 - -// WithPriorityAndFairness limits the number of in-flight -// requests in a fine-grained way. -func WithPriorityAndFairness( - handler http.Handler, - longRunningRequestCheck apirequest.LongRunningRequestCheck, - fcIfc utilflowcontrol.Interface, -) http.Handler { - if fcIfc == nil { - klog.Warningf("priority and fairness support not found, skipping") - return handler - } - startOnce.Do(startRecordingUsage) - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - requestInfo, ok := apirequest.RequestInfoFrom(ctx) - if !ok { - handleError(w, r, fmt.Errorf("no RequestInfo found in context")) - return - } - user, ok := apirequest.UserFrom(ctx) - if !ok { - handleError(w, r, fmt.Errorf("no User found in context")) - return - } - - // Skip tracking long running requests. - if longRunningRequestCheck != nil && longRunningRequestCheck(r, requestInfo) { - klog.V(6).Infof("Serving RequestInfo=%#+v, user.Info=%#+v as longrunning\n", requestInfo, user) - handler.ServeHTTP(w, r) - return - } - - var classification *PriorityAndFairnessClassification - note := func(fs *fcv1a1.FlowSchema, pl *fcv1a1.PriorityLevelConfiguration) { - classification = &PriorityAndFairnessClassification{ - FlowSchemaName: fs.Name, - FlowSchemaUID: fs.UID, - PriorityLevelName: pl.Name, - PriorityLevelUID: pl.UID} - } - - var served bool - isMutatingRequest := !nonMutatingRequestVerbs.Has(requestInfo.Verb) - execute := func() { - var mutatingLen, readOnlyLen int - if isMutatingRequest { - mutatingLen = int(atomic.AddInt32(&atomicMutatingLen, 1)) - } else { - readOnlyLen = int(atomic.AddInt32(&atomicNonMutatingLen, 1)) - } - defer func() { - if isMutatingRequest { - atomic.AddInt32(&atomicMutatingLen, -11) - watermark.recordMutating(mutatingLen) - } else { - atomic.AddInt32(&atomicNonMutatingLen, -1) - watermark.recordReadOnly(readOnlyLen) - } - }() - served = true - innerCtx := context.WithValue(ctx, priorityAndFairnessKey, classification) - innerReq := r.Clone(innerCtx) - w.Header().Set(responseHeaderMatchedPriorityLevelConfigurationUID, string(classification.PriorityLevelUID)) - w.Header().Set(responseHeaderMatchedFlowSchemaUID, string(classification.FlowSchemaUID)) - handler.ServeHTTP(w, innerReq) - } - digest := utilflowcontrol.RequestDigest{requestInfo, user} - fcIfc.Handle(ctx, digest, note, execute) - if !served { - tooManyRequests(r, w) - return - } - - }) -} diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go b/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go index 9b8d6d4b138..adb179f8235 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go @@ -28,7 +28,6 @@ import ( "time" apierrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apiserver/pkg/endpoints/metrics" apirequest "k8s.io/apiserver/pkg/endpoints/request" ) @@ -59,7 +58,7 @@ func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning apir postTimeoutFn := func() { cancel() - metrics.RecordRequestTermination(req, requestInfo, metrics.APIServerComponent, http.StatusGatewayTimeout) + metrics.Record(req, requestInfo, "", http.StatusGatewayTimeout, 0, 0) } return req, time.After(timeout), postTimeoutFn, apierrors.NewTimeoutError(fmt.Sprintf("request did not complete within %s", timeout), 0) } @@ -93,50 +92,28 @@ func (t *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - // resultCh is used as both errCh and stopCh - resultCh := make(chan interface{}) + errCh := make(chan interface{}) tw := newTimeoutWriter(w) go func() { defer func() { err := recover() - // do not wrap the sentinel ErrAbortHandler panic value - if err != nil && err != http.ErrAbortHandler { - // Same as stdlib http server code. Manually allocate stack - // trace buffer size to prevent excessively large logs + if err != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] err = fmt.Sprintf("%v\n%s", err, buf) } - resultCh <- err + errCh <- err }() t.handler.ServeHTTP(tw, r) }() select { - case err := <-resultCh: - // panic if error occurs; stop otherwise + case err := <-errCh: if err != nil { panic(err) } return case <-after: - defer func() { - // resultCh needs to have a reader, since the function doing - // the work needs to send to it. This is defer'd to ensure it runs - // ever if the post timeout work itself panics. - go func() { - res := <-resultCh - if res != nil { - switch t := res.(type) { - case error: - utilruntime.HandleError(t) - default: - utilruntime.HandleError(fmt.Errorf("%v", res)) - } - } - }() - }() - postTimeoutFn() tw.timeout(err) } diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go b/vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go index 4ad8717c018..26f571d08af 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/timeout_test.go @@ -52,14 +52,14 @@ func (r *recorder) Count() int { return r.count } -func newHandler(responseCh <-chan string, panicCh <-chan interface{}, writeErrCh chan<- error) http.HandlerFunc { +func newHandler(responseCh <-chan string, panicCh <-chan struct{}, writeErrCh chan<- error) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { select { case resp := <-responseCh: _, err := w.Write([]byte(resp)) writeErrCh <- err - case panicReason := <-panicCh: - panic(panicReason) + case <-panicCh: + panic("inner handler panics") } }) } @@ -72,7 +72,7 @@ func TestTimeout(t *testing.T) { }() sendResponse := make(chan string, 1) - doPanic := make(chan interface{}, 1) + doPanic := make(chan struct{}, 1) writeErrors := make(chan error, 1) gotPanic := make(chan interface{}, 1) timeout := make(chan time.Time, 1) @@ -139,7 +139,7 @@ func TestTimeout(t *testing.T) { } // Panics - doPanic <- "inner handler panics" + doPanic <- struct{}{} res, err = http.Get(ts.URL) if err != nil { t.Fatal(err) @@ -156,22 +156,4 @@ func TestTimeout(t *testing.T) { case <-time.After(30 * time.Second): t.Fatalf("expected to see a handler panic, but didn't") } - - // Panics with http.ErrAbortHandler - doPanic <- http.ErrAbortHandler - res, err = http.Get(ts.URL) - if err != nil { - t.Fatal(err) - } - if res.StatusCode != http.StatusInternalServerError { - t.Errorf("got res.StatusCode %d; expected %d due to panic", res.StatusCode, http.StatusInternalServerError) - } - select { - case err := <-gotPanic: - if err != http.ErrAbortHandler { - t.Errorf("expected unwrapped http.ErrAbortHandler, got %#v", err) - } - case <-time.After(30 * time.Second): - t.Fatalf("expected to see a handler panic, but didn't") - } } diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go b/vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go index 857ce188307..b40a4227296 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go @@ -18,16 +18,11 @@ package filters import ( "errors" - "fmt" "net/http" - "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" apirequest "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/client-go/kubernetes/scheme" ) // WithWaitGroup adds all non long-running requests to wait group, which is used for graceful shutdown. @@ -43,14 +38,7 @@ func WithWaitGroup(handler http.Handler, longRunning apirequest.LongRunningReque if !longRunning(req, requestInfo) { if err := wg.Add(1); err != nil { - // When apiserver is shutting down, signal clients to retry - // There is a good chance the client hit a different server, so a tight retry is good for client responsiveness. - w.Header().Add("Retry-After", "1") - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - w.Header().Set("X-Content-Type-Options", "nosniff") - statusErr := apierrors.NewServiceUnavailable("apiserver is shutting down").Status() - w.WriteHeader(int(statusErr.Code)) - fmt.Fprintln(w, runtime.EncodeOrDie(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &statusErr)) + http.Error(w, "apiserver is shutting down.", http.StatusInternalServerError) return } defer wg.Done() diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go b/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go index 96bebdbd600..0a75845611d 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go @@ -25,28 +25,23 @@ import ( "k8s.io/apiserver/pkg/server/httplog" ) -// WithPanicRecovery wraps an http Handler to recover and log panics (except in the special case of http.ErrAbortHandler panics, which suppress logging). +// WithPanicRecovery wraps an http Handler to recover and log panics. func WithPanicRecovery(handler http.Handler) http.Handler { return withPanicRecovery(handler, func(w http.ResponseWriter, req *http.Request, err interface{}) { - if err == http.ErrAbortHandler { - // honor the http.ErrAbortHandler sentinel panic value: - // ErrAbortHandler is a sentinel panic value to abort a handler. - // While any panic from ServeHTTP aborts the response to the client, - // panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log. - return - } http.Error(w, "This request caused apiserver to panic. Look in the logs for details.", http.StatusInternalServerError) klog.Errorf("apiserver panic'd on %v %v", req.Method, req.RequestURI) }) } func withPanicRecovery(handler http.Handler, crashHandler func(http.ResponseWriter, *http.Request, interface{})) http.Handler { - handler = httplog.WithLogging(handler, httplog.DefaultStacktracePred) return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { defer runtime.HandleCrash(func(err interface{}) { crashHandler(w, req, err) }) + logger := httplog.NewLogged(req, &w) + defer logger.Log() + // Dispatch to the internal handler handler.ServeHTTP(w, req) }) diff --git a/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go b/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go index 9c623f6485d..011de3c7061 100644 --- a/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -25,14 +25,14 @@ import ( "time" systemd "github.com/coreos/go-systemd/daemon" - "github.com/go-openapi/spec" + "github.com/emicklei/go-restful-swagger12" + "k8s.io/klog" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/sets" utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup" "k8s.io/apiserver/pkg/admission" @@ -45,10 +45,8 @@ import ( "k8s.io/apiserver/pkg/server/routes" utilopenapi "k8s.io/apiserver/pkg/util/openapi" restclient "k8s.io/client-go/rest" - "k8s.io/klog" openapibuilder "k8s.io/kube-openapi/pkg/builder" openapicommon "k8s.io/kube-openapi/pkg/common" - "k8s.io/kube-openapi/pkg/handler" openapiutil "k8s.io/kube-openapi/pkg/util" openapiproto "k8s.io/kube-openapi/pkg/util/proto" ) @@ -77,10 +75,6 @@ type APIGroupInfo struct { NegotiatedSerializer runtime.NegotiatedSerializer // ParameterCodec performs conversions for query parameters passed to API calls ParameterCodec runtime.ParameterCodec - - // StaticOpenAPISpec is the spec derived from the definitions of all resources installed together. - // It is set during InstallAPIGroups, InstallAPIGroup, and InstallLegacyAPIGroup. - StaticOpenAPISpec *spec.Swagger } // GenericAPIServer contains state for a Kubernetes cluster api server. @@ -127,16 +121,9 @@ type GenericAPIServer struct { DiscoveryGroupManager discovery.GroupManager // Enable swagger and/or OpenAPI if these configs are non-nil. + swaggerConfig *swagger.Config openAPIConfig *openapicommon.Config - // OpenAPIVersionedService controls the /openapi/v2 endpoint, and can be used to update the served spec. - // It is set during PrepareRun. - OpenAPIVersionedService *handler.OpenAPIService - - // StaticOpenAPISpec is the spec derived from the restful container endpoints. - // It is set during PrepareRun. - StaticOpenAPISpec *spec.Swagger - // PostStartHooks are each called after the server has started listening, in a separate go func for each // with no guarantee of ordering between them. The map key is a name used for error reporting. // It may kill the process with a panic if it wishes to by returning an error. @@ -150,22 +137,9 @@ type GenericAPIServer struct { preShutdownHooksCalled bool // healthz checks - healthzLock sync.Mutex - healthzChecks []healthz.HealthChecker - healthzChecksInstalled bool - // livez checks - livezLock sync.Mutex - livezChecks []healthz.HealthChecker - livezChecksInstalled bool - // readyz checks - readyzLock sync.Mutex - readyzChecks []healthz.HealthChecker - readyzChecksInstalled bool - livezGracePeriod time.Duration - livezClock clock.Clock - // the readiness stop channel is used to signal that the apiserver has initiated a shutdown sequence, this - // will cause readyz to return unhealthy. - readinessStopCh chan struct{} + healthzLock sync.Mutex + healthzChecks []healthz.HealthzChecker + healthzCreated bool // auditing. The backend is started after the server starts listening. AuditBackend audit.Backend @@ -175,10 +149,6 @@ type GenericAPIServer struct { // the create-on-update case Authorizer authorizer.Authorizer - // EquivalentResourceRegistry provides information about resources equivalent to a given resource, - // and the kind associated with a given resource. As resources are installed, they are registered here. - EquivalentResourceRegistry runtime.EquivalentResourceRegistry - // enableAPIResponseCompression indicates whether API Responses should support compression // if the client requests it via Accept-Encoding enableAPIResponseCompression bool @@ -189,11 +159,6 @@ type GenericAPIServer struct { // HandlerChainWaitGroup allows you to wait for all chain handlers finish after the server shutdown. HandlerChainWaitGroup *utilwaitgroup.SafeWaitGroup - // ShutdownDelayDuration allows to block shutdown for some time, e.g. until endpoints pointing to this API server - // have converged on all node. During this time, the API server keeps serving, /healthz will return 200, - // but /readyz will return failure. - ShutdownDelayDuration time.Duration - // The limit on the request body size that would be accepted and decoded in a write request. // 0 means no limit. maxRequestBodyBytes int64 @@ -212,16 +177,13 @@ type DelegationTarget interface { PreShutdownHooks() map[string]preShutdownHookEntry // HealthzChecks returns the healthz checks that need to be combined - HealthzChecks() []healthz.HealthChecker + HealthzChecks() []healthz.HealthzChecker // ListedPaths returns the paths for supporting an index ListedPaths() []string // NextDelegate returns the next delegationTarget in the chain of delegations NextDelegate() DelegationTarget - - // PrepareRun does post API installation setup steps. It calls recursively the same function of the delegates. - PrepareRun() preparedGenericAPIServer } func (s *GenericAPIServer) UnprotectedHandler() http.Handler { @@ -234,7 +196,7 @@ func (s *GenericAPIServer) PostStartHooks() map[string]postStartHookEntry { func (s *GenericAPIServer) PreShutdownHooks() map[string]preShutdownHookEntry { return s.preShutdownHooks } -func (s *GenericAPIServer) HealthzChecks() []healthz.HealthChecker { +func (s *GenericAPIServer) HealthzChecks() []healthz.HealthzChecker { return s.healthzChecks } func (s *GenericAPIServer) ListedPaths() []string { @@ -261,8 +223,8 @@ func (s emptyDelegate) PostStartHooks() map[string]postStartHookEntry { func (s emptyDelegate) PreShutdownHooks() map[string]preShutdownHookEntry { return map[string]preShutdownHookEntry{} } -func (s emptyDelegate) HealthzChecks() []healthz.HealthChecker { - return []healthz.HealthChecker{} +func (s emptyDelegate) HealthzChecks() []healthz.HealthzChecker { + return []healthz.HealthzChecker{} } func (s emptyDelegate) ListedPaths() []string { return []string{} @@ -270,42 +232,31 @@ func (s emptyDelegate) ListedPaths() []string { func (s emptyDelegate) NextDelegate() DelegationTarget { return nil } -func (s emptyDelegate) PrepareRun() preparedGenericAPIServer { - return preparedGenericAPIServer{nil} -} // preparedGenericAPIServer is a private wrapper that enforces a call of PrepareRun() before Run can be invoked. type preparedGenericAPIServer struct { *GenericAPIServer } -// PrepareRun does post API installation setup steps. It calls recursively the same function of the delegates. +// PrepareRun does post API installation setup steps. func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer { - s.delegationTarget.PrepareRun() - + if s.swaggerConfig != nil { + routes.Swagger{Config: s.swaggerConfig}.Install(s.Handler.GoRestfulContainer) + } if s.openAPIConfig != nil { - s.OpenAPIVersionedService, s.StaticOpenAPISpec = routes.OpenAPI{ + routes.OpenAPI{ Config: s.openAPIConfig, }.Install(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux) } s.installHealthz() - s.installLivez() - err := s.addReadyzShutdownCheck(s.readinessStopCh) - if err != nil { - klog.Errorf("Failed to install readyz shutdown check %s", err) - } - s.installReadyz() // Register audit backend preShutdownHook. if s.AuditBackend != nil { - err := s.AddPreShutdownHook("audit-backend", func() error { + s.AddPreShutdownHook("audit-backend", func() error { s.AuditBackend.Shutdown() return nil }) - if err != nil { - klog.Errorf("Failed to add pre-shutdown hook for audit-backend %s", err) - } } return preparedGenericAPIServer{s} @@ -314,38 +265,18 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer { // Run spawns the secure http server. It only returns if stopCh is closed // or the secure port cannot be listened on initially. func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error { - delayedStopCh := make(chan struct{}) - - go func() { - defer close(delayedStopCh) - - <-stopCh - - // As soon as shutdown is initiated, /readyz should start returning failure. - // This gives the load balancer a window defined by ShutdownDelayDuration to detect that /readyz is red - // and stop sending traffic to this server. - close(s.readinessStopCh) - - time.Sleep(s.ShutdownDelayDuration) - }() - - // close socket after delayed stopCh - err := s.NonBlockingRun(delayedStopCh) + err := s.NonBlockingRun(stopCh) if err != nil { return err } <-stopCh - // run shutdown hooks directly. This includes deregistering from the kubernetes endpoint in case of kube-apiserver. err = s.RunPreShutdownHooks() if err != nil { return err } - // wait for the delayed stopCh before closing the handler chain (it rejects everything after Wait has been called). - <-delayedStopCh - // Wait for all requests to finish, which are bounded by the RequestTimeout variable. s.HandlerChainWaitGroup.Wait() @@ -369,13 +300,10 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error { // Use an internal stop channel to allow cleanup of the listeners on error. internalStopCh := make(chan struct{}) - var stoppedCh <-chan struct{} + if s.SecureServingInfo != nil && s.Handler != nil { - var err error - stoppedCh, err = s.SecureServingInfo.Serve(s.Handler, s.ShutdownTimeout, internalStopCh) - if err != nil { + if err := s.SecureServingInfo.Serve(s.Handler, s.ShutdownTimeout, internalStopCh); err != nil { close(internalStopCh) - close(auditStopCh) return err } } @@ -386,9 +314,6 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error { go func() { <-stopCh close(internalStopCh) - if stoppedCh != nil { - <-stoppedCh - } s.HandlerChainWaitGroup.Wait() close(auditStopCh) }() @@ -403,7 +328,11 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error { } // installAPIResources is a private method for installing the REST storage backing each api groupversionresource -func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, openAPIModels openapiproto.Models) error { +func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error { + openAPIGroupModels, err := s.getOpenAPIModelsForGroup(apiPrefix, apiGroupInfo) + if err != nil { + return fmt.Errorf("unable to get openapi models for group %v: %v", apiPrefix, err) + } for _, groupVersion := range apiGroupInfo.PrioritizedVersions { if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 { klog.Warningf("Skipping API %v because it has no resources.", groupVersion) @@ -414,7 +343,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A if apiGroupInfo.OptionsExternalVersion != nil { apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion } - apiGroupVersion.OpenAPIModels = openAPIModels + apiGroupVersion.OpenAPIModels = openAPIGroupModels apiGroupVersion.MaxRequestBodyBytes = s.maxRequestBodyBytes if err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer); err != nil { @@ -429,13 +358,7 @@ func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo if !s.legacyAPIGroupPrefixes.Has(apiPrefix) { return fmt.Errorf("%q is not in the allowed legacy API prefixes: %v", apiPrefix, s.legacyAPIGroupPrefixes.List()) } - - openAPIModels, err := s.getOpenAPIModels(apiPrefix, apiGroupInfo) - if err != nil { - return fmt.Errorf("unable to get openapi models: %v", err) - } - - if err := s.installAPIResources(apiPrefix, apiGroupInfo, openAPIModels); err != nil { + if err := s.installAPIResources(apiPrefix, apiGroupInfo); err != nil { return err } @@ -446,64 +369,51 @@ func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo return nil } -// Exposes given api groups in the API. -func (s *GenericAPIServer) InstallAPIGroups(apiGroupInfos ...*APIGroupInfo) error { - for _, apiGroupInfo := range apiGroupInfos { - // Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned. - // Catching these here places the error much closer to its origin - if len(apiGroupInfo.PrioritizedVersions[0].Group) == 0 { - return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo) - } - if len(apiGroupInfo.PrioritizedVersions[0].Version) == 0 { - return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo) - } +// Exposes the given api group in the API. +func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error { + // Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned. + // Catching these here places the error much closer to its origin + if len(apiGroupInfo.PrioritizedVersions[0].Group) == 0 { + return fmt.Errorf("cannot register handler with an empty group for %#v", *apiGroupInfo) + } + if len(apiGroupInfo.PrioritizedVersions[0].Version) == 0 { + return fmt.Errorf("cannot register handler with an empty version for %#v", *apiGroupInfo) } - openAPIModels, err := s.getOpenAPIModels(APIGroupPrefix, apiGroupInfos...) - if err != nil { - return fmt.Errorf("unable to get openapi models: %v", err) + if err := s.installAPIResources(APIGroupPrefix, apiGroupInfo); err != nil { + return err } - for _, apiGroupInfo := range apiGroupInfos { - if err := s.installAPIResources(APIGroupPrefix, apiGroupInfo, openAPIModels); err != nil { - return fmt.Errorf("unable to install api resources: %v", err) + // setup discovery + // Install the version handler. + // Add a handler at /apis/ to enumerate all versions supported by this group. + apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{} + for _, groupVersion := range apiGroupInfo.PrioritizedVersions { + // Check the config to make sure that we elide versions that don't have any resources + if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 { + continue } + apiVersionsForDiscovery = append(apiVersionsForDiscovery, metav1.GroupVersionForDiscovery{ + GroupVersion: groupVersion.String(), + Version: groupVersion.Version, + }) + } + preferredVersionForDiscovery := metav1.GroupVersionForDiscovery{ + GroupVersion: apiGroupInfo.PrioritizedVersions[0].String(), + Version: apiGroupInfo.PrioritizedVersions[0].Version, + } + apiGroup := metav1.APIGroup{ + Name: apiGroupInfo.PrioritizedVersions[0].Group, + Versions: apiVersionsForDiscovery, + PreferredVersion: preferredVersionForDiscovery, + } - // setup discovery - // Install the version handler. - // Add a handler at /apis/ to enumerate all versions supported by this group. - apiVersionsForDiscovery := []metav1.GroupVersionForDiscovery{} - for _, groupVersion := range apiGroupInfo.PrioritizedVersions { - // Check the config to make sure that we elide versions that don't have any resources - if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 { - continue - } - apiVersionsForDiscovery = append(apiVersionsForDiscovery, metav1.GroupVersionForDiscovery{ - GroupVersion: groupVersion.String(), - Version: groupVersion.Version, - }) - } - preferredVersionForDiscovery := metav1.GroupVersionForDiscovery{ - GroupVersion: apiGroupInfo.PrioritizedVersions[0].String(), - Version: apiGroupInfo.PrioritizedVersions[0].Version, - } - apiGroup := metav1.APIGroup{ - Name: apiGroupInfo.PrioritizedVersions[0].Group, - Versions: apiVersionsForDiscovery, - PreferredVersion: preferredVersionForDiscovery, - } + s.DiscoveryGroupManager.AddGroup(apiGroup) + s.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(s.Serializer, apiGroup).WebService()) - s.DiscoveryGroupManager.AddGroup(apiGroup) - s.Handler.GoRestfulContainer.Add(discovery.NewAPIGroupHandler(s.Serializer, apiGroup).WebService()) - } return nil } -// Exposes the given api group in the API. -func (s *GenericAPIServer) InstallAPIGroup(apiGroupInfo *APIGroupInfo) error { - return s.InstallAPIGroups(apiGroupInfo) -} - func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion schema.GroupVersion, apiPrefix string) *genericapi.APIGroupVersion { storage := make(map[string]rest.Storage) for k, v := range apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version] { @@ -529,11 +439,10 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV Typer: apiGroupInfo.Scheme, Linker: runtime.SelfLinker(meta.NewAccessor()), - EquivalentResourceRegistry: s.EquivalentResourceRegistry, - - Admit: s.admissionControl, - MinRequestTimeout: s.minRequestTimeout, - Authorizer: s.Authorizer, + Admit: s.admissionControl, + MinRequestTimeout: s.minRequestTimeout, + EnableAPIResponseCompression: s.enableAPIResponseCompression, + Authorizer: s.Authorizer, } } @@ -551,34 +460,12 @@ func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec } } -// getOpenAPIModels is a private method for getting the OpenAPI models -func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (openapiproto.Models, error) { +// getOpenAPIModelsForGroup is a private method for getting the OpenAPI Schemas for each api group +func (s *GenericAPIServer) getOpenAPIModelsForGroup(apiPrefix string, apiGroupInfo *APIGroupInfo) (openapiproto.Models, error) { if s.openAPIConfig == nil { return nil, nil } pathsToIgnore := openapiutil.NewTrie(s.openAPIConfig.IgnorePrefixes) - resourceNames := make([]string, 0) - for _, apiGroupInfo := range apiGroupInfos { - groupResources, err := getResourceNamesForGroup(apiPrefix, apiGroupInfo, pathsToIgnore) - if err != nil { - return nil, err - } - resourceNames = append(resourceNames, groupResources...) - } - - // Build the openapi definitions for those resources and convert it to proto models - openAPISpec, err := openapibuilder.BuildOpenAPIDefinitionsForResources(s.openAPIConfig, resourceNames...) - if err != nil { - return nil, err - } - for _, apiGroupInfo := range apiGroupInfos { - apiGroupInfo.StaticOpenAPISpec = openAPISpec - } - return utilopenapi.ToProtoModels(openAPISpec) -} - -// getResourceNamesForGroup is a private method for getting the canonical names for each resource to build in an api group -func getResourceNamesForGroup(apiPrefix string, apiGroupInfo *APIGroupInfo, pathsToIgnore openapiutil.Trie) ([]string, error) { // Get the canonical names of every resource we need to build in this api group resourceNames := make([]string, 0) for _, groupVersion := range apiGroupInfo.PrioritizedVersions { @@ -599,5 +486,10 @@ func getResourceNamesForGroup(apiPrefix string, apiGroupInfo *APIGroupInfo, path } } - return resourceNames, nil + // Build the openapi definitions for those resources and convert it to proto models + openAPISpec, err := openapibuilder.BuildOpenAPIDefinitionsForResources(s.openAPIConfig, resourceNames...) + if err != nil { + return nil, err + } + return utilopenapi.ToProtoModels(openAPISpec) } diff --git a/vendor/k8s.io/apiserver/pkg/server/genericapiserver_test.go b/vendor/k8s.io/apiserver/pkg/server/genericapiserver_test.go index a304b6db651..a3dda1a44ff 100644 --- a/vendor/k8s.io/apiserver/pkg/server/genericapiserver_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/genericapiserver_test.go @@ -89,18 +89,18 @@ func buildTestOpenAPIDefinition() kubeopenapi.OpenAPIDefinition { }, VendorExtensible: openapi.VendorExtensible{ Extensions: openapi.Extensions{ - "x-kubernetes-group-version-kind": []interface{}{ - map[string]interface{}{ + "x-kubernetes-group-version-kind": []map[string]string{ + { "group": "", "version": "v1", "kind": "Getter", }, - map[string]interface{}{ + { "group": "batch", "version": "v1", "kind": "Getter", }, - map[string]interface{}{ + { "group": "extensions", "version": "v1", "kind": "Getter", @@ -137,6 +137,7 @@ func setUp(t *testing.T) (Config, *assert.Assertions) { config.OpenAPIConfig = DefaultOpenAPIConfig(testGetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(runtime.NewScheme())) config.OpenAPIConfig.Info.Version = "unversioned" + config.SwaggerConfig = DefaultSwaggerConfig() sharedInformers := informers.NewSharedInformerFactory(clientset, config.LoopbackClientConfig.Timeout) config.Complete(sharedInformers) @@ -161,6 +162,11 @@ func TestNew(t *testing.T) { // Verify many of the variables match their config counterparts assert.Equal(s.legacyAPIGroupPrefixes, config.LegacyAPIGroupPrefixes) assert.Equal(s.admissionControl, config.AdmissionControl) + + // these values get defaulted + assert.Equal(net.JoinHostPort(config.PublicAddress.String(), "443"), s.ExternalAddress) + assert.NotNil(s.swaggerConfig) + assert.Equal("http://"+s.ExternalAddress, s.swaggerConfig.WebServicesUrl) } // Verifies that AddGroupVersions works as expected. @@ -315,7 +321,7 @@ func TestInstallAPIGroups(t *testing.T) { func TestPrepareRun(t *testing.T) { s, config, assert := newMaster(t) - assert.NotNil(config.OpenAPIConfig) + assert.NotNil(config.SwaggerConfig) server := httptest.NewServer(s.Handler.Director) defer server.Close() @@ -324,8 +330,8 @@ func TestPrepareRun(t *testing.T) { s.PrepareRun() s.RunPostStartHooks(done) - // openapi is installed in PrepareRun - resp, err := http.Get(server.URL + "/openapi/v2") + // swagger is installed in PrepareRun + resp, err := http.Get(server.URL + "/swaggerapi/") assert.NoError(err) assert.Equal(http.StatusOK, resp.StatusCode) @@ -338,46 +344,6 @@ func TestPrepareRun(t *testing.T) { assert.Equal(http.StatusOK, resp.StatusCode) } -func TestUpdateOpenAPISpec(t *testing.T) { - s, _, assert := newMaster(t) - s.PrepareRun() - s.RunPostStartHooks(make(chan struct{})) - - server := httptest.NewServer(s.Handler.Director) - defer server.Close() - - // verify the static spec in record is what we currently serve - oldSpec, err := json.Marshal(s.StaticOpenAPISpec) - assert.NoError(err) - - resp, err := http.Get(server.URL + "/openapi/v2") - assert.NoError(err) - assert.Equal(http.StatusOK, resp.StatusCode) - - body, err := ioutil.ReadAll(resp.Body) - assert.NoError(err) - assert.Equal(oldSpec, body) - resp.Body.Close() - - // verify we are able to update the served spec using the exposed service - newSpec := []byte(`{"swagger":"2.0","info":{"title":"Test Updated Generic API Server Swagger","version":"v0.1.0"},"paths":null}`) - swagger := new(openapi.Swagger) - err = json.Unmarshal(newSpec, swagger) - assert.NoError(err) - - err = s.OpenAPIVersionedService.UpdateSpec(swagger) - assert.NoError(err) - - resp, err = http.Get(server.URL + "/openapi/v2") - assert.NoError(err) - defer resp.Body.Close() - assert.Equal(http.StatusOK, resp.StatusCode) - - body, err = ioutil.ReadAll(resp.Body) - assert.NoError(err) - assert.Equal(newSpec, body) -} - // TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions. func TestCustomHandlerChain(t *testing.T) { config, _ := setUp(t) @@ -440,8 +406,10 @@ func TestNotRestRoutesHaveAuth(t *testing.T) { config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix") config.Authorization.Authorizer = &authz + config.EnableSwaggerUI = true config.EnableIndex = true config.EnableProfiling = true + config.SwaggerConfig = DefaultSwaggerConfig() kubeVersion := fakeVersion() config.Version = &kubeVersion @@ -455,6 +423,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) { route string }{ {"/"}, + {"/swagger-ui/"}, {"/debug/pprof/"}, {"/debug/flags/"}, {"/version"}, @@ -477,7 +446,7 @@ type mockAuthorizer struct { lastURI string } -func (authz *mockAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { +func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { authz.lastURI = a.GetPath() return authorizer.DecisionAllow, "", nil } @@ -548,23 +517,19 @@ func TestGracefulShutdown(t *testing.T) { return handler } - s, err := config.Complete(nil).New("test", NewEmptyDelegate()) - if err != nil { - t.Fatalf("Error in bringing up the server: %v", err) - } - - twoSecondHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { wg.Done() time.Sleep(2 * time.Second) w.WriteHeader(http.StatusOK) graceShutdown = true }) - okHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - w.WriteHeader(http.StatusOK) - }) - s.Handler.NonGoRestfulMux.Handle("/test", twoSecondHandler) - s.Handler.NonGoRestfulMux.Handle("/200", okHandler) + s, err := config.Complete(nil).New("test", NewEmptyDelegate()) + if err != nil { + t.Fatalf("Error in bringing up the server: %v", err) + } + + s.Handler.NonGoRestfulMux.Handle("/test", handler) insecureServer := &http.Server{ Addr: "0.0.0.0:0", @@ -579,9 +544,9 @@ func TestGracefulShutdown(t *testing.T) { // get port serverPort := ln.Addr().(*net.TCPAddr).Port - stoppedCh, err := RunServer(insecureServer, ln, 10*time.Second, stopCh) + err = RunServer(insecureServer, ln, 10*time.Second, stopCh) if err != nil { - t.Fatalf("RunServer err: %v", err) + t.Errorf("RunServer err: %v", err) } graceCh := make(chan struct{}) @@ -600,15 +565,8 @@ func TestGracefulShutdown(t *testing.T) { // close stopCh after request sent to server to guarantee request handler is running. wg.Wait() close(stopCh) - - time.Sleep(500 * time.Millisecond) - if _, err := http.Get("http://127.0.0.1:" + strconv.Itoa(serverPort) + "/200"); err == nil { - t.Errorf("Unexpected http success after stopCh was closed") - } - // wait for wait group handler finish s.HandlerChainWaitGroup.Wait() - <-stoppedCh // check server all handlers finished. if !graceShutdown { diff --git a/vendor/k8s.io/apiserver/pkg/server/healthz.go b/vendor/k8s.io/apiserver/pkg/server/healthz.go index 645886949bb..43e102b5cc7 100644 --- a/vendor/k8s.io/apiserver/pkg/server/healthz.go +++ b/vendor/k8s.io/apiserver/pkg/server/healthz.go @@ -18,142 +18,28 @@ package server import ( "fmt" - "net/http" - "time" - "k8s.io/apimachinery/pkg/util/clock" "k8s.io/apiserver/pkg/server/healthz" ) -// AddHealthChecks adds HealthCheck(s) to health endpoints (healthz, livez, readyz) but -// configures the liveness grace period to be zero, which means we expect this health check -// to immediately indicate that the apiserver is unhealthy. -func (s *GenericAPIServer) AddHealthChecks(checks ...healthz.HealthChecker) error { - // we opt for a delay of zero here, because this entrypoint adds generic health checks - // and not health checks which are specifically related to kube-apiserver boot-sequences. - return s.addHealthChecks(0, checks...) -} - -// AddBootSequenceHealthChecks adds health checks to the old healthz endpoint (for backwards compatibility reasons) -// as well as livez and readyz. The livez grace period is defined by the value of the -// command-line flag --livez-grace-period; before the grace period elapses, the livez health checks -// will default to healthy. One may want to set a grace period in order to prevent the kubelet from restarting -// the kube-apiserver due to long-ish boot sequences. Readyz health checks, on the other hand, have no grace period, -// since readyz should fail until boot fully completes. -func (s *GenericAPIServer) AddBootSequenceHealthChecks(checks ...healthz.HealthChecker) error { - return s.addHealthChecks(s.livezGracePeriod, checks...) -} - -// addHealthChecks adds health checks to healthz, livez, and readyz. The delay passed in will set -// a corresponding grace period on livez. -func (s *GenericAPIServer) addHealthChecks(livezGracePeriod time.Duration, checks ...healthz.HealthChecker) error { +// AddHealthzCheck allows you to add a HealthzCheck. +func (s *GenericAPIServer) AddHealthzChecks(checks ...healthz.HealthzChecker) error { s.healthzLock.Lock() defer s.healthzLock.Unlock() - if s.healthzChecksInstalled { + + if s.healthzCreated { return fmt.Errorf("unable to add because the healthz endpoint has already been created") } - s.healthzChecks = append(s.healthzChecks, checks...) - return s.addLivezChecks(livezGracePeriod, checks...) -} -// addReadyzChecks allows you to add a HealthCheck to readyz. -func (s *GenericAPIServer) addReadyzChecks(checks ...healthz.HealthChecker) error { - s.readyzLock.Lock() - defer s.readyzLock.Unlock() - if s.readyzChecksInstalled { - return fmt.Errorf("unable to add because the readyz endpoint has already been created") - } - s.readyzChecks = append(s.readyzChecks, checks...) + s.healthzChecks = append(s.healthzChecks, checks...) return nil } -// addLivezChecks allows you to add a HealthCheck to livez. It will also automatically add a check to readyz, -// since we want to avoid being ready when we are not live. -func (s *GenericAPIServer) addLivezChecks(delay time.Duration, checks ...healthz.HealthChecker) error { - s.livezLock.Lock() - defer s.livezLock.Unlock() - if s.livezChecksInstalled { - return fmt.Errorf("unable to add because the livez endpoint has already been created") - } - for _, check := range checks { - s.livezChecks = append(s.livezChecks, delayedHealthCheck(check, s.livezClock, delay)) - } - return s.addReadyzChecks(checks...) -} - -// addReadyzShutdownCheck is a convenience function for adding a readyz shutdown check, so -// that we can register that the api-server is no longer ready while we attempt to gracefully -// shutdown. -func (s *GenericAPIServer) addReadyzShutdownCheck(stopCh <-chan struct{}) error { - return s.addReadyzChecks(shutdownCheck{stopCh}) -} - // installHealthz creates the healthz endpoint for this server func (s *GenericAPIServer) installHealthz() { s.healthzLock.Lock() defer s.healthzLock.Unlock() - s.healthzChecksInstalled = true - healthz.InstallHandler(s.Handler.NonGoRestfulMux, s.healthzChecks...) -} + s.healthzCreated = true -// installReadyz creates the readyz endpoint for this server. -func (s *GenericAPIServer) installReadyz() { - s.readyzLock.Lock() - defer s.readyzLock.Unlock() - s.readyzChecksInstalled = true - healthz.InstallReadyzHandler(s.Handler.NonGoRestfulMux, s.readyzChecks...) -} - -// installLivez creates the livez endpoint for this server. -func (s *GenericAPIServer) installLivez() { - s.livezLock.Lock() - defer s.livezLock.Unlock() - s.livezChecksInstalled = true - healthz.InstallLivezHandler(s.Handler.NonGoRestfulMux, s.livezChecks...) -} - -// shutdownCheck fails if the embedded channel is closed. This is intended to allow for graceful shutdown sequences -// for the apiserver. -type shutdownCheck struct { - StopCh <-chan struct{} -} - -func (shutdownCheck) Name() string { - return "shutdown" -} - -func (c shutdownCheck) Check(req *http.Request) error { - select { - case <-c.StopCh: - return fmt.Errorf("process is shutting down") - default: - } - return nil -} - -// delayedHealthCheck wraps a health check which will not fail until the explicitly defined delay has elapsed. This -// is intended for use primarily for livez health checks. -func delayedHealthCheck(check healthz.HealthChecker, clock clock.Clock, delay time.Duration) healthz.HealthChecker { - return delayedLivezCheck{ - check, - clock.Now().Add(delay), - clock, - } -} - -type delayedLivezCheck struct { - check healthz.HealthChecker - startCheck time.Time - clock clock.Clock -} - -func (c delayedLivezCheck) Name() string { - return c.check.Name() -} - -func (c delayedLivezCheck) Check(req *http.Request) error { - if c.clock.Now().After(c.startCheck) { - return c.check.Check(req) - } - return nil + healthz.InstallHandler(s.Handler.NonGoRestfulMux, s.healthzChecks...) } diff --git a/vendor/k8s.io/apiserver/pkg/server/healthz/doc.go b/vendor/k8s.io/apiserver/pkg/server/healthz/doc.go index d938caa3713..06e67f6fe3c 100644 --- a/vendor/k8s.io/apiserver/pkg/server/healthz/doc.go +++ b/vendor/k8s.io/apiserver/pkg/server/healthz/doc.go @@ -17,5 +17,5 @@ limitations under the License. // Package healthz implements basic http server health checking. // Usage: // import "k8s.io/apiserver/pkg/server/healthz" -// healthz.InstallHandler(mux) +// healthz.DefaultHealthz() package healthz // import "k8s.io/apiserver/pkg/server/healthz" diff --git a/vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go b/vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go index b5ca8afb294..17d85fbe637 100644 --- a/vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go +++ b/vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go @@ -25,21 +25,29 @@ import ( "sync/atomic" "time" + "k8s.io/klog" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/endpoints/metrics" - "k8s.io/apiserver/pkg/server/httplog" - "k8s.io/klog" ) -// HealthChecker is a named healthz checker. -type HealthChecker interface { +// HealthzChecker is a named healthz checker. +type HealthzChecker interface { Name() string Check(req *http.Request) error } +var defaultHealthz = sync.Once{} + +// DefaultHealthz installs the default healthz check to the http.DefaultServeMux. +func DefaultHealthz(checks ...HealthzChecker) { + defaultHealthz.Do(func() { + InstallHandler(http.DefaultServeMux, checks...) + }) +} + // PingHealthz returns true automatically when checked -var PingHealthz HealthChecker = ping{} +var PingHealthz HealthzChecker = ping{} // ping implements the simplest possible healthz checker. type ping struct{} @@ -54,7 +62,7 @@ func (ping) Check(_ *http.Request) error { } // LogHealthz returns true if logging is not blocked -var LogHealthz HealthChecker = &log{} +var LogHealthz HealthzChecker = &log{} type log struct { startOnce sync.Once @@ -82,7 +90,7 @@ func (l *log) Check(_ *http.Request) error { } // NamedCheck returns a healthz checker for the given name and function. -func NamedCheck(name string, check func(r *http.Request) error) HealthChecker { +func NamedCheck(name string, check func(r *http.Request) error) HealthzChecker { return &healthzCheck{name, check} } @@ -90,48 +98,24 @@ func NamedCheck(name string, check func(r *http.Request) error) HealthChecker { // "/healthz" to mux. *All handlers* for mux must be specified in // exactly one call to InstallHandler. Calling InstallHandler more // than once for the same mux will result in a panic. -func InstallHandler(mux mux, checks ...HealthChecker) { +func InstallHandler(mux mux, checks ...HealthzChecker) { InstallPathHandler(mux, "/healthz", checks...) } -// InstallReadyzHandler registers handlers for health checking on the path -// "/readyz" to mux. *All handlers* for mux must be specified in -// exactly one call to InstallHandler. Calling InstallHandler more -// than once for the same mux will result in a panic. -func InstallReadyzHandler(mux mux, checks ...HealthChecker) { - InstallPathHandler(mux, "/readyz", checks...) -} - -// InstallLivezHandler registers handlers for liveness checking on the path -// "/livez" to mux. *All handlers* for mux must be specified in -// exactly one call to InstallHandler. Calling InstallHandler more -// than once for the same mux will result in a panic. -func InstallLivezHandler(mux mux, checks ...HealthChecker) { - InstallPathHandler(mux, "/livez", checks...) -} - // InstallPathHandler registers handlers for health checking on // a specific path to mux. *All handlers* for the path must be // specified in exactly one call to InstallPathHandler. Calling // InstallPathHandler more than once for the same path and mux will // result in a panic. -func InstallPathHandler(mux mux, path string, checks ...HealthChecker) { +func InstallPathHandler(mux mux, path string, checks ...HealthzChecker) { if len(checks) == 0 { klog.V(5).Info("No default health checks specified. Installing the ping handler.") - checks = []HealthChecker{PingHealthz} + checks = []HealthzChecker{PingHealthz} } - klog.V(5).Infof("Installing health checkers for (%v): %v", path, formatQuoted(checkerNames(checks...)...)) - - mux.Handle(path, - metrics.InstrumentHandlerFunc("GET", - /* group = */ "", - /* version = */ "", - /* resource = */ "", - /* subresource = */ path, - /* scope = */ "", - /* component = */ "", - handleRootHealthz(checks...))) + klog.V(5).Info("Installing healthz checkers:", formatQuoted(checkerNames(checks...)...)) + + mux.Handle(path, handleRootHealthz(checks...)) for _, check := range checks { mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check)) } @@ -142,13 +126,13 @@ type mux interface { Handle(pattern string, handler http.Handler) } -// healthzCheck implements HealthChecker on an arbitrary name and check function. +// healthzCheck implements HealthzChecker on an arbitrary name and check function. type healthzCheck struct { name string check func(r *http.Request) error } -var _ HealthChecker = &healthzCheck{} +var _ HealthzChecker = &healthzCheck{} func (c *healthzCheck) Name() string { return c.name @@ -168,7 +152,7 @@ func getExcludedChecks(r *http.Request) sets.String { } // handleRootHealthz returns an http.HandlerFunc that serves the provided checks. -func handleRootHealthz(checks ...HealthChecker) http.HandlerFunc { +func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { failed := false excluded := getExcludedChecks(r) @@ -183,7 +167,7 @@ func handleRootHealthz(checks ...HealthChecker) http.HandlerFunc { if err := check.Check(r); err != nil { // don't include the error since this endpoint is public. If someone wants more detail // they should have explicit permission to the detailed checks. - klog.V(4).Infof("healthz check %v failed: %v", check.Name(), err) + klog.V(6).Infof("healthz check %v failed: %v", check.Name(), err) fmt.Fprintf(&verboseOut, "[-]%v failed: reason withheld\n", check.Name()) failed = true } else { @@ -197,13 +181,10 @@ func handleRootHealthz(checks ...HealthChecker) http.HandlerFunc { } // always be verbose on failure if failed { - klog.V(2).Infof("%vhealthz check failed", verboseOut.String()) - http.Error(httplog.Unlogged(r, w), fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError) + http.Error(w, fmt.Sprintf("%vhealthz check failed", verboseOut.String()), http.StatusInternalServerError) return } - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") if _, found := r.URL.Query()["verbose"]; !found { fmt.Fprint(w, "ok") return @@ -227,7 +208,7 @@ func adaptCheckToHandler(c func(r *http.Request) error) http.HandlerFunc { } // checkerNames returns the names of the checks in the same order as passed in. -func checkerNames(checks ...HealthChecker) []string { +func checkerNames(checks ...HealthzChecker) []string { // accumulate the names of checks for printing them out. checkerNames := make([]string, 0, len(checks)) for _, check := range checks { diff --git a/vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go b/vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go index 321d5bd809c..704532237b7 100644 --- a/vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/healthz/healthz_test.go @@ -23,13 +23,9 @@ import ( "net/http/httptest" "net/url" "reflect" - "strings" "testing" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apiserver/pkg/endpoints/metrics" - "k8s.io/component-base/metrics/legacyregistry" - "k8s.io/component-base/metrics/testutil" ) func TestInstallHandler(t *testing.T) { @@ -44,10 +40,6 @@ func TestInstallHandler(t *testing.T) { if w.Code != http.StatusOK { t.Errorf("expected %v, got %v", http.StatusOK, w.Code) } - c := w.Header().Get("Content-Type") - if c != "text/plain; charset=utf-8" { - t.Errorf("expected %v, got %v", "text/plain", c) - } if w.Body.String() != "ok" { t.Errorf("expected %v, got %v", "ok", w.Body.String()) } @@ -66,10 +58,6 @@ func TestInstallPathHandler(t *testing.T) { if w.Code != http.StatusOK { t.Errorf("expected %v, got %v", http.StatusOK, w.Code) } - c := w.Header().Get("Content-Type") - if c != "text/plain; charset=utf-8" { - t.Errorf("expected %v, got %v", "text/plain", c) - } if w.Body.String() != "ok" { t.Errorf("expected %v, got %v", "ok", w.Body.String()) } @@ -83,10 +71,6 @@ func TestInstallPathHandler(t *testing.T) { if w.Code != http.StatusOK { t.Errorf("expected %v, got %v", http.StatusOK, w.Code) } - c = w.Header().Get("Content-Type") - if c != "text/plain; charset=utf-8" { - t.Errorf("expected %v, got %v", "text/plain", c) - } if w.Body.String() != "ok" { t.Errorf("expected %v, got %v", "ok", w.Body.String()) } @@ -115,7 +99,7 @@ func testMultipleChecks(path string, t *testing.T) { for i, test := range tests { mux := http.NewServeMux() - checks := []HealthChecker{PingHealthz} + checks := []HealthzChecker{PingHealthz} if test.addBadCheck { checks = append(checks, NamedCheck("bad", func(_ *http.Request) error { return errors.New("this will fail") @@ -136,10 +120,6 @@ func testMultipleChecks(path string, t *testing.T) { if w.Code != test.expectedStatus { t.Errorf("case[%d] Expected: %v, got: %v", i, test.expectedStatus, w.Code) } - c := w.Header().Get("Content-Type") - if c != "text/plain; charset=utf-8" { - t.Errorf("case[%d] Expected: %v, got: %v", i, "text/plain", c) - } if w.Body.String() != test.expectedResponse { t.Errorf("case[%d] Expected:\n%v\ngot:\n%v\n", i, test.expectedResponse, w.Body.String()) } @@ -162,14 +142,14 @@ func TestCheckerNames(t *testing.T) { testCases := []struct { desc string - have []HealthChecker + have []HealthzChecker want []string }{ - {"no checker", []HealthChecker{}, []string{}}, - {"one checker", []HealthChecker{c1}, []string{n1}}, - {"other checker", []HealthChecker{c2}, []string{n2}}, - {"checker order", []HealthChecker{c1, c2}, []string{n1, n2}}, - {"different checker order", []HealthChecker{c2, c1}, []string{n2, n1}}, + {"no checker", []HealthzChecker{}, []string{}}, + {"one checker", []HealthzChecker{c1}, []string{n1}}, + {"other checker", []HealthzChecker{c2}, []string{n2}}, + {"checker order", []HealthzChecker{c1, c2}, []string{n1, n2}}, + {"different checker order", []HealthzChecker{c2, c1}, []string{n2, n1}}, } for _, tc := range testCases { @@ -236,35 +216,6 @@ func TestGetExcludedChecks(t *testing.T) { } } -func TestMetrics(t *testing.T) { - mux := http.NewServeMux() - InstallHandler(mux) - InstallLivezHandler(mux) - InstallReadyzHandler(mux) - metrics.Register() - metrics.Reset() - - paths := []string{"/healthz", "/livez", "/readyz"} - for _, path := range paths { - req, err := http.NewRequest("GET", fmt.Sprintf("http://example.com%s", path), nil) - if err != nil { - t.Errorf("%v", err) - } - mux.ServeHTTP(httptest.NewRecorder(), req) - } - - expected := strings.NewReader(` - # HELP apiserver_request_total [ALPHA] Counter of apiserver requests broken out for each verb, dry run value, group, version, resource, scope, component, and HTTP response contentType and code. - # TYPE apiserver_request_total counter - apiserver_request_total{code="200",component="",contentType="text/plain; charset=utf-8",dry_run="",group="",resource="",scope="",subresource="/healthz",verb="GET",version=""} 1 - apiserver_request_total{code="200",component="",contentType="text/plain; charset=utf-8",dry_run="",group="",resource="",scope="",subresource="/livez",verb="GET",version=""} 1 - apiserver_request_total{code="200",component="",contentType="text/plain; charset=utf-8",dry_run="",group="",resource="",scope="",subresource="/readyz",verb="GET",version=""} 1 -`) - if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, expected, "apiserver_request_total"); err != nil { - t.Error(err) - } -} - func createGetRequestWithUrl(rawUrlString string) *http.Request { url, _ := url.Parse(rawUrlString) return &http.Request{ diff --git a/vendor/k8s.io/apiserver/pkg/server/healthz_test.go b/vendor/k8s.io/apiserver/pkg/server/healthz_test.go deleted file mode 100644 index eb4ce2abd31..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/healthz_test.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2019 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 server - -import ( - "testing" - "time" - - "k8s.io/apimachinery/pkg/util/clock" -) - -func TestDelayedHealthCheck(t *testing.T) { - t.Run("test that liveness check returns true until the delay has elapsed", func(t *testing.T) { - t0 := time.Unix(0, 0) - c := clock.NewFakeClock(t0) - doneCh := make(chan struct{}) - - healthCheck := delayedHealthCheck(postStartHookHealthz{"test", doneCh}, c, time.Duration(10)*time.Second) - err := healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - c.Step(10 * time.Second) - err = healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - c.Step(1 * time.Millisecond) - err = healthCheck.Check(nil) - if err == nil || err.Error() != "not finished" { - t.Errorf("Got '%v', but expected error to be 'not finished'", err) - } - close(doneCh) - err = healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - }) - t.Run("test that liveness check does not toggle false even if done channel is closed early", func(t *testing.T) { - t0 := time.Unix(0, 0) - c := clock.NewFakeClock(t0) - - doneCh := make(chan struct{}) - - healthCheck := delayedHealthCheck(postStartHookHealthz{"test", doneCh}, c, time.Duration(10)*time.Second) - err := healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - close(doneCh) - c.Step(10 * time.Second) - err = healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - c.Step(1 * time.Millisecond) - err = healthCheck.Check(nil) - if err != nil { - t.Errorf("Got %v, expected no error", err) - } - }) - -} diff --git a/vendor/k8s.io/apiserver/pkg/server/hooks.go b/vendor/k8s.io/apiserver/pkg/server/hooks.go index 04e7f830234..921255218bc 100644 --- a/vendor/k8s.io/apiserver/pkg/server/hooks.go +++ b/vendor/k8s.io/apiserver/pkg/server/hooks.go @@ -20,13 +20,13 @@ import ( "errors" "fmt" "net/http" - "runtime/debug" + + "k8s.io/klog" utilerrors "k8s.io/apimachinery/pkg/util/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apiserver/pkg/server/healthz" restclient "k8s.io/client-go/rest" - "k8s.io/klog" ) // PostStartHookFunc is a function that is called after the server has started. @@ -58,21 +58,11 @@ type PostStartHookProvider interface { type postStartHookEntry struct { hook PostStartHookFunc - // originatingStack holds the stack that registered postStartHooks. This allows us to show a more helpful message - // for duplicate registration. - originatingStack string // done will be closed when the postHook is finished done chan struct{} } -type PostStartHookConfigEntry struct { - hook PostStartHookFunc - // originatingStack holds the stack that registered postStartHooks. This allows us to show a more helpful message - // for duplicate registration. - originatingStack string -} - type preShutdownHookEntry struct { hook PreShutdownHookFunc } @@ -83,10 +73,9 @@ func (s *GenericAPIServer) AddPostStartHook(name string, hook PostStartHookFunc) return fmt.Errorf("missing name") } if hook == nil { - return fmt.Errorf("hook func may not be nil: %q", name) + return nil } if s.disabledPostStartHooks.Has(name) { - klog.V(1).Infof("skipping %q because it was explicitly disabled", name) return nil } @@ -96,18 +85,15 @@ func (s *GenericAPIServer) AddPostStartHook(name string, hook PostStartHookFunc) if s.postStartHooksCalled { return fmt.Errorf("unable to add %q because PostStartHooks have already been called", name) } - if postStartHook, exists := s.postStartHooks[name]; exists { - // this is programmer error, but it can be hard to debug - return fmt.Errorf("unable to add %q because it was already registered by: %s", name, postStartHook.originatingStack) + if _, exists := s.postStartHooks[name]; exists { + return fmt.Errorf("unable to add %q because it is already registered", name) } // done is closed when the poststarthook is finished. This is used by the health check to be able to indicate // that the poststarthook is finished done := make(chan struct{}) - if err := s.AddBootSequenceHealthChecks(postStartHookHealthz{name: "poststarthook/" + name, done: done}); err != nil { - return err - } - s.postStartHooks[name] = postStartHookEntry{hook: hook, originatingStack: string(debug.Stack()), done: done} + s.AddHealthzChecks(postStartHookHealthz{name: "poststarthook/" + name, done: done}) + s.postStartHooks[name] = postStartHookEntry{hook: hook, done: done} return nil } @@ -226,7 +212,7 @@ type postStartHookHealthz struct { done chan struct{} } -var _ healthz.HealthChecker = postStartHookHealthz{} +var _ healthz.HealthzChecker = postStartHookHealthz{} func (h postStartHookHealthz) Name() string { return h.name diff --git a/vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go b/vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go index 2ad5cf20551..dcdba69225d 100644 --- a/vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go +++ b/vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go @@ -18,7 +18,6 @@ package httplog import ( "bufio" - "context" "fmt" "net" "net/http" @@ -35,11 +34,6 @@ type logger interface { Addf(format string, data ...interface{}) } -type respLoggerContextKeyType int - -// respLoggerContextKey is used to store the respLogger pointer in the request context. -const respLoggerContextKey respLoggerContextKeyType = iota - // Add a layer on top of ResponseWriter, so we can track latency and error // message sources. // @@ -75,54 +69,47 @@ func DefaultStacktracePred(status int) bool { return (status < http.StatusOK || status >= http.StatusInternalServerError) && status != http.StatusSwitchingProtocols } -// WithLogging wraps the handler with logging. -func WithLogging(handler http.Handler, pred StacktracePred) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ctx := req.Context() - if old := respLoggerFromContext(req); old != nil { - panic("multiple WithLogging calls!") - } - rl := newLogged(req, w).StacktraceWhen(pred) - req = req.WithContext(context.WithValue(ctx, respLoggerContextKey, rl)) - - defer rl.Log() - handler.ServeHTTP(rl, req) - }) -} - -// respLoggerFromContext returns the respLogger or nil. -func respLoggerFromContext(req *http.Request) *respLogger { - ctx := req.Context() - val := ctx.Value(respLoggerContextKey) - if rl, ok := val.(*respLogger); ok { - return rl +// NewLogged turns a normal response writer into a logged response writer. +// +// Usage: +// +// defer NewLogged(req, &w).StacktraceWhen(StatusIsNot(200, 202)).Log() +// +// (Only the call to Log() is deferred, so you can set everything up in one line!) +// +// Note that this *changes* your writer, to route response writing actions +// through the logger. +// +// Use LogOf(w).Addf(...) to log something along with the response result. +func NewLogged(req *http.Request, w *http.ResponseWriter) *respLogger { + if _, ok := (*w).(*respLogger); ok { + // Don't double-wrap! + panic("multiple NewLogged calls!") } - return nil -} - -// newLogged turns a normal response writer into a logged response writer. -func newLogged(req *http.Request, w http.ResponseWriter) *respLogger { - return &respLogger{ + rl := &respLogger{ startTime: time.Now(), req: req, - w: w, + w: *w, logStacktracePred: DefaultStacktracePred, } + *w = rl // hijack caller's writer! + return rl } // LogOf returns the logger hiding in w. If there is not an existing logger // then a passthroughLogger will be created which will log to stdout immediately // when Addf is called. func LogOf(req *http.Request, w http.ResponseWriter) logger { - if rl := respLoggerFromContext(req); rl != nil { + if rl, ok := w.(*respLogger); ok { return rl } + return &passthroughLogger{} } // Unlogged returns the original ResponseWriter, or w if it is not our inserted logger. -func Unlogged(req *http.Request, w http.ResponseWriter) http.ResponseWriter { - if rl := respLoggerFromContext(req); rl != nil { +func Unlogged(w http.ResponseWriter) http.ResponseWriter { + if rl, ok := w.(*respLogger); ok { return rl.w } return w @@ -138,13 +125,13 @@ func (rl *respLogger) StacktraceWhen(pred StacktracePred) *respLogger { // StatusIsNot returns a StacktracePred which will cause stacktraces to be logged // for any status *not* in the given list. func StatusIsNot(statuses ...int) StacktracePred { - statusesNoTrace := map[int]bool{} - for _, s := range statuses { - statusesNoTrace[s] = true - } return func(status int) bool { - _, ok := statusesNoTrace[status] - return !ok + for _, s := range statuses { + if status == s { + return false + } + } + return true } } @@ -158,17 +145,9 @@ func (rl *respLogger) Log() { latency := time.Since(rl.startTime) if klog.V(3) { if !rl.hijacked { - klog.InfoDepth(1, fmt.Sprintf("verb=%q URI=%q latency=%v resp=%v UserAgent=%q srcIP=%q: %v%v", - rl.req.Method, rl.req.RequestURI, - latency, rl.status, - rl.req.UserAgent(), rl.req.RemoteAddr, - rl.statusStack, rl.addedInfo, - )) + klog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) %v%v%v [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.status, rl.statusStack, rl.addedInfo, rl.req.UserAgent(), rl.req.RemoteAddr)) } else { - klog.InfoDepth(1, fmt.Sprintf("verb=%q URI=%q latency=%v UserAgent=%q srcIP=%q: hijacked", - rl.req.Method, rl.req.RequestURI, - latency, rl.req.UserAgent(), rl.req.RemoteAddr, - )) + klog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) hijacked [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.req.UserAgent(), rl.req.RemoteAddr)) } } } diff --git a/vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go b/vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go index 62f5ed76de8..680b1e478c6 100644 --- a/vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/httplog/httplog_test.go @@ -56,24 +56,22 @@ func TestStatusIsNot(t *testing.T) { } } -func TestWithLogging(t *testing.T) { +func TestNewLogged(t *testing.T) { req, err := http.NewRequest("GET", "http://example.com", nil) if err != nil { t.Errorf("Unexpected error: %v", err) } - var handler http.Handler - handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) - handler = WithLogging(WithLogging(handler, DefaultStacktracePred), DefaultStacktracePred) - - func() { + handler := func(w http.ResponseWriter, r *http.Request) { + NewLogged(req, &w) defer func() { if r := recover(); r == nil { - t.Errorf("Expected newLogged to panic") + t.Errorf("Expected NewLogged to panic") } }() - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) - }() + NewLogged(req, &w) + } + w := httptest.NewRecorder() + handler(w, req) } func TestLogOf(t *testing.T) { @@ -83,23 +81,21 @@ func TestLogOf(t *testing.T) { if err != nil { t.Errorf("Unexpected error: %v", err) } - var want string - var handler http.Handler - handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + handler := func(w http.ResponseWriter, r *http.Request) { + var want string + if makeLogger { + NewLogged(req, &w) + want = "*httplog.respLogger" + } else { + want = "*httplog.passthroughLogger" + } got := reflect.TypeOf(LogOf(r, w)).String() if want != got { t.Errorf("Expected %v, got %v", want, got) } - }) - if makeLogger { - handler = WithLogging(handler, DefaultStacktracePred) - want = "*httplog.respLogger" - } else { - want = "*httplog.passthroughLogger" } - w := httptest.NewRecorder() - handler.ServeHTTP(w, req) + handler(w, req) } } @@ -110,20 +106,18 @@ func TestUnlogged(t *testing.T) { if err != nil { t.Errorf("Unexpected error: %v", err) } - - origWriter := httptest.NewRecorder() - var handler http.Handler - handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - got := Unlogged(r, w) - if origWriter != got { - t.Errorf("Expected origin writer, got %#v", got) + handler := func(w http.ResponseWriter, r *http.Request) { + want := w + if makeLogger { + NewLogged(req, &w) + } + got := Unlogged(w) + if want != got { + t.Errorf("Expected %v, got %v", want, got) } - }) - if makeLogger { - handler = WithLogging(handler, DefaultStacktracePred) } - - handler.ServeHTTP(origWriter, req) + w := httptest.NewRecorder() + handler(w, req) } } @@ -140,7 +134,7 @@ func TestLoggedStatus(t *testing.T) { } var tw http.ResponseWriter = new(testResponseWriter) - logger := newLogged(req, tw) + logger := NewLogged(req, &tw) logger.Write(nil) if logger.status != http.StatusOK { @@ -148,7 +142,7 @@ func TestLoggedStatus(t *testing.T) { } tw = new(testResponseWriter) - logger = newLogged(req, tw) + logger = NewLogged(req, &tw) logger.WriteHeader(http.StatusForbidden) logger.Write(nil) diff --git a/vendor/k8s.io/apiserver/pkg/server/mux/OWNERS b/vendor/k8s.io/apiserver/pkg/server/mux/OWNERS old mode 100644 new mode 100755 index 4da107c8c38..9d268c4d148 --- a/vendor/k8s.io/apiserver/pkg/server/mux/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/server/mux/OWNERS @@ -1,4 +1,2 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - sttts diff --git a/vendor/k8s.io/apiserver/pkg/server/mux/doc.go b/vendor/k8s.io/apiserver/pkg/server/mux/doc.go index 178aa9fe6c0..da9fb8ed7f5 100644 --- a/vendor/k8s.io/apiserver/pkg/server/mux/doc.go +++ b/vendor/k8s.io/apiserver/pkg/server/mux/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package mux contains abstractions for http multiplexing of APIs. -package mux // import "k8s.io/apiserver/pkg/server/mux" +package mux diff --git a/vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go b/vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go index 74ed8f6776a..16857cc8a6b 100644 --- a/vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go +++ b/vendor/k8s.io/apiserver/pkg/server/mux/pathrecorder.go @@ -55,7 +55,7 @@ type PathRecorderMux struct { pathStacks map[string]string } -// pathHandler is an http.Handler that will satisfy requests first by exact match, then by prefix, +// pathHandler is an http.Handler that will satify requests first by exact match, then by prefix, // then by notFoundHandler type pathHandler struct { // muxName is used for logging so you can trace requests through diff --git a/vendor/k8s.io/apiserver/pkg/server/options/OWNERS b/vendor/k8s.io/apiserver/pkg/server/options/OWNERS old mode 100644 new mode 100755 index 0e84109d7d4..9d6b439de8d --- a/vendor/k8s.io/apiserver/pkg/server/options/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/server/options/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - smarterclayton - wojtek-t diff --git a/vendor/k8s.io/apiserver/pkg/server/options/admission.go b/vendor/k8s.io/apiserver/pkg/server/options/admission.go index 765e2ad2b65..b53c05f62a6 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/admission.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/admission.go @@ -28,17 +28,16 @@ import ( "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" + "k8s.io/apiserver/pkg/admission/plugin/initialization" "k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle" mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating" validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating" apiserverapi "k8s.io/apiserver/pkg/apis/apiserver" - apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" "k8s.io/apiserver/pkg/server" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/component-base/featuregate" ) var configScheme = runtime.NewScheme() @@ -46,7 +45,6 @@ var configScheme = runtime.NewScheme() func init() { utilruntime.Must(apiserverapi.AddToScheme(configScheme)) utilruntime.Must(apiserverapiv1alpha1.AddToScheme(configScheme)) - utilruntime.Must(apiserverapiv1.AddToScheme(configScheme)) } // AdmissionOptions holds the admission options @@ -64,8 +62,6 @@ type AdmissionOptions struct { ConfigFile string // Plugins contains all registered plugins. Plugins *admission.Plugins - // Decorators is a list of admission decorator to wrap around the admission plugins - Decorators admission.Decorators } // NewAdmissionOptions creates a new instance of AdmissionOptions @@ -78,14 +74,13 @@ type AdmissionOptions struct { // Servers that do care can overwrite/append that field after creation. func NewAdmissionOptions() *AdmissionOptions { options := &AdmissionOptions{ - Plugins: admission.NewPlugins(), - Decorators: admission.Decorators{admission.DecoratorFunc(admissionmetrics.WithControllerMetrics)}, + Plugins: admission.NewPlugins(), // This list is mix of mutating admission plugins and validating // admission plugins. The apiserver always runs the validating ones // after all the mutating ones, so their relative order in this list // doesn't matter. - RecommendedPluginOrder: []string{lifecycle.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName}, - DefaultOffPlugins: sets.NewString(), + RecommendedPluginOrder: []string{lifecycle.PluginName, initialization.PluginName, mutatingwebhook.PluginName, validatingwebhook.PluginName}, + DefaultOffPlugins: sets.NewString(initialization.PluginName), } server.RegisterAllAdmissionPlugins(options.Plugins) return options @@ -112,7 +107,7 @@ func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) { } // ApplyTo adds the admission chain to the server configuration. -// In case admission plugin names were not provided by a cluster-admin they will be prepared from the recommended/default values. +// In case admission plugin names were not provided by a custer-admin they will be prepared from the recommended/default values. // In addition the method lazily initializes a generic plugin that is appended to the list of pluginInitializers // note this method uses: // genericconfig.Authorizer @@ -120,13 +115,18 @@ func (a *AdmissionOptions) ApplyTo( c *server.Config, informers informers.SharedInformerFactory, kubeAPIServerClientConfig *rest.Config, - features featuregate.FeatureGate, + scheme *runtime.Scheme, pluginInitializers ...admission.PluginInitializer, ) error { if a == nil { return nil } + // Admission need scheme to construct admission initializer. + if scheme == nil { + return fmt.Errorf("admission depends on a scheme, it cannot be nil") + } + // Admission depends on CoreAPI to set SharedInformerFactory and ClientConfig. if informers == nil { return fmt.Errorf("admission depends on a Kubernetes core API shared informer, it cannot be nil") @@ -143,12 +143,12 @@ func (a *AdmissionOptions) ApplyTo( if err != nil { return err } - genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, features) + genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, scheme) initializersChain := admission.PluginInitializers{} pluginInitializers = append(pluginInitializers, genericInitializer) initializersChain = append(initializersChain, pluginInitializers...) - admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, a.Decorators) + admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, admission.DecoratorFunc(admissionmetrics.WithControllerMetrics)) if err != nil { return err } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go b/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go index 794e89dedb6..71eda2981a6 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/api_enablement.go @@ -25,32 +25,29 @@ import ( "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/resourceconfig" serverstore "k8s.io/apiserver/pkg/server/storage" - cliflag "k8s.io/component-base/cli/flag" + utilflag "k8s.io/apiserver/pkg/util/flag" ) // APIEnablementOptions contains the options for which resources to turn on and off. // Given small aggregated API servers, this option isn't required for "normal" API servers type APIEnablementOptions struct { - RuntimeConfig cliflag.ConfigurationMap + RuntimeConfig utilflag.ConfigurationMap } func NewAPIEnablementOptions() *APIEnablementOptions { return &APIEnablementOptions{ - RuntimeConfig: make(cliflag.ConfigurationMap), + RuntimeConfig: make(utilflag.ConfigurationMap), } } // AddFlags adds flags for a specific APIServer to the specified FlagSet func (s *APIEnablementOptions) AddFlags(fs *pflag.FlagSet) { fs.Var(&s.RuntimeConfig, "runtime-config", ""+ - "A set of key=value pairs that enable or disable built-in APIs. Supported options are:\n"+ - "v1=true|false for the core API group\n"+ - "/=true|false for a specific API group and version (e.g. apps/v1=true)\n"+ - "api/all=true|false controls all API versions\n"+ - "api/ga=true|false controls all API versions of the form v[0-9]+\n"+ - "api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+\n"+ - "api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+\n"+ - "api/legacy is deprecated, and will be removed in a future version") + "A set of key=value pairs that describe runtime configuration that may be passed "+ + "to apiserver. / (or for the core group) key can be used to "+ + "turn on/off specific api versions. api/all is special key to control all api versions, "+ + "be careful setting it false, unless you know what you do. api/legacy is deprecated, "+ + "we will remove it in the future, so stop using it.") } // Validate validates RuntimeConfig with a list of registries. @@ -64,9 +61,9 @@ func (s *APIEnablementOptions) Validate(registries ...GroupRegisty) []error { } errors := []error{} - if s.RuntimeConfig[resourceconfig.APIAll] == "false" && len(s.RuntimeConfig) == 1 { + if s.RuntimeConfig["api/all"] == "false" && len(s.RuntimeConfig) == 1 { // Do not allow only set api/all=false, in such case apiserver startup has no meaning. - return append(errors, fmt.Errorf("invalid key with only %v=false", resourceconfig.APIAll)) + return append(errors, fmt.Errorf("invalid key with only api/all=false")) } groups, err := resourceconfig.ParseGroups(s.RuntimeConfig) @@ -87,7 +84,6 @@ func (s *APIEnablementOptions) Validate(registries ...GroupRegisty) []error { // ApplyTo override MergedResourceConfig with defaults and registry func (s *APIEnablementOptions) ApplyTo(c *server.Config, defaultResourceConfig *serverstore.ResourceConfig, registry resourceconfig.GroupVersionRegistry) error { - if s == nil { return nil } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/api_enablement_test.go b/vendor/k8s.io/apiserver/pkg/server/options/api_enablement_test.go index fb146bf28bc..e08fcd2a1fb 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/api_enablement_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/api_enablement_test.go @@ -21,7 +21,7 @@ import ( "testing" utilerrors "k8s.io/apimachinery/pkg/util/errors" - cliflag "k8s.io/component-base/cli/flag" + utilflag "k8s.io/apiserver/pkg/util/flag" ) type fakeGroupRegisty struct{} @@ -42,28 +42,28 @@ func TestAPIEnablementOptionsValidate(t *testing.T) { { name: "test when invalid key with only api/all=false", testOptions: &APIEnablementOptions{ - RuntimeConfig: cliflag.ConfigurationMap{"api/all": "false"}, + RuntimeConfig: utilflag.ConfigurationMap{"api/all": "false"}, }, expectErr: "invalid key with only api/all=false", }, { name: "test when ConfigurationMap key is invalid", testOptions: &APIEnablementOptions{ - RuntimeConfig: cliflag.ConfigurationMap{"apiall": "false"}, + RuntimeConfig: utilflag.ConfigurationMap{"apiall": "false"}, }, expectErr: "runtime-config invalid key", }, { name: "test when unknown api groups", testOptions: &APIEnablementOptions{ - RuntimeConfig: cliflag.ConfigurationMap{"api/v1": "true"}, + RuntimeConfig: utilflag.ConfigurationMap{"api/v1": "true"}, }, expectErr: "unknown api groups", }, { name: "test when valid api groups", testOptions: &APIEnablementOptions{ - RuntimeConfig: cliflag.ConfigurationMap{"apiregistration.k8s.io/v1beta1": "true"}, + RuntimeConfig: utilflag.ConfigurationMap{"apiregistration.k8s.io/v1beta1": "true"}, }, }, } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/audit.go b/vendor/k8s.io/apiserver/pkg/server/options/audit.go index 8a3503cab36..402a703ac61 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/audit.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/audit.go @@ -29,7 +29,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" - utilnet "k8s.io/apimachinery/pkg/util/net" auditinternal "k8s.io/apiserver/pkg/apis/audit" auditv1 "k8s.io/apiserver/pkg/apis/audit/v1" auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1" @@ -38,7 +37,6 @@ import ( "k8s.io/apiserver/pkg/audit/policy" "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/server" - "k8s.io/apiserver/pkg/server/egressselector" utilfeature "k8s.io/apiserver/pkg/util/feature" pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered" plugindynamic "k8s.io/apiserver/plugin/pkg/audit/dynamic" @@ -150,14 +148,9 @@ type AuditWebhookOptions struct { GroupVersionString string } -// AuditDynamicOptions control the configuration of dynamic backends for audit events type AuditDynamicOptions struct { // Enabled tells whether the dynamic audit capability is enabled. Enabled bool - - // Configuration for batching backend. This is currently only used as an override - // for integration tests - BatchConfig *pluginbuffered.BatchConfig } func NewAuditOptions() *AuditOptions { @@ -181,8 +174,7 @@ func NewAuditOptions() *AuditOptions { GroupVersionString: "audit.k8s.io/v1", }, DynamicOptions: AuditDynamicOptions{ - Enabled: false, - BatchConfig: plugindynamic.NewDefaultWebhookBatchConfig(), + Enabled: false, }, } } @@ -325,15 +317,7 @@ func (o *AuditOptions) ApplyTo( if checker == nil { klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend") } else { - if c.EgressSelector != nil { - egressDialer, err := c.EgressSelector.Lookup(egressselector.Master.AsNetworkContext()) - if err != nil { - return err - } - webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(egressDialer) - } else { - webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(nil) - } + webhookBackend, err = o.WebhookOptions.newUntruncatedBackend() if err != nil { return err } @@ -600,9 +584,9 @@ func (o *AuditWebhookOptions) enabled() bool { // newUntruncatedBackend returns a webhook backend without the truncate options applied // this is done so that the same trucate backend can wrap both the webhook and dynamic backends -func (o *AuditWebhookOptions) newUntruncatedBackend(customDial utilnet.DialFunc) (audit.Backend, error) { +func (o *AuditWebhookOptions) newUntruncatedBackend() (audit.Backend, error) { groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString) - webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff, customDial) + webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff) if err != nil { return nil, fmt.Errorf("initializing audit webhook: %v", err) } @@ -650,7 +634,7 @@ func (o *AuditDynamicOptions) newBackend( dc := &plugindynamic.Config{ Informer: informer, - BufferedConfig: o.BatchConfig, + BufferedConfig: plugindynamic.NewDefaultWebhookBatchConfig(), EventConfig: plugindynamic.EventConfig{ Sink: eventSink, Source: corev1.EventSource{ diff --git a/vendor/k8s.io/apiserver/pkg/server/options/audit_test.go b/vendor/k8s.io/apiserver/pkg/server/options/audit_test.go index 55ddb0de54e..7137c521b10 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/audit_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/audit_test.go @@ -28,11 +28,11 @@ import ( "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/server" utilfeature "k8s.io/apiserver/pkg/util/feature" + utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd/api/v1" - featuregatetesting "k8s.io/component-base/featuregate/testing" "github.com/spf13/pflag" "github.com/stretchr/testify/assert" @@ -46,7 +46,7 @@ func TestAuditValidOptions(t *testing.T) { policy := makeTmpPolicy(t) defer os.Remove(policy) - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicAuditing, true)() + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicAuditing, true)() clientConfig := &restclient.Config{} informerFactory := informers.NewSharedInformerFactory(fake.NewSimpleClientset(), 0) diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authentication.go b/vendor/k8s.io/apiserver/pkg/server/options/authentication.go index e2e2d33451b..877dc9133a7 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/authentication.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/authentication.go @@ -17,22 +17,22 @@ limitations under the License. package options import ( + "encoding/json" "fmt" - "strings" + "io/ioutil" "time" - "k8s.io/apiserver/pkg/server/dynamiccertificates" - "github.com/spf13/pflag" + "k8s.io/klog" + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/authentication/authenticatorfactory" - "k8s.io/apiserver/pkg/authentication/request/headerrequest" "k8s.io/apiserver/pkg/server" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog" openapicommon "k8s.io/kube-openapi/pkg/common" ) @@ -47,35 +47,6 @@ type RequestHeaderAuthenticationOptions struct { AllowedNames []string } -func (s *RequestHeaderAuthenticationOptions) Validate() []error { - allErrors := []error{} - - if err := checkForWhiteSpaceOnly("requestheader-username-headers", s.UsernameHeaders...); err != nil { - allErrors = append(allErrors, err) - } - if err := checkForWhiteSpaceOnly("requestheader-group-headers", s.GroupHeaders...); err != nil { - allErrors = append(allErrors, err) - } - if err := checkForWhiteSpaceOnly("requestheader-extra-headers-prefix", s.ExtraHeaderPrefixes...); err != nil { - allErrors = append(allErrors, err) - } - if err := checkForWhiteSpaceOnly("requestheader-allowed-names", s.AllowedNames...); err != nil { - allErrors = append(allErrors, err) - } - - return allErrors -} - -func checkForWhiteSpaceOnly(flag string, headerNames ...string) error { - for _, headerName := range headerNames { - if len(strings.TrimSpace(headerName)) == 0 { - return fmt.Errorf("empty value in %q", flag) - } - } - - return nil -} - func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { if s == nil { return @@ -103,48 +74,23 @@ func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { // ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options // if necessary, nil otherwise. -func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() (*authenticatorfactory.RequestHeaderConfig, error) { +func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig { if len(s.ClientCAFile) == 0 { - return nil, nil - } - - caBundleProvider, err := dynamiccertificates.NewDynamicCAContentFromFile("request-header", s.ClientCAFile) - if err != nil { - return nil, err + return nil } return &authenticatorfactory.RequestHeaderConfig{ - UsernameHeaders: headerrequest.StaticStringSlice(s.UsernameHeaders), - GroupHeaders: headerrequest.StaticStringSlice(s.GroupHeaders), - ExtraHeaderPrefixes: headerrequest.StaticStringSlice(s.ExtraHeaderPrefixes), - CAContentProvider: caBundleProvider, - AllowedClientNames: headerrequest.StaticStringSlice(s.AllowedNames), - }, nil + UsernameHeaders: s.UsernameHeaders, + GroupHeaders: s.GroupHeaders, + ExtraHeaderPrefixes: s.ExtraHeaderPrefixes, + ClientCA: s.ClientCAFile, + AllowedClientNames: s.AllowedNames, + } } -// ClientCertAuthenticationOptions provides different options for client cert auth. You should use `GetClientVerifyOptionFn` to -// get the verify options for your authenticator. type ClientCertAuthenticationOptions struct { // ClientCA is the certificate bundle for all the signers that you'll recognize for incoming client certificates ClientCA string - - // CAContentProvider are the options for verifying incoming connections using mTLS and directly assigning to users. - // Generally this is the CA bundle file used to authenticate client certificates - // If non-nil, this takes priority over the ClientCA file. - CAContentProvider dynamiccertificates.CAContentProvider -} - -// GetClientVerifyOptionFn provides verify options for your authenticator while respecting the preferred order of verifiers. -func (s *ClientCertAuthenticationOptions) GetClientCAContentProvider() (dynamiccertificates.CAContentProvider, error) { - if s.CAContentProvider != nil { - return s.CAContentProvider, nil - } - - if len(s.ClientCA) == 0 { - return nil, nil - } - - return dynamiccertificates.NewDynamicCAContentFromFile("client-ca-bundle", s.ClientCA) } func (s *ClientCertAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { @@ -194,8 +140,6 @@ func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions { func (s *DelegatingAuthenticationOptions) Validate() []error { allErrors := []error{} - allErrors = append(allErrors, s.RequestHeader.Validate()...) - return allErrors } @@ -210,7 +154,7 @@ func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { } fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+ "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+ - "tokenreviews.authentication.k8s.io."+optionalKubeConfigSentence) + "tokenaccessreviews.authentication.k8s.io."+optionalKubeConfigSentence) fs.DurationVar(&s.CacheTTL, "authentication-token-webhook-cache-ttl", s.CacheTTL, "The duration to cache responses from the webhook token authenticator.") @@ -226,9 +170,9 @@ func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { "Note that this can result in authentication that treats all requests as anonymous.") } -func (s *DelegatingAuthenticationOptions) ApplyTo(authenticationInfo *server.AuthenticationInfo, servingInfo *server.SecureServingInfo, openAPIConfig *openapicommon.Config) error { +func (s *DelegatingAuthenticationOptions) ApplyTo(c *server.AuthenticationInfo, servingInfo *server.SecureServingInfo, openAPIConfig *openapicommon.Config) error { if s == nil { - authenticationInfo.Authenticator = nil + c.Authenticator = nil return nil } @@ -244,67 +188,32 @@ func (s *DelegatingAuthenticationOptions) ApplyTo(authenticationInfo *server.Aut // configure token review if client != nil { - cfg.TokenAccessReviewClient = client.AuthenticationV1().TokenReviews() + cfg.TokenAccessReviewClient = client.AuthenticationV1beta1().TokenReviews() } - // get the clientCA information - clientCAFileSpecified := len(s.ClientCert.ClientCA) > 0 - var clientCAProvider dynamiccertificates.CAContentProvider - if clientCAFileSpecified { - clientCAProvider, err = s.ClientCert.GetClientCAContentProvider() + // look into configmaps/external-apiserver-authentication for missing authn info + if !s.SkipInClusterLookup { + err := s.lookupMissingConfigInCluster(client) if err != nil { - return fmt.Errorf("unable to load client CA file %q: %v", s.ClientCert.ClientCA, err) - } - cfg.ClientCertificateCAContentProvider = clientCAProvider - if err = authenticationInfo.ApplyClientCert(cfg.ClientCertificateCAContentProvider, servingInfo); err != nil { - return fmt.Errorf("unable to assign client CA file: %v", err) - } - - } else if !s.SkipInClusterLookup { - if client == nil { - klog.Warningf("No authentication-kubeconfig provided in order to lookup client-ca-file in configmap/%s in %s, so client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) - } else { - clientCAProvider, err = dynamiccertificates.NewDynamicCAFromConfigMapController("client-ca", authenticationConfigMapNamespace, authenticationConfigMapName, "client-ca-file", client) - if err != nil { - return fmt.Errorf("unable to load configmap based client CA file: %v", err) - } - cfg.ClientCertificateCAContentProvider = clientCAProvider - if err = authenticationInfo.ApplyClientCert(cfg.ClientCertificateCAContentProvider, servingInfo); err != nil { - return fmt.Errorf("unable to assign configmap based client CA file: %v", err) + if s.TolerateInClusterLookupFailure { + klog.Warningf("Error looking up in-cluster authentication configuration: %v", err) + klog.Warningf("Continuing without authentication configuration. This may treat all requests as anonymous.") + klog.Warningf("To require authentication configuration lookup to succeed, set --authentication-tolerate-lookup-failure=false") + } else { + return err } - } } - requestHeaderCAFileSpecified := len(s.RequestHeader.ClientCAFile) > 0 - var requestHeaderConfig *authenticatorfactory.RequestHeaderConfig - if requestHeaderCAFileSpecified { - requestHeaderConfig, err = s.RequestHeader.ToAuthenticationRequestHeaderConfig() - if err != nil { - return fmt.Errorf("unable to create request header authentication config: %v", err) - } - - } else if !s.SkipInClusterLookup { - if client == nil { - klog.Warningf("No authentication-kubeconfig provided in order to lookup requestheader-client-ca-file in configmap/%s in %s, so request-header client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) - } else { - requestHeaderConfig, err = s.createRequestHeaderConfig(client) - if err != nil { - if s.TolerateInClusterLookupFailure { - klog.Warningf("Error looking up in-cluster authentication configuration: %v", err) - klog.Warningf("Continuing without authentication configuration. This may treat all requests as anonymous.") - klog.Warningf("To require authentication configuration lookup to succeed, set --authentication-tolerate-lookup-failure=false") - } else { - return fmt.Errorf("unable to load configmap based request-header-client-ca-file: %v", err) - } - } - } + // configure AuthenticationInfo config + cfg.ClientCAFile = s.ClientCert.ClientCA + if err = c.ApplyClientCert(s.ClientCert.ClientCA, servingInfo); err != nil { + return fmt.Errorf("unable to load client CA file: %v", err) } - if requestHeaderConfig != nil { - cfg.RequestHeaderConfig = requestHeaderConfig - if err = authenticationInfo.ApplyClientCert(cfg.RequestHeaderConfig.CAContentProvider, servingInfo); err != nil { - return fmt.Errorf("unable to load request-header-client-ca-file: %v", err) - } + + cfg.RequestHeaderConfig = s.RequestHeader.ToAuthenticationRequestHeaderConfig() + if err = c.ApplyClientCert(s.RequestHeader.ClientCAFile, servingInfo); err != nil { + return fmt.Errorf("unable to load client CA file: %v", err) } // create authenticator @@ -312,10 +221,11 @@ func (s *DelegatingAuthenticationOptions) ApplyTo(authenticationInfo *server.Aut if err != nil { return err } - authenticationInfo.Authenticator = authenticator + c.Authenticator = authenticator if openAPIConfig != nil { openAPIConfig.SecurityDefinitions = securityDefinitions } + c.SupportsBasicAuth = false return nil } @@ -327,28 +237,137 @@ const ( // by --requestheader-username-headers. This is created in the cluster by the kube-apiserver. // "WARNING: generally do not depend on authorization being already done for incoming requests.") authenticationConfigMapName = "extension-apiserver-authentication" + authenticationRoleName = "extension-apiserver-authentication-reader" ) -func (s *DelegatingAuthenticationOptions) createRequestHeaderConfig(client kubernetes.Interface) (*authenticatorfactory.RequestHeaderConfig, error) { - dynamicRequestHeaderProvider, err := newDynamicRequestHeaderController(client) +func (s *DelegatingAuthenticationOptions) lookupMissingConfigInCluster(client kubernetes.Interface) error { + if len(s.ClientCert.ClientCA) > 0 && len(s.RequestHeader.ClientCAFile) > 0 { + return nil + } + if client == nil { + if len(s.ClientCert.ClientCA) == 0 { + klog.Warningf("No authentication-kubeconfig provided in order to lookup client-ca-file in configmap/%s in %s, so client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) + } + if len(s.RequestHeader.ClientCAFile) == 0 { + klog.Warningf("No authentication-kubeconfig provided in order to lookup requestheader-client-ca-file in configmap/%s in %s, so request-header client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) + } + return nil + } + + authConfigMap, err := client.CoreV1().ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{}) + switch { + case errors.IsNotFound(err): + // ignore, authConfigMap is nil now + case errors.IsForbidden(err): + klog.Warningf("Unable to get configmap/%s in %s. Usually fixed by "+ + "'kubectl create rolebinding -n %s ROLE_NAME --role=%s --serviceaccount=YOUR_NS:YOUR_SA'", + authenticationConfigMapName, authenticationConfigMapNamespace, authenticationConfigMapNamespace, authenticationRoleName) + return err + case err != nil: + return err + } + + if len(s.ClientCert.ClientCA) == 0 { + if authConfigMap != nil { + opt, err := inClusterClientCA(authConfigMap) + if err != nil { + return err + } + if opt != nil { + s.ClientCert = *opt + } + } + if len(s.ClientCert.ClientCA) == 0 { + klog.Warningf("Cluster doesn't provide client-ca-file in configmap/%s in %s, so client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) + } + } + + if len(s.RequestHeader.ClientCAFile) == 0 { + if authConfigMap != nil { + opt, err := inClusterRequestHeader(authConfigMap) + if err != nil { + return err + } + if opt != nil { + s.RequestHeader = *opt + } + } + if len(s.RequestHeader.ClientCAFile) == 0 { + klog.Warningf("Cluster doesn't provide requestheader-client-ca-file in configmap/%s in %s, so request-header client certificate authentication won't work.", authenticationConfigMapName, authenticationConfigMapNamespace) + } + } + + return nil +} + +func inClusterClientCA(authConfigMap *v1.ConfigMap) (*ClientCertAuthenticationOptions, error) { + clientCA, ok := authConfigMap.Data["client-ca-file"] + if !ok { + // not having a client-ca is fine, return nil + return nil, nil + } + + f, err := ioutil.TempFile("", "client-ca-file") if err != nil { - return nil, fmt.Errorf("unable to create request header authentication config: %v", err) + return nil, err } + if err := ioutil.WriteFile(f.Name(), []byte(clientCA), 0600); err != nil { + return nil, err + } + return &ClientCertAuthenticationOptions{ClientCA: f.Name()}, nil +} - // look up authentication configuration in the cluster and in case of an err defer to authentication-tolerate-lookup-failure flag - if err := dynamicRequestHeaderProvider.RunOnce(); err != nil { +func inClusterRequestHeader(authConfigMap *v1.ConfigMap) (*RequestHeaderAuthenticationOptions, error) { + requestHeaderCA, ok := authConfigMap.Data["requestheader-client-ca-file"] + if !ok { + // not having a requestheader-client-ca is fine, return nil + return nil, nil + } + + f, err := ioutil.TempFile("", "requestheader-client-ca-file") + if err != nil { + return nil, err + } + if err := ioutil.WriteFile(f.Name(), []byte(requestHeaderCA), 0600); err != nil { + return nil, err + } + usernameHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-username-headers"]) + if err != nil { + return nil, err + } + groupHeaders, err := deserializeStrings(authConfigMap.Data["requestheader-group-headers"]) + if err != nil { + return nil, err + } + extraHeaderPrefixes, err := deserializeStrings(authConfigMap.Data["requestheader-extra-headers-prefix"]) + if err != nil { + return nil, err + } + allowedNames, err := deserializeStrings(authConfigMap.Data["requestheader-allowed-names"]) + if err != nil { return nil, err } - return &authenticatorfactory.RequestHeaderConfig{ - CAContentProvider: dynamicRequestHeaderProvider, - UsernameHeaders: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.UsernameHeaders)), - GroupHeaders: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.GroupHeaders)), - ExtraHeaderPrefixes: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.ExtraHeaderPrefixes)), - AllowedClientNames: headerrequest.StringSliceProvider(headerrequest.StringSliceProviderFunc(dynamicRequestHeaderProvider.AllowedClientNames)), + return &RequestHeaderAuthenticationOptions{ + UsernameHeaders: usernameHeaders, + GroupHeaders: groupHeaders, + ExtraHeaderPrefixes: extraHeaderPrefixes, + ClientCAFile: f.Name(), + AllowedNames: allowedNames, }, nil } +func deserializeStrings(in string) ([]string, error) { + if len(in) == 0 { + return nil, nil + } + var ret []string + if err := json.Unmarshal([]byte(in), &ret); err != nil { + return nil, err + } + return ret, nil +} + // getClient returns a Kubernetes clientset. If s.RemoteKubeConfigFileOptional is true, nil will be returned // if no kubeconfig is specified by the user and the in-cluster config is not found. func (s *DelegatingAuthenticationOptions) getClient() (kubernetes.Interface, error) { diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go b/vendor/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go deleted file mode 100644 index 5c558b06d68..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/authentication_dynamic_request_header.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2020 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 options - -import ( - "fmt" - - "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apiserver/pkg/authentication/request/headerrequest" - "k8s.io/apiserver/pkg/server/dynamiccertificates" - "k8s.io/client-go/kubernetes" -) - -var _ dynamiccertificates.ControllerRunner = &DynamicRequestHeaderController{} -var _ dynamiccertificates.Notifier = &DynamicRequestHeaderController{} -var _ dynamiccertificates.CAContentProvider = &DynamicRequestHeaderController{} - -var _ headerrequest.RequestHeaderAuthRequestProvider = &DynamicRequestHeaderController{} - -// DynamicRequestHeaderController combines DynamicCAFromConfigMapController and RequestHeaderAuthRequestController -// into one controller for dynamically filling RequestHeaderConfig struct -type DynamicRequestHeaderController struct { - *dynamiccertificates.ConfigMapCAController - *headerrequest.RequestHeaderAuthRequestController -} - -// newDynamicRequestHeaderController creates a new controller that implements DynamicRequestHeaderController -func newDynamicRequestHeaderController(client kubernetes.Interface) (*DynamicRequestHeaderController, error) { - requestHeaderCAController, err := dynamiccertificates.NewDynamicCAFromConfigMapController( - "client-ca", - authenticationConfigMapNamespace, - authenticationConfigMapName, - "requestheader-client-ca-file", - client) - if err != nil { - return nil, fmt.Errorf("unable to create DynamicCAFromConfigMap controller: %v", err) - } - - requestHeaderAuthRequestController := headerrequest.NewRequestHeaderAuthRequestController( - authenticationConfigMapName, - authenticationConfigMapNamespace, - client, - "requestheader-username-headers", - "requestheader-group-headers", - "requestheader-extra-headers-prefix", - "requestheader-allowed-names", - ) - return &DynamicRequestHeaderController{ - ConfigMapCAController: requestHeaderCAController, - RequestHeaderAuthRequestController: requestHeaderAuthRequestController, - }, nil -} - -func (c *DynamicRequestHeaderController) RunOnce() error { - errs := []error{} - errs = append(errs, c.ConfigMapCAController.RunOnce()) - errs = append(errs, c.RequestHeaderAuthRequestController.RunOnce()) - return errors.NewAggregate(errs) -} - -func (c *DynamicRequestHeaderController) Run(workers int, stopCh <-chan struct{}) { - go c.ConfigMapCAController.Run(workers, stopCh) - go c.RequestHeaderAuthRequestController.Run(workers, stopCh) - <-stopCh -} diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authentication_test.go b/vendor/k8s.io/apiserver/pkg/server/options/authentication_test.go index aa8de47cda8..a196b1c76da 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/authentication_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/authentication_test.go @@ -24,7 +24,6 @@ import ( "testing" "k8s.io/apiserver/pkg/authentication/authenticatorfactory" - "k8s.io/apiserver/pkg/authentication/request/headerrequest" "k8s.io/apiserver/pkg/server" openapicommon "k8s.io/kube-openapi/pkg/common" ) @@ -38,44 +37,34 @@ func TestToAuthenticationRequestHeaderConfig(t *testing.T) { { name: "test when ClientCAFile is nil", testOptions: &RequestHeaderAuthenticationOptions{ - UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, - GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, - ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, - AllowedNames: headerrequest.StaticStringSlice{"kube-aggregator"}, + UsernameHeaders: []string{"x-remote-user"}, + GroupHeaders: []string{"x-remote-group"}, + ExtraHeaderPrefixes: []string{"x-remote-extra-"}, + AllowedNames: []string{"kube-aggregator"}, }, }, { name: "test when ClientCAFile is not nil", testOptions: &RequestHeaderAuthenticationOptions{ - ClientCAFile: "testdata/root.pem", - UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, - GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, - ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, - AllowedNames: headerrequest.StaticStringSlice{"kube-aggregator"}, + ClientCAFile: "/testClientCAFile", + UsernameHeaders: []string{"x-remote-user"}, + GroupHeaders: []string{"x-remote-group"}, + ExtraHeaderPrefixes: []string{"x-remote-extra-"}, + AllowedNames: []string{"kube-aggregator"}, }, expectConfig: &authenticatorfactory.RequestHeaderConfig{ - UsernameHeaders: headerrequest.StaticStringSlice{"x-remote-user"}, - GroupHeaders: headerrequest.StaticStringSlice{"x-remote-group"}, - ExtraHeaderPrefixes: headerrequest.StaticStringSlice{"x-remote-extra-"}, - CAContentProvider: nil, // this is nil because you can't compare functions - AllowedClientNames: headerrequest.StaticStringSlice{"kube-aggregator"}, + UsernameHeaders: []string{"x-remote-user"}, + GroupHeaders: []string{"x-remote-group"}, + ExtraHeaderPrefixes: []string{"x-remote-extra-"}, + ClientCA: "/testClientCAFile", + AllowedClientNames: []string{"kube-aggregator"}, }, }, } for _, testcase := range testCases { t.Run(testcase.name, func(t *testing.T) { - resultConfig, err := testcase.testOptions.ToAuthenticationRequestHeaderConfig() - if err != nil { - t.Fatal(err) - } - if resultConfig != nil { - if resultConfig.CAContentProvider == nil { - t.Error("missing requestheader verify") - } - resultConfig.CAContentProvider = nil - } - + resultConfig := testcase.testOptions.ToAuthenticationRequestHeaderConfig() if !reflect.DeepEqual(resultConfig, testcase.expectConfig) { t.Errorf("got RequestHeaderConfig: %#v, expected RequestHeaderConfig: %#v", resultConfig, testcase.expectConfig) } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authorization.go b/vendor/k8s.io/apiserver/pkg/server/options/authorization.go index 7284c261f18..5d81d9e8660 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/authorization.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/authorization.go @@ -146,7 +146,7 @@ func (s *DelegatingAuthorizationOptions) toAuthorizer(client kubernetes.Interfac klog.Warningf("No authorization-kubeconfig provided, so SubjectAccessReview of authorization tokens won't work.") } else { cfg := authorizerfactory.DelegatingAuthorizerConfig{ - SubjectAccessReviewClient: client.AuthorizationV1().SubjectAccessReviews(), + SubjectAccessReviewClient: client.AuthorizationV1beta1().SubjectAccessReviews(), AllowCacheTTL: s.AllowCacheTTL, DenyCacheTTL: s.DenyCacheTTL, } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go b/vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go index 1c066313c2c..804f04bca96 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/deprecated_insecure_serving.go @@ -43,7 +43,7 @@ type DeprecatedInsecureServingOptions struct { // ListenFunc can be overridden to create a custom listener, e.g. for mocking in tests. // It defaults to options.CreateListener. - ListenFunc func(network, addr string, config net.ListenConfig) (net.Listener, int, error) + ListenFunc func(network, addr string) (net.Listener, int, error) } // Validate ensures that the insecure port values within the range of the port. @@ -54,8 +54,8 @@ func (s *DeprecatedInsecureServingOptions) Validate() []error { errors := []error{} - if s.BindPort < 0 || s.BindPort > 65535 { - errors = append(errors, fmt.Errorf("insecure port %v must be between 0 and 65535, inclusive. 0 for turning off insecure (HTTP) port", s.BindPort)) + if s.BindPort < 0 || s.BindPort > 65335 { + errors = append(errors, fmt.Errorf("insecure port %v must be between 0 and 65335, inclusive. 0 for turning off insecure (HTTP) port", s.BindPort)) } return errors @@ -69,13 +69,11 @@ func (s *DeprecatedInsecureServingOptions) AddFlags(fs *pflag.FlagSet) { fs.IPVar(&s.BindAddress, "insecure-bind-address", s.BindAddress, ""+ "The IP address on which to serve the --insecure-port (set to 0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).") - // Though this flag is deprecated, we discovered security concerns over how to do health checks without it e.g. #43784 fs.MarkDeprecated("insecure-bind-address", "This flag will be removed in a future version.") fs.Lookup("insecure-bind-address").Hidden = false fs.IntVar(&s.BindPort, "insecure-port", s.BindPort, ""+ "The port on which to serve unsecured, unauthenticated access.") - // Though this flag is deprecated, we discovered security concerns over how to do health checks without it e.g. #43784 fs.MarkDeprecated("insecure-port", "This flag will be removed in a future version.") fs.Lookup("insecure-port").Hidden = false } @@ -96,7 +94,7 @@ func (s *DeprecatedInsecureServingOptions) AddUnqualifiedFlags(fs *pflag.FlagSet fs.Lookup("port").Hidden = false } -// ApplyTo adds DeprecatedInsecureServingOptions to the insecureserverinfo and kube-controller manager configuration. +// ApplyTo adds DeprecatedInsecureServingOptions to the insecureserverinfo amd kube-controller manager configuration. // Note: the double pointer allows to set the *DeprecatedInsecureServingInfo to nil without referencing the struct hosting this pointer. func (s *DeprecatedInsecureServingOptions) ApplyTo(c **server.DeprecatedInsecureServingInfo) error { if s == nil { @@ -113,7 +111,7 @@ func (s *DeprecatedInsecureServingOptions) ApplyTo(c **server.DeprecatedInsecure listen = s.ListenFunc } addr := net.JoinHostPort(s.BindAddress.String(), fmt.Sprintf("%d", s.BindPort)) - s.Listener, s.BindPort, err = listen(s.BindNetwork, addr, net.ListenConfig{}) + s.Listener, s.BindPort, err = listen(s.BindNetwork, addr) if err != nil { return fmt.Errorf("failed to create listener: %v", err) } @@ -132,8 +130,7 @@ func (o *DeprecatedInsecureServingOptions) WithLoopback() *DeprecatedInsecureSer } // DeprecatedInsecureServingOptionsWithLoopback adds loopback functionality to the DeprecatedInsecureServingOptions. -// DEPRECATED: all insecure serving options will be removed in a future version, however note that -// there are security concerns over how health checks can work here - see e.g. #43784 +// DEPRECATED: all insecure serving options are removed in a future version type DeprecatedInsecureServingOptionsWithLoopback struct { *DeprecatedInsecureServingOptions } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/egress_selector.go b/vendor/k8s.io/apiserver/pkg/server/options/egress_selector.go deleted file mode 100644 index c5e579c3cfb..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/egress_selector.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2019 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 options - -import ( - "fmt" - "github.com/spf13/pflag" - "k8s.io/utils/path" - - "k8s.io/apiserver/pkg/server" - "k8s.io/apiserver/pkg/server/egressselector" -) - -// EgressSelectorOptions holds the api server egress selector options. -// See https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190226-network-proxy.md -type EgressSelectorOptions struct { - // ConfigFile is the file path with api-server egress selector configuration. - ConfigFile string -} - -// NewEgressSelectorOptions creates a new instance of EgressSelectorOptions -// -// The option is to point to a configuration file for egress/konnectivity. -// This determines which types of requests use egress/konnectivity and how they use it. -// If empty the API Server will attempt to connect directly using the network. -func NewEgressSelectorOptions() *EgressSelectorOptions { - return &EgressSelectorOptions{} -} - -// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet -func (o *EgressSelectorOptions) AddFlags(fs *pflag.FlagSet) { - if o == nil { - return - } - - fs.StringVar(&o.ConfigFile, "egress-selector-config-file", o.ConfigFile, - "File with apiserver egress selector configuration.") -} - -// ApplyTo adds the egress selector settings to the server configuration. -// In case egress selector settings were not provided by a cluster-admin -// they will be prepared from the recommended/default/no-op values. -func (o *EgressSelectorOptions) ApplyTo(c *server.Config) error { - if o == nil { - return nil - } - - npConfig, err := egressselector.ReadEgressSelectorConfiguration(o.ConfigFile) - if err != nil { - return fmt.Errorf("failed to read egress selector config: %v", err) - } - errs := egressselector.ValidateEgressSelectorConfiguration(npConfig) - if len(errs) > 0 { - return fmt.Errorf("failed to validate egress selector configuration: %v", errs.ToAggregate()) - } - - cs, err := egressselector.NewEgressSelector(npConfig) - if err != nil { - return fmt.Errorf("failed to setup egress selector with config %#v: %v", npConfig, err) - } - c.EgressSelector = cs - return nil -} - -// Validate verifies flags passed to EgressSelectorOptions. -func (o *EgressSelectorOptions) Validate() []error { - if o == nil || o.ConfigFile == "" { - return nil - } - - errs := []error{} - - if exists, err := path.Exists(path.CheckFollowSymlink, o.ConfigFile); exists == false || err != nil { - errs = append(errs, fmt.Errorf("egress-selector-config-file %s does not exist", o.ConfigFile)) - } - - return errs -} diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/OWNERS b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/OWNERS index 71edc3ecdcc..498b470c9bf 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/OWNERS @@ -1,5 +1,3 @@ -# See the OWNERS docs at https://go.k8s.io/owners - approvers: - sig-auth-encryption-at-rest-approvers reviewers: diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index 372ab5eb8a6..d86a3e10181 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -20,13 +20,10 @@ import ( "crypto/aes" "crypto/cipher" "encoding/base64" - "errors" "fmt" "io" "io/ioutil" - "net/http" "os" - "sync" "time" "k8s.io/apimachinery/pkg/runtime" @@ -34,8 +31,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" apiserverconfig "k8s.io/apiserver/pkg/apis/config" apiserverconfigv1 "k8s.io/apiserver/pkg/apis/config/v1" - "k8s.io/apiserver/pkg/apis/config/validation" - "k8s.io/apiserver/pkg/server/healthz" "k8s.io/apiserver/pkg/storage/value" aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes" "k8s.io/apiserver/pkg/storage/value/encrypt/envelope" @@ -48,111 +43,9 @@ const ( aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:" secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:" kmsTransformerPrefixV1 = "k8s:enc:kms:v1:" - kmsPluginHealthzNegativeTTL = 3 * time.Second - kmsPluginHealthzPositiveTTL = 20 * time.Second + kmsPluginConnectionTimeout = 3 * time.Second ) -type kmsPluginHealthzResponse struct { - err error - received time.Time -} - -type kmsPluginProbe struct { - name string - ttl time.Duration - envelope.Service - lastResponse *kmsPluginHealthzResponse - l *sync.Mutex -} - -func (h *kmsPluginProbe) toHealthzCheck(idx int) healthz.HealthChecker { - return healthz.NamedCheck(fmt.Sprintf("kms-provider-%d", idx), func(r *http.Request) error { - return h.Check() - }) -} - -// GetKMSPluginHealthzCheckers extracts KMSPluginProbes from the EncryptionConfig. -func GetKMSPluginHealthzCheckers(filepath string) ([]healthz.HealthChecker, error) { - f, err := os.Open(filepath) - if err != nil { - return nil, fmt.Errorf("error opening encryption provider configuration file %q: %v", filepath, err) - } - defer f.Close() - var result []healthz.HealthChecker - probes, err := getKMSPluginProbes(f) - if err != nil { - return nil, err - } - - for i, p := range probes { - probe := p - result = append(result, probe.toHealthzCheck(i)) - } - return result, nil -} - -func getKMSPluginProbes(reader io.Reader) ([]*kmsPluginProbe, error) { - var result []*kmsPluginProbe - - configFileContents, err := ioutil.ReadAll(reader) - if err != nil { - return result, fmt.Errorf("could not read content of encryption provider configuration: %v", err) - } - - config, err := loadConfig(configFileContents) - if err != nil { - return result, fmt.Errorf("error while parsing encrypiton provider configuration: %v", err) - } - - for _, r := range config.Resources { - for _, p := range r.Providers { - if p.KMS != nil { - s, err := envelope.NewGRPCService(p.KMS.Endpoint, p.KMS.Timeout.Duration) - if err != nil { - return nil, fmt.Errorf("could not configure KMS-Plugin's probe %q, error: %v", p.KMS.Name, err) - } - - result = append(result, &kmsPluginProbe{ - name: p.KMS.Name, - ttl: kmsPluginHealthzNegativeTTL, - Service: s, - l: &sync.Mutex{}, - lastResponse: &kmsPluginHealthzResponse{}, - }) - } - } - } - - return result, nil -} - -// Check encrypts and decrypts test data against KMS-Plugin's gRPC endpoint. -func (h *kmsPluginProbe) Check() error { - h.l.Lock() - defer h.l.Unlock() - - if (time.Since(h.lastResponse.received)) < h.ttl { - return h.lastResponse.err - } - - p, err := h.Service.Encrypt([]byte("ping")) - if err != nil { - h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()} - h.ttl = kmsPluginHealthzNegativeTTL - return fmt.Errorf("failed to perform encrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err) - } - - if _, err := h.Service.Decrypt(p); err != nil { - h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()} - h.ttl = kmsPluginHealthzNegativeTTL - return fmt.Errorf("failed to perform decrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err) - } - - h.lastResponse = &kmsPluginHealthzResponse{err: nil, received: time.Now()} - h.ttl = kmsPluginHealthzPositiveTTL - return nil -} - // GetTransformerOverrides returns the transformer overrides by reading and parsing the encryption provider configuration file func GetTransformerOverrides(filepath string) (map[schema.GroupResource]value.Transformer, error) { f, err := os.Open(filepath) @@ -161,14 +54,15 @@ func GetTransformerOverrides(filepath string) (map[schema.GroupResource]value.Tr } defer f.Close() - result, err := parseEncryptionConfiguration(f) + result, err := ParseEncryptionConfiguration(f) if err != nil { return nil, fmt.Errorf("error while parsing encryption provider configuration file %q: %v", filepath, err) } return result, nil } -func parseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.Transformer, error) { +// ParseEncryptionConfiguration parses configuration data and returns the transformer overrides +func ParseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.Transformer, error) { configFileContents, err := ioutil.ReadAll(f) if err != nil { return nil, fmt.Errorf("could not read contents: %v", err) @@ -183,7 +77,7 @@ func parseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.T // For each entry in the configuration for _, resourceConfig := range config.Resources { - transformers, err := prefixTransformers(&resourceConfig) + transformers, err := GetPrefixTransformers(&resourceConfig) if err != nil { return nil, err } @@ -204,6 +98,7 @@ func parseEncryptionConfiguration(f io.Reader) (map[schema.GroupResource]value.T } +// loadConfig decodes data as a EncryptionConfiguration object. func loadConfig(data []byte) (*apiserverconfig.EncryptionConfiguration, error) { scheme := runtime.NewScheme() codecs := serializer.NewCodecFactory(scheme) @@ -218,55 +113,94 @@ func loadConfig(data []byte) (*apiserverconfig.EncryptionConfiguration, error) { if !ok { return nil, fmt.Errorf("got unexpected config type: %v", gvk) } - - return config, validation.ValidateEncryptionConfiguration(config).ToAggregate() + return config, nil } // The factory to create kms service. This is to make writing test easier. var envelopeServiceFactory = envelope.NewGRPCService -func prefixTransformers(config *apiserverconfig.ResourceConfiguration) ([]value.PrefixTransformer, error) { +// GetPrefixTransformers constructs and returns the appropriate prefix transformers for the passed resource using its configuration. +func GetPrefixTransformers(config *apiserverconfig.ResourceConfiguration) ([]value.PrefixTransformer, error) { var result []value.PrefixTransformer for _, provider := range config.Providers { - var ( - transformer value.PrefixTransformer - err error - ) - - switch { - case provider.AESGCM != nil: - transformer, err = aesPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1) - case provider.AESCBC != nil: - transformer, err = aesPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1) - case provider.Secretbox != nil: - transformer, err = secretboxPrefixTransformer(provider.Secretbox) - case provider.KMS != nil: - envelopeService, err := envelopeServiceFactory(provider.KMS.Endpoint, provider.KMS.Timeout.Duration) + found := false + + var transformer value.PrefixTransformer + var err error + + if provider.AESGCM != nil { + transformer, err = GetAESPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1) if err != nil { - return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) + return result, err + } + found = true + } + + if provider.AESCBC != nil { + if found == true { + return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") } + transformer, err = GetAESPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1) + found = true + } - transformer, err = envelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1) - case provider.Identity != nil: + if provider.Secretbox != nil { + if found == true { + return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") + } + transformer, err = GetSecretboxPrefixTransformer(provider.Secretbox) + found = true + } + + if provider.Identity != nil { + if found == true { + return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") + } transformer = value.PrefixTransformer{ Transformer: identity.NewEncryptCheckTransformer(), Prefix: []byte{}, } - default: - return nil, errors.New("provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity") + found = true + } + + if provider.KMS != nil { + if found == true { + return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") + } + + // Ensure the endpoint is provided. + if len(provider.KMS.Endpoint) == 0 { + return nil, fmt.Errorf("remote KMS provider can't use empty string as endpoint") + } + + // Get gRPC client service with endpoint. + envelopeService, err := envelopeServiceFactory(provider.KMS.Endpoint, kmsPluginConnectionTimeout) + if err != nil { + return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err) + } + + transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1) + found = true } if err != nil { return result, err } result = append(result, transformer) + + if found == false { + return result, fmt.Errorf("invalid provider configuration: at least one provider must be specified") + } } return result, nil } -type blockTransformerFunc func(cipher.Block) value.Transformer +// BlockTransformerFunc takes an AES cipher block and returns a value transformer. +type BlockTransformerFunc func(cipher.Block) value.Transformer -func aesPrefixTransformer(config *apiserverconfig.AESConfiguration, fn blockTransformerFunc, prefix string) (value.PrefixTransformer, error) { +// GetAESPrefixTransformer returns a prefix transformer from the provided configuration. +// Returns an AES transformer based on the provided prefix and block transformer. +func GetAESPrefixTransformer(config *apiserverconfig.AESConfiguration, fn BlockTransformerFunc, prefix string) (value.PrefixTransformer, error) { var result value.PrefixTransformer if len(config.Keys) == 0 { @@ -313,7 +247,8 @@ func aesPrefixTransformer(config *apiserverconfig.AESConfiguration, fn blockTran return result, nil } -func secretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration) (value.PrefixTransformer, error) { +// GetSecretboxPrefixTransformer returns a prefix transformer from the provided configuration +func GetSecretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration) (value.PrefixTransformer, error) { var result value.PrefixTransformer if len(config.Keys) == 0 { @@ -363,8 +298,10 @@ func secretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguration) return result, nil } -func envelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) { - envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), aestransformer.NewCBCTransformer) +// getEnvelopePrefixTransformer returns a prefix transformer from the provided config. +// envelopeService is used as the root of trust. +func getEnvelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) { + envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, int(config.CacheSize), aestransformer.NewCBCTransformer) if err != nil { return value.PrefixTransformer{}, err } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go index 3b4ece8e3a8..6ba28763749 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go @@ -19,81 +19,267 @@ package encryptionconfig import ( "bytes" "encoding/base64" - "errors" - "io" - "io/ioutil" - "os" - "sync" + "reflect" + "strings" "testing" "time" - "github.com/google/go-cmp/cmp" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" apiserverconfig "k8s.io/apiserver/pkg/apis/config" "k8s.io/apiserver/pkg/storage/value" "k8s.io/apiserver/pkg/storage/value/encrypt/envelope" ) const ( - sampleText = "abcdefghijklmnopqrstuvwxyz" - sampleContextText = "0123456789" -) - -func mustReadConfig(t *testing.T, path string) []byte { - t.Helper() - f, err := os.Open(path) - if err != nil { - t.Fatalf("error opening encryption configuration file %q: %v", path, err) - } - defer f.Close() + sampleText = "abcdefghijklmnopqrstuvwxyz" - configFileContents, err := ioutil.ReadAll(f) - if err != nil { - t.Fatalf("could not read contents of encryption config: %v", err) - } - - return configFileContents -} + sampleContextText = "0123456789" -func mustConfigReader(t *testing.T, path string) io.Reader { - return bytes.NewReader(mustReadConfig(t, path)) -} + legacyV1Config = ` + kind: EncryptionConfig + apiVersion: v1 + resources: + - resources: + - secrets + - namespaces + providers: + - identity: {} + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + ` + + correctConfigWithIdentityFirst = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + - namespaces + providers: + - identity: {} + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= +` + + correctConfigWithAesGcmFirst = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + providers: + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - identity: {} +` + + correctConfigWithAesCbcFirst = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + providers: + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - identity: {} + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== +` + + correctConfigWithSecretboxFirst = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + providers: + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - identity: {} + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== +` + + correctConfigWithKMSFirst = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + providers: + - kms: + name: testprovider + endpoint: unix:///tmp/testprovider.sock + cachesize: 10 + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - identity: {} + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== +` + + incorrectConfigNoSecretForKey = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - namespaces + - secrets + providers: + - aesgcm: + keys: + - name: key1 +` + + incorrectConfigInvalidKey = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - namespaces + - secrets + providers: + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: YSBzZWNyZXQgYSBzZWNyZXQ= +` + + incorrectConfigNoEndpointForKMS = ` +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + providers: + - kms: + name: testprovider + cachesize: 10 +` +) // testEnvelopeService is a mock envelope service which can be used to simulate remote Envelope services // for testing of the envelope transformer with other transformers. type testEnvelopeService struct { - err error } func (t *testEnvelopeService) Decrypt(data []byte) ([]byte, error) { - if t.err != nil { - return nil, t.err - } return base64.StdEncoding.DecodeString(string(data)) } func (t *testEnvelopeService) Encrypt(data []byte) ([]byte, error) { - if t.err != nil { - return nil, t.err - } return []byte(base64.StdEncoding.EncodeToString(data)), nil } // The factory method to create mock envelope service. func newMockEnvelopeService(endpoint string, timeout time.Duration) (envelope.Service, error) { - return &testEnvelopeService{nil}, nil -} - -// The factory method to create mock envelope service which always returns error. -func newMockErrorEnvelopeService(endpoint string, timeout time.Duration) (envelope.Service, error) { - return &testEnvelopeService{errors.New("test")}, nil + return &testEnvelopeService{}, nil } func TestLegacyConfig(t *testing.T) { - legacyV1Config := "testdata/valid-configs/legacy.yaml" - legacyConfigObject, err := loadConfig(mustReadConfig(t, legacyV1Config)) - cacheSize := int32(10) + legacyConfigObject, err := loadConfig([]byte(legacyV1Config)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, legacyV1Config) } @@ -113,8 +299,7 @@ func TestLegacyConfig(t *testing.T) { {KMS: &apiserverconfig.KMSConfiguration{ Name: "testprovider", Endpoint: "unix:///tmp/testprovider.sock", - CacheSize: &cacheSize, - Timeout: &metav1.Duration{Duration: 3 * time.Second}, + CacheSize: 10, }}, {AESCBC: &apiserverconfig.AESConfiguration{ Keys: []apiserverconfig.Key{ @@ -131,11 +316,10 @@ func TestLegacyConfig(t *testing.T) { }, }, } - if d := cmp.Diff(expected, legacyConfigObject); d != "" { - t.Fatalf("EncryptionConfig mismatch (-want +got):\n%s", d) + if !reflect.DeepEqual(legacyConfigObject, expected) { + t.Fatal(diff.ObjectReflectDiff(expected, legacyConfigObject)) } } - func TestEncryptionProviderConfigCorrect(t *testing.T) { // Set factory for mock envelope service factory := envelopeServiceFactory @@ -147,32 +331,27 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) { // Creates compound/prefix transformers with different ordering of available transformers. // Transforms data using one of them, and tries to untransform using the others. // Repeats this for all possible combinations. - correctConfigWithIdentityFirst := "testdata/valid-configs/identity-first.yaml" - identityFirstTransformerOverrides, err := parseEncryptionConfiguration(mustConfigReader(t, correctConfigWithIdentityFirst)) + identityFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithIdentityFirst)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithIdentityFirst) } - correctConfigWithAesGcmFirst := "testdata/valid-configs/aes-gcm-first.yaml" - aesGcmFirstTransformerOverrides, err := parseEncryptionConfiguration(mustConfigReader(t, correctConfigWithAesGcmFirst)) + aesGcmFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithAesGcmFirst)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithAesGcmFirst) } - correctConfigWithAesCbcFirst := "testdata/valid-configs/aes-cbc-first.yaml" - aesCbcFirstTransformerOverrides, err := parseEncryptionConfiguration(mustConfigReader(t, correctConfigWithAesCbcFirst)) + aesCbcFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithAesCbcFirst)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithAesCbcFirst) } - correctConfigWithSecretboxFirst := "testdata/valid-configs/secret-box-first.yaml" - secretboxFirstTransformerOverrides, err := parseEncryptionConfiguration(mustConfigReader(t, correctConfigWithSecretboxFirst)) + secretboxFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithSecretboxFirst)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithSecretboxFirst) } - correctConfigWithKMSFirst := "testdata/valid-configs/kms-first.yaml" - kmsFirstTransformerOverrides, err := parseEncryptionConfiguration(mustConfigReader(t, correctConfigWithKMSFirst)) + kmsFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithKMSFirst)) if err != nil { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithKMSFirst) } @@ -212,201 +391,31 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) { if stale != (transformer.Name != testCase.Name) { t.Fatalf("%s: wrong stale information on reading using %s transformer, should be %v", testCase.Name, transformer.Name, testCase.Name == transformer.Name) } - if !bytes.Equal(untransformedData, originalText) { + if bytes.Compare(untransformedData, originalText) != 0 { t.Fatalf("%s: %s transformer transformed data incorrectly. Expected: %v, got %v", testCase.Name, transformer.Name, originalText, untransformedData) } } } -} - -func TestKMSPluginHealthz(t *testing.T) { - service, err := envelope.NewGRPCService("unix:///tmp/testprovider.sock", 3*time.Second) - if err != nil { - t.Fatalf("Could not initialize envelopeService, error: %v", err) - } - testCases := []struct { - desc string - config string - want []*kmsPluginProbe - wantErr bool - }{ - { - desc: "Install Healthz", - config: "testdata/valid-configs/kms/default-timeout.yaml", - want: []*kmsPluginProbe{ - { - name: "foo", - Service: service, - }, - }, - }, - { - desc: "Install multiple healthz", - config: "testdata/valid-configs/kms/multiple-providers.yaml", - want: []*kmsPluginProbe{ - { - name: "foo", - Service: service, - }, - { - name: "bar", - Service: service, - }, - }, - }, - { - desc: "No KMS Providers", - config: "testdata/valid-configs/aes/aes-gcm.yaml", - }, - } - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - got, err := getKMSPluginProbes(mustConfigReader(t, tt.config)) - if err != nil && !tt.wantErr { - t.Fatalf("got %v, want nil for error", err) - } - - if d := cmp.Diff(tt.want, got, cmp.Comparer(serviceComparer)); d != "" { - t.Fatalf("HealthzConfig mismatch (-want +got):\n%s", d) - } - }) - } } -func TestKMSPluginHealthzTTL(t *testing.T) { - service, _ := newMockEnvelopeService("unix:///tmp/testprovider.sock", 3*time.Second) - errService, _ := newMockErrorEnvelopeService("unix:///tmp/testprovider.sock", 3*time.Second) - - testCases := []struct { - desc string - probe *kmsPluginProbe - wantTTL time.Duration - }{ - { - desc: "kms provider in good state", - probe: &kmsPluginProbe{ - name: "test", - ttl: kmsPluginHealthzNegativeTTL, - Service: service, - l: &sync.Mutex{}, - lastResponse: &kmsPluginHealthzResponse{}, - }, - wantTTL: kmsPluginHealthzPositiveTTL, - }, - { - desc: "kms provider in bad state", - probe: &kmsPluginProbe{ - name: "test", - ttl: kmsPluginHealthzPositiveTTL, - Service: errService, - l: &sync.Mutex{}, - lastResponse: &kmsPluginHealthzResponse{}, - }, - wantTTL: kmsPluginHealthzNegativeTTL, - }, - } - - for _, tt := range testCases { - t.Run(tt.desc, func(t *testing.T) { - tt.probe.Check() - if tt.probe.ttl != tt.wantTTL { - t.Fatalf("want ttl %v, got ttl %v", tt.wantTTL, tt.probe.ttl) - } - }) +// Throw error if key has no secret +func TestEncryptionProviderConfigNoSecretForKey(t *testing.T) { + if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigNoSecretForKey)); err == nil { + t.Fatalf("invalid configuration file (one key has no secret) got parsed:\n%s", incorrectConfigNoSecretForKey) } } -// As long as got and want contain envelope.Service we will return true. -// If got has an envelope.Service and want does note (or vice versa) this will return false. -func serviceComparer(_, _ envelope.Service) bool { - return true -} - -func TestCBCKeyRotationWithOverlappingProviders(t *testing.T) { - testCBCKeyRotationWithProviders( - t, - "testdata/valid-configs/aes/aes-cbc-multiple-providers.json", - "k8s:enc:aescbc:v1:1:", - "testdata/valid-configs/aes/aes-cbc-multiple-providers-reversed.json", - "k8s:enc:aescbc:v1:2:", - ) -} - -func TestCBCKeyRotationWithoutOverlappingProviders(t *testing.T) { - testCBCKeyRotationWithProviders( - t, - "testdata/valid-configs/aes/aes-cbc-multiple-keys.json", - "k8s:enc:aescbc:v1:A:", - "testdata/valid-configs/aes/aes-cbc-multiple-keys-reversed.json", - "k8s:enc:aescbc:v1:B:", - ) -} - -func testCBCKeyRotationWithProviders(t *testing.T, firstEncryptionConfig, firstPrefix, secondEncryptionConfig, secondPrefix string) { - p := getTransformerFromEncryptionConfig(t, firstEncryptionConfig) - - context := value.DefaultContext([]byte("authenticated_data")) - - out, err := p.TransformToStorage([]byte("firstvalue"), context) - if err != nil { - t.Fatal(err) - } - if !bytes.HasPrefix(out, []byte(firstPrefix)) { - t.Fatalf("unexpected prefix: %q", out) - } - from, stale, err := p.TransformFromStorage(out, context) - if err != nil { - t.Fatal(err) - } - if stale || !bytes.Equal([]byte("firstvalue"), from) { - t.Fatalf("unexpected data: %t %q", stale, from) - } - - // verify changing the context fails storage - _, _, err = p.TransformFromStorage(out, value.DefaultContext([]byte("incorrect_context"))) - if err != nil { - t.Fatalf("CBC mode does not support authentication: %v", err) - } - - // reverse the order, use the second key - p = getTransformerFromEncryptionConfig(t, secondEncryptionConfig) - from, stale, err = p.TransformFromStorage(out, context) - if err != nil { - t.Fatal(err) - } - if !stale || !bytes.Equal([]byte("firstvalue"), from) { - t.Fatalf("unexpected data: %t %q", stale, from) - } - - out, err = p.TransformToStorage([]byte("firstvalue"), context) - if err != nil { - t.Fatal(err) - } - if !bytes.HasPrefix(out, []byte(secondPrefix)) { - t.Fatalf("unexpected prefix: %q", out) - } - from, stale, err = p.TransformFromStorage(out, context) - if err != nil { - t.Fatal(err) - } - if stale || !bytes.Equal([]byte("firstvalue"), from) { - t.Fatalf("unexpected data: %t %q", stale, from) +// Throw error if invalid key for AES +func TestEncryptionProviderConfigInvalidKey(t *testing.T) { + if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigInvalidKey)); err == nil { + t.Fatalf("invalid configuration file (bad AES key) got parsed:\n%s", incorrectConfigInvalidKey) } } -func getTransformerFromEncryptionConfig(t *testing.T, encryptionConfigPath string) value.Transformer { - t.Helper() - transformers, err := parseEncryptionConfiguration(mustConfigReader(t, encryptionConfigPath)) - if err != nil { - t.Fatal(err) - } - if len(transformers) != 1 { - t.Fatalf("input config does not have exactly one resource: %s", encryptionConfigPath) - } - for _, transformer := range transformers { - return transformer +// Throw error if kms has no endpoint +func TestEncryptionProviderConfigNoEndpointForKMS(t *testing.T) { + if _, err := ParseEncryptionConfiguration(strings.NewReader(incorrectConfigNoEndpointForKMS)); err == nil { + t.Fatalf("invalid configuration file (kms has no endpoint) got parsed:\n%s", incorrectConfigNoEndpointForKMS) } - panic("unreachable") } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-cbc-first.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-cbc-first.yaml deleted file mode 100644 index a3e9b93e6bf..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-cbc-first.yaml +++ /dev/null @@ -1,27 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - identity: {} - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-gcm-first.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-gcm-first.yaml deleted file mode 100644 index 99bdf859ede..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes-gcm-first.yaml +++ /dev/null @@ -1,27 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - identity: {} diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/README.md b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/README.md deleted file mode 100644 index 47ed1717554..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/README.md +++ /dev/null @@ -1 +0,0 @@ -Keys and secrets in this directory are generated for testing purposes only. diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys-reversed.json b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys-reversed.json deleted file mode 100644 index b50cead6433..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys-reversed.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "kind": "EncryptionConfiguration", - "apiVersion": "apiserver.config.k8s.io/v1", - "resources": [ - { - "resources": [ - "ignored" - ], - "providers": [ - { - "aescbc": { - "keys": [ - { - "name": "B", - "secret": "+qcnfOFX3aRXM9PuY7lQXDWYIQ3GWUdBc3nYBo91SCA=" - }, - { - "name": "A", - "secret": "Owq7A4JrJpSjrvH8kXkvl4JmOLzvZ6j9BcGRkR8OPQ4=" - } - ] - } - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys.json b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys.json deleted file mode 100644 index e1320450151..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-keys.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "kind": "EncryptionConfiguration", - "apiVersion": "apiserver.config.k8s.io/v1", - "resources": [ - { - "resources": [ - "ignored" - ], - "providers": [ - { - "aescbc": { - "keys": [ - { - "name": "A", - "secret": "Owq7A4JrJpSjrvH8kXkvl4JmOLzvZ6j9BcGRkR8OPQ4=" - }, - { - "name": "B", - "secret": "+qcnfOFX3aRXM9PuY7lQXDWYIQ3GWUdBc3nYBo91SCA=" - } - ] - } - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers-reversed.json b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers-reversed.json deleted file mode 100644 index 0d3be557205..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers-reversed.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "kind": "EncryptionConfiguration", - "apiVersion": "apiserver.config.k8s.io/v1", - "resources": [ - { - "resources": [ - "ignored" - ], - "providers": [ - { - "aescbc": { - "keys": [ - { - "name": "2", - "secret": "+qcnfOFX3aRXM9PuY7lQXDWYIQ3GWUdBc3nYBo91SCA=" - } - ] - } - }, - { - "aescbc": { - "keys": [ - { - "name": "1", - "secret": "Owq7A4JrJpSjrvH8kXkvl4JmOLzvZ6j9BcGRkR8OPQ4=" - } - ] - } - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers.json b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers.json deleted file mode 100644 index d2435a50317..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-cbc-multiple-providers.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "kind": "EncryptionConfiguration", - "apiVersion": "apiserver.config.k8s.io/v1", - "resources": [ - { - "resources": [ - "ignored" - ], - "providers": [ - { - "aescbc": { - "keys": [ - { - "name": "1", - "secret": "Owq7A4JrJpSjrvH8kXkvl4JmOLzvZ6j9BcGRkR8OPQ4=" - } - ] - } - }, - { - "aescbc": { - "keys": [ - { - "name": "2", - "secret": "+qcnfOFX3aRXM9PuY7lQXDWYIQ3GWUdBc3nYBo91SCA=" - } - ] - } - } - ] - } - ] -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-gcm.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-gcm.yaml deleted file mode 100644 index 51e153e8433..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/aes/aes-gcm.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/identity-first.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/identity-first.yaml deleted file mode 100644 index 203dea5f144..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/identity-first.yaml +++ /dev/null @@ -1,28 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - - namespaces - providers: - - identity: {} - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms-first.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms-first.yaml deleted file mode 100644 index 4e8dff541b5..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms-first.yaml +++ /dev/null @@ -1,27 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - identity: {} - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/default-timeout.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/default-timeout.yaml deleted file mode 100644 index 0ec743f5bb9..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/default-timeout.yaml +++ /dev/null @@ -1,9 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - kms: - name: foo - endpoint: unix:///tmp/testprovider.sock \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/multiple-providers.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/multiple-providers.yaml deleted file mode 100644 index e2158b66d39..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/kms/multiple-providers.yaml +++ /dev/null @@ -1,14 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - kms: - name: foo - endpoint: unix:///tmp/testprovider.sock - timeout: 15s - - kms: - name: bar - endpoint: unix:///tmp/testprovider.sock - timeout: 15s \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/legacy.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/legacy.yaml deleted file mode 100644 index 8303918c6e1..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/legacy.yaml +++ /dev/null @@ -1,28 +0,0 @@ -kind: EncryptionConfig -apiVersion: v1 -resources: - - resources: - - secrets - - namespaces - providers: - - identity: {} - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/secret-box-first.yaml b/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/secret-box-first.yaml deleted file mode 100644 index a29c8248fbb..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/testdata/valid-configs/secret-box-first.yaml +++ /dev/null @@ -1,27 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - secretbox: - keys: - - name: key1 - secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= - - aescbc: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== - - kms: - name: testprovider - endpoint: unix:///tmp/testprovider.sock - cachesize: 10 - - identity: {} - - aesgcm: - keys: - - name: key1 - secret: c2VjcmV0IGlzIHNlY3VyZQ== - - name: key2 - secret: dGhpcyBpcyBwYXNzd29yZA== \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/etcd.go b/vendor/k8s.io/apiserver/pkg/server/options/etcd.go index 358776a790b..7db2cad8bb5 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/etcd.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/etcd.go @@ -31,7 +31,6 @@ import ( genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/healthz" - "k8s.io/apiserver/pkg/server/options/encryptionconfig" serverstorage "k8s.io/apiserver/pkg/server/storage" "k8s.io/apiserver/pkg/storage/storagebackend" storagefactory "k8s.io/apiserver/pkg/storage/storagebackend/factory" @@ -82,7 +81,7 @@ func (s *EtcdOptions) Validate() []error { } allErrors := []error{} - if len(s.StorageConfig.Transport.ServerList) == 0 { + if len(s.StorageConfig.ServerList) == 0 { allErrors = append(allErrors, fmt.Errorf("--etcd-servers must be specified")) } @@ -135,10 +134,9 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) { "Default watch cache size. If zero, watch cache will be disabled for resources that do not have a default watch size set.") fs.StringSliceVar(&s.WatchCacheSizes, "watch-cache-sizes", s.WatchCacheSizes, ""+ - "Watch cache size settings for some resources (pods, nodes, etc.), comma separated. "+ - "The individual setting format: resource[.group]#size, where resource is lowercase plural (no version), "+ - "group is omitted for resources of apiVersion v1 (the legacy core API) and included for others, "+ - "and size is a number. It takes effect when watch-cache is enabled. "+ + "List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. "+ + "The individual override format: resource[.group]#size, where resource is lowercase plural (no version), "+ + "group is optional, and size is a number. It takes effect when watch-cache is enabled. "+ "Some resources (replicationcontrollers, endpoints, nodes, pods, services, apiservices.apiregistration.k8s.io) "+ "have system defaults set by heuristics, others default to default-watch-cache-size") @@ -149,19 +147,19 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) { fs.IntVar(&dummyCacheSize, "deserialization-cache-size", 0, "Number of deserialized json objects to cache in memory.") fs.MarkDeprecated("deserialization-cache-size", "the deserialization cache was dropped in 1.13 with support for etcd2") - fs.StringSliceVar(&s.StorageConfig.Transport.ServerList, "etcd-servers", s.StorageConfig.Transport.ServerList, + fs.StringSliceVar(&s.StorageConfig.ServerList, "etcd-servers", s.StorageConfig.ServerList, "List of etcd servers to connect with (scheme://ip:port), comma separated.") fs.StringVar(&s.StorageConfig.Prefix, "etcd-prefix", s.StorageConfig.Prefix, "The prefix to prepend to all resource paths in etcd.") - fs.StringVar(&s.StorageConfig.Transport.KeyFile, "etcd-keyfile", s.StorageConfig.Transport.KeyFile, + fs.StringVar(&s.StorageConfig.KeyFile, "etcd-keyfile", s.StorageConfig.KeyFile, "SSL key file used to secure etcd communication.") - fs.StringVar(&s.StorageConfig.Transport.CertFile, "etcd-certfile", s.StorageConfig.Transport.CertFile, + fs.StringVar(&s.StorageConfig.CertFile, "etcd-certfile", s.StorageConfig.CertFile, "SSL certification file used to secure etcd communication.") - fs.StringVar(&s.StorageConfig.Transport.TrustedCAFile, "etcd-cafile", s.StorageConfig.Transport.TrustedCAFile, + fs.StringVar(&s.StorageConfig.CAFile, "etcd-cafile", s.StorageConfig.CAFile, "SSL Certificate Authority file used to secure etcd communication.") fs.StringVar(&s.EncryptionProviderConfigFilepath, "experimental-encryption-provider-config", s.EncryptionProviderConfigFilepath, @@ -176,9 +174,6 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) { fs.DurationVar(&s.StorageConfig.CountMetricPollPeriod, "etcd-count-metric-poll-period", s.StorageConfig.CountMetricPollPeriod, ""+ "Frequency of polling etcd for number of resources per type. 0 disables the metric collection.") - - fs.DurationVar(&s.StorageConfig.DBMetricPollInterval, "etcd-db-metric-poll-interval", s.StorageConfig.DBMetricPollInterval, - "The interval of requests to poll etcd and update metric. 0 disables the metric collection") } func (s *EtcdOptions) ApplyTo(c *server.Config) error { @@ -205,18 +200,9 @@ func (s *EtcdOptions) addEtcdHealthEndpoint(c *server.Config) error { if err != nil { return err } - c.AddHealthChecks(healthz.NamedCheck("etcd", func(r *http.Request) error { + c.HealthzChecks = append(c.HealthzChecks, healthz.NamedCheck("etcd", func(r *http.Request) error { return healthCheck() })) - - if s.EncryptionProviderConfigFilepath != "" { - kmsPluginHealthzChecks, err := encryptionconfig.GetKMSPluginHealthzCheckers(s.EncryptionProviderConfigFilepath) - if err != nil { - return err - } - c.AddHealthChecks(kmsPluginHealthzChecks...) - } - return nil } @@ -242,7 +228,6 @@ func (f *SimpleRestOptionsFactory) GetRESTOptions(resource schema.GroupResource) if !ok { cacheSize = f.Options.DefaultWatchCacheSize } - // depending on cache size this might return an undecorated storage ret.Decorator = genericregistry.StorageWithCacher(cacheSize) } return ret, nil @@ -276,7 +261,6 @@ func (f *StorageFactoryRestOptionsFactory) GetRESTOptions(resource schema.GroupR if !ok { cacheSize = f.Options.DefaultWatchCacheSize } - // depending on cache size this might return an undecorated storage ret.Decorator = genericregistry.StorageWithCacher(cacheSize) } @@ -300,6 +284,7 @@ func ParseWatchCacheSizes(cacheSizes []string) (map[schema.GroupResource]int, er if size < 0 { return nil, fmt.Errorf("watch cache size cannot be negative: %s", c) } + watchCacheSizes[schema.ParseGroupResource(tokens[0])] = size } return watchCacheSizes, nil diff --git a/vendor/k8s.io/apiserver/pkg/server/options/etcd_test.go b/vendor/k8s.io/apiserver/pkg/server/options/etcd_test.go index 423059d4af6..7f772f5b397 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/etcd_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/etcd_test.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/storage/storagebackend" ) @@ -37,14 +36,12 @@ func TestEtcdOptionsValidate(t *testing.T) { name: "test when ServerList is not specified", testOptions: &EtcdOptions{ StorageConfig: storagebackend.Config{ - Type: "etcd3", - Prefix: "/registry", - Transport: storagebackend.TransportConfig{ - ServerList: nil, - KeyFile: "/var/run/kubernetes/etcd.key", - TrustedCAFile: "/var/run/kubernetes/etcdca.crt", - CertFile: "/var/run/kubernetes/etcdce.crt", - }, + Type: "etcd3", + ServerList: nil, + Prefix: "/registry", + KeyFile: "/var/run/kubernetes/etcd.key", + CAFile: "/var/run/kubernetes/etcdca.crt", + CertFile: "/var/run/kubernetes/etcdce.crt", CompactionInterval: storagebackend.DefaultCompactInterval, CountMetricPollPeriod: time.Minute, }, @@ -61,14 +58,12 @@ func TestEtcdOptionsValidate(t *testing.T) { name: "test when storage-backend is invalid", testOptions: &EtcdOptions{ StorageConfig: storagebackend.Config{ - Type: "etcd4", - Prefix: "/registry", - Transport: storagebackend.TransportConfig{ - ServerList: []string{"http://127.0.0.1"}, - KeyFile: "/var/run/kubernetes/etcd.key", - TrustedCAFile: "/var/run/kubernetes/etcdca.crt", - CertFile: "/var/run/kubernetes/etcdce.crt", - }, + Type: "etcd4", + ServerList: []string{"http://127.0.0.1"}, + Prefix: "/registry", + KeyFile: "/var/run/kubernetes/etcd.key", + CAFile: "/var/run/kubernetes/etcdca.crt", + CertFile: "/var/run/kubernetes/etcdce.crt", CompactionInterval: storagebackend.DefaultCompactInterval, CountMetricPollPeriod: time.Minute, }, @@ -85,14 +80,12 @@ func TestEtcdOptionsValidate(t *testing.T) { name: "test when etcd-servers-overrides is invalid", testOptions: &EtcdOptions{ StorageConfig: storagebackend.Config{ - Type: "etcd3", - Transport: storagebackend.TransportConfig{ - ServerList: []string{"http://127.0.0.1"}, - KeyFile: "/var/run/kubernetes/etcd.key", - TrustedCAFile: "/var/run/kubernetes/etcdca.crt", - CertFile: "/var/run/kubernetes/etcdce.crt", - }, + Type: "etcd3", + ServerList: []string{"http://127.0.0.1"}, Prefix: "/registry", + KeyFile: "/var/run/kubernetes/etcd.key", + CAFile: "/var/run/kubernetes/etcdca.crt", + CertFile: "/var/run/kubernetes/etcdce.crt", CompactionInterval: storagebackend.DefaultCompactInterval, CountMetricPollPeriod: time.Minute, }, @@ -109,14 +102,12 @@ func TestEtcdOptionsValidate(t *testing.T) { name: "test when EtcdOptions is valid", testOptions: &EtcdOptions{ StorageConfig: storagebackend.Config{ - Type: "etcd3", - Prefix: "/registry", - Transport: storagebackend.TransportConfig{ - ServerList: []string{"http://127.0.0.1"}, - KeyFile: "/var/run/kubernetes/etcd.key", - TrustedCAFile: "/var/run/kubernetes/etcdca.crt", - CertFile: "/var/run/kubernetes/etcdce.crt", - }, + Type: "etcd3", + ServerList: []string{"http://127.0.0.1"}, + Prefix: "/registry", + KeyFile: "/var/run/kubernetes/etcd.key", + CAFile: "/var/run/kubernetes/etcdca.crt", + CertFile: "/var/run/kubernetes/etcdce.crt", CompactionInterval: storagebackend.DefaultCompactInterval, CountMetricPollPeriod: time.Minute, }, @@ -195,48 +186,3 @@ func TestParseWatchCacheSizes(t *testing.T) { }) } } - -func TestKMSHealthzEndpoint(t *testing.T) { - testCases := []struct { - name string - encryptionConfigPath string - wantChecks []string - }{ - { - name: "single kms-provider, expect single kms healthz check", - encryptionConfigPath: "testdata/encryption-configs/single-kms-provider.yaml", - wantChecks: []string{"etcd", "kms-provider-0"}, - }, - { - name: "two kms-providers, expect two kms healthz checks", - encryptionConfigPath: "testdata/encryption-configs/multiple-kms-providers.yaml", - wantChecks: []string{"etcd", "kms-provider-0", "kms-provider-1"}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - serverConfig := &server.Config{} - etcdOptions := &EtcdOptions{ - EncryptionProviderConfigFilepath: tc.encryptionConfigPath, - } - if err := etcdOptions.addEtcdHealthEndpoint(serverConfig); err != nil { - t.Fatalf("Failed to add healthz error: %v", err) - } - - for _, n := range tc.wantChecks { - found := false - for _, h := range serverConfig.HealthzChecks { - if n == h.Name() { - found = true - break - } - } - if !found { - t.Errorf("Missing HealthzChecker %s", n) - } - found = false - } - }) - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/options/feature.go b/vendor/k8s.io/apiserver/pkg/server/options/feature.go index 235635ea9b6..7e02a183b7a 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/feature.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/feature.go @@ -26,6 +26,7 @@ import ( type FeatureOptions struct { EnableProfiling bool EnableContentionProfiling bool + EnableSwaggerUI bool } func NewFeatureOptions() *FeatureOptions { @@ -34,6 +35,7 @@ func NewFeatureOptions() *FeatureOptions { return &FeatureOptions{ EnableProfiling: defaults.EnableProfiling, EnableContentionProfiling: defaults.EnableContentionProfiling, + EnableSwaggerUI: defaults.EnableSwaggerUI, } } @@ -46,9 +48,8 @@ func (o *FeatureOptions) AddFlags(fs *pflag.FlagSet) { "Enable profiling via web interface host:port/debug/pprof/") fs.BoolVar(&o.EnableContentionProfiling, "contention-profiling", o.EnableContentionProfiling, "Enable lock contention profiling, if profiling is enabled") - dummy := false - fs.BoolVar(&dummy, "enable-swagger-ui", dummy, "Enables swagger ui on the apiserver at /swagger-ui") - fs.MarkDeprecated("enable-swagger-ui", "swagger 1.2 support has been removed") + fs.BoolVar(&o.EnableSwaggerUI, "enable-swagger-ui", o.EnableSwaggerUI, + "Enables swagger ui on the apiserver at /swagger-ui") } func (o *FeatureOptions) ApplyTo(c *server.Config) error { @@ -58,6 +59,7 @@ func (o *FeatureOptions) ApplyTo(c *server.Config) error { c.EnableProfiling = o.EnableProfiling c.EnableContentionProfiling = o.EnableContentionProfiling + c.EnableSwaggerUI = o.EnableSwaggerUI return nil } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/recommended.go b/vendor/k8s.io/apiserver/pkg/server/options/recommended.go index 3d634a2e6ff..500d578d6bd 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/recommended.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/recommended.go @@ -21,13 +21,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission" - "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/storage/storagebackend" - "k8s.io/apiserver/pkg/util/feature" - utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol" - "k8s.io/client-go/kubernetes" - "k8s.io/component-base/featuregate" ) // RecommendedOptions contains the recommended options for running an API server. @@ -42,8 +37,6 @@ type RecommendedOptions struct { Features *FeatureOptions CoreAPI *CoreAPIOptions - // FeatureGate is a way to plumb feature gate through if you have them. - FeatureGate featuregate.FeatureGate // ExtraAdmissionInitializers is called once after all ApplyTo from the options above, to pass the returned // admission plugin initializers to Admission.ApplyTo. ExtraAdmissionInitializers func(c *server.RecommendedConfig) ([]admission.PluginInitializer, error) @@ -51,8 +44,6 @@ type RecommendedOptions struct { // ProcessInfo is used to identify events created by the server. ProcessInfo *ProcessInfo Webhook *WebhookOptions - // API Server Egress Selector is used to control outbound traffic from the API Server - EgressSelector *EgressSelectorOptions } func NewRecommendedOptions(prefix string, codec runtime.Codec, processInfo *ProcessInfo) *RecommendedOptions { @@ -65,22 +56,17 @@ func NewRecommendedOptions(prefix string, codec runtime.Codec, processInfo *Proc sso.HTTP2MaxStreamsPerConnection = 1000 return &RecommendedOptions{ - Etcd: NewEtcdOptions(storagebackend.NewDefaultConfig(prefix, codec)), - SecureServing: sso.WithLoopback(), - Authentication: NewDelegatingAuthenticationOptions(), - Authorization: NewDelegatingAuthorizationOptions(), - Audit: NewAuditOptions(), - Features: NewFeatureOptions(), - CoreAPI: NewCoreAPIOptions(), - // Wired a global by default that sadly people will abuse to have different meanings in different repos. - // Please consider creating your own FeatureGate so you can have a consistent meaning for what a variable contains - // across different repos. Future you will thank you. - FeatureGate: feature.DefaultFeatureGate, + Etcd: NewEtcdOptions(storagebackend.NewDefaultConfig(prefix, codec)), + SecureServing: sso.WithLoopback(), + Authentication: NewDelegatingAuthenticationOptions(), + Authorization: NewDelegatingAuthorizationOptions(), + Audit: NewAuditOptions(), + Features: NewFeatureOptions(), + CoreAPI: NewCoreAPIOptions(), ExtraAdmissionInitializers: func(c *server.RecommendedConfig) ([]admission.PluginInitializer, error) { return nil, nil }, Admission: NewAdmissionOptions(), ProcessInfo: processInfo, Webhook: NewWebhookOptions(), - EgressSelector: NewEgressSelectorOptions(), } } @@ -93,12 +79,12 @@ func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) { o.Features.AddFlags(fs) o.CoreAPI.AddFlags(fs) o.Admission.AddFlags(fs) - o.EgressSelector.AddFlags(fs) } // ApplyTo adds RecommendedOptions to the server configuration. +// scheme is the scheme of the apiserver types that are sent to the admission chain. // pluginInitializers can be empty, it is only need for additional initializers. -func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error { +func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig, scheme *runtime.Scheme) error { if err := o.Etcd.ApplyTo(&config.Config); err != nil { return err } @@ -122,20 +108,10 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error { } if initializers, err := o.ExtraAdmissionInitializers(config); err != nil { return err - } else if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, config.ClientConfig, o.FeatureGate, initializers...); err != nil { + } else if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, config.ClientConfig, scheme, initializers...); err != nil { return err } - if err := o.EgressSelector.ApplyTo(&config.Config); err != nil { - return err - } - if feature.DefaultFeatureGate.Enabled(features.APIPriorityAndFairness) { - config.FlowControl = utilflowcontrol.New( - config.SharedInformerFactory, - kubernetes.NewForConfigOrDie(config.ClientConfig).FlowcontrolV1alpha1(), - config.MaxRequestsInFlight+config.MaxMutatingRequestsInFlight, - config.RequestTimeout/4, - ) - } + return nil } @@ -149,7 +125,6 @@ func (o *RecommendedOptions) Validate() []error { errors = append(errors, o.Features.Validate()...) errors = append(errors, o.CoreAPI.Validate()...) errors = append(errors, o.Admission.Validate()...) - errors = append(errors, o.EgressSelector.Validate()...) return errors } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go b/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go index 346364b5c79..de6b32f455f 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go @@ -26,6 +26,9 @@ import ( "k8s.io/apiserver/pkg/server" utilfeature "k8s.io/apiserver/pkg/util/feature" + // add the generic feature gates + _ "k8s.io/apiserver/pkg/features" + "github.com/spf13/pflag" ) @@ -38,10 +41,7 @@ type ServerRunOptions struct { MaxRequestsInFlight int MaxMutatingRequestsInFlight int RequestTimeout time.Duration - GoawayChance float64 - LivezGracePeriod time.Duration MinRequestTimeout int - ShutdownDelayDuration time.Duration // We intentionally did not add a flag for this option. Users of the // apiserver library can wire it to a flag. JSONPatchMaxCopyBytes int64 @@ -49,9 +49,8 @@ type ServerRunOptions struct { // decoded in a write request. 0 means no limit. // We intentionally did not add a flag for this option. Users of the // apiserver library can wire it to a flag. - MaxRequestBodyBytes int64 - TargetRAMMB int - EnablePriorityAndFairness bool + MaxRequestBodyBytes int64 + TargetRAMMB int } func NewServerRunOptions() *ServerRunOptions { @@ -60,12 +59,9 @@ func NewServerRunOptions() *ServerRunOptions { MaxRequestsInFlight: defaults.MaxRequestsInFlight, MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight, RequestTimeout: defaults.RequestTimeout, - LivezGracePeriod: defaults.LivezGracePeriod, MinRequestTimeout: defaults.MinRequestTimeout, - ShutdownDelayDuration: defaults.ShutdownDelayDuration, JSONPatchMaxCopyBytes: defaults.JSONPatchMaxCopyBytes, MaxRequestBodyBytes: defaults.MaxRequestBodyBytes, - EnablePriorityAndFairness: true, } } @@ -75,11 +71,8 @@ func (s *ServerRunOptions) ApplyTo(c *server.Config) error { c.ExternalAddress = s.ExternalHost c.MaxRequestsInFlight = s.MaxRequestsInFlight c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight - c.LivezGracePeriod = s.LivezGracePeriod c.RequestTimeout = s.RequestTimeout - c.GoawayChance = s.GoawayChance c.MinRequestTimeout = s.MinRequestTimeout - c.ShutdownDelayDuration = s.ShutdownDelayDuration c.JSONPatchMaxCopyBytes = s.JSONPatchMaxCopyBytes c.MaxRequestBodyBytes = s.MaxRequestBodyBytes c.PublicAddress = s.AdvertiseAddress @@ -111,11 +104,6 @@ func (s *ServerRunOptions) Validate() []error { if s.TargetRAMMB < 0 { errors = append(errors, fmt.Errorf("--target-ram-mb can not be negative value")) } - - if s.LivezGracePeriod < 0 { - errors = append(errors, fmt.Errorf("--livez-grace-period can not be a negative value")) - } - if s.MaxRequestsInFlight < 0 { errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value")) } @@ -127,18 +115,10 @@ func (s *ServerRunOptions) Validate() []error { errors = append(errors, fmt.Errorf("--request-timeout can not be negative value")) } - if s.GoawayChance < 0 || s.GoawayChance > 0.02 { - errors = append(errors, fmt.Errorf("--goaway-chance can not be less than 0 or greater than 0.02")) - } - if s.MinRequestTimeout < 0 { errors = append(errors, fmt.Errorf("--min-request-timeout can not be negative value")) } - if s.ShutdownDelayDuration < 0 { - errors = append(errors, fmt.Errorf("--shutdown-delay-duration can not be negative value")) - } - if s.JSONPatchMaxCopyBytes < 0 { errors = append(errors, fmt.Errorf("--json-patch-max-copy-bytes can not be negative value")) } @@ -169,11 +149,11 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) { "Memory limit for apiserver in MB (used to configure sizes of caches, etc.)") fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost, - "The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs or OpenID Discovery).") + "The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).") deprecatedMasterServiceNamespace := metav1.NamespaceDefault fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+ - "DEPRECATED: the namespace from which the Kubernetes master services should be injected into pods.") + "DEPRECATED: the namespace from which the kubernetes master services should be injected into pods.") fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+ "The maximum number of non-mutating requests in flight at a given time. When the server exceeds this, "+ @@ -188,30 +168,11 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) { "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.Float64Var(&s.GoawayChance, "goaway-chance", s.GoawayChance, ""+ - "To prevent HTTP/2 clients from getting stuck on a single apiserver, randomly close a connection (GOAWAY). "+ - "The client's other in-flight requests won't be affected, and the client will reconnect, likely landing on a different apiserver after going through the load balancer again. "+ - "This argument sets the fraction of requests that will be sent a GOAWAY. Clusters with single apiservers, or which don't use a load balancer, should NOT enable this. "+ - "Min is 0 (off), Max is .02 (1/50 requests); .001 (1/1000) is a recommended starting point.") - - fs.DurationVar(&s.LivezGracePeriod, "livez-grace-period", s.LivezGracePeriod, ""+ - "This option represents the maximum amount of time it should take for apiserver to complete its startup sequence "+ - "and become live. From apiserver's start time to when this amount of time has elapsed, /livez will assume "+ - "that unfinished post-start hooks will complete successfully and therefore return true.") - 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 "+ "handler, which picks a randomized value above this number as the connection timeout, "+ "to spread out load.") - fs.BoolVar(&s.EnablePriorityAndFairness, "enable-priority-and-fairness", s.EnablePriorityAndFairness, ""+ - "If true and the APIPriorityAndFairness feature gate is enabled, replace the max-in-flight handler with an enhanced one that queues and dispatches with priority and fairness") - - fs.DurationVar(&s.ShutdownDelayDuration, "shutdown-delay-duration", s.ShutdownDelayDuration, ""+ - "Time to delay the termination. During that time the server keeps serving requests normally and /healthz "+ - "returns success, but /readyz immediately returns failure. Graceful termination starts after this delay "+ - "has elapsed. This can be used to allow load balancer to stop sending traffic to this server.") - - utilfeature.DefaultMutableFeatureGate.AddFlag(fs) + utilfeature.DefaultFeatureGate.AddFlag(fs) } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/server_run_options_test.go b/vendor/k8s.io/apiserver/pkg/server/options/server_run_options_test.go index 2661128b7bc..bb7e618230e 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/server_run_options_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/server_run_options_test.go @@ -136,38 +136,6 @@ func TestServerRunOptionsValidate(t *testing.T) { }, expectErr: "--max-resource-write-bytes can not be negative value", }, - { - name: "Test when LivezGracePeriod is negative value", - testOptions: &ServerRunOptions{ - AdvertiseAddress: net.ParseIP("192.168.10.10"), - CorsAllowedOriginList: []string{"10.10.10.100", "10.10.10.200"}, - MaxRequestsInFlight: 400, - MaxMutatingRequestsInFlight: 200, - RequestTimeout: time.Duration(2) * time.Minute, - MinRequestTimeout: 1800, - JSONPatchMaxCopyBytes: 10 * 1024 * 1024, - MaxRequestBodyBytes: 10 * 1024 * 1024, - TargetRAMMB: 65536, - LivezGracePeriod: -time.Second, - }, - expectErr: "--livez-grace-period can not be a negative value", - }, - { - name: "Test when MinimalShutdownDuration is negative value", - testOptions: &ServerRunOptions{ - AdvertiseAddress: net.ParseIP("192.168.10.10"), - CorsAllowedOriginList: []string{"10.10.10.100", "10.10.10.200"}, - MaxRequestsInFlight: 400, - MaxMutatingRequestsInFlight: 200, - RequestTimeout: time.Duration(2) * time.Minute, - MinRequestTimeout: 1800, - JSONPatchMaxCopyBytes: 10 * 1024 * 1024, - MaxRequestBodyBytes: 10 * 1024 * 1024, - TargetRAMMB: 65536, - ShutdownDelayDuration: -time.Second, - }, - expectErr: "--shutdown-delay-duration can not be negative value", - }, { name: "Test when ServerRunOptions is valid", testOptions: &ServerRunOptions{ diff --git a/vendor/k8s.io/apiserver/pkg/server/options/serving.go b/vendor/k8s.io/apiserver/pkg/server/options/serving.go index 65d95caaa7c..939e05741da 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/serving.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/serving.go @@ -17,7 +17,7 @@ limitations under the License. package options import ( - "context" + "crypto/tls" "fmt" "net" "path" @@ -29,10 +29,8 @@ import ( utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/server" - "k8s.io/apiserver/pkg/server/dynamiccertificates" + utilflag "k8s.io/apiserver/pkg/util/flag" certutil "k8s.io/client-go/util/cert" - "k8s.io/client-go/util/keyutil" - cliflag "k8s.io/component-base/cli/flag" ) type SecureServingOptions struct { @@ -56,7 +54,7 @@ type SecureServingOptions struct { // ServerCert is the TLS cert info for serving secure traffic ServerCert GeneratableKeyCert // SNICertKeys are named CertKeys for serving secure traffic with SNI support. - SNICertKeys []cliflag.NamedCertKey + SNICertKeys []utilflag.NamedCertKey // CipherSuites is the list of allowed cipher suites for the server. // Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). CipherSuites []string @@ -67,10 +65,6 @@ type SecureServingOptions struct { // HTTP2MaxStreamsPerConnection is the limit that the api server imposes on each client. // A value of zero means to use the default provided by golang's HTTP/2 support. HTTP2MaxStreamsPerConnection int - - // PermitPortSharing controls if SO_REUSEPORT is used when binding the port, which allows - // more than one instance to bind on the same address and port. - PermitPortSharing bool } type CertKey struct { @@ -93,7 +87,7 @@ type GeneratableKeyCert struct { PairName string // GeneratedCert holds an in-memory generated certificate if CertFile/KeyFile aren't explicitly set, and CertDirectory/PairName are not set. - GeneratedCert dynamiccertificates.CertKeyContentProvider + GeneratedCert *tls.Certificate // FixtureDirectory is a directory that contains test fixture used to avoid regeneration of certs during tests. // The format is: @@ -114,10 +108,10 @@ func NewSecureServingOptions() *SecureServingOptions { } func (s *SecureServingOptions) DefaultExternalAddress() (net.IP, error) { - if s.ExternalAddress != nil && !s.ExternalAddress.IsUnspecified() { + if !s.ExternalAddress.IsUnspecified() { return s.ExternalAddress, nil } - return utilnet.ResolveBindAddress(s.BindAddress) + return utilnet.ChooseBindAddress(s.BindAddress) } func (s *SecureServingOptions) Validate() []error { @@ -148,13 +142,13 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) { fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+ "The IP address on which to listen for the --secure-port port. The "+ "associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+ - "clients. If blank or an unspecified address (0.0.0.0 or ::), all interfaces will be used.") + "clients. If blank, all interfaces will be used (0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).") desc := "The port on which to serve HTTPS with authentication and authorization." if s.Required { - desc += " It cannot be switched off with 0." + desc += "It cannot be switched off with 0." } else { - desc += " If 0, don't serve HTTPS at all." + desc += "If 0, don't serve HTTPS at all." } fs.IntVar(&s.BindPort, "secure-port", s.BindPort, desc) @@ -171,23 +165,21 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.ServerCert.CertKey.KeyFile, "tls-private-key-file", s.ServerCert.CertKey.KeyFile, "File containing the default x509 private key matching --tls-cert-file.") - tlsCipherPossibleValues := cliflag.TLSCipherPossibleValues() + tlsCipherPossibleValues := utilflag.TLSCipherPossibleValues() fs.StringSliceVar(&s.CipherSuites, "tls-cipher-suites", s.CipherSuites, "Comma-separated list of cipher suites for the server. "+ "If omitted, the default Go cipher suites will be use. "+ "Possible values: "+strings.Join(tlsCipherPossibleValues, ",")) - tlsPossibleVersions := cliflag.TLSPossibleVersions() + tlsPossibleVersions := utilflag.TLSPossibleVersions() fs.StringVar(&s.MinTLSVersion, "tls-min-version", s.MinTLSVersion, "Minimum TLS version supported. "+ "Possible values: "+strings.Join(tlsPossibleVersions, ", ")) - fs.Var(cliflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+ + fs.Var(utilflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+ "A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+ "domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+ - "segments. The domain patterns also allow IP addresses, but IPs should only be used if "+ - "the apiserver has visibility to the IP address requested by a client. "+ - "If no domain patterns are provided, the names of the certificate are "+ + "segments. If no domain patterns are provided, the names of the certificate are "+ "extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+ "trump over extracted names. For multiple key/certificate pairs, use the "+ "--tls-sni-cert-key multiple times. "+ @@ -197,10 +189,6 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) { "The limit that the server gives to clients for "+ "the maximum number of streams in an HTTP/2 connection. "+ "Zero means to use golang's default.") - - fs.BoolVar(&s.PermitPortSharing, "permit-port-sharing", s.PermitPortSharing, - "If true, SO_REUSEPORT will be used when binding the port, which allows "+ - "more than one instance to bind on the same address and port. [default=false]") } // ApplyTo fills up serving information in the server configuration. @@ -215,14 +203,7 @@ func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error if s.Listener == nil { var err error addr := net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.BindPort)) - - c := net.ListenConfig{} - - if s.PermitPortSharing { - c.Control = permitPortReuse - } - - s.Listener, s.BindPort, err = CreateListener(s.BindNetwork, addr, c) + s.Listener, s.BindPort, err = CreateListener(s.BindNetwork, addr) if err != nil { return fmt.Errorf("failed to create listener: %v", err) } @@ -243,17 +224,17 @@ func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error serverCertFile, serverKeyFile := s.ServerCert.CertKey.CertFile, s.ServerCert.CertKey.KeyFile // load main cert if len(serverCertFile) != 0 || len(serverKeyFile) != 0 { - var err error - c.Cert, err = dynamiccertificates.NewDynamicServingContentFromFiles("serving-cert", serverCertFile, serverKeyFile) + tlsCert, err := tls.LoadX509KeyPair(serverCertFile, serverKeyFile) if err != nil { - return err + return fmt.Errorf("unable to load server certificate: %v", err) } + c.Cert = &tlsCert } else if s.ServerCert.GeneratedCert != nil { c.Cert = s.ServerCert.GeneratedCert } if len(s.CipherSuites) != 0 { - cipherSuites, err := cliflag.TLSCipherSuites(s.CipherSuites) + cipherSuites, err := utilflag.TLSCipherSuites(s.CipherSuites) if err != nil { return err } @@ -261,21 +242,27 @@ func (s *SecureServingOptions) ApplyTo(config **server.SecureServingInfo) error } var err error - c.MinTLSVersion, err = cliflag.TLSVersion(s.MinTLSVersion) + c.MinTLSVersion, err = utilflag.TLSVersion(s.MinTLSVersion) if err != nil { return err } // load SNI certs - namedTLSCerts := make([]dynamiccertificates.SNICertKeyContentProvider, 0, len(s.SNICertKeys)) + namedTLSCerts := make([]server.NamedTLSCert, 0, len(s.SNICertKeys)) for _, nck := range s.SNICertKeys { - tlsCert, err := dynamiccertificates.NewDynamicSNIContentFromFiles("sni-serving-cert", nck.CertFile, nck.KeyFile, nck.Names...) - namedTLSCerts = append(namedTLSCerts, tlsCert) + tlsCert, err := tls.LoadX509KeyPair(nck.CertFile, nck.KeyFile) + namedTLSCerts = append(namedTLSCerts, server.NamedTLSCert{ + TLSCert: tlsCert, + Names: nck.Names, + }) if err != nil { return fmt.Errorf("failed to load SNI cert and key: %v", err) } } - c.SNICerts = namedTLSCerts + c.SNICerts, err = server.GetNamedCertificateMap(namedTLSCerts) + if err != nil { + return err + } return nil } @@ -305,7 +292,8 @@ func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress str if !canReadCertAndKey { // add either the bind address or localhost to the valid alternates - if s.BindAddress.IsUnspecified() { + bindIP := s.BindAddress.String() + if bindIP == "0.0.0.0" { alternateDNS = append(alternateDNS, "localhost") } else { alternateIPs = append(alternateIPs, s.BindAddress) @@ -317,15 +305,16 @@ func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress str if err := certutil.WriteCert(keyCert.CertFile, cert); err != nil { return err } - if err := keyutil.WriteKey(keyCert.KeyFile, key); err != nil { + if err := certutil.WriteKey(keyCert.KeyFile, key); err != nil { return err } klog.Infof("Generated self-signed cert (%s, %s)", keyCert.CertFile, keyCert.KeyFile) } else { - s.ServerCert.GeneratedCert, err = dynamiccertificates.NewStaticCertKeyContent("Generated self signed cert", cert, key) + tlsCert, err := tls.X509KeyPair(cert, key) if err != nil { - return err + return fmt.Errorf("unable to generate self signed cert: %v", err) } + s.ServerCert.GeneratedCert = &tlsCert klog.Infof("Generated self-signed cert in-memory") } } @@ -333,12 +322,11 @@ func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress str return nil } -func CreateListener(network, addr string, config net.ListenConfig) (net.Listener, int, error) { +func CreateListener(network, addr string) (net.Listener, int, error) { if len(network) == 0 { network = "tcp" } - - ln, err := config.Listen(context.TODO(), network, addr) + ln, err := net.Listen(network, addr) if err != nil { return nil, 0, fmt.Errorf("failed to listen on %v: %v", addr, err) } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/serving_test.go b/vendor/k8s.io/apiserver/pkg/server/options/serving_test.go index 53a8f601bfa..73375bb70c2 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/serving_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/serving_test.go @@ -37,20 +37,23 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/version" "k8s.io/apiserver/pkg/server" + . "k8s.io/apiserver/pkg/server" + utilflag "k8s.io/apiserver/pkg/util/flag" "k8s.io/client-go/discovery" restclient "k8s.io/client-go/rest" - cliflag "k8s.io/component-base/cli/flag" ) -func setUp(t *testing.T) server.Config { +func setUp(t *testing.T) Config { scheme := runtime.NewScheme() codecs := serializer.NewCodecFactory(scheme) - config := server.NewConfig(codecs) + config := NewConfig(codecs) return *config } @@ -65,6 +68,190 @@ type NamedTestCertSpec struct { explicitNames []string // as --tls-sni-cert-key explicit names } +func TestGetNamedCertificateMap(t *testing.T) { + tests := []struct { + certs []NamedTestCertSpec + explicitNames []string + expected map[string]int // name to certs[*] index + errorString string + }{ + { + // empty certs + expected: map[string]int{}, + }, + { + // only one cert + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "test.com", + }, + }, + }, + expected: map[string]int{ + "test.com": 0, + }, + }, + { + // ips are ignored + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "test.com", + ips: []string{"1.2.3.4"}, + }, + }, + }, + expected: map[string]int{ + "test.com": 0, + }, + }, + { + // two certs with the same name + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "test.com", + }, + }, + { + TestCertSpec: TestCertSpec{ + host: "test.com", + }, + }, + }, + expected: map[string]int{ + "test.com": 0, + }, + }, + { + // two certs with different names + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "test2.com", + }, + }, + { + TestCertSpec: TestCertSpec{ + host: "test1.com", + }, + }, + }, + expected: map[string]int{ + "test1.com": 1, + "test2.com": 0, + }, + }, + { + // two certs with the same name, explicit trumps + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "test.com", + }, + }, + { + TestCertSpec: TestCertSpec{ + host: "test.com", + }, + explicitNames: []string{"test.com"}, + }, + }, + expected: map[string]int{ + "test.com": 1, + }, + }, + { + // certs with partial overlap; ips are ignored + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "a", + names: []string{"a.test.com", "test.com"}, + }, + }, + { + TestCertSpec: TestCertSpec{ + host: "b", + names: []string{"b.test.com", "test.com"}, + }, + }, + }, + expected: map[string]int{ + "a": 0, "b": 1, + "a.test.com": 0, "b.test.com": 1, + "test.com": 0, + }, + }, + { + // wildcards + certs: []NamedTestCertSpec{ + { + TestCertSpec: TestCertSpec{ + host: "a", + names: []string{"a.test.com", "test.com"}, + }, + explicitNames: []string{"*.test.com", "test.com"}, + }, + { + TestCertSpec: TestCertSpec{ + host: "b", + names: []string{"b.test.com", "test.com"}, + }, + explicitNames: []string{"dev.test.com", "test.com"}, + }}, + expected: map[string]int{ + "test.com": 0, + "*.test.com": 0, + "dev.test.com": 1, + }, + }, + } + +NextTest: + for i, test := range tests { + var namedTLSCerts []NamedTLSCert + bySignature := map[string]int{} // index in test.certs by cert signature + for j, c := range test.certs { + cert, err := createTestTLSCerts(c.TestCertSpec) + if err != nil { + t.Errorf("%d - failed to create cert %d: %v", i, j, err) + continue NextTest + } + + namedTLSCerts = append(namedTLSCerts, NamedTLSCert{ + TLSCert: cert, + Names: c.explicitNames, + }) + + sig, err := certSignature(cert) + if err != nil { + t.Errorf("%d - failed to get signature for %d: %v", i, j, err) + continue NextTest + } + bySignature[sig] = j + } + + certMap, err := GetNamedCertificateMap(namedTLSCerts) + if err == nil && len(test.errorString) != 0 { + t.Errorf("%d - expected no error, got: %v", i, err) + } else if err != nil && err.Error() != test.errorString { + t.Errorf("%d - expected error %q, got: %v", i, test.errorString, err) + } else { + got := map[string]int{} + for name, cert := range certMap { + x509Certs, err := x509.ParseCertificates(cert.Certificate[0]) + assert.NoError(t, err, "%d - invalid certificate for %q", i, name) + assert.True(t, len(x509Certs) > 0, "%d - expected at least one x509 cert in tls cert for %q", i, name) + got[name] = bySignature[x509CertSignature(x509Certs[0])] + } + + assert.EqualValues(t, test.expected, got, "%d - wrong certificate map", i) + } + } +} + func TestServerRunWithSNI(t *testing.T) { tests := map[string]struct { Cert TestCertSpec @@ -230,7 +417,7 @@ func TestServerRunWithSNI(t *testing.T) { caCerts := []*x509.Certificate{ca} // create SNI certs - var namedCertKeys []cliflag.NamedCertKey + var namedCertKeys []utilflag.NamedCertKey serverSig, err := certFileSignature(serverCertBundleFile, serverKeyFile) if err != nil { t.Fatalf("failed to get server cert signature: %v", err) @@ -247,7 +434,7 @@ func TestServerRunWithSNI(t *testing.T) { t.Fatalf("failed to create SNI cert %d: %v", j, err) } - namedCertKeys = append(namedCertKeys, cliflag.NamedCertKey{ + namedCertKeys = append(namedCertKeys, utilflag.NamedCertKey{ KeyFile: keyFile, CertFile: certBundleFile, Names: c.explicitNames, @@ -309,7 +496,7 @@ func TestServerRunWithSNI(t *testing.T) { // add poststart hook to know when the server is up. startedCh := make(chan struct{}) - s.AddPostStartHookOrDie("test-notifier", func(context server.PostStartHookContext) error { + s.AddPostStartHook("test-notifier", func(context PostStartHookContext) error { close(startedCh) return nil }) @@ -388,6 +575,16 @@ func parseIPList(ips []string) []net.IP { return netIPs } +func createTestTLSCerts(spec TestCertSpec) (tlsCert tls.Certificate, err error) { + certPem, keyPem, err := generateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names) + if err != nil { + return tlsCert, err + } + + tlsCert, err = tls.X509KeyPair(certPem, keyPem) + return tlsCert, err +} + func getOrCreateTestCertFiles(certFileName, keyFileName string, spec TestCertSpec) (err error) { if _, err := os.Stat(certFileName); err == nil { if _, err := os.Stat(keyFileName); err == nil { diff --git a/vendor/k8s.io/apiserver/pkg/server/options/serving_unix_test.go b/vendor/k8s.io/apiserver/pkg/server/options/serving_unix_test.go deleted file mode 100644 index e34dc56009f..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/serving_unix_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// +build !windows - -/* -Copyright 2020 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 options - -import ( - "net" - "testing" -) - -func TestCreateListenerSharePort(t *testing.T) { - addr := "127.0.0.1:12345" - c := net.ListenConfig{Control: permitPortReuse} - - if _, _, err := CreateListener("tcp", addr, c); err != nil { - t.Fatalf("failed to create listener: %v", err) - } - - if _, _, err := CreateListener("tcp", addr, c); err != nil { - t.Fatalf("failed to create 2nd listener: %v", err) - } -} - -func TestCreateListenerPreventUpgrades(t *testing.T) { - addr := "127.0.0.1:12346" - - if _, _, err := CreateListener("tcp", addr, net.ListenConfig{}); err != nil { - t.Fatalf("failed to create listener: %v", err) - } - - if _, _, err := CreateListener("tcp", addr, net.ListenConfig{Control: permitPortReuse}); err == nil { - t.Fatalf("creating second listener without port sharing should fail") - } -} diff --git a/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go b/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go index 9f9a42f81b0..7f19206425e 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/serving_with_loopback.go @@ -17,12 +17,12 @@ limitations under the License. package options import ( + "crypto/tls" "fmt" - "github.com/google/uuid" + "github.com/pborman/uuid" "k8s.io/apiserver/pkg/server" - "k8s.io/apiserver/pkg/server/dynamiccertificates" "k8s.io/client-go/rest" certutil "k8s.io/client-go/util/cert" ) @@ -55,12 +55,12 @@ func (s *SecureServingOptionsWithLoopback) ApplyTo(secureServingInfo **server.Se if err != nil { return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err) } - certProvider, err := dynamiccertificates.NewStaticSNICertKeyContent("self-signed loopback", certPem, keyPem, server.LoopbackClientServerNameOverride) + tlsCert, err := tls.X509KeyPair(certPem, keyPem) if err != nil { return fmt.Errorf("failed to generate self-signed certificate for loopback connection: %v", err) } - secureLoopbackClientConfig, err := (*secureServingInfo).NewLoopbackClientConfig(uuid.New().String(), certPem) + secureLoopbackClientConfig, err := (*secureServingInfo).NewLoopbackClientConfig(uuid.NewRandom().String(), certPem) switch { // if we failed and there's no fallback loopback client config, we need to fail case err != nil && *loopbackClientConfig == nil: @@ -71,8 +71,7 @@ func (s *SecureServingOptionsWithLoopback) ApplyTo(secureServingInfo **server.Se default: *loopbackClientConfig = secureLoopbackClientConfig - // Write to the front of SNICerts so that this overrides any other certs with the same name - (*secureServingInfo).SNICerts = append([]dynamiccertificates.SNICertKeyContentProvider{certProvider}, (*secureServingInfo).SNICerts...) + (*secureServingInfo).SNICerts[server.LoopbackClientServerNameOverride] = &tlsCert } return nil diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/README.md b/vendor/k8s.io/apiserver/pkg/server/options/testdata/README.md deleted file mode 100644 index a78ddfbd05a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/README.md +++ /dev/null @@ -1 +0,0 @@ -Keys in this directory are generated for testing purposes only. diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/localhost__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/localhost__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/localhost__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/apiserver-loopback-client__/localhost__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-expired.pem b/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-expired.pem deleted file mode 100644 index 1c33f46184f..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-expired.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBpTCCAUugAwIBAgIUPV4LAC5KK8YWY1FegyTuhkGUr3EwCgYIKoZIzj0EAwIw -GjEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlLUNBMB4XDTkwMTIzMTIzNTkwMFoXDTkw -MTIzMTIzNTkwMFowFDESMBAGA1UEAxMJTXkgQ2xpZW50MFkwEwYHKoZIzj0CAQYI -KoZIzj0DAQcDQgAEyYUnseNUN87rfHgekrfZu5sj4wlt5LYr3JYZZkfSbsb+BW3/ -RzX02ifjp+8w7mI4qUGg6y6J7oXHGFT3uj9kj6N1MHMwDgYDVR0PAQH/BAQDAgWg -MBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKsX -EnXwDg8j2LIEM1QzmFrE6537MB8GA1UdIwQYMBaAFF+p0JcY31pz+mjNZnjv0Gum -92vZMAoGCCqGSM49BAMCA0gAMEUCIG4FBcb57oqOCoaFiJ+Yx6S0zkaash7bTv3V -CIy9JvFdAiEAy8bf2S9EkvZyURZ6ycgEMnekll57Ebze6rjlPx8+B1Y= ------END CERTIFICATE----- diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-valid.pem b/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-valid.pem deleted file mode 100644 index 620483f8a2d..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client-valid.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBqDCCAU2gAwIBAgIUfbqeieihh/oERbfvRm38XvS/xHAwCgYIKoZIzj0EAwIw -GjEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlLUNBMCAXDTE2MTAxMTA1MDYwMFoYDzIx -MTYwOTE3MDUwNjAwWjAUMRIwEAYDVQQDEwlNeSBDbGllbnQwWTATBgcqhkjOPQIB -BggqhkjOPQMBBwNCAARv6N4R/sjMR65iMFGNLN1GC/vd7WhDW6J4X/iAjkRLLnNb -KbRG/AtOUZ+7upJ3BWIRKYbOabbQGQe2BbKFiap4o3UwczAOBgNVHQ8BAf8EBAMC -BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU -K/pZOWpNcYai6eHFpmJEeFpeQlEwHwYDVR0jBBgwFoAUX6nQlxjfWnP6aM1meO/Q -a6b3a9kwCgYIKoZIzj0EAwIDSQAwRgIhAIWTKw/sjJITqeuNzJDAKU4xo1zL+xJ5 -MnVCuBwfwDXCAiEAw/1TA+CjPq9JC5ek1ifR0FybTURjeQqYkKpve1dveps= ------END CERTIFICATE----- diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.config.json b/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.config.json deleted file mode 100644 index 57f012b7a42..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "signing": { - "profiles": { - "valid": { - "expiry": "876000h", - "usages": [ - "signing", - "key encipherment", - "client auth" - ] - }, - "expired": { - "expiry": "1h", - "not_before": "1990-12-31T23:59:00Z", - "not_after": "1990-12-31T23:59:00Z", - "usages": [ - "signing", - "key encipherment", - "client auth" - ] - } - } - } -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.csr.json b/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.csr.json deleted file mode 100644 index 17b45773c63..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/client.csr.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "CN": "My Client" -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/multiple-kms-providers.yaml b/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/multiple-kms-providers.yaml deleted file mode 100644 index 39a37ebc870..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/multiple-kms-providers.yaml +++ /dev/null @@ -1,14 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - kms: - name: kms-provider-1 - cachesize: 1000 - endpoint: unix:///@provider1.sock - - kms: - name: kms-provider-2 - cachesize: 1000 - endpoint: unix:///@provider2.sock \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/single-kms-provider.yaml b/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/single-kms-provider.yaml deleted file mode 100644 index 0209c07f0d2..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/encryption-configs/single-kms-provider.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: EncryptionConfiguration -apiVersion: apiserver.config.k8s.io/v1 -resources: - - resources: - - secrets - providers: - - kms: - name: kms-provider-1 - cachesize: 1000 - endpoint: unix:///@kms-provider.sock \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/generate.sh b/vendor/k8s.io/apiserver/pkg/server/options/testdata/generate.sh deleted file mode 100755 index 0bb39c0aa33..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/generate.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -cfssl gencert -initca root.csr.json | cfssljson -bare root - -cfssl gencert -initca intermediate.csr.json | cfssljson -bare intermediate -cfssl sign -ca root.pem -ca-key root-key.pem -config intermediate.config.json intermediate.csr | cfssljson -bare intermediate - -cfssl gencert -ca intermediate.pem -ca-key intermediate-key.pem -config client.config.json --profile=valid client.csr.json | cfssljson -bare client-valid -cfssl gencert -ca intermediate.pem -ca-key intermediate-key.pem -config client.config.json --profile=expired client.csr.json | cfssljson -bare client-expired - diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.config.json b/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.config.json deleted file mode 100644 index 94f9da4dbb8..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "signing": { - "default": { - "usages": [ - "digital signature", - "cert sign", - "crl sign", - "signing", - "key encipherment", - "client auth" - ], - "expiry": "876000h", - "ca_constraint": { - "is_ca": true - } - } - } -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.csr.json b/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.csr.json deleted file mode 100644 index 29d684b8ee1..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.csr.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "CN": "Intermediate-CA", - "ca": { - "expiry": "876000h" - } -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.pem b/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.pem deleted file mode 100644 index 7f157d5b37a..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/intermediate.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBqDCCAU6gAwIBAgIUfqZtjoFgczZ+oQZbEC/BDSS2J6wwCgYIKoZIzj0EAwIw -EjEQMA4GA1UEAxMHUm9vdC1DQTAgFw0xNjEwMTEwNTA2MDBaGA8yMTE2MDkxNzA1 -MDYwMFowGjEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlLUNBMFkwEwYHKoZIzj0CAQYI -KoZIzj0DAQcDQgAEyWHEMMCctJg8Xa5YWLqaCPbk3MjB+uvXac42JM9pj4k9jedD -kpUJRkWIPzgJI8Zk/3cSzluUTixP6JBSDKtwwaN4MHYwDgYDVR0PAQH/BAQDAgGm -MBMGA1UdJQQMMAoGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FF+p0JcY31pz+mjNZnjv0Gum92vZMB8GA1UdIwQYMBaAFB7P6+i4/pfNjqZgJv/b -dgA7Fe4tMAoGCCqGSM49BAMCA0gAMEUCIQCTT1YWQZaAqfQ2oBxzOkJE2BqLFxhz -3smQlrZ5gCHddwIgcvT7puhYOzAgcvMn9+SZ1JOyZ7edODjshCVCRnuHK2c= ------END CERTIFICATE----- diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/apiserver-loopback-client__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/apiserver-loopback-client__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/apiserver-loopback-client__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/apiserver-loopback-client__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/test.com__10.0.0.1/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/test.com__10.0.0.1/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/test.com__10.0.0.1/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__10.0.0.1,127.0.0.1/test.com__10.0.0.1/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/localhost__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com_star.test.com_/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com_star.test.com_/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com_star.test.com_/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost__127.0.0.1/test.com_star.test.com_/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/localhost_test.com_127.0.0.1/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.csr.json b/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.csr.json deleted file mode 100644 index 3b509d73e8c..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.csr.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "CN": "Root-CA", - "ca": { - "expiry": "876000h" - } -} \ No newline at end of file diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.pem b/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.pem deleted file mode 100644 index 1eed5387819..00000000000 --- a/vendor/k8s.io/apiserver/pkg/server/options/testdata/root.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBizCCATGgAwIBAgIUH4plk9qwD61FVXgiOTngFU5FeSkwCgYIKoZIzj0EAwIw -EjEQMA4GA1UEAxMHUm9vdC1DQTAgFw0xNjEwMTEwNTA2MDBaGA8yMTE2MDkxNzA1 -MDYwMFowEjEQMA4GA1UEAxMHUm9vdC1DQTBZMBMGByqGSM49AgEGCCqGSM49AwEH -A0IABI2CsrAnMGT8P2VGU2MLo5pv86Z74kcV9hgkLJUkSaeNyc1s89w7X5V2wvwu -iWEJRGm5RoZJausmyZLZEoKEVXejYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MB0GA1UdDgQWBBQez+vouP6XzY6mYCb/23YAOxXuLTAfBgNVHSME -GDAWgBQez+vouP6XzY6mYCb/23YAOxXuLTAKBggqhkjOPQQDAgNIADBFAiBGclts -vJRM+QMVoV/1L9b+hvhgLIp/OupUFsSOReefIwIhALY06hBklyh8eFwuBtyX2VcE -8xlVn4/5idUvc3Xv2h9s ------END CERTIFICATE----- diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/cert b/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/cert old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/key b/vendor/k8s.io/apiserver/pkg/server/options/testdata/test.com__/localhost__/key old mode 100644 new mode 100755 diff --git a/vendor/k8s.io/apiserver/pkg/server/plugins.go b/vendor/k8s.io/apiserver/pkg/server/plugins.go index 7a9094337db..84813aafe6b 100644 --- a/vendor/k8s.io/apiserver/pkg/server/plugins.go +++ b/vendor/k8s.io/apiserver/pkg/server/plugins.go @@ -19,6 +19,7 @@ package server // This file exists to force the desired plugin implementations to be linked into genericapi pkg. import ( "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/plugin/initialization" "k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle" mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating" validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating" @@ -27,6 +28,7 @@ import ( // RegisterAllAdmissionPlugins registers all admission plugins func RegisterAllAdmissionPlugins(plugins *admission.Plugins) { lifecycle.Register(plugins) + initialization.Register(plugins) validatingwebhook.Register(plugins) mutatingwebhook.Register(plugins) } diff --git a/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers.go b/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers.go index 85e5e1c46d9..cb1c54e3f0b 100644 --- a/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers.go +++ b/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers.go @@ -18,15 +18,13 @@ package resourceconfig import ( "fmt" - "regexp" "strconv" "strings" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" serverstore "k8s.io/apiserver/pkg/server/storage" - cliflag "k8s.io/component-base/cli/flag" - "k8s.io/klog" + utilflag "k8s.io/apiserver/pkg/util/flag" ) // GroupVersionRegistry provides access to registered group versions. @@ -52,53 +50,37 @@ func MergeResourceEncodingConfigs( return resourceEncodingConfig } -// Recognized values for the --runtime-config parameter to enable/disable groups of APIs -const ( - APIAll = "api/all" - APIGA = "api/ga" - APIBeta = "api/beta" - APIAlpha = "api/alpha" -) - -var ( - gaPattern = regexp.MustCompile(`^v\d+$`) - betaPattern = regexp.MustCompile(`^v\d+beta\d+$`) - alphaPattern = regexp.MustCompile(`^v\d+alpha\d+$`) - - matchers = map[string]func(gv schema.GroupVersion) bool{ - // allows users to address all api versions - APIAll: func(gv schema.GroupVersion) bool { return true }, - // allows users to address all api versions in the form v[0-9]+ - APIGA: func(gv schema.GroupVersion) bool { return gaPattern.MatchString(gv.Version) }, - // allows users to address all beta api versions - APIBeta: func(gv schema.GroupVersion) bool { return betaPattern.MatchString(gv.Version) }, - // allows users to address all alpha api versions - APIAlpha: func(gv schema.GroupVersion) bool { return alphaPattern.MatchString(gv.Version) }, +// MergeGroupEncodingConfigs merges the given defaultResourceConfig with specific GroupVersion overrides. +func MergeGroupEncodingConfigs( + defaultResourceEncoding *serverstore.DefaultResourceEncodingConfig, + storageEncodingOverrides map[string]schema.GroupVersion, +) *serverstore.DefaultResourceEncodingConfig { + resourceEncodingConfig := defaultResourceEncoding + for group, storageEncodingVersion := range storageEncodingOverrides { + resourceEncodingConfig.SetVersionEncoding(group, storageEncodingVersion, schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal}) } - - matcherOrder = []string{APIAll, APIGA, APIBeta, APIAlpha} -) + return resourceEncodingConfig +} // MergeAPIResourceConfigs merges the given defaultAPIResourceConfig with the given resourceConfigOverrides. // Exclude the groups not registered in registry, and check if version is // not registered in group, then it will fail. func MergeAPIResourceConfigs( defaultAPIResourceConfig *serverstore.ResourceConfig, - resourceConfigOverrides cliflag.ConfigurationMap, + resourceConfigOverrides utilflag.ConfigurationMap, registry GroupVersionRegistry, ) (*serverstore.ResourceConfig, error) { resourceConfig := defaultAPIResourceConfig overrides := resourceConfigOverrides - for _, flag := range matcherOrder { - if value, ok := overrides[flag]; ok { - if value == "false" { - resourceConfig.DisableMatchingVersions(matchers[flag]) - } else if value == "true" { - resourceConfig.EnableMatchingVersions(matchers[flag]) - } else { - return nil, fmt.Errorf("invalid value %v=%v", flag, value) - } + // "api/all=false" allows users to selectively enable specific api versions. + allAPIFlagValue, ok := overrides["api/all"] + if ok { + if allAPIFlagValue == "false" { + // Disable all group versions. + resourceConfig.DisableAll() + } else if allAPIFlagValue == "true" { + resourceConfig.EnableAll() } } @@ -107,12 +89,12 @@ func MergeAPIResourceConfigs( // Iterate through all group/version overrides specified in runtimeConfig. for key := range overrides { // Have already handled them above. Can skip them here. - if _, ok := matchers[key]; ok { + if key == "api/all" { continue } tokens := strings.Split(key, "/") - if len(tokens) < 2 { + if len(tokens) != 2 { continue } groupVersionString := tokens[0] + "/" + tokens[1] @@ -121,13 +103,6 @@ func MergeAPIResourceConfigs( return nil, fmt.Errorf("invalid key %s", key) } - // individual resource enablement/disablement is only supported in the extensions/v1beta1 API group for legacy reasons. - // all other API groups are expected to contain coherent sets of resources that are enabled/disabled together. - if len(tokens) > 2 && (groupVersion != schema.GroupVersion{Group: "extensions", Version: "v1beta1"}) { - klog.Warningf("ignoring invalid key %s, individual resource enablement/disablement is not supported in %s, and will prevent starting in future releases", key, groupVersion.String()) - continue - } - // Exclude group not registered into the registry. if !registry.IsGroupRegistered(groupVersion.Group) { continue @@ -142,28 +117,16 @@ func MergeAPIResourceConfigs( return nil, err } if enabled { - // enable the groupVersion for "group/version=true" and "group/version/resource=true" resourceConfig.EnableVersions(groupVersion) - } else if len(tokens) == 2 { - // disable the groupVersion only for "group/version=false", not "group/version/resource=false" - resourceConfig.DisableVersions(groupVersion) - } - - if len(tokens) < 3 { - continue - } - groupVersionResource := groupVersion.WithResource(tokens[2]) - if enabled { - resourceConfig.EnableResources(groupVersionResource) } else { - resourceConfig.DisableResources(groupVersionResource) + resourceConfig.DisableVersions(groupVersion) } } return resourceConfig, nil } -func getRuntimeConfigValue(overrides cliflag.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) { +func getRuntimeConfigValue(overrides utilflag.ConfigurationMap, apiKey string, defaultValue bool) (bool, error) { flagValue, ok := overrides[apiKey] if ok { if flagValue == "" { @@ -179,10 +142,10 @@ func getRuntimeConfigValue(overrides cliflag.ConfigurationMap, apiKey string, de } // ParseGroups takes in resourceConfig and returns parsed groups. -func ParseGroups(resourceConfig cliflag.ConfigurationMap) ([]string, error) { +func ParseGroups(resourceConfig utilflag.ConfigurationMap) ([]string, error) { groups := []string{} for key := range resourceConfig { - if _, ok := matchers[key]; ok { + if key == "api/all" { continue } tokens := strings.Split(key, "/") diff --git a/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers_test.go b/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers_test.go index f78550d5251..6ae41f7143b 100644 --- a/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers_test.go +++ b/vendor/k8s.io/apiserver/pkg/server/resourceconfig/helpers_test.go @@ -66,7 +66,7 @@ func TestParseRuntimeConfig(t *testing.T) { { // version enabled by runtimeConfig override. runtimeConfig: map[string]string{ - "apps/v1": "", + "extensions/v1beta1": "", }, defaultResourceConfig: func() *serverstore.ResourceConfig { config := newFakeAPIResourceConfigSource() @@ -137,79 +137,6 @@ func TestParseRuntimeConfig(t *testing.T) { }, err: false, }, - { - // enable specific extensions resources - runtimeConfig: map[string]string{ - "extensions/v1beta1/deployments": "true", - }, - defaultResourceConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - expectedAPIConfig: func() *serverstore.ResourceConfig { - config := newFakeAPIResourceConfigSource() - config.EnableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments")) - return config - }, - err: false, - }, - { - // disable specific extensions resources - runtimeConfig: map[string]string{ - "extensions/v1beta1/ingresses": "false", - }, - defaultResourceConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - expectedAPIConfig: func() *serverstore.ResourceConfig { - config := newFakeAPIResourceConfigSource() - config.DisableResources(extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses")) - return config - }, - err: false, - }, - { - // disable all extensions resources - runtimeConfig: map[string]string{ - "extensions/v1beta1": "false", - }, - defaultResourceConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - expectedAPIConfig: func() *serverstore.ResourceConfig { - config := newFakeAPIResourceConfigSource() - config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) - return config - }, - err: false, - }, - { - // disable a non-extensions resource - runtimeConfig: map[string]string{ - "apps/v1/deployments": "false", - }, - defaultResourceConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - expectedAPIConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - err: false, // no error for backwards compatibility - }, - { - // disable all beta resources - runtimeConfig: map[string]string{ - "api/beta": "false", - }, - defaultResourceConfig: func() *serverstore.ResourceConfig { - return newFakeAPIResourceConfigSource() - }, - expectedAPIConfig: func() *serverstore.ResourceConfig { - config := newFakeAPIResourceConfigSource() - config.DisableVersions(extensionsapiv1beta1.SchemeGroupVersion) - return config - }, - err: false, // no error for backwards compatibility - }, } for index, test := range testCases { t.Log(scheme.PrioritizedVersionsAllGroups()) @@ -234,14 +161,6 @@ func newFakeAPIResourceConfigSource() *serverstore.ResourceConfig { apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, ) - ret.EnableResources( - extensionsapiv1beta1.SchemeGroupVersion.WithResource("ingresses"), - ) - ret.DisableResources( - extensionsapiv1beta1.SchemeGroupVersion.WithResource("deployments"), - extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"), - extensionsapiv1beta1.SchemeGroupVersion.WithResource("daemonsets"), - ) return ret } diff --git a/vendor/k8s.io/apiserver/pkg/server/routes/OWNERS b/vendor/k8s.io/apiserver/pkg/server/routes/OWNERS old mode 100644 new mode 100755 index 4da107c8c38..9d268c4d148 --- a/vendor/k8s.io/apiserver/pkg/server/routes/OWNERS +++ b/vendor/k8s.io/apiserver/pkg/server/routes/OWNERS @@ -1,4 +1,2 @@ -# See the OWNERS docs at https://go.k8s.io/owners - reviewers: - sttts diff --git a/vendor/k8s.io/apiserver/pkg/server/routes/data/README.md b/vendor/k8s.io/apiserver/pkg/server/routes/data/README.md new file mode 100644 index 00000000000..974aec20a1c --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/server/routes/data/README.md @@ -0,0 +1,12 @@ +The datafiles contained in these directories were generated by the script +```sh +hack/build-ui.sh +``` + +Do not edit by hand. + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/genericapiserver/addons/data/README.md?pixel)]() + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/pkg/genericapiserver/server/routes/data/README.md?pixel)]() diff --git a/vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/datafile.go b/vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/datafile.go new file mode 100644 index 00000000000..619809ea0b6 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/server/routes/data/swagger/datafile.go @@ -0,0 +1,17087 @@ +/* +Copyright 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. +*/ + +// generated by hack/build-ui.sh; DO NOT EDIT + +// Code generated by go-bindata. +// sources: +// third_party/swagger-ui/LICENSE +// third_party/swagger-ui/README.md +// third_party/swagger-ui/css/reset.css +// third_party/swagger-ui/css/screen.css +// third_party/swagger-ui/css/typography.css +// third_party/swagger-ui/fonts/droid-sans-v6-latin-700.eot +// third_party/swagger-ui/fonts/droid-sans-v6-latin-700.svg +// third_party/swagger-ui/fonts/droid-sans-v6-latin-700.ttf +// third_party/swagger-ui/fonts/droid-sans-v6-latin-700.woff +// third_party/swagger-ui/fonts/droid-sans-v6-latin-700.woff2 +// third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.eot +// third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.svg +// third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.ttf +// third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.woff +// third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.woff2 +// third_party/swagger-ui/images/explorer_icons.png +// third_party/swagger-ui/images/logo_small.png +// third_party/swagger-ui/images/pet_store_api.png +// third_party/swagger-ui/images/throbber.gif +// third_party/swagger-ui/images/wordnik_api.png +// third_party/swagger-ui/index.html +// third_party/swagger-ui/lib/backbone-min.js +// third_party/swagger-ui/lib/handlebars-1.0.0.js +// third_party/swagger-ui/lib/handlebars-2.0.0.js +// third_party/swagger-ui/lib/highlight.7.3.pack.js +// third_party/swagger-ui/lib/jquery-1.8.0.min.js +// third_party/swagger-ui/lib/jquery.ba-bbq.min.js +// third_party/swagger-ui/lib/jquery.slideto.min.js +// third_party/swagger-ui/lib/jquery.wiggle.min.js +// third_party/swagger-ui/lib/marked.js +// third_party/swagger-ui/lib/shred/content.js +// third_party/swagger-ui/lib/shred.bundle.js +// third_party/swagger-ui/lib/swagger-client.js +// third_party/swagger-ui/lib/swagger-oauth.js +// third_party/swagger-ui/lib/swagger.js +// third_party/swagger-ui/lib/underscore-min.js +// third_party/swagger-ui/o2c.html +// third_party/swagger-ui/swagger-ui.js +// third_party/swagger-ui/swagger-ui.min.js +// DO NOT EDIT! + +package swagger + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _third_partySwaggerUiLicense = []byte(`Copyright 2014 Reverb Technologies, Inc. + +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 [apache.org/licenses/LICENSE-2.0](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. +`) + +func third_partySwaggerUiLicenseBytes() ([]byte, error) { + return _third_partySwaggerUiLicense, nil +} + +func third_partySwaggerUiLicense() (*asset, error) { + bytes, err := third_partySwaggerUiLicenseBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/LICENSE", size: 596, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiReadmeMd = []byte(`# Readme + +URL: https://github.com/swagger-api/swagger-ui/tree/master/dist +License: Apache License, Version 2.0 +License File: LICENSE + +## Description +Files from dist folder of https://github.com/swagger-api/swagger-ui. +These are dependency-free collection of HTML, Javascript, and CSS assets that +dynamically generate beautiful documentation and sandbox from a +Swagger-compliant API. +Instructions on how to use these: +https://github.com/swagger-api/swagger-ui#how-to-use-it + +## Local Modifications +- Updated the url in index.html to "../../swaggerapi" as per instructions at: +https://github.com/swagger-api/swagger-ui#how-to-use-it +- Modified swagger-ui.js to list resources and operations in sorted order: https://github.com/kubernetes/kubernetes/pull/3421 +- Set supportedSubmitMethods: [] in index.html to remove "Try it out" buttons. +- Remove the url query param to fix XSS issue: + https://github.com/kubernetes/kubernetes/pull/23234 + +LICENSE file has been created for compliance purposes. +Not included in original distribution. +`) + +func third_partySwaggerUiReadmeMdBytes() ([]byte, error) { + return _third_partySwaggerUiReadmeMd, nil +} + +func third_partySwaggerUiReadmeMd() (*asset, error) { + bytes, err := third_partySwaggerUiReadmeMdBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/README.md", size: 1032, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiCssResetCss = []byte(`/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +`) + +func third_partySwaggerUiCssResetCssBytes() ([]byte, error) { + return _third_partySwaggerUiCssResetCss, nil +} + +func third_partySwaggerUiCssResetCss() (*asset, error) { + bytes, err := third_partySwaggerUiCssResetCssBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/css/reset.css", size: 1066, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiCssScreenCss = []byte(`/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog p.error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog button.api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog button.api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +.swagger-section .access { + float: right; +} +.swagger-section .auth { + float: right; +} +.swagger-section #api_information_panel { + position: absolute; + background: #FFF; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + max-width: 300px; + line-height: 30px; + color: black; + padding: 5px; +} +.swagger-section #api_information_panel p .api-msg-enabled { + color: green; +} +.swagger-section #api_information_panel p .api-msg-disabled { + color: red; +} +.swagger-section .api-ic { + height: 18px; + vertical-align: middle; + display: inline-block; + background: url(../images/explorer_icons.png) no-repeat; +} +.swagger-section .ic-info { + background-position: 0 0; + width: 18px; + margin-top: -7px; + margin-left: 4px; +} +.swagger-section .ic-warning { + background-position: -60px 0; + width: 18px; + margin-top: -7px; + margin-left: 4px; +} +.swagger-section .ic-error { + background-position: -30px 0; + width: 18px; + margin-top: -7px; + margin-left: 4px; +} +.swagger-section .ic-off { + background-position: -90px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section .ic-on { + background-position: -160px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section #header { + background-color: #89bf04; + padding: 14px; +} +.swagger-section #header a#logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo_small.png) no-repeat left center; + padding: 20px 0 20px 40px; + color: white; +} +.swagger-section #header form#api_selector { + display: block; + clear: none; + float: right; +} +.swagger-section #header form#api_selector .input { + display: block; + clear: none; + float: left; + margin: 0 10px 0 0; +} +.swagger-section #header form#api_selector .input input#input_apiKey { + width: 200px; +} +.swagger-section #header form#api_selector .input input#input_baseUrl { + width: 400px; +} +.swagger-section #header form#api_selector .input a#explore { + display: block; + text-decoration: none; + font-weight: bold; + padding: 6px 8px; + font-size: 0.9em; + color: white; + background-color: #547f00; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -o-border-radius: 4px; + -ms-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; +} +.swagger-section #header form#api_selector .input a#explore:hover { + background-color: #547f00; +} +.swagger-section #header form#api_selector .input input { + font-size: 0.9em; + padding: 3px; + margin: 0; +} +.swagger-section #content_message { + margin: 10px 15px; + font-style: italic; + color: #999999; +} +.swagger-section #message-bar { + min-height: 30px; + text-align: center; + padding-top: 10px; +} +`) + +func third_partySwaggerUiCssScreenCssBytes() ([]byte, error) { + return _third_partySwaggerUiCssScreenCss, nil +} + +func third_partySwaggerUiCssScreenCss() (*asset, error) { + bytes, err := third_partySwaggerUiCssScreenCssBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/css/screen.css", size: 43042, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiCssTypographyCss = []byte(`/* droid-sans-regular - latin */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/droid-sans-v6-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Droid Sans'), local('DroidSans'), + url('../fonts/droid-sans-v6-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/droid-sans-v6-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/droid-sans-v6-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/droid-sans-v6-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/droid-sans-v6-latin-regular.svg#DroidSans') format('svg'); /* Legacy iOS */ +} +/* droid-sans-700 - latin */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 700; + src: url('../fonts/droid-sans-v6-latin-700.eot'); /* IE9 Compat Modes */ + src: local('Droid Sans Bold'), local('DroidSans-Bold'), + url('../fonts/droid-sans-v6-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/droid-sans-v6-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/droid-sans-v6-latin-700.woff') format('woff'), /* Modern Browsers */ + url('../fonts/droid-sans-v6-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/droid-sans-v6-latin-700.svg#DroidSans') format('svg'); /* Legacy iOS */ +} +`) + +func third_partySwaggerUiCssTypographyCssBytes() ([]byte, error) { + return _third_partySwaggerUiCssTypographyCss, nil +} + +func third_partySwaggerUiCssTypographyCss() (*asset, error) { + bytes, err := third_partySwaggerUiCssTypographyCssBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/css/typography.css", size: 1474, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6Latin700Eot = []byte("\x8cY\x00\x00\xaeX\x00\x00\x02\x00\x02\x00\x04\x00\x00\x00\x02\v\b\x06\x03\b\x04\x02\x02\x04\x01\x00\xbc\x02\x00\x00\b\x00LP\xef\x02\x00\xe0[ \x00@(\x00\x00\x00\x00\x00\x00\x00\x9f\x01\x00 \x00\x00\x00\x00\u05c26W\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00\x00\x00\b\x00B\x00o\x00l\x00d\x00\x00\x00,\x00V\x00e\x00r\x00s\x00i\x00o\x00n\x00 \x001\x00.\x000\x000\x00 \x00b\x00u\x00i\x00l\x00d\x00 \x001\x001\x002\x00\x00\x00\x1e\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00 \x00B\x00o\x00l\x00d\x00\x00\x00\x00\x00BSGP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00w$\x009J\x00Q\xb2\x00-\x92\x12\xcd\xe9\x8a\xc8`\xd8W\xc9hKropq\"U:b,/\x962\xd9\xe3\xdb\xd3\xf0\xe0\xc6g@\x9e\xba\xd6$@6\xa4\x92\x9f\x83\xec\x03\x8a;\"\xf1\xa5\xb1\x18\xe0[E\xc7LFM\xad#^S[\xaf\xd0\u03cb^>\x17\x1eZ\xc9\"\xc5$\xc0\xf1tYx\xa2X\xad\xa9\x86y\xe0\t.~iVAV\x91\xa5\xb5\fqIH3Y\xa2K]I\x165\xe6K\xefcB\xec\x80>E\xadZ\x93+\u0361,\xb0\xa3J\x85\xb7fEk2\f-\x15\xf5\xe2\x02\x82zF\x15\x99\u778f\xd5B\xecj\x1eK\u04aeS\xeb\n\xac\a\xc7XJ\x8b\x17UX\x0f)\xddJmq\xf51\xbal\x02\xd4l\x10\xc5\xd4]\xd9\x18%\x9b\x974S\xe5\x98\t\xdf%\u0547CY9\x9f\u038c\xab60IZ\x10\u03e1RI\a\xbbx\xcd\xd4o\xc0\u00c3\xefL\xbd\x12U\xe2\xf8.\xe6nc\xb4\xb4\xc67'\"\xdcI\x8f\x00Mg\u007f\f\xa8\u0175\x95\x9c\xb4\xdc\x04Z\x15\xee\nC#\xe4f\xbf/5\x9f\xea\xbf'\xad\x9f\xa6C\x84\xaa\x953\x91\x16\x19\xb8'\xe1z\xfet8n\x89\xff`\xdbs/J\xcf\b\xad\x93v\u007f\xa2\x918\x11EH\xc0\x84\"\xc1\x85\xb2p\x15\x83\x00s\xa0o\x85\xaa\xa48M\x17\xa4\x1e`\x1f\xe0\x8e\u06ca4\u054c>P6D\xc9\f#\"4i\x82S\x14\x11%\x0e5\xdce\xd8\xc3^\xb0\x16\xe1Sn\n\x9fBYL`\n\x9aB\x18\x12.\x03\xcc\x061\xfcJ\x18Vp\x06\x02\x87\xe8\xa9\xe6\xe2\xa2W\x13\\\xa0\xac\xee\xb1\xb2~\xcaq\xe7v\x83\u007fNt\xf3m\x92v5\xa3q\xa7\x1d\xa6\xda\xcbb\u0743\xb6\xbd\u05ee\xbd\xa5\xef/\xa9\x9cq[\xcb\xd6\xf9\xdbS\u01de\xbca\xc6\xef>\xe5?\v\x8ez\x8d\xe8.=]D\uf5d7\x1e\xc5sH\u028e\xacd\xcf7\xf8K\x8c\xd9\x10@\x12\x1em\xbbe9\x82\x8dr.\xe6\x05 \xc8<)\x02\x04\xfd\x12)\x18\xa1\x01\f\x8e\x9a\xe9h\u0562;\xf5p\xe6 \x95\x1f\xba\x03\x8f\xb93\x93\xb9=+\xf9\u0308]\x92^\xd3\xf6\u07f8\xfd\xd7\xf1:\xe8,\x84\xcb\b\xe7}d!x\xe0R\xeb\xfa\x1c\xbf\xb5\xa7V2\x03\xe4$\x9fC\x94\x99\x8a\x14\x82\\6\x04F\u019b\xf6S\x90\xb9\x13\xee>\xea]i\xfe\x1fzh\u0465\xb6\x8dZ>B\xa5\xd7\x16\x90\x83}\x99\x93j\x05X\f\x0f\xcd\xe7'9\xb9\xd1N\xaaxR\xa2\x95T\xac\xa5uz^\xf5\xfcg,\xa4ZR\u0697\x17\xc1[T\xf2\xe2\xfe\xa9\xe9@K\x8c\xc2S\x05^X\x8d\xc0\x87Y\x90\xf1\xc7\a\"\xb0\x98\x9d\x8a\xc1\b-\xca\f0i\x83\x8d\xb0\xe4\xa18\f a\x13\t\x1c\xa1\xb6\x87\x8a\xfd\x99C\x1b2y\b\xca\u0733k\xb8\x9d\xf1\xcd\x05\x98q\xb7\x1b\xcd\x00\x85N\x90\x1e\x8e\xe3\xb1\u049a\x8a\x16+\xe9#\xc2+`\x00\x1c4{\xe0LO\x00\x00\xa2\xbb\x9b\x01\x8b\x18\xa9\xa1\x18\x86\x06O\xeb\xa0R\x81\x8c\x0e`\x83\x04\x98(\xe7\x0et\xe7\x8e|\xd0\r\xbc\xe4\xec\t\xa3F\xa8:\x93\xaa7\x83A0\x9a\x8bJaC\xa6?%\x9dy\x86z\xabB\u06c7\xe2\f\x9a\x94\n\xf8WgG\x80x)\xa52\u0359W\xbb\x83'\xca\u065d\xf0\xd1\u0547d\t\x8cL\x12\x00\xa6\x99,E6\x19\xbd\xf2x\xe9\x05\xa3\fa\xe3\x17\xee\xe0\x19#`\xed\x11\r\x00\xdbX\u06b8\x87/\x9c\x10k(J\x04Wn\xc4\x10\u0542y\xaf\x1e\xa8\x9d\u021c@\x90\x82\xe6\x03S\xe4\x1a\x85r+\"\xff\xa1\xb0\x06%\xc42g\xa9\xe2\x82\u5dc7\x18$\xb57A]\r\x90\u05d6;\u0343n\xbc\x8e(`*m\xf8\n\x1b\"Zd\xc1\xb0&\xfb\xe7\u0258dA\xf5?y\xf8=\u0178`\x93\x86\r\n\xa1\xe2\xe9\x03\v\xbc\xbd\x10\v\xe0\t\x18?\xa2\xa5P4$\xa3\x81j\xc2\x06\xe4m\xb8o\x8e\b\xb7<\xaaIx\xf4~k\xa8\x1b\u019b5\xfe)[w\xf5\xbdlQ\xc0\xb5\xebw\xd6\xe8y\xdbA\x81\xf4\xe6\x1b\x8e\x9cW\xf0+#}\n\xb6E \xe3\u00be\xc4n3\xc7\xd1!\x06%\x85/=,K\x02\x97-\x11aBa(\xc6Qu\xd0\x12\xa8\x83\x11\x9a7\xe8V4\xeb~\x15H\x84\xf5\xb19\x88\\%,&_Q\xcd[C\xf6fj\x98\xda$\u0709\xb5\x93)\xa2\x1d%\xe7}\bq\x95dv\x10{,d%\xb1N\x04\x1c\xc0\x97\x03.\x12\x9a\b\x94\xa2\x8a\u007f\x98^p/\x99a\xa4\xe1.\x86-L\x955\xa6\xfd\n\x83\x00f\xc1\u00f6\xe3N1\xfd\"0\xe1(\n\x18\xd0\xfbwM\u0374\xe1zzqb\x14\xe6+:\xd8\xf5aU\xb2\xcewb!\x87\x0f\x8c`DH\v\x9bF;!\x8aIl\x8cfJ4\u050bS\xa1\x84\x1by\xd9\xd1Rq\x97DI\x9ac\x90\u0671P\x1d\x9d\x93\x03\xceR\xe3\x82\bN\"\xa4\x90\xc8\x11\x12e\x91\x12H\xc5\xe3\xe9\xfa\xfc\xcdg\x14}<`\v\xd2\x14#\x9c!<\";\xf3\xaa**T\vu%%\xac\x9a\x00\xcf\u052a\xa9\xc7X\x11Q\x82MA\xfd3\u01c7p\xd6\xdc.\xe8Ws\x17\r\xae\x1f\x8eJ\xe23\xea\xd8\uaf2eu\xfa6\x16j_>$\x18\x14\xf6J\x8e\x9eJ\x95\x1b\x9e\x8cM\x96\f\x18\x8e,\x8cfn\xff[\xbcM\xdb~\x90\xc5\x00_Bo)\xae\x05\xde\a\u0468KQ\xfds\xca]\xe3\u02e4\xa9\x95\xcaEF\xe6\x1d\xd8~\u043a\xf2\x98\x17\x8d\x13\r2+\xcbz\xbc\x9d3\xbe\xd7+C\u05e1\x96\xbd\xdf\xe4\"\xfe\u0551<\xf2\xe0\x8c\xfb\x13\xe1:\xac\x01\x19\x94[=\x02d\xff^\x12\xcd\x12\n\f\xb1j\xd6N\xc8A\xad\xdf\r\u0190\x10X\a\xcc,f(T-XM\xf8\xde\xd5\xd2\"\x11\xbap\xa8\xf0\xd7\xc1\xf0\xe5Qa\xcb\x1f\xc1\x96\x8c\xc1\x8d\xaf\n\xc4F\xec-=\xe0H\u02a5w\xc2O&\x81\xba\xd0 i$~\xe0\xab~F\xdb>2\x9bz\xc0\xd6'\r\n\x03\x12wL=\x98\x9c\x1c\xc8 \u03ad\xa3\t\xadh,3l\x9d\xd3\xfce\x14\xd1\xda:\x02f\"H\xbb\xe76D\x18%3\xb0\x0e\xacz\xc1\x18\x95\x10\x00\xd65T \r\x98\xa4\x95\xbb\u03bdiU\x06)\xbe\xb1 (V\r\v\xce[75\"\x06\x13\x93\x824t\xccy\u0402\xdc\xc8\x00\xca\x0f<\xba\x10\xbd\x8c\x9f\x8d\xb8'\x0e\xac\x02;\x85\xe2>@\xcf\xda\xccy\x14t\xce\xe3:\x01\xbf\xf4\xd4=\x9c\xc6\xce/\x02\xdd\xef\xa1\u03af\xc6(+I\x16 \x00\x1e5<\x11?\x80\x84B8|,9\x92\f]\u034eV\xbb\v\xd4\xc0\x06\x0eSI\b>\x84x\xd4\x01p\x17>v4\xa3g\\JS\xe6\x93#\xf2\xb1\xe7v\x83jgDo\x02\x91\xc0Q\xc8\x03\x90\x18\x03hs\xe4qh(F\u0443hK\x12br\xdb\x0e\xd3\xdc3}\x15\xc3\x1c#\xdb\xf5sf\x9d(\xaa\xd2T\x02\xfc\xb4\xb4H+:!1\x86\x94\xc9S\xd8P8\xdb\xee:1\xa5s\t\u02ead\x85\x03GJ\xb8N\x95\xcf\xe9w\x1eL?\xaa\xd5\u028d\xcc\xc4\x11\x00oV\xcb%\xbd\x13\x96G,\x87'\xaamy\xc0\x8e\x1c\xd0C\x0e\x18\x00\x8f\x18\x12\xc4\xd8\x00\x98\xa5\xb5\xcd\xde\x00\xd95\x15\x0fr\xcf\rK%2D\xd8b\x82\x06tT'\x88t\xdc&@\x94\xd7B\xd1O\xac\x9d\xdb]\x11\x9df\xf0\x10\xe9\"\x89 \xb4M\x80\x0e\xc0\u040d|\x06\xef\x89c\xdcl\xef>.\u0236A\x04L\x0f\xd6\x1b2b\u03fd\x10\xcc\x0f\x14\x8bV\x12J*\x9fc!\x19\x05\a\x0ef\x04R\x82%-\xf3\x8f\xe7\tF\x02\xdf\xd5+\x01\x88\xe1;o\f\x1b\x88. \x85/E\xc1\x82\u00a4\xc1`\xa9\x95}\x04\x95\xa3`de\xa0\xfb\xa2b\xd2w\xb7\xa3DI!\x10\xe4;\"\fiz\xfaOE\xdb({\xeb\"\x1d\x9cK\xd6\x03x\x89\xdaL}\xe4?\xd8\xdae\"^w\x96gG2\xc1\x03\x95\xf6[\xaf\x93X\x17\"\xa91\xbf\x99\x98\xa5\x01\xf4\xee\x11<\xc4M\f[P\xc4\u0146\x94R\xf6\x11\xfb\x83jK\xf2r\x13\x05j\x06\xd7+\x03\x925R\xf0\xbb\x84h,\xf9\xe6\xf8u[o\x90\u0630\x92\u0319\xcb\xc8sK7b\xfcB\xc4&\x18\xe6=h\xa3\b/Y&\\\x91\x19plR\x90l\xfex\x8c>\xcbi\xbb\xc6P\x01\x0f\xd2P9\xa0$~\xff\a;Y\x1a&R\u0308q\x88\xa1\xf9\v0V\x8a\xe0/\x87\x9d\xc9f4\xfb\xd70?\x82N@\n+\x95\x02/N\x12M\x0e\x16n\x13\x8e\xfc\x88J\xcfU@o\x933\x9fW\x11\xfa\xdc\xdfY\xa4\xc9+\xe2$\x00\xca +\x9c\xc2S\xef\x955~F\xb8(\x96\xf4\xa3\xa8?T\x1bn\xfc\u05d9\xdf\xcbv\x01\u0718\xe5~\uc73d\x1e\x03\u007fMpk\xd3@\x87\x85u\xe1\x15\xfb\x93 \xeaV\x9fE\u04c7\xf7\xed\x9ck\x90F\xcd\xf2\xad!P#*J\xc13\xf0Fj\xbaL\x81u\x04\x9f\xa0\xbe.S\xff\xf0\x90t\x18m8D^\xe9.M\x82\xe2\x0e\x03\x97\x8aU\xd4s^\x9dGW\x8a.\xb0\xa5r\x81\xe5?\x05\xcd \xfe\xc5\x17\xc5,H\xab\x9c\x11\xf8\u06d1'\xa8C#{RK\x85D\x15\x03\rW\xd2\xdd\x00\x1f\x95\x11!n\xab\x15\u054bjj\xb8m\xe9\x00\x96\xed\uc419\xe4wv\xd0\x12_T\x11\x9c&\xa1_\xca\x17\u01c8\xb74\xa8\v\xab4\\\x01\x18\x1e\xc8\f\xd1sc\xb9\xa8\x86\x88\xe8J\xd7\xd8/\xeb\x16\x15\x98\xe8+dQ\x94T\x91\x12k\x9c\x834\f\x0e38\xc1\xed\x0fd*\x10U,\xcd\xc7DX(\x9e`\\\xa7\u058f)\r?2&\xdf\xfc+\x14\xff\xbd\x82\xb1\v\xee\x84\v\r\xdf\xc2\x17\x83 D\xa5\x84\xc8/\x85\xf5\xf8\xae`\a\xa3\xbb\xa0\x0e\xe4a\xc0}dx\xff\\zKTh\xabc\xe9\xa5\xe1~\xb2\xbe\xdc\x00\x86\xa0\xfaS\xe2\x1fq,\u0268s\x16-\xb9}B\xe83\u036a\n\x91\xdf\xf2fJ$\x02\x8e\xd0 1-\xddq\xd7\xfd\xa7\x15\xd9\xe7\x80{\fm\xaeN\xc9\xcb\xe3\b\xc0\xd1\ns\xa3\x87\x9a\t\xb3\x83:\xd1\u1373|\xdbYz`7\xec\xc4t\xec\x10!1\xf15\x15\x17\x1b\xfd\xbdbCy\x93\x8f\x1a\xbd\a\x80\xb3\x8c\xbb+\xa6\xf9v\x82\x83/\x0f\xeb=\r\x84\u007fu\u1aa6\x18\xf0\xa6\x88=\xdc\x14\f\xc9\x11\x03ft\xbfmx\xf2}\xc2\x19\x84\x01\x8a\xa1\x1b\xf0\u0250(3\x98\x99j\xe2\xa1A\xd9?\xcf\u0313 \xa0%{\t\x96\xb0\x06\x94\xfdY\xb7OkoR\x89?\aE\xc7-\x852\x1ep;\xbav\xc2^.#w\xa9\b[\u007f\x8d\x18[5\x91=I\xae\xcemU\xf6\xdfT\x8e\xea\x89*\xc8c\xf3M\xf61jz\x8a\xddo^\xf9\xa6\u0317\x1aK\x19O\xac\xed\u0093\x15\x13IIj\x8f\x95\x10\xb0\xb0\x95Q\x13I\xb2\x0f\x80?\xb9\x8d\xce\xf0\xb9<\x86T\xea\x00|TV\x1an\xe9\xf3\x1b\xa0\x86\xed\xf6\x9c\u007f\x8a?\xfe\x05\fU\x1d(xhH\x848\xaf\x9e$7\x81QF\u9d55:;\x82f9\xfc5-N\xb9V\xb2\b\x8a\u0585qeh\xb4+\xb8\xab3hE8\f\x05q\xec3\x82C\xe1\xa5;\xd1Y\xcd|\xeb*b\x88BO\xd3\x0f\u007f\xa7\x95\x80x\u03e8v:\xb1\xef\t\x1dz+oV\xbb\xeb\x87E\xb6\x904b\xaf\xc8\xee,\xec}\x9b\u0092\x03\xe2\xc6S\xc4h\xdb\x00B\x02\xcdd5\xd4G\xaa\x13\x17\xfadr+\xbd*\x1c\xf7*@\x12\v&q\x1b\x81\xacp(\f\a\x80\x1d\xcb\x03\xeab\xa1\u01ae\x8a\xfbA\xa6\x86J\xba\xc3p9yl\xe9\xea^\xc2\xf0=i\n\x03\v\\\xf4p\x1b\xdc(\xa2[\u0762Du\xac\x80\xe4\x19\x1b)\x9b\xcat\xc2\xec\x9c\xdc\xe1\x00\xae{)U\x95\xb5\x1f\x90}r\xe3\xb3e\b\xa7\x15\x14\x1d\xb2+~[6HO\xa9\xc2\x136\x86\u065d7#\xa6\n^\x11\xe2\f\xf8\xf4\x80M\xfd\xc0\x13\xd0\x13\x83\x1b\xb2B6\x9b\xd1\xc2L%o\u0249\xd0N&g\x19R|{\xb1\x84\x9a\xc5-Ri\x94N&n\x0e46\x14(L\x03\xee\xf1\xc0-%\xc3)\x1d\xf9H\x8e\xf1\x86[\xbeh\xebeQE\xa9\x85\xc8\xd1\xc0\x98\xa0_\x19\x95\xe0l\xa1\x12bp\xa00\x9a\u0667@8\xec\x1b\u0154\x04\xae\xadUE\xf1\x9a?\x9bg\x12DE\x02\xfd#\xb9\xbaLm~\xcb\xd3HZI\xb0\xe1\xc5'R\u0140\x12\xf8\xb6D\x9f\xff%\xc3p\x80\a\tM\xaa\xb8o\xc6\xe7\x9d\\J\x1aL\xa39\xbcp1\xae\xe4u<.\xe8\x1c\x83\xb3\xec3\xac}\b\xde)\x1eZa\x92g\xe7\x1f\xc0\x8c\x9a\x96\f\x14\x94@\xa1\xc5\v$\tRi\xf6\xe8\xf1\xa4N%CQ\xc1h\xa8\x90\xac\u079e(\u007fY\xef{{\u06d1\x03\xbeI\xaa\U000bc0f8\f\xacND\xefDZ$\x9b\t\xc5\aTV\xa9\xfd\xc2\x16\x02\xf9\xf66\x8b\x90\f\xb2{\x00\x00\x06\x90\n\x84\x87Q\xaf\a\xe50W\xf95\x95\x91<\x9a\xd1\xe4\u0638?\x82xD\x871Vr\xcf\xd1\xf7E\xb0_\x9a\xf9\xea\x16\x13\x8a\xc0@\u0114F\xcfA\xb9Ly\x11{I\a\xbc^\xea\x0eE\t&\xdcet2%\xa5\x19\x01%D\xf5$\xf3Kym\u0774\x9a\\\xda\xe3S\xb3\xb8f\xac8\x0f\x06w-\xdc_%\x93}*\xf2\x13\x12\xd8c\xad1\xb4\xe7y\x81\xbb\xf2\xcbi\u007f\xf8\x12\xa6\xe8F]\xfd^\x0e\x99TL\xf3w\xb6\xc1DP\x96r,S\x03\x06\x05\xd6\xf2\xc9d\x0eW\xc7g\x9f\x92\x02Z\xf4\x1d#Dl\x88yr+^\xbfb\xf7\xe4\xa1U\xac\x9b\xf1\xb3\xd8S\xab\x81\xd4Rt\xb0\xd6\x1e\xa3R\x1d5\xf0\\\xb7\xef-_\xe7X`\n\xc5\t\xef\xb8\xe8\xdd'\x8e\x11\x87\xf3\x05_\x95f\xdfA\a\xa70\x8b^\xa8u\xefV}\xbc\x96\xe4\xc0h\x87\xd6%\x04Q}O\xe4\\\xf5\x82\x8d0o>\xdeF~-|\u007f\x13kXP\xbb\r}m*e`!\xeb!\xb0\xda\xc4KC\x90\x1e8\x9c\u0229\"\x8c?\xa0\t\u02df\xd2\u049d\"\x82\x00\xad0cj\ucb0a%\x80TCE\xad\xe6\x19\x91\x8c|F\xa6j\xd499\xe1\x95\x13\xbep\xd1\\\xe1\x85{\xf5\xe3Y\xd9\x11\xac*\xdb\u029c\x03\x01\x14!\x19\u0707.\xcbQ\x14XP\x178*\x19\x17\x16\xfc\u025d`\u03b8\x82x\xc11\xfc\u05c5\x00*nGR\x83\xc0sS\x9am\x8f\xe0\xbf\xd5~\xeaX%\r+z\f+\xbf5\xb4\xb8\x91\x93fe\xe8W)\xbc\x80\bW\xc5I\xd5rk6\xcd*\x01\\Dp\xaf/\x92(x\xee\xf3\x19^\xedk^h\u05d6\xfe\xf0X\xfb\x17 \xbe\u007fO\x93m\xac\x1b(\xdaq\x00=\u03f5\u0611\xf7\xaf\xeb\xa0\b\x81\xbc\vJ\u0797f\x82\x00?D\xffy\x12\xf1K\x8a\xa55;\t\xb2\xb4\x03S\x90\r1\x8f\x06\xac\x95D5\x00T\x91\xc1z\v>\x9f\x04\x85\x82\x04\x14Y\x9a\x94\x81vC\xa6C$\x00Q\xa2b\xd1\xd1\x15\xac0\xd5\x1d\u0501O\xa3=d^\x9ej\u070e7\xa3j\xe4O/\xbb\x84l\x97z\xf9&;\u052d\xd46O\x11\x1c\u064a\xc22.\xf3\xfe\xf6\x8d\u03c7\xb9%\x1d\xa8\xaci\x18\xc3L\x1cvDW\x83FE\x90(\t\xb2xg\x00\xda_\xdd\xcbeTj\x976NU(T\x8b\xce\xd3\xe2\x9e-\x9f99\x89\u02fd\xb2(O%?\xcc$\xfe\xc8u\xbcd\xf0\x83\akg\xe6\xef\xa9\xf8!K\xf9T\xf0<\u0338B\x8b\x1dg\x84`{\x99\xd8\xc0>\x84\xefie\xa1\x00m\x1bi\xe1\x0fZ\x8c\x8e\xd9;\x8a\x85\xf2\xd8!\x04P{{6\x83d\xd9e\xf7tN\xd1\x17\xe20\xbe\xe1\xfc\xce\xcf'\\\xafd\xc1x\xc9{\xe5\xa2s\xa5\x18\u0273K*\xd8\xc9+@\x10\x8d\xb9z\xd8w!\xcdu0)\x05\x1e\x9c\xfa\x1f\xf5\u069bFp\nV\x16\xe1K\n\xac*\xaag\xa8o\xaa/\xe0\xe4\x06\xeaM\xca!q\x92\u02ab\xb5\xa4\x15\x9d\u05c8*b\xb4S\x9bz\xa3\xaft3\x96 \x8f\xf1\x03F\xf2\x1b\xc7\u007f\u0440e\x00\x0e\xbb\xc9N\x9b\x9f_\"t\ube4e{\xe2=\xa4h\xd8K\xa2&Pd0(<\xd9eQ\xbd\x12]0A0\v'\x02\x03\xb3\xf9gh\xd7\u0269\r\xce\x0fy\xb1\xa2\xf8le@!e\xbdPq\xa2\xd2:J\xaap\t\xe5\r\x1f\xef%/\xbc\x9b\x81x4&\xabj\xa9\x8dr5]\u028f\x14F\x9a\xbd\xc1m\xe3\x1a\x18\xee\xdf\xf0\u007f\x8f\xafq\x1fW\xb1\xed\xa4\u04d3(\x05\xec\xa0\x04\b\xdf\xdd\x14*\x84E\u009e\xec\x1f\xcc\x14H&\f\x11\x06\x10xA\xea(\xe9\xc5\xd60\x1d\xfc\x82\xae\xe4\x87\xfa\x1a\xfd\x94\xa2\a\x02\xb3A8\r\xf2:\xc9\x18.\xa1\xfa\xa6{\x1f\xad\xd9/\xb1\xf3\x8c\x8d\f\x8e\x88\xa2 \xfc~\x89[dP[\xa5Iw\xbe>\xc5\x13\u03b2\x97\u05611\x0f\xa1@\x15\x940~\xe4\x03G\xa4:\u07702\xb9%\xe3\xc2\\\xb7\x02rJ:\x00\xe7\xc6\xc1\x88n\x93\xcc\x1e!\x9b\x97\xe3\x94\x19\xe8\\/MbTkV\xac5\xd9\xfan\xc1\x87\xb9\xe9\x10:\t\x83N\xb2H\xe0\xf1\x9ei\xe2\xacm\x83\xf9\x94\xfb\u007f;\x99\xa2\xb2*t\x06\xefX-\xe6\xb2tM\x9e\xe9\xb0\xd1\u0228\xd9\x1f\x1bC\x01O@(7=\x13=\xccp\v\xaa\xc2\x13\xeb\xde\xfb\xc2 \xf3\xf3\xfb\xae\xf2\x83`d\x8a\x1e\x9a+v4\x9c+\xe36)=13S\xfa&H\x83\x83$\x9e\xcbb\xb8\x81\xe1\xeakY&*\u0219\u0468\x9a2\xa8\aiY\a!V-<\x97\xd8Ik\xebCju\xbc\xc0\xc7hz\xe7\xd5E\x8d\xe9\xcd]vN\x9b+\xe2\xec\x9b\xfb\f\x1e\xf2\xeb\xca\x10RI\x98+N3M\xda\x1d\x92Pf\x1c0\x9c\u0798l\x84\n\xf2\x95\u069e?t\xf96!p9\x10s*M\x8e\xac^\x86\x8b\xa8P\xf5V\x01\r.\xa3 \xaf\x16\u007f\xacax1\x041`\x85\x19\x146z\x13a&\xd3q\x1a\x8cg\t\t\x8f\xf2#\xf3\xa5\x0f\x0f\x0flf\xfa5\xee\u00c3\xe4[\xa8\xfd\x92\x05pt2o\xb6\xaasp_\x87\xecL#\x90do\x9c\xdaH\x1e\u7f4e\x10\xac\x04u3\xf0\f\x13\xf4|8\xb1\xe1'\x14\x88\xc2T\x9d\xa2\xf9,\xcf\a\u0286h\xef'\xc6\t{&5\xd62\to-_\x04\x04\x8d\x8a\xbb\x1dv\x88\xccF\xa0\xb6\x8b\x03\x82\xb5 og\xf1\x8c\\b\x9f\xe7&\xcb\xc1\u0447\x90\x04\xddC\xba,\x82\xa0e#\x01)\xa1$n\xcb\xea\x8e\xd2\t\xa4\xfa\x18hM\xa5\xb3a<\x8ez?\vk\x15Fo\r\x9b\xe3\x16\xc2IP\x06x\x91\xfePO\xf9\xce\xd9\nV=\x04|<\xa6\xd9\xcb\xe1\xc2f\xb6\xae8r\xda\x1d\xfb$\\\x16\x0e4\xd7\xd1{<\u028c=i^Q\xf2\xc0kJ\xc42MT5>\xf9o*\x10!\xe3=\xe6N \u0678\xfa+eYqP\x8e,\a\xeb\xb4\xca\xc4\xcd #hT\xeby\x82\v\t\f\r\xc3y\x8b2\u06b6\xa6\xc1\xd7\xc53\xc05\r\xec\x1f\x1f\xf8\xdfK\xf6\x90\xa8\x1d\xa2C\x90\x11\x96\x18\xb7L0\x8c\x99O;,\xed\xed1\x14\x82IG\xb6\u05de\x98\xef\xaf\xfe\x11\b\x9d\u01f5r;\xbb\xb4%D\xc0\u03b1F)U]hn\x8b\xd8\n\xb9\xaf\xf2\xf4R\xc0_Au\x04\xab\x92\xbem\x05\v\x01\x8f\x92\x01\x98\xfc~\xf0A,7 \u007f\xbc\x18\xf4\xd0\x11\b^\xc2\v\xad\xbb\u0560/\x99H'\xed\\\xeb\xad\u04bc\x14\x02\x04\v\xbd\x01B\x00^\xacL.\xa4T \xeb\xd2(\x06\vu\xfa\xa4\x9b\x05\xfeW\x11u\a\x82\x10\xc0\v^d\xac\nQ*I\xc2\xf8\x81Izc\xa2\x872\x92 \xb8\x8e\u06bd\u03aa\xd79\x91\xbc\v(\x98\x01!J\xf2\xc0\xb0`\x92\xfdL\xc3k\xfb\x82\xf4Y\x90\x88\xb8fGWR\xa3\u0404\n\xc0H[\x9bC\x14\x01]Ii\x85\xcb\u066f\xa2T\v\xb7\xa0\f\x87\u0180\xde\xc2f\xd1P\xd5RF\n\xf5\xb6\f\f\xa8\x96>\u009e~\x1b\x04^\xe6!z\xac\x14a\x90%\xa4\x06\xf1xl\xb9% \x8a\xbb\r?\x10\xf0\xf7u\xcdX\t\u03b0\x05\xbe\xbe\xa3\xcd+,\u02baT\xf2\xbe3\xa2`\x92\x9b\xacl\n\xa26\u02c0|\x9e\xacSb\\\xb7\x1b\xf7\x84V\x00K\xb4\x94Z#\x12\xbe\x8a\xa8`7J\x03@\x04Bb\xdc\xcd@\u0655\xe8\xa1/\xc9\xda)2\xc2\x01\x05\xd4\xcc=\xdaL{e\x9f\ap3\xf3\xd91\xa8:\x1f\x91\xfay|Z\xe6~\x14\xc6M\x1c\xacV\xbaN\xaf\xe3t'`\xe2\xa01\xa4F4P\xa9e\v\x87?\x10\xfc\xed\u350eO\x01\xc4\xe0\xfe[h\xc1-\xd0;\x17!\xe2\x9eG\xc0\x00\xd4\f\xb7\x01l\xd2\x05\xe1\u031a<\x93\xbb}<\x92\xf2\"Q\x1d\xdb\xda:\xf7s\x9a\x98\xd4'\xbdU@\xa3}M\x88\xb7\xdf\x11D\xb4N\xd18\xb8\xb3\xa4~$\xa8\xed.\x1c\xfd\xe6~\x0f1t6g\t\xb5/l\x14\x9a\xbd\x1a\x850?l\x1d5\xcb\xef\x0f\xe8\u011d\x94\xd39;\x97\x87\x1e\u05d1\x8f\xad\\\xb5\xec,\x9e\xeb\xbfB\x16\xf0J\x0e\xb4KD6\xecl\xf1\xb9\xa4\xee\xf1%\x83\xd4\x14\xb9~\x95\a\u04d9\x9e\aptVbg\xab\x10v\x81\"B-\xc4U\xe0\xd7\xc1\t\u0298\xcf|4?<\x16\xaf\xa97QL\x93\x85\a9|\xae\x14\u00a9c\xa2\xeb7d(\xe0\"\x92\x1db4+\xf8i[\xdc\xea\xa36\x1dZ)\x8c5W\xfd\xae\x9c\x98 \x9f\x15\x1e\x89\xe2\x14o\xc0\xb6.\x1dVh\xa6\x92\xb4t2,\x9aC\xcb\xe0\xf9\x81\x00\u01f4\x92\xcbA\xf2\x98\xa3\x02\xf1\xfeR3\xad\xea\\\x12;\x85\x10\x87\xa1\u015c\xda{\xeb\x01!\x98\xf9\x95\x1b\x94\xce\x19\xae\xba\u045b\x0e\xb8$a\xc5FL\xf5\x8cu\xf2\x12\x1b\xd8\xe6\u04eb)>,k9\f;b\t\xb8$\xa57\x8e\xd0\xc2Y$\xd7\x10\x85\xb6\xa2\x8d\u046dR\x01P\a\x95\xd2\xc21\x03_\u007fA\xb4\x1ff\x81\xc2\xd9\xd1\xccKT\xff\\\b@\x00\x82\xd9\xe6\x9bX\xea?\xa4N\x17*\xe51b\xba\xda{\x8b\x06z4m]\xe5\x83\x1d\xc3\x1b\xf6\xe3\xa2\xc4a\a\x8b\xd9\xe6\x88WQ\nz\xfd@5\x16\x97\xaaNH\xfeJZ\x13\x955\u00db\xfe0\xbbL \xffP\x13\xe7(\x9dc\x12\x02;p\x0fG\x98\xfd)N\xbe\xe17nn\xc8\xd88?\xe2\xe1\u042b\xa2\x99\x04\xa0\x88D\x0f\x18\xf4\xec:eN\xeb\xc3\xee#\xee\x87\x1e\xfa\v\xe0R(/\xf0H\xa3X\x0eG&\xbb+\t4X\xd2\xdf\x01.3|\xfdWZD\xb9\x99\x04;\x9e\xe6\x0eq\xed72\xe0jR\xf0\xc0\xd8\x10\x0e\xb0\ued60\xf8\x04\x94,\u0671SC\xa9\x92My`~ku\x9a6\t&\u0132a\xdb\u027fa&\x9d2\u0334\x10\xb0\xc4JQ\xfa\x87\xd5xW\x97#\xe4\x15\xaf!\xf4s\x87\xecc~.\xbe\xec\x0e\x11\x9a\x14\xe1\u0516\u0524\xcc\x0eA\xef\xb86\xd2k\x83\xac\xbc\xc6\r\u03a8=\xfc\xa6>\xc5\v\xee#\x90\x94\xf8r\n)\x9ey\"\x99\x14\xc5d\xcf\xd5\xc1\x029b&\x97:\x80@\n\t\x93\xc9\xc4 \x16\x9d\xee\xe8\xee\x15\x10Oy\xd5\xe3\x89f\U0006b484\"\xbeK\xd8\x17^\xb8>L\xa3\x9a\x16\x02\x06\xf1\x88\xbb^$_\xad\x1e\b~\xd3tBzhOB\xcf(\x89\x94\vja\xe0\xdav\x93\x11\x93\x99\u074a\xb4\xd1\x1e,\\XP9^\t\n\xd0y_\xa6^\xb8H \xfa\xd8\x00\x94f\xab\x17\x05\xd6\xd2c%R\xd5Y\xe6g\x8f\x9b\xf3\xc4\xebEp\xe5Qm\x8b\x05\x17\v\x9f#{,D\xfd\xe9\x8f]\xa9\x8f\x13\x97\xa9\xaaR\xa5|'\x1c\xc7,I\x06\x01\x12\x0e\x98\xa6\x19\x1b\xa8\xc8\\Q5m\x9d\xa3\xf9%\xdc0S\x0f\x95W/\xe52\xe6\x8a`\xe9N\xa7\x03zpY\x1cR\xbc\x12Gad\xd3<(\x02\xb5#$\x82\xb8\xe3,\xc1\"\x12\xa0\x94m\xccQ\x1e\xc8.C\x12}PX\x19(\xeb\xaao\x8b\xe4\xdck,\x99\x1a\u0789\xd4\x0e\xd1,\xd3\n\xcfl\u07df]_S\x90\xaf$\x81\xc3\x15\xaa\r\xc8w\\I\xc32,\xe2\x8cVR\xbbML\xf1\xc3s9\x17R\x02Ad\xb1\u07b0Y-O\xc7\xce+V\xb7\f\x068D\xcfK\xe2\xe1li\xed\x9a\x15\xe5\xeel\x8a\"\xb2\x0f\xa4u\x18\x8a,0\xffl\xbd3\xdb[\x9d\x9e\t\x83v\xe2\x80l\xb7\xa4\xf7\x84\x06\xbd\x05+\x1b\xf0\xa2\xa9.\xd1m\xd5\xc6\x15l\x14j\x9c\x8e\xc2:l,\x11\x01S\xb8\x9d\x90\xaawz\x86\xf1&^\x16$\x06g<\u00b4\xa0\xf2M\x1eV\x1c\xc0.v\xc5*\u0104\x8805:\x88%?\u04a9\xb0\x1c\xd8\x19\xfedw$\u042e&\x17E\bk\x10\xae\"!\x82\xf8\x98H\x1fe_WA\xc1\a\xa0C\x95\xd9\x02\xc3b*\\(\xea\x1e>\xb2U\xb0l]\x01\x80\x91\x18\x14Up\x1c\x85\xa5\xd8n\xb4\xfb\x99\x82\xa51\x98\xc1\x8e\xb4\x85\xc1A\x0e\x1b\x16\xc4z\x93yKnV>JO\u04b3\xb3U\v\x93X\x0e\xde\u05bc=\xf7\xd0a\x82\xbc\xb1\xe8\uc838;I\xa3[\x14\x13i|\xeb\x9b8#\xb7vg\x1c\u04a2\xfc\xc6a\x9a\x80\xa7\x16\xacFj\x01\x8b\xfb\x97\x85\xbf\\\x95\xa2]\x88\x9dJa\x96x\x87\x19\x01410\x13Ci\xfd\u017b\xdb\u0438\xbc\x9b9\x9e\xfd\xe6\rVp\xa4\x12\x1c\xa5\u02ad\xdcfC\xa7\xa5]OV$\xae\xa7\u04c8!\xf8v\xbao\xd2\x06\xf4\x87Qx\xd2+6T\x02B\x8d\x81F\x8b\xeb\x13\"a6$\x83Q9\xd015\u061bj\x1bPB@\x99\x8e\xa4\x8b\xbeM\x99\xb2L\td?31\x99HX\xdb-%\x06p\xbd\xfa\a\x9e\x89'\a\xa7\xfeEOh\x9fMBiJ\xc5\xfb\x8e\xa1\x82\xfeCR\xa6\xe7\xf8\x134\xba\x84\xd0\x1e\x89\xd3\xe0\n#\xaf8nBNu#\x9c\x1bD\xc3\xc7o\xc1\xb9\x89\x98\xb7{\x83i\xd4=\xf0\xb0\u007f\xdcy|\fP\x9d\xe5\x95\xf1MR\xc6\xe6\a\xb9\xfa\x80\x99\xd0\x0f\xea\xa9\x10\xf2\xe8\r\x01Y\xd2|9ZY\x8a\xb2\x11W\xe4\b<\xf7Q\xf1\xd1\xcf\xef\xef\xa1~\x16v\xe3<\x80\x19\xff7l\x03\x8d\nD\x11\t\b\x1e-\x8c:\xdd\b\x83\xa4a\x8f1\xbf\r\x8f\x04\u01c9\x00wI\xf3\xc50*\xc4\x13}\x11O\xa5.\xa9#\xf7\x03-9\x92\x1b\xdaqp\x16\v\xf3=\xbf\xf8\u034at\xcaj\xe1G\x03\xb7\xe9\xf2\xce\xf8\x97+\xb6\xae\x83\xf4\xf8\xafa\xca|s\x1bB\xab\x1b`q\x9c\x9f)h\t,\xec8A\xecC\x14\xe9i\xfd\x94!\\\xb1)_\xa2/\xd3\x19`\x97\x12\x86\x1d)\x98\x82\x88\x9f\\:\x02\xbc\xd93+o\xc1\xe0\x19\xbe\u0423r\xd4\xdb\x10\xf9\xafb{\xeb2\u05ea\xb7\xdb\xc9|r\x85\x1f\u05d0\xb4\x02\xc5\xe1\xb8c\x89i\xc8Y\xf3h\xee\xa6\xd1W\xaa\x8a\xe7d\x0f\x97E8\xc2@\x96H\xd7l\xf5\x02\\\xd2\xfe\xae\x82\xfa\x87\xc5\xed.\v\xb4\xa1\xde\xed#\x9a\xf0\x1amn\xad4\xc1\xe1\\T\x11%\x0f\xd5\x1d\xa5*8\xc1\xe4\xd1\f\xfd\x8a\xc2!\xbc\x86\xe9\x99\x15\xfe\x1b\x04\xb1\x1dI\xbc\x99t\xc5I\x03\x9e\xa0\f4\x94\xea\b\xa4p\x8dP\xef)~$\x80j\xe6`\xe5\x03#\xf9G\f\x87(y\xe7i\x8e\xe0\x88\x1a(\x8a5\xa1\xb4\xf7\xcd\xff_\x10z\xe8f\xe7\x9f\xce)\xcc\xe1\xeddR\x9e\u01b2\x98\x0f\x10\x90*\x82\xa4\x8d\xa6 M\x03\x936a\xea\xe5\x1e@\x1d\xfa\x17z\xa4$#M\xd9-\x0e\x8e\xb9H\t\xde\xeaw\x92\x16Bi\xf3\x85\x1ej\x01\xe2\xab?!#\\\xac2\x16c\xa6\xd8\xdeYZE\xcc<\xdc\xf05qRc\x98\x83/\x19\x9f#G]\xc4\xf49B7t3\x01\xa9\xb9\x8e\u024e\r~\xb5\xd9\x11h\xb2aL\xf8\u0624\u08d8e\xfd\a.\xed\x8dg^z\xd6X\xfbK6\xa8Y\xbd\x1fb\x00\xe9\x00\x03x\x1c\xb5\x92\x066\xe4\xd1m\x8ct\xd5\xf4t\xe9\x10Z:t\x88\xa7\xab\x145\x98\xf7q3\x8e&\xc6my\xdd\u007f\xb8\x16\f%+a\x87\xaad\xf9\xa0\x90\x8a\x15\x91;\x8aP\x93\xd5\x18\x86\xd8\x05\xf8\xe4g\xb3\x85\xdc\xc7\x03\x81\xf1\x1a\xa4DQXi\xb7>\x13\x9fUn\xf9B\x88\x8ai\xa3\x85\x10)/PCO\x19~s\x92[M\xdcm\xf0X\u03c8f\x8f6\x9f\xfc,\xf5\x15\xc1\xa1\x9fp\x95\xc5?/\xa2\xe8\"\x886{6s\x8eq\xf5\x81\x15@\x17\xd2\xdeVW\x9d\xff9Z9;\xe8 x\xb3=?H\xe1\x9e\xf0}a<\xa0\x06\x02\xf9\t\x9c\x873\xeb\x17M\xed5\xd3\x12\xb3\xe2j\xae\x16:\x1d\x96_I\x11\x1fn\xd17\x17\x81\xb3\x01\xe5\x89#\x06\xf9\x03\x90\u04fceb\x87\xa6\xb5\x9c\xe9# \x8c\xc6\r\x1f\xef\x91\"\x03\xf2\u053f3\x83\xe6o\x9a\xd6\xd4\v\x880}kY\xfdT\xf2\x86\xbbE\xb8]Y\x82\xd0\t\x1bD\x9e.\xa8\xcf\xe7\xf4><\u0693j\xe0\x96\xd2\u0688\xfc\xb5\u051f*bXl\xca\xfe\fJ\x95\xed7{b\x99\x0e\u018aB\x18\x99q\"\x9f\x18K\xa3\u0596\x15b\x8c\xaa\ve\xaa\x82VG\xf4\x99Hs\x88\xe5q@\xc0\f\xe3\x94\f\xb1\x86\u03a0*\x83\xe8\x9d&\xf4\vA\x95\x01\xc7Q.\xc5T\xfd\xdc\xe5lI\x85:\xae\x8e\xc1\xb3\xcd\xf0\x1bX\xb5\tk1\xd7\xfdq,-\xf2S\x0f\x98|\xe8l\xb2\x1e\x13;\x91\xdf\x1f\xd1\u00bejI\x06F\x91\xcf\xc1T\x82\xfc\xf2\xf1!I\xc1\x1dt!\xf0\xcd\x1aJ\t\x1c\xa3\xecb\xce%2\xcf\x0f\xaa\x85\u0379L)\xfb\xf54\xa7\xeb\x93v4@\xa4\xb9\x06\xf1\x8d\x86\x0f\x19\x06\x19\xb6\xc4\xf9\xac\xda7\x14\xd9t\x9a^\x83\x91u\x8by\u04fb\xabE\xc5\u007f\\\\yd`Y\x87\x82\x88R,\x1c\x106T\u0748\x88\xb6T\xb6G\xee\xa9\x16\x9d\x02H~\x83\x10PZ\x97\xf0\xfc\x03\x1d\xf1\x94\xb8p\u043a\xa4\xb6:\xc9F\xb3\u04f6n\xa0\xf6(\x021\xff\x15\n\xd7^\x91]\x05\u00c8\xb9\xf1\x8dm \xd7\xcfQZ\xea?\xc8\x02\f.\x86\xa1\xc7S\x01\x14Rex\xf9V\x86\xf3t\x1dX\x80\xb2\xc8\x1e\xc9dJ(\xe6\xbfN\x84y\xddB\x11\xed&x\xcf\x04\xa4\x84>\xd9\u0466B\f*\xd5=\x0esG#\x1b\x8f\xe0\xea\xa5,\x9cV\xb8pk\x9d\x11\x87L\x06\t\xd8\xedC0L\x13]\u01bc\al\xd04,\x9a\u05a5l\xe2\xec\xb8za\u8eda\x99\xb5\x1f\xe9\x14h\xdb\xd2|T\xc2;S7\x14A\x91\xf1t\xd8\x03\xb8\xe8\x9b\xfc\xd0A\x95\xf2\x0f\xc3\xc6e\x85\xf2\u0508\xa4\x8eN\xe6\x16\x85\xa1U3\x87\\Q\xd1Z\xb3\x86\xa1\x88\xe0\x9f\x1bBd\xe0\x19\b0\xbfJ\xc0\x17\xd4\xf1\x18\x19E\x84C\xa9DHXE\xbc&\x12\x12\xf5\xfb\xd9\x1b'a\xb0\u0753v\xb0\x02J\xa5S{\x91\xfb\xd8\x1b\xe3G\x14\xee\xdf!HfqB~\xefG\x81\xf1\xf3\xd8\x1d\x82a\xa6S\xb8\xe6\x12\x81K\x9f\x14\x1a\a\xcb\xc8\xfd\x8c(3\x8du\x8f\x96\xf5\xdd]\x9a\xbc[\xe0\vc%\x1b.\xed\xed\x95O\n\x98\x8dv\xdc'\x17\xa2\xe7\x83\xc0\xd1\u0169\xf9\x9e\xea\xb5;h\u04f2\xb4i]4\xb4\x97\xc0\x01\xc7\xc6\u00e2)\u04ebb\x10O\xa9t\v\u007f0\x983\b\x83*\u25d9l\xcd\n\xed\xd0v)u\x10\xf0\"^\x92\x88\xaaM\u936e\xc9e[ o\v\xaeg\xf7\xab\xca\x02\u045b\x1a\x1a\x00\xec:-\xe5yB\xff\x9c\xceW\xd17\x03v|6\xd3u\x1f:\xb0\xb5XY^\xf2\xeb\xa7V~J\xcfO8\xf7\xb4\x87cX\xa4\x04]\xf3 \xba\x89\xc0D\xbb\x0fO\xf5\xc942\xcc\x10M\xea\x81Jp.\xa9\xe6K\x97\xf6\x80\xd7\x14Z\xb4I\xfc\x8e\x91\x91\xca\x1c\xac\u42aas\xb2\xc6~\x89\x13\x02\xab\x18Q\x17\xc9I\x82\xa2&&\xc7B\x04\xf8\v\x11\xba\nc\xff\x18\xfb\xbc\xdc\x10\xf4\xc81\x909A\x99\x92\x145\xdfV\x86\xd0\x12\xe4\x11<1Q mX\\\\A\x83$\x9b-\u007f\xf5\xc0\u0213L\u0271;`\xed\xc0\xea\xdc\"[\b\x03J\x19\xa4#\x8bI7}\x97\x1d\x98\xd7/gQ:>\\\xe3)7\xb0\xd6\x19\xbao_\xe0N\x9av\xe4\xeb\x13\nz\xdcU\xe5\x17\xae\x1a-\xeb\xf9\x12\xe4\xa3A\x1b\xacK\xf2\xc1\x17Q!\x937\x10\x89\xc032&\x95\xc3\xcaL\xa7\xdfi \x8a3@\xdf\u0452\x1aOD#\t\xbc\xf6B\\t\x1b\xe2$z\xcd\u03a0)\xa6\x939\xd4C\xc5\xc9\xdbSI \x17q\x95\x80\xb0\u04f2Tpv\xe5\xb5\xfe\xf6\n\xea\xa7J\u0314\x18\t\x17 (\x17Z!\xebD6.\r\u007f\x19Q\x17\x1f\xf7\u0766\xb2\x8f\x98\x89pE\xe4\xf6\xcb3U\xdcF\xcf ,|\x13m.\"z*\xaaA\u0201\xfa\x15\x05\t\xa0\xf0\x15=\x11l\xe4\x01\xc32\u04fa\x01T$\x02b\x1d\xd1\xc2\xf40\xbc\x13\x8bqa \xb5\x06+d8\x14\xc1\xb5W\x92je\x857\xaa\xd0i#\x94Cg\r~\xa6\x93\xb8\xf2\xd8\xda\x1bC8\x95\xec\x04$\xab\x19\xbe@\x88-\x01\xbcF\u9880\x82\xce\xec\x82HB\u0529\xfb$v\x1c\x0f\x91\n;Y\b\x1c\xed%\x8cX\xe9\x924\xa2$^\n\x9f\xcc\u0764GU\xa7\xc0\x1b\xc7`*G\xe6\xe4\xf5\xf1\xceS\xfeq\xf4\u007fe\n?\x9c\x11\x9f\xa9K\x18h\x1fq\xbe\xb2\xc3\x16\xe06\xd6z\xa5\b\x1a\x99$\x89|K!,Fj\x80v\u74f8/2\x91\n\xef\x12\u054b\xdc-\xf2\xd1\ts37\xb8=A\xb3\x12\xc2\u01f2\xa2\x94\x12\xee7\xe4s[\xa2N\x90\xb5}^aD\x04Dd]:\u062d<\x03\xa2\xe4 \x1e\xe2\xa4fI\xbf\x10gIa\x1c\xe6\xd5M\xe9\xbe\x00\x9d\xeb\xe7\x0fRR o)7(\xa2<\xa9\u007f <\xd8\xdf/\x0f\u007f8!\xbb\x98Q7\xe0D2c\x16D\xc2\xdb0\x80\xfb\b\x1a\xe9~\xd9\xf7^\x122\xa9\xa6\xdf\xee\xa3!L\xd0l\xadS\u0558\x9d\x8d7\x91\xd6\xc45\x87\xbbV\x8a\x9d\x9a\u017cj\r\xee\xcd\\\xb5\x04z\x8c\x147\x1e;p?\xd1aR\xc0\xc7\t\xa6\x9f\xe3ZS\x16\xabviT\xef\xaf*\xf6\xbfka\x9fN7\xb1\x91V\xc2.\xc0\xef\x17)qq\x00Y:\xf9yH\xae\xf7w\xd8\xc8Db\xb2\x84\xd1\xe3\\\x91\xf99Cs\xdb\xf7k\x9c\x8f\xed\x13y\xad\xac\xc0 \u0697\x04\xae|3\x90\xb5\x9f\u05a3q\xe2\x1b\x9a\x89\xad\u07d6\u009e\u06f6R\x9e\xdb\xc0\r\x9b\x9f\xec\xfa\u052f\x16F\x19jZYRB\xa3\xdb\xceQ$V'\x82IXiY\xfb\x831\xaf\x11&T\x1a\xa1\xe5\xc1\n\x1f\t\xedLGd\"\xa7c'\xb1\xc1\xfc\xb9\x800a\x12\x8c\x87\x06\xe5\x10-\x8a%\xe3\x9a?C\xaa\x9d\xbd\xc01\xc9\u02a6\xe01\xb0\x00 \x97\x80`U\x80\xc5\x18\xf0\f\xc2\x01\x95~\xe6\xd4\xf4\x06f\xe7:\u007f,a\x96j\xadX\x80\xea,\xf1BnQ\u03a5n8\x88\xba\x89O^X\xbc\xf8\xc0U\x8c(\xa2Y\xfc\xae}\xc6\xcb2Dx\xf90\x11\xea\f\x01\x83T\xefV2F\xa6\x0f-v\xd1x]\\\xa4\xc1\x80\x0fG)\x98\xaa\x9d]\tw{\xf7\u0381p\x1e\x8dS\x15Q\xd80Nz\a\x1fp\b\xd4\x04gq\xa2cW\xef\u043e-\xca]\xab\xb7\xdfX\xc0\xd1`W=\xb90(\r\x17\xa8Z\a1\xd6\u0207\xbb\u0603\x917J\x14u\xcf4\xf9\xads\x923\x8d)\x8b\x85\xd8>fL\xad\xf9\xca\x00\x12\u29fb%\xa8\xae\b\x9b\xec\x02\xf4\x1d\xea4\a\x11\x06\n\xe1\u03ba\x19\xa6\xc8\x13\x91)\xee\x9a,\xfa\x85'\x1a\f\x0f\u018c\xd4\xe2!\x03\x039\x971\xbf\xd3\x1d6Ng:\xc8L-\x1f\xf2\xda\xcea\x0f\x05\xea\u01cc\xa1\xf7\xf3\u00ac\xfc\xbf\xa8\xd8f\xca\xd1\xdf\xe6\xbb\xd6E\u046b_\xe4u\x93x#\xd3i\x93I_h\x02\f\xfdD\xb9)\xfb_!v\xf3\xf1\xb2\u39e7\U000cb357\\\xb1_\x00*cJL\xa5\xc4\xe1 \xb5\x836\xf2\xb7\x83\xed,\xb7\xca{\x90\x10H\xfe\xa1n\x02T~\xab\x89\xa0J=40mK3\x83\xb4\xdf`\x86\xb2K\xd4\xc7\xd5u\x9c\xb5\x026%#Z\xef\x81\fP\x1c-g\xa5\u07ff+\x12\n\u01be6H\xff\x1b:\x81\xc7\u14a87\x8d3\"F\x05\x87\xfe\xe0\xcb{^,k\xbe\x19\xeeg3\xd5I\xd1?\xed\xaa\u05d2\x03\xb6\x1c\u05aaP\x89\a\xdbt:\xd9\n\xab,\xfe^\xc1[\x91\x02$\x88B\xaa\xa5*.\xa5/-\xd7@\xcd\x05&\xac\x9c\xc0hq\xea\xf9\x95Z1F\xbe{\xebs\xedG\xb0\xd3\xd1y\x94\xed\x04\xc1\xdf\u0790\x1b&\x82\xe5\x9b \xf5\x15)\x92\\\u5645\xa9\xe0\x9b\x90\xba|@\x13NI\xb1\xa9z\xfa\xdd\xf85\x92\xb0\x9c\b\xa6DH\xff\x14A\xaf\x06\xb5K\xe8y\b\xaf\x90 \xb8\xa5tDeZ\xc1MD\u0528\xda\xe70v\x91Dcr\xdc\u023cA\x89\x9bMk=\xac\xd5\xc8\x14\x06\x97Y\xaa\xd7/\x9c1G\x93\xfdD-G\xf3\x12nO\x9b\xcd\u6981h\xa0\"\xf0\\\xc8!\xa3X\xc0\xc8<\xea\x1f\x81\av\x1d\xe2\x82\x01\x88X\xd6JX\xfe\xb77\xc1\xe5\xd9\x11\x8a5.\xea\xc1K\xc0\x01\f\xfb\x95\x92\x00F9\"\x13\\\xc2\x10\xde+\rn\x8a\xe7\x95A\x94|\xbf\u0175\x92_\xc0\x98J\"\b-\x95\x96\x89\xc0\xb1\x11\x1c\x01\xf0\xe8#\x15\x06\x04\x19/G\xc2\u01a2\xda0\xbd\xea\x10Bmh\xe0\x88&>6\x89\xa1\xab-\x1c\x05\xb6\xc1D!\xa9tF#\u063b\x02\u0716'|\b`\xbf\xc3[HJ\xec\bm\xa0E-\xf2\x1d[CH\x000M\xec\f>\xd2CC\u007f\u02d3\r\x06F\xc9\xcf\xda\xf4Q\xc1\xf6\u0613\x05n\x15\x17\xe5\xeb\x84h\xf6)\xb4\x13\u0544\xe8K\xbf\xcb\x03\xecga\x18\x82\x87&\x9f\x18\x94\xdcaA\x85\xe03*\x1d\b\xf5m\x90\t\xe8\xe2d\xa3\x92\xe7\xd8g\v\xa7\xa4\xef\x81r[\xf35 \x15#E.N\xe4\u01c8h\x9fm\xc0[\x1d\xd2\"\uc4fal\xb3\f-sn6;\v\xb0\x8d\u0187\xc2W\u04cf\x86\x82\xfb\r\xe1\x1f\x02]\f\xbcg\x95\x92M\xa7\x1d\x18\xe5n\x906\x10}(S\bd:\xd2\\\x96\xd0Y\x01\x91\x8eW\xfdw\x92h\xc6*\x96\xba\xf6p\xeex\xe5Q\x12\xa0\xbdM\xebe5\xae\xff\x8c\xa9\xa1\u0294mUs1\x93\x03LC1\fv\xad\ub3bb\xe2\x10\xa9\xdea\x9f\x19q\x98CG\t\x13\xca\x01\xf8s\u62b5\x80:\xa3\xb6\x8bxc]\xb4=\x98\xf8\x0e\x99\x06\x98\xb9\xfb\xc8\u058e\xf9\xe4\xb0\xdc1I\u42b1\xce\xe3\x151\x1a\x03;[\xf6p\xeeI\x1f\x88\xc5\xfa}\xee\xcef\xe8\xe8\xaa8\u0614\xa8S\xdaC\t\xc2044\x1b\xf8*\xb3vT\u018e\x98\x1aO\x833\xaa\x90\xfa0>\xa5\xf9k\xd0Q0\xaf|\xc0\x97\x06\xc5N)&\x06V,\af\xf5\xd8<[\x12\xe0\x11\xf1+\x85\u0428\xba\x1e(\xfd[&\u0543\x8e\x01\x90=H1+ET\xa1}yyd\x8ax\xeeC\xb4\xe8\\O%?>H\x94\x95\xcb`\xcd\xeb\x04\x97\x0e\xdc-\x82\x06\x9f\u0398\\_\x86\xfc-&\xf1{c\xc8\xc3\xca\xeb\x9f(\xd0i\xe9\xf7>\xada\x0e\x84\x01B\xc4\xeb\xdb\x1d\x92\x8es\xf4\xae\x1c\x83M\x8b\xf3 \xa1\x1c\xdbo\xaf\xad^\xbb`{\xe8\xf7\x01\xe7\b\xb9\x90e%\xdb\xfe]\x15'\x8e\x13\x81\x13\xbb\xca\x11i\xdeI\vM\xd2\x03*ehL\xe3\x80(}\x1e\xf25,\xc8\xe8\xe6i\xb0\x12r\x1a\x84\x03\xe0]\x02\"\xa0N\xbc2^\xb6\x01\xc6\xc4b\xcd\x0f\u03b0\xb7A\x80d\xe8k\xe1\xd2B\x91?.,\xa3]\r\x97\xe4K\v\xbf\x14D\x16\u018f/\x1b.j\uef35\xec\xf1\x1c \x96\xa3P\xd2\xd9\x11\xa9\u0080\xa3\xfe\x84\xc0*\x1f\u058d,\x0f\x89.\xa7\xaf\x963\xa6\x1fZ\u029f4i\x88\xc5r\x9d\u01b5,\xfb\x91\x1d\xb93\xba\xf0\xf9\x1a~\u035a/\xc3?\xc2,I)\vk\xb0\xd3\xe5\x8a\x14\x11h54\u063e\x0f\x18\x92-0w<\x06\x81\xba\xec\x0fp\xa6m\x8f\xd7\x00n\xf1\x97@\xcf\xd7\b\xb4T3\xc3F\xc4_\xb1\xc0\x98\x9bH*\x8b\b\xf3&\xa0\xbfkdd\xd6\x0e\xed\x90\xf6\x83;\x18\u07cb\xdfh\xe8\x9e\u0481\x91=KS\xc4OW}5\ub810\xabo\xb7l\xc1\x92\xaa\x0eJ!\x9awQ\xb7Y@\xa6.+\xd3\xf0\xd32\x8fHz\xe4\xed\xf3\xd9\x00L\x00\u0094 t\x1f\x03\u0274po%I\x19\xf9\xe2\xe2\x13\u06e8\xdc>\x16\xe5\x9f\u0281\x04\x06\xdc\x14/\xb1\xd2X\xcf\xf7\x0eX'\xe9\xb7]\x8b\xfb9\xfa\x80\xce\x0e\x8b\x93\xf7\u0366\xd4D\xab\x93\x84\"B>\x1f{F70\xa2{\rn\xcf?\xe9\xa6<\xfe\xec\x87\xfd'\xf7\xf3\\\xf0\xff\xa4R9\xa3kr\x18e\xf1\xb4\xeb\x05\xbd\xfbt\x8f\u45fe\xd0f-6\xf7\x12\x8ar\xb0\xe3\xb0\xe8\xe1\xd3\xd6\x01\x17\xc0\">\x8f\x9e\u07b6\xb6-\x0e\x1fX\x87\xa8\x02Vq\xfc\xf8\x1c\xfcr\x10t\xa1\x06Fk \x14\x97\xfd\x15'\xab\xe4IX\xd5u\xcb;\xdcu0\xc22\x87\xc7I\xb1P\xc4I8\xbax\xe4\xbeVs\u01c4\xac\xd0\xd2DW\u06bf\x96\x99D\x92\xb8\xfa\x06'\xa7\x12@\xbdD\a\xc4K\xf5iG\x9d\xb7>\xe5\x8e\x18\b|\x89\u07f1\xa9\xf8\x01c\u0416!\xdd\f\x8c\xb6R#T\xa0r\xa1\xa0*\x051\x11\x1e\xee\xc4\u01fa`\x9a\x8d\xb8\xf4Mj\x16!b\xd7B\t\x10\x15\u01fe_\x90\xdd\x1f\v\xf1\x01!\xe6y`j\xaa\xb5\x83\xf7z\xe1'\x0fc\xdbS\xe8\x1a\xb7,\x03\x00\ube66m\x86\x13\x00t\xa9\xc1\xba\x80r?\xb4\xb4Gk\x87(0\xe0j\xb6SE\xfd\x86\x8c\xbc\u007fL\xe5\xbf\xe8i\xfbo\xdc\xed\xe7\x03\xd86G\x94M\xaf]\xa8\xa2e\xae#sd\x9cVg{\xff@\x8d\xa4\x9a(\x9e\x15@:\xb9\xc6!_\u06d4\xfbq\xccp\xb2\xd8\x19y\xc67\xcbP\xfcX\x18\xefN\xab\x1e\xf5?9\xa0=\xa4\xad-\x15(u\x06)\u04ef\r'\xfa\x98\x9d|\xd5#\x83\x88\x00V1t\x1f\xc2j\x12M:1\a\f:fys\x04\x107n)-D\xf2\ub3c7Z\xba\xf7\xdd\xd6yc{W\n\x0e\xe4sSl\xf8\x0e\xdaS\xddp\xe2\x91\xe8\xac\xc3H\xa7\x11r\x87S@\xb9\xa0\xa5\xbdL\x17\xc0h\u00f4\x94\x9anj\x9b\u03dcQq\xbbM\xf9J\u04c6\xbe\u04b8\x994\xa5~b\x1aZ\xaeX\xec\u043e\xe4%\xc7\xeb\x05V\x02\xac\x1d\u061c\xb0W` \xdf\x13\x8e\b\u007f\u06ee\rEC\x11\xab\xae\x10q\xbf\xa0\xafb\u015a\x11\x04*\x90^@k\xf7\x13\u0270[\xc1;\\\x13W\xee\x13\x1e\xc0\x9f4c\xda{\xae\xd5\xe2\x85\x1e\xb9\a\xae\x9a\xaf[\x1d\u0638\x89.@\x9dN\xbe)x\xfe\a\x1aMN\x94\x9f!\xc7\b&\x91c3C\x83\x82\xb1\xf4\xb0N\xed\xcc\xc1C\xbb&\x9e;Z<\v\xa3\xb9V q\xc5I\x85\x80\v\xc7.\b\xcd96\xc6\xe2\xe1\xe2\xcbpV\x9d6\xael\x1dI\xa9A&~\u1fd1\tg\u015b\xdd<\xf0\x04l:u:\xd0\xe8.[kA\x1e\"\xbcKM\xf0\b\u1bc4\x1a\u040b\x13,\x8b\xa5\f\f\x12\x13S\x02\xb0r\x13t\xabt\x00\x1e\xe5dcx\u057e\r\a\xbc\xfb\x8d\xe6\xbc\b\xc4\xd3\x10\xc2\xd8\x19\x8cE*\xd6\x11@\x05\x02m\xc0\xdf\xc5[\xc9L\xec[\x15\xe7M\f\fSK\xa9\x8e\x17\x9cEj\x02B\xb4\xb3}\x1d\a%\xaf\xf2y\x9b\xac\x00tQWE\x8d\xf4\xe1S;d\x91/o&0\\hY\x10\xd1_8\xc7\xda\x17\xeefV\x16\xc3\xd2\xf3\x88T&\xb3\xe5\x17\xea%\b\x11\xca\u0170P\xcbS\x86`\xa8\xa6XmQ\x03\x97\x15ARu\xa9\xa0}\x0f\u02b1\xe5\t\xebS:\x0e\x98\xd2~uL\x0eU\x02\xeb7/SbT\b\xa2h\x9c\xd2D\xdf\xec<\xb5{\xb0\xe5\xc8\xcb\xc4\x0f\ucee7T\xb2\x90Tp5)\x01Z\n\xd2)a{\u47ef\x97T\x15\t\xbc/\xa4\u0245B.XF\xce\xc4\xd3\xd2`\xe2\xa2(\x81\u02f9\x9a\x92\xce\xc451\x95S\xb6\vLHaQQ\xc4\xf0\xdf\xe7\x16\x14\x02'\x10\x84\x93\xc4)N\xc2\x12\x85m\xe1\x05\xe22\x9du\x92\x99 \xe2\f\xa5\x00\xb7;\x0f\xc2\x130\xbb\xbd0\u02b9\x00\xca\x14\xa4[\xe3\x9e$\xa7\xfee\u013b\xf1%\xfd\xa0nlm\xbc\xb5(0;\xca\xd2z1\x19\x02\t\xd2Io\xf6%\x12dL\xc6\xf2\\i+\x03\xcc\x1d\xbe\xb8v(\x13\xc6Mo\x8d\xc2\xe8\x1f\xab\x8bzg\xe2\x99\xd3'Y\x9d\xdd\x18\xa9!\x8e~\xcb\xe25\xc5\f\xea\xaeO5\xc4&\v\x16Ig{g\xeb\x90\x02*\x80P\x815w~\xaal\xe7\x17\x80zE\x80\x00\x10`m\x99\x01b`\xd9P\xc4UZ\x13\xb5Ue\x1f\x17\x00G\x82\xcf\x12\xb3D\xb0-\xad\x91:)\xa4\xaaj\xc1\x01\xa7\xa6\xf4dQ\xb2%\x18V}\xdbdV\xb7\x16\xd8f\u04a60\xb1\u35d8bf\xf6X\xa72\n\xdc\xe6\xb9R\xd07\x10,\x8bY\xdf\x11\v.\fQM,\xc8\xe3|\xd9\xed#i$\xe2I\xb4L\x89\xb8\x1f\x81F{\xaa\xddb\xb6\xb1\xef\xa3\xd4u|e@E\xe5\x02\xacl\xf1=l$\xb6&\xbc\xb5f\u42aaL\xed\xfeL\xf69\xcaN-\xcd#\xf2\x99\xc5c\xd4\xf40\x04\x86\x8e\x94\xa4\xbb\x92;Q_\x82p\x04EB\">\nv\xa5\xc1\x93\x9b}\x176\xee\x92]\x84\v\xa2\t\x0f\xdac\xc0\x8c\xbf}\xfc\u00a1\x90\xc8D\xb5q\x89\xf9|5\x00\x97\vTVo\x02\x88\x86\xec\x03'\xea\x05\xa7B \xa6)\x90\xb0\xb6;p\xd4\b\xab\xb2_c\xb0\x9ca\xc4\xc7A7\xc7\x18s_\x84\vXC\\\xa4\x1dM\xd2\x1c)I\xe9\x1a\xacI\x0f\xb3\x9a\x1d\x11\u77d7\x94\xdaP\x01P\x90\xbd\x93\xf0Du(6\xa2\xd0)$\xb1r\x98QB\xfdTyuT\x18!P\xe0D\xfe\xd2L \x95\u01d2^p\xba\x9e\f\x8b\xef\xb1H\x8a\xa2v\xd8\"\xbe\x8c\x98\xb0\x16\x9d\xe0\x903\xb3H\x1b\xca\\\xa7\x8cy\x18j\xb5\x03\u048d V\xd6\xe4\x87\u0340\x86S\xe4\x1a\r\xf8\x10'\xf0p\xdc\xf3\x1e\x10G8\xb0\x84\xfa\x05q\xd1\xd1\xf3\xccJ\u0268\xcbH\r\xf3\x1f\xc6+b\x80\x98\xdb~\xf9\x9c3\xd5\xf8\xea\xf47\x9a\xadh\x92\xb5\xeb\x1da:\x82\x1a\xdc\x1c\x0e\xac\xfbB\x9e\xac4H(\xac\u0592\xa4\xd8~\xb6\xe4RS#\u07c2$\x14\x10\at\xa1\xb9\xa8\xc2\xf9\xaeP\x06\x16\t\xdd3\vqe\xa7\x879\nkV\"\xd6\x1c:jS\xebJ4\x96\xf9\xef\xaf\xca\xe8\xa2O\xb8]\x87\xcb\rn\u0308\xd0\u052b\xef\xed9\xfa\xbc\x10p\xe3\xf3\xe64\x19\x9cc\xf2\x84\xe3\x1f\xeaj$\xe0\xa4\x16k\xec\xfd\x81\x95\x81u0\u007f\xf6\n\xcd\xfd}\u059b^*N\xf45\xb0\xf3\x97Y\x01\xa0\xb6hpV3\x1f\x83\x84(I\xc7\xc8)\u007f/\x19\xa8\x81r\x16A6\xe9\xa3H\xbb\xa7\x97&%\x8d\xd2\xc3\xd37.\x9a\xfc\x17|\x9ad\x97\xe2\xda|\x9d\x88\x96\xf8,3l\xe4i\xb5\bDQL\xc1G\x86\x1c!\xa1\xd3\x0e\x9e\x8d&\xacFPG\xe8C\xe8\xf4\xa8Aj\u03f1\x813\xff\xd4g\xf0Njx`\x91<=LN\xbaAw\xed\xf7\x9c\u0746\xf2\xa9\x98\xf0\xbe1@\x9d2\x8b\xe2\x85*\xbc\xf2/$\xaa\x8bM\xff\\L\xacK|\x18X\x85\xfc3<\x90@\x95\xbd\xdft+\xbd\xccD\xe1r\xaf\xa8E\xeb\xd8F\\\xc1Q\xc1\xb6\xd7C\u06f2\xf8\x06u\xb6\xe6\xe9\xb5\b\xc1\u07a68e)\x89X\x14&\xfe\x02\x05\xa2ky\xce\xd5\u04fe>g\xfd\aD\xc0XmV@@\xc7\x1a6\xb8\xe1raH\xd1\xd1}\x8a\xe0\xe6\x02>\x11\x8d\x1b\x1d\x13y\x88\x14\xb7GE\x9eV\xd5\xe5\xe1\xfd\x1fT\x86Y\x11\xcfqi#1G_\xd4\xe8XaD _;R\xa3~\xf4}|aV\x81\x91\x9el\xe7,\x0f~\xc0\xfaAR\xbd\xb1\xc5sZe\xa0\x06Wi\x13\xb1uH\x98iyc\u04cfz\x0fDi\x01v\xbd\x80VX\xe5i\x9c\xf0`UL\x0e\xda\xd2h3\x8d\xf27\xc0M:5\xb5\xd9\xc2\xe3\x06\x19\xf0bG\x870\xcd0S\xf8I\x97r=\x992\xba6D\xb1\x9d\x0e(e\x1fJ\x10\x11\x81d\xbcj\x0eT\xcd^EY5s\x96\xd8J\x88\x03\x9e>\x1a\xc8v\xf2\x93[\xd8\xca\xf8\x80#J\u01bf&t\x00\xa4&NV\x9bC[\xa1\xa1\xed1\x02\x12\xf3\u04e2\xe7H)\xfd\xe5\u007fi\xaa\xe8\xc5\xcfO\xac\xf7\x04\xa2\x14I\x05J\vW\xc3NI\r\xa0\xa4\xc0T$\xc0;\xef\nS\xa4\x85\\\xea\x88w\xe1\xec{Tm\x13\fMe\x92\xbb>n\x1cO\x13\u0326\x1bJ(l\xf9\x15:\x93\x16$\xc6TRO\u0717\xf9;\x85\xd84\x8b\xe8\xebS\x84\aw[A\xc2\x19\x03\xfdx\x90<\xf0\x16\xdaiI\xcf\xccnP\xfd\xa1\xf2\xa3\xa1\xfcO\xa5\xe8\xf0\xe0W\xee6\xf0\xda\u05aec\xfd\xb7\x1c$Y\xf0\xf2Ci\xdbi\x03)\u067b\x02\x8e,$\xce#\t\xd5\xffp\x18&\uf0a0\xc6J#\x13\xe1\x11P&\xbbu\xa3K(\xe1#r_\b\xb8\xbc!\xdb\x0e\xc0\x92u\x11\x1d\xe8\xdb\u0341\xfd\xfb4\x9b\xbaW\xb0w\x16\x05\x83L\xd05q\xda\x10\x8a\x80\x8b(\x03`\xc0+#~\b\x8d\x0f\xd5K\xcf_C\t\xdc\xf8u\bh\x16\xf5\xbe\xb2\x05\xc84a\xb2\xce\x17XY\x8d \xf8\x13\x85\x02\x9f\xe5\xbeG\xab\xf9\x80T\x13\xa1\x1b\x10\x83`\b\x98\x82D\xc0\b_/\u0611\x89a=\u069a\x92]\f\xbd\x13\x96P\x10D\xbd\xdf&LY\x8bm\xb0m\x8cvw\xf1I\xb6\x00l\xeb\xa2\xc5\v\x04u=\xf0(\xc0Bn\xfd\xd00\x1d\xeak\xf8\xf8\xa0\xe0\x8e\x9aU!\x91\u00a0\xee\xc3\x04\xc1x_\x00p\x90\xa2\"H\x0eF\x91F\x12o\x91A\x90\x1b\x92\xfc\x84\x93\x91>\xe6\x1a\xb2\xba\xd3\xc3\x05\xa9\xca\x1f\xe2\x04\xe0\x02\xf0\xe8\x94+P\xd0\xf1v\x13\xd8D/\x03\xc4\u0518\xbfx\nKj\x013n^a\xbd\xee\xe4b(\xb0\xceR\xa3\x18\t{9`f\xa7\x8c-su\x8c\xf6\xb7\xaf4T\x85e\x18\x9f\x97\xf2\xb9\x03\xf1#Wr\x85\x14\xb1\x00\xa1`?\xcd)\x1a\xbc\x99x\xd0\xe2\x18\xd8\u01e9m\x00l\x0f\x9a\x0eM\x9d\xb7e\xaa:\x1d\xb1\t_y\x8bFA\xc2\xdeQf!-\x92 \x83\xfcQ\x89\xbc-\xc9\u0776/\x05\x1f\xf9\xb0\xd9}X\x97{Z\xc8d\xf7\x96U3\"(\aq/)Z\xd3!(\x03\xef\x900\xf4\u07c3\x1f\\L\t\x88r\xb1\x8e\x16H\xa4\x17\xe3k$$\xa2\x91~\x03T\xce:\x9a\x81i\xb3%\x00\xe2L\n G*3\x123\xdc\xc1Y\x0f\x1ax\x1f\xfeF\x9d\xc5\xda\x01\x18\xbe^\x82E\xdaH~\\F\x96\x04\xd7\xe4\x12\x96h\xc6]\xb8\xa4}\xa4V)i\u3930\x0ej\xe5\xc2\u0655l\xcbs\x95y\x82+0\x1e$\xa7\bU\x90\x0f\xad\xb84\xa6\xcaw\\\x91\xca\x033\x06B\x8a\x93\"&\xae\xdfSM\xb6\xa79\x13\x01e\xbc\x8e\xaex\xf5\xee\x84\"\x0f\x10\u040f\xbe\x05\x8c\u007fF\xf9S\x18\x81\\\u00d4K\x16\xe3~\xab\xa4\x86\x17n\x9b\xf4j\xac\x88\a\x03\r\x88R\xe8\xc5\xd8G\xf17\xc9\x19\xff\xe5\xd0\x1eD\x8a\xc0\x0e\xd8=\n\x94\xc5$\xf3\xdf\xdc\\\\\xdc\x11/\xe1\x18\xa5\xa5\xbc\xec\xd4MD\u01d9\xb4\xae\x06~\xd3R\xdb\x10\r\xe0\xef\x93V\xd5h\x11.\xc0;\xb6\x15\"raR \x9e\xfc\x013\u007f\xee\xbdnv%C\xdf8a\xed>\xc0\x013\xc1\xa0\x84\xe1a9\xfc\x01\f\xd8\xe4\x90\a\xa5n\x16\xda\x02f!\xc8\x12p\xe7/-\x01\xf5c\x00\xad\v\xf61es\xaa\xbd/\xf8\x8f\xb8\xd8x\bW\u0245U\x172\xb4\xf6\x01y\xf8\x82\xe7\xeb`\f\xf5\xb8\xc5\x13\x83[lQl\xa3\xd07\x9a\xb7\xdc\xdc\x11W\xbd?\u0271\x9e?\xb2}\x91\t!E`\x120\xa1\x1e$\xaa \x00\xa0'\u0369Y\xd7*#\xe9\xb8\x01=\xc3l\xa4\f9K\x01\x01[`\t\x19P3\nA\x81\x9b ?\xcc\xc5\x19\x80@qM\xf9\xe8$\b\xc5\x14\xd4\x16\x88\x06H\x11\x124\x18\xab\xdaj`i\xf4\x88\xbaS\x81]\rc\x9d\x9e\x13\xbbCvb\xf8,\x83\"\x8f\x1f\x14\xc8DRA\x81-\x11\xe96\xa4i6\xaeU)\xa3o\xa8\xae\v7\xe4\x93{U\":\xa9=\xc31\nj^\x91i\x89\xc1\xf3\xcbH\xee\u0210\xb2\u06f0\x03\x1c$\xe6\xed`h\xea\x86\xdc\xd3\xc9d\x93\xa2\r\xacY\xfe\x03%\x99V\xd9i\u007fW\x9esp-0\x04Rb\xde\xe3^i\xa9\xe0\xf6\x8e/i@T\xfa\x8d\xc8\x11Z\xc0\x92\xa6\x99\xba\xb9qKc\xce$\xad\x0e\xdb\xdd5\x88[\rh\xde\x80\u0339\x87\u01e6\xb2\xc78\xe7\xf5\x86\xa2\bY\xc3}\xe2\x02\x99\xed\xa1+\\\x92\xc7\x01\xd1\xef\x00\x8c\xd9\x04\x83\xf6\x94z\xb6\xb7\xf6QX\xd6\b\xb9\xe8\x9dd\xa2\x13%\x91\xd58^\xc5l\x9cJ\xd2f\x1e\xe8\x10\xbc\xef\a\xa1|c\x10<\xf0\xea[\xa9\x1c\u038e[\x00\x06\xa6z}\x82\xcc\xeb\x1a\x1e\xe5\xc1\x1d\xf0\x01q\x95\xabr\x85o\xbe\bY\xcbN\x8e\x87Tz\xe87Ko-A!\xae\x15)\xc8\b\xc1\x10c\x06\u04a4\xab\x81\xbc>\x06\xda\xdfo\x0f\xe1l\x8dK_\x96\xfbd\x14\xd8M\xd4M\x03)&\u0787\x1fd\xe8\u007fz~\xad\u007f\x034}\xdb\x15\x883\x1c\xe1J\a/\xafR*`y\xd2/\x95*\x18\x8c\x82\xf2\x8c\xec~\xa27Y\x1d\xa1\u00b6\x80\xa0\x89\x9f4\x1c \x91\x8f\xc7\xdc\x18\x85\x12I\x85\xec\x04\x01\t$\x1d=\xa2\xb0\x1c\xb1&/\xc1\x93,\x0f\u0203\xbd\x10\r\xe0\u0501\x8a8=\xab\xa5^\x0e\xc4Zk(\x9dN\x80\xd7\xd1\xe2\xd8\xe4\xe1\t\xa9\xfa\xd37)\xa7\u06e6J8F\xe4\x87\uf9d5\x06Rht\xe50\xee\x95\u06b52\b\x06\xd2tX\u07ccC\vTN\xa2\x9a\xc0\xbb\xaaKUn}KTNQ\xce\xc2z\x89\xb5g\xb9\x02\"|q\xdfL\xa8\x15\xba\xb8v\x81%\x87x\x11>E\x10\x97\n\xc8\x0e]\u06bd\x19N9c\xbf\xc0\xe8\x89d\x82\xd9\xeb)\xaf\u01e2\n\x843\xef\xea\xa1\x06\xdbL\xf4\xd6-E\xe7\xcd6\x91\xb7\x1b\u0417fh\xfa\xba\x15\x17\x84\x9a\xb6\xd5s\xfb\x18+\xcb\xc5`0@\x02z\v\u026c\ua143\r\xb5\u058e\xc9uU#\xa5\xf7B\xd4\x0e\x03\xe8^\x10B^\xc1O\x80k\xc67\xe02\xc2\xf5\xaf/Ej\x9d\xb4\xbcp\xb2\xc1\xac\xa5\x83\n\x1d\x82\x11\x81&\xbe\x1c\x16[Rh1\xd6\bQ\xe8[\xe73\xbb\xdb\v\xe81\xcf\xea\x87\xe9/6\u04a08sF,\xf02\xd9|;=\x885A@\x0e\x13\xad\x9b\xac\xb8A\x8ayX\t\x0e`\x88\u048b\xcc\x13\x16\xb0\xec\xe4\U00064384\r!{\x12\a\x88%\x03s\xc0\xe8\x80q\xd3jU(\x97\xf0\x18\x85\xedV\xf3\xadw\x98s\ud6a0A\x9ddh;\xf9\x15\xb8\x8c\xb2f\xfe\x92B\x8c\x9aW4Y\xdb'L\xce\t\xee*3+\xc7\x14U\x113I\xb7\x0f3\xcc\x1f\xfce\xb2\xc1e\xa7\xc7\x02.K\xa0\xaa\xea\xeb\x93\xde\xe8P\xc2V\xd4\x18\xa3\x81E\xec7\x8f\xdc\xed\x04P\xb40p_\x13\u04ea\x0eH\x8dz\x84\x90\x90\x9f\x87\xa0\xf0`\xdap\xf4\u007fa\b\xe9\xbc\a\xb7=\xd9\u02ed\x8eN\x00\xea\xf4\x1c\xb3\x89{-\u027b\x03E`5\u06ccWV\x8d\xbe*El\xfamSv/$\x84\x02f:\xd4\x0ey\x059\xb0\xec\x15\x83\x83\xcc\xe0\xfc\xdf \xec\\\x1c+\xb9\xab\xb8P{pE\x8d\xc5u*k\xf7\x16\x8f\xb9y\xd6\xc4d\\\xe8\xc3\x14+\x99(?}Q\xb5\x11\bO\xdd\xd7\xd1\x14\xbaP\x13\xa5\xdcR\xd0\x1dA\a\x8e\\\xbf\xa7\xf3\xb8hx\x85\x15@\\S\x80z\xeb\x873\x91\u04a8\xe1\xf5D7\xe64\xf9v\x9e\xb0g\xed\xda\xcc70\x03[&b\x90\xc2\u8eeb\x82j{\xf4\x9a\xcf\\\xea\xaaXm-\xb0\v>@\xb3\x10\xfa[\u0289\x85\x9ep\x9f$U_9\x97b\xabKVC\xe6^XQ\xd1\x12\x82\u07ac\x9cI]&\x1b\x12\xe1\xf3\xbe\xfacM\t\xfex\x9d,\xe4\xc6:d\xc0\x8b\xf8\x0f\f\x16\xd26)\xc4(r\x9c\xc5\u0732\xf8(\x96^\xb1\xd0Fg\x1d!\xfe\xa8\xbe\x83\xf1S?i\x84\x91Bc\xcabB\u0298_\x82\"\xed\x0fSj\xacd\xc1\xe5\u028c\v\xdb\x0ekj\x94\x94\x19F\x02\x9a\x11\xec\xeax\x12\x81\f\xf6y\xc2h\x14\v7N\x90=d\xe7\x00\x8b\x05\x1c\xc0z\xec\xd0\x03\xd0B\xe8\x11\xdd\x11a\x81\xe0\xc4\\\a-\xd2}9\x98\x105ya\xe3(B\xc6\u04b19\f\x0e\x80\x8b\x8a\xe1\xa9\x11\xa4\x8e\xc1L\xc1\x95\xa6}\x9f\x17\xa6a\x10\x92\x8a\xac\u03b04\r\x90\u068d\x18R\xca\xe8-\xad\x15+q\x1cBa\rW\xf8\x82\x06\x83t\x17\x0eI\x94\xed\x01R\xe2t&|\xaf\x16\x87\xa0]~\xc2\xd0`\xcc\x1d\xf92Z\x9d\x8eWd\xa0,\xa3\xf1\xb9\xac \x95\t\xcb\x1a\xb4\x06\xe1\t\xd3R\x92M\xcd\xfd\xe7\xb9\x14+\xf9\x9c\xb2\x83\xe2QBNq^@-J~\x85\x83\xa09_2\xb7\x00\xe0\x85b\x03\xc3\t\x10p1g{\x80\xe33\xb68'\x98Aha\a@`\xb8\xe7\xcc\x03jy\x82.\xa4f\t\x12I\r(\xb4\xeb\xc3ss\x00\xf8]\xae\xa8\x19\xa5n\xc7&\u06cf\xf3g\xa5\xe6$p\xb9\xf1BQ\xad*\x98&\x84\u0289\xaa\xf2\xd4ra\xc4\x03\xc1o\x10J\xaa\x1e\x86$A\xed\xbde,njo\x8b\n\xb9\xbef\xd8\x18\xb5M\xf6\xbcW\v\u02f3\x884\b\x140M\x0e\xe9\xaf\u03a4\u0753\x06\xf4\x19\x90I\xa4\x01\x89\u052aF\xdft\x8d(A\x88\xfb\xe6\xfc\xb1\x9ee\x17\xca~\x04\xf3\x8c\xab5\x94\x96\x85\xb6T\x0e\x1c\xb9\x8a!\xb7\xb0\x96#\x84\xadz&\xa4\xe2\xb0'\xbc\xb5\xa3\x12n\x99\x1eE\xb1\xa6\xdc\t-,\xb1\xe7S>\xb3\xd3.\xdc\fTU8tIO\x8a\x18\x88\x03\x90\xa0\xbap\x92A^r\x8awA\xd69`\xcbZ\x90\xd0\x16\xae![\x9f{\x9d\xacx\xb4\xd39\x1e\x16\" \xd9P\xb2\xc8q\xf9\xf3\u06be\xe3\xfa\xb1\xfe\xe7s\blIA\xd7I\x9f\x12]`\x9e\x00p\u0357\x16\x11\n\xe0\xe2-\x8ex\x8cc[\x8dQ\xc9\\\xf6R\xa9\xe3\x9f\xfd\u047f\x94\x96J\x84i\xd6<\u063aXho\x0fJ\xa8\xd9\xd5a \u079e\xfb\xb81\x110\x0e\x14\t\x10\x15\x84\xa0\xe1\f\x8b\u0328\xea\xb6\"|\x90@\xffv\xaf\xa9`=u\x0f\u0105T\xe9f#|*\xd5\bT\xb3\x91-\xa3\xc1g\x8a\x1a\x14\x99\x10>_z\xaf\xf9\x95\x00\xbe*U3\x8b\x86\xf1CV\xe3\xa1A\xa9\xa23\xa4\xe2a\"g\x11q\x82\x93\v\xd0\xf7\xa2bIr\x91B\x91\x02)\x1d\x02\xb1\x94\xaeO\x0e\xe8\xd5\xc2d\x98\x06\x93\x88\x1a\xed\x10\xac\xfe\x1dyQ\xe4\xd1e!sl \xa6^P\xcf\f\xcd\xd54 \xc6\x15\xfdrP\xe9\x86\xe0\xa1m:\x051\x87\xed@\xf0\xf2\xea\x04\xa0:,\xf8\xe1\xfbO\x15\x19\xf2\xaeZ\xa7*W8I\x04\\\u7e62\x93\fO\xc1\xdcC\x0fA>\x031\xb4P\xae)!KQ\xb9\x1d=\b\\\x94\xfe\xa1Idg\x1f\xd1F\xf5\xf3]\x19\xf9-\xb9(\xc1S\x86\u06e6'7B\x16!\xc2B\u06aa\xa1kncJ\n\xb0gi\x13n\xda;\xd32\x98@\xc5KEo\xc5\x1d\x14\x04\x10\xb9\xf2}\u01ceN\xe8\xcb'\x85H\x91\x00S\xca0\x1e\x89:,\x06\xeb\x82\u0178\xd1&\x00g\xb6D\x1d=iQ$sj\xb9\xf6w\xee\xc0\x19\x80\x13\xf9iP\xfa\x84\xfc\x1f/b\xb8\x11\nQ\x85g\x0e\x94F\xe9\x01\xca\xccO\x1a\xb0C\u9c93[y\x02\xebf^\xd8\"zK\xc1\x15\xaf\xd4\xc0\xf7b^\t\xc6\n\x9cYw\x9e5\u07a0\xba\x17\x84!\xf5\x13\xadW\xbb\u03d5^\xaa\xc1\x94\x92\xb7'~U\xbc\x89\xbb\x9b\x88\uea95M[\xa3\u0235 bR\xa0L*\x9d\xa54\x1c\xa83\xb7\xcctP\xc5\x1f\xaf\x98v\x90\x88\x14W\"\x86N\xfc4\x19}\x92\xa1\x02\x04\xa4\xb1\x9c\x91(\xb0\xb8o\x84\b\xac\xd2Y\xcbAe\x85o\b\x11\xe5v,\x93L\xec\xe5\xf6\x10\x1b\xe6\xf6\u0193Sd\n0\x95\xc1m\xe3a\x1a\x92\xdan\xe8\x9f7\xef\ty\xe9\x8eH~o\x99\xeb|\xf5=\x84\b~\u00f8T\x93_mX0\u048b]$\n\xec_n\xe0\xa5\xe1p)3\xe3=!/\xbf2\x06\f\x8b+Io3\x00s\xbc\xb5RZ\xea\u007f\u0311\xed\xbfRT?\xd3/Y\xda\x04\xceJb:\xa6\xef\v\xd6H\xfc&\xa8\xa0\xcf\x00[a\xc1\x03\xe9E\x00]3\x00|\r\xc2\xc0\x14\xa8\x95A\x83\xe03\xba\xcc \xc7K\xe0A\t\x9dt\xbc\x97\x84\xaa\x85\x10#\x00w\xe5q\xc4W\xcfM\xf6\x1bV\v\x01n\f/\xec%\x9a\xd2\x1a\xd7 \xc1\u0095\xa5\x89WVT*E\u019a\x05FYT\x95\xdd\x11,\xbfI\xc1\u0121\xbe\xee!\xe4W\xfcW\xfc\"\xec\xba\x1f7\x8dV\xfc\xc8.\x96\x0fIT\xc8\"\x05\xed cr\xe0\xaa\xf8 \x9c\v(x\xb0:\x1d\xf8\xa7\x96\u0081d\xcc\nJ\x15\xc0\x02X\u0082\xdf[\x06\x86 _\xe3\x12*\x9a\xb1\x96\x04\x9c\x87\u05c1K\x16H\xee\xba\x04\xd5\xef\xaa\f5\x86\xc0L\xaf\u04ee\x1e\x00C\xb2\xf4\u0486\x9c\x03\x01\xb1\x9c8\xa4\xb6\f\xc7\xf9\x00\x12\x98\xc0\xe3M\x1a*RA\nu\x01\x87\x847t5\xe0\x85\xc0\xdb~\xc1\xb9\x00>\xaa\u050f\xea\t\xc4$\xe0T\xcdA#Gx\xba\a\xc1tx\xf5]P\xddy\xf0\x97\x03\xf4\xbe\x1f\x88`\x91b\xe6\xa2\xf2\xf8\x8f\xd6\x03\\\xa6\x04z\xbfk\x02\xf3\xb0Eo\x04\xda^\xba\xb7\xf4\xad\x11!*@/\xad0\t\xc9\x18\xe5\xc98\x93\xaa,S\ub99dN\xe9 B\x93\xf6\xa9[\xa1\xb7\xfe\x98`F\x84\x92\xfb\x04\xaa\x9a\xb5L\xed\x8b~\xc1=\xab\x04\x03\x8ev\x84\u03b5\xf1Z\x88X?v\b\x10\xb3G\x026\xbb\xb9\r\x9dG\xb0\xba\u85b1n\xb1a\xb8F\xab\xa8\x14\xbf0&de\xf4I\xf4\b&V\xc0\x843\xe0\x16\x8e\xe9\xf07\x16-\x9b\xdf\xe8\xc1\xd2e\x8f\x1cG\xb5\xacHPNR\xb0\x8aZQ\x84y\x96\x1e\x17ZB1%\r\xd4\x05\x020\x95\xe3\u03e1\x9e\f\xb3\xdb\x13\a.\x98\x00\x03\xe6\xa3\xc6X\u032cv\xb4\xd8\xd09!]Z\x8e\xf4\x832T\x10\xb4\x1fb\u06a8\x80\xcb+\xbc,1C\xf3\x923\xf6\x03S\xc3*h\xe5\xe1\x9d \x19\xcd&\xc9\xd5*\xa1qE\xb7\x8f\xfac\xd1{!E\xbfn\r\x1b\x15\x18\x98\x99\x1bk\xb7\x16\x1c\xb7\xa6a\xe1\xb7\xf7\x1f\xde\x00\xac\x03\xbc=\xb3\xb5\xa44\xdc\u063aJ\xa4`\xd0W]\xb2\xc4\x13z\xb3\x0e\u0767\xe8Q\x85\x99\xb9\xab\x9c\x0e_\xa4\x95\r\"\u055a9\xca\xf7\xaf\xa0\x04\xa3\x06eB\xcf$4\x1fb\x05\xc7S ,\xad\u007f\xa0P\x13v\xf3J\xa3n\x85\\\x01O \xfbN\u0656.\an\x9f\xdb&'n-\x96$\xe4\xd7\x12AC\\\xc0\x92\x9a~(d\x87\x80#\xc0\x00A\x9e{\xfe\x9b\xc7`*Zt&\x89\x9d\xb3s$6\xdbff\xe4 6|ne5\x86H!\xab\x87U\xb6f(;\x02C\xf7\xe6Y\b\x12F\x80\xbd8\xdb>\xc0\x97\xb8\xefQ\xbf\xf2\x00s\xa4\xf6K\x85\xe6Ou*\x13\x9a\xba\xa7Ka\xb8\x8e\x8c\xca\x13nn\x11#B\x898A!\x87UQ\xe5\x17k\a\x890\u0148d\xaaJ\xb3\xa1\u0315\xad.\xee\x8d \x16U\xa5\xf1\x0e\x1aCR\xed$I\xc3?A\xcd\x04Rjhyq4\x1d\xb8M\xa2\u0746\x9a\x9b\xd4\xe0\x85\v\x06\u06b1&')\xa7\xf7\xee\xc2kF\xfb\r=\x16\xc9~kX\x80\xf9\x06\u0316\x022\bDm\x80\x8c\xf20\xa2\xb8\x8a\x99\x9d\xf8\x0fA\\\x86\x90\x19R\xc2\x12L\xff\xa8\u0568\xab\xb6\xffQ\xbf\x03\\\x1d\xedF\xff\xf4J\xd5~O7\xa1\xber\x80Yx\x80\xbd\x0f\xdf\t\x15\x9a\x10Q\xd5tE\xe42T\"\xfa\b(q\xf0\xe2p?\x03\xe6\xc1\x8b;1\xa6\xbfD\x1bC\x02\xb4o@\x0f>\u04013\u036cE\xd4V\x14\xbdD\xb6\x9d\xa5\x89\xc1\u010d\xc0\x85\xdf3\x14,\xbdH\xc47\x1fO,\xe4\x1e\xe0\r\xccG\xe9}\x9e\x98\xc1\u0136@\x00\b\xb0\n\u0696\x85\x1f\"\xc3\xe2'\x17\x88\x85\x10\x18]\x16\x82\u00b8\xb63z\x1a\xb4\xc4OX&%\x04\x18\xa3\x19\xf0\xe5`h\x8b\x04\xa9\x9c\xe1\f\x85P\xe0\xc0+\u048f6-\n\x15Q\xa0\f\x10\xa0)\xc0}\x02\xbd\x01`.\x82Rj\xea/\x14`\x13\xc1\xa8\x0e.\x80f\x03\xdc\x01\xb8\xd4\x00nGQp+1\xc4\x11\xf7\xa7\x83GXt\x0e\x98\xfa6\x8e\t\\[Z+\xb9\x84\xa7\xf2\xb5\xabP=\x94\xdb\xe5\xd6D\xf0\xc4\xe2UR\x0e\xea\xffI\u058dc\x1f%\xf5\x867\xca\x1a\u04e3\xc8e\x99f\xb1\xa4~\xd7Q\vf\xf6~)3\xb6\xaf\x83\a\x8c\xdc\xf3\x05(\x80\x82:\fa0;\x9f\x05\xe3M\xe1\xcfX\x9c\x9c\n\xb6w)\x04L\x17\x05\x1a3_\xf9l\u007f\xddMGxbg\xb4\x12\x83\u0100\xe4\xc0\xab\"\xfe9e\u0089\x1f\xf6`R\xff\xd9\x17\x1cA[\x00$\xc0\x8a\xb9O\x1d\xea\xe30\xbf\"\r\x80\x14\x05\x92F\u007f\xb9\xab\x1c\xea\xc6A\"\xb1\r\txF\x9e+\x0f=\xc5\x06\xe8\x0e\xb5n\xe1t\x86]\"\x1dg\x02\x8d\xe7c\xfcEW&\x97\x11\xb6\x82R\xd1\x0e\x94$\x90\x16\x0e\a\xb1q\xcd\x12{\tK\xdb\x1ez\x15\x01!\x1c\x96\x84:\x167\xab%iMa\xea\\\xc1$1\rDb\xef\u053cU\x11\xff\x01\xd5\xc8\x1b\xc620\x02\xe3U\xe7\u007f\xed,\x12\x85A\x96\x88\x83\x0e\xa7\xd1;\v\x8cdD\xfc\xd2\xc2\v}\x11r\fD\xd81\x10\xa3\xddQ\u0341y\xbf\xe9\u0570\x80|\u0148\xa29\x9dJ\xd8c\nK\x01\x9c8dq\xae\xf0\xa1\x10l\xc8\tgNP\xd3k\xab\xdaNm\xb2\xef\xca\x17\xa5_\xcc^\xbbCX:\xdc?\x8b\x81\xabQ\x14\xb5\x90\x18\v*\xbd\u0185j\x17\x18\xc9Q\x94\xd0/-_R\xa1\xc8\v\f\xf5\x9fU\f\xe0\x84^f\xfb\u007f\xe4\n\xe3\x9de\x00\xb0\x02\x9c\xdb&2`\xdd\b\x82F\xa9\x89[\xdd\xf0&b\xcbS\xf2T\xb31\xe1V`\xb1~u\xd4|rU,\x01\xdbH!\b + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`) + +func third_partySwaggerUiFontsDroidSansV6Latin700SvgBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6Latin700Svg, nil +} + +func third_partySwaggerUiFontsDroidSansV6Latin700Svg() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6Latin700SvgBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-700.svg", size: 73575, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6Latin700Ttf = []byte("\x00\x01\x00\x00\x00\x11\x01\x00\x00\x04\x00\x10GDEF\x00\x10\x00\xd2\x00\x00\x8b`\x00\x00\x00\x16GPOS\xf2ZM^\x00\x00\x8bx\x00\x00\x12\xc0GSUB\x00\x15\x00\n\x00\x00\x9e8\x00\x00\x00\fOS/2\xa2\t\xb7\x96\x00\x00{\xa8\x00\x00\x00`cmapmag\xda\x00\x00|\b\x00\x00\x00\x8ccvt K\xe2RQ\x00\x00\x86\x00\x00\x00\x02\x06fpgms\xd3#\xb0\x00\x00|\x94\x00\x00\a\x05gasp\x00\a\x00\a\x00\x00\x8bT\x00\x00\x00\fglyf}]p\b\x00\x00\x01\x1c\x00\x00u\x1chead\xf5\xcd \xd7\x00\x00x\x00\x00\x00\x006hhea\r\x9b\x05a\x00\x00{\x84\x00\x00\x00$hmtx\x9f\xc7I\xb4\x00\x00x8\x00\x00\x03Llocada\x83\"\x00\x00vX\x00\x00\x01\xa8maxp\x03\x17\x02\x14\x00\x00v8\x00\x00\x00 name\x19w4\x0f\x00\x00\x88\b\x00\x00\x01dpost\xa2\xc2\x0f;\x00\x00\x89l\x00\x00\x01\xe7prepeq\u058a\x00\x00\x83\x9c\x00\x00\x02b\x00\x02\x00u\xff\xe5\x01\xd3\x05\xb6\x00\x03\x00\x17\x00]@B\xb0\x19\xe0\x19\xf0\x19\x03\x1f\x19/\x19?\x19\u007f\x19\x9f\x19\x05\xd7\x03\x01\xc6\x03\x01w\x03\x01\x16\x03f\x03\x02\x03\x03\x01\x03\x0e\x96\xd8\x02\x01\xc9\x02\x01x\x02\x01i\x02\x01\x02 \x04\x01\x00\x04`\x04\x02\x04\x01\t\x9b\x13\x02\x03\x00?/\xfd\xce\x01/]q3]]]]\xed2]]]]]]]10\x01#\x03!\x014>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01\xa0\xf43\x01Z\xfe\xa2\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x01\xe5\x03\xd1\xfa\xd9/A(\x12\x12(A/-@*\x13\x13*@\x00\x00\x00\x02\x00\x85\x03\xa6\x03B\x05\xb6\x00\x03\x00\a\x00/@\x1a\x04\x98\a\a\t_\t\x01\x00\x98\x00\x03\x10\x03\x02\b\x03\x06\x00\x01\x01\x01\x01\a\x03\x03\x00?33/]3\x01/^]\xe1]\x129/\xe110\x01\x03#\x03!\x03#\x03\x01\x9c)\xc5)\x02\xbd)\xc5)\x05\xb6\xfd\xf0\x02\x10\xfd\xf0\x02\x10\x00\x00\x02\x00-\x00\x00\x04\xfe\x05\xb4\x00\x1b\x00\x1f\x00\xcd@\x80\x03\x03\x1a\x1a\x18\x16\x1e\x1d\a\x04\x06\x17\x17\x06\x19\x00\x01\x04\x04\x05\xb1\xf4\x18\x01P\x18\x01\x18\x18!\x15\x1f\x1c\b\x04\t\x14\x14\x12\x0f\x0e\v\x04\x13\xb1\n`\x10\x01\x10\x10\f\f\t\xfb\n\x01`\np\n\x02\n\x1c\x01H\r\x01\r\xae\f\b\x04\f\x1f\x00\xe7\x10\x01\x10\xae\x11\x19\x15\x11\xf4\f\x01\xe5\f\x01\x92\f\x01T\f\x010\f@\f\x02\xeb\x11\xfb\x11\x02\x9d\x11\x01[\x11\x01?\x11O\x11\x02\f\x11\f\x11\x05\x17\x13\x06\n\x05\x00/3?3\x1299//]]]]]]]]]\x1133\x10\xe9]22\x1133\x10\xe9]22\x01/]]33/3/]\x10\xec\x1792\x11\x12\x179\x113/]]\xec\x17923\x11\x12\x179\x113/3/10\x01\a!\x15!\x03#\x13#\x03#\x13#5!7#5!\x133\x033\x133\x033\x15\x0537#\x03\xe7/\x01\x02\xfe\xd7M\xdcN\xc2L\xd7J\xee\x01\x15/\xfc\x01!M\xdbM\xc6N\xd7N\xf0\xfd\x1d\xc4/\xc4\x03L\xe8\xce\xfej\x01\x96\xfej\x01\x96\xce\xe8\xd1\x01\x97\xfei\x01\x97\xfei\xd1\xe8\xe8\x00\x00\x00\x00\x03\x00b\xff\x89\x04%\x06\x14\x003\x00<\x00C\x00\xce@F&.@#@\xfb@\x01?@\x01@:\x06\x13\xf4\a\x01\xe6\a\x01\x00\a\x10\a0\a\x03\a\a\x1e\v4\x1b4+4{4\x8b4\x054)\x0f\x00O\x00\x02\x00E\x04=\x14=$=t=\x84=\x05=\x0e\x90\x1e\xa0\x1e\x02\x1e\xb8\xff\xc0@?\v\x0fH\x1e-*AA&9\x14\x14.@\xb6@\x01\x89@\x01@\x13&%@\x0e\x14H%%# &@&P&\x80&\xb0&\x05\x0f&\x01&:\x0e\x13\x13\bP\a`\a\x02\a\a\x05@\b\x01\b\x00/]33/]\x113\x1133/]]33/+\x11\x129]]\x1133\x113\x113\x1133\x01/+]3\xc9]\x10\xde]2\xc9]\x119/]]]3\xc923]]\x113\x10\xc9210\x01\x14\x0e\x02\a\x15#5.\x03'\x11\x1e\x03\x17\x11&'.\x01'.\x0354>\x02753\x15\x1e\x01\x17\a.\x01'\x11\x17\x1e\x03\x054.\x02'\x15>\x01\x01\x14\x16\x175\x0e\x01\x04%5i\x9cf\x89BpbY+*cjm4\b\t\b\x10\x06[\x88[-9j\x98_\x89W\xb6deA\x8d>'_\x8e^.\xfe\xd3\r\x1c+\x1f;8\xfe\x974967\x01\xc9K\x80`>\n\xcd\xc9\x02\f\x16\x1f\x13\x01\b\x15&\x1f\x16\x03\x01>\x03\x04\x03\x06\x02#L^rHK{[9\t\x9d\x97\x05(+\xea\x1a)\x05\xfe\xdb\x0e#J\\rR\x18$\x1e\x19\x0e\xfc\t<\x02\x8e/?\x15\xe9\x060\x00\x00\x00\x00\x05\x00?\xff\xee\x06\xcd\x05\xcb\x00\n\x00\x1e\x00\"\x00-\x00A\x00\x9d\xb51\x18\t\rH?\xb8\xff\xe8@\x0e\t\rH:\x18\t\rH5\x18\t\rH\x1c\xb8\xff\xe8@$\t\rH\x18\x18\t\rH\x13(\t\rH\x0e\x18\t\rH#\xb48\xb5.Y\"\x01\"\x1fV \x01 !\x1f\x10!\xb8\xff\xf0@#\x1f!\x1f!\x15)\xb4.C\x06\xb4\v\xb5\x00\xb4\x15+\xb6=\xb7&\xb63\x19\"\x06!\x03\xb6\x10\xb7\b\xb6\x1a\a\x00?\xe9\xfc\xe9/??\xe9\xfc\xe9\x01/\xe9\xfc\xe9\x10\xde\xe9\x1299//88\x113]\x113]\x10\xfc\xe910\x00+\x01++\x00++\x01+\x00++\x01\x14\x1632654#\"\x06\x05\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\t\x01#\x01\x13\x14\x1632654#\"\x06\x05\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x01;-21/`2-\x01\xbb)V\x84[U\x81W,(U\x82ZV\x83X-\x02\x9b\xfc\xd5\xef\x03+p-21/`2-\x01\xbb)V\x84[U\x80W,(T\x82ZV\x83X-\x04\x00\u007f}|\x80\xfa{}l\xacv??v\xacll\xaau>>u\xaa\x01H\xfaJ\x05\xb6\xfc\x02\u007f}|\x80\xfa{}l\xabv??v\xabll\xaau>>u\xaa\x00\x00\x03\x00R\xff\xec\x05\xc3\x05\xcb\x00-\x009\x00I\x00\x9f@A'G():\x89:\x02:H\x1eG#$-\x04\x00&D\x86D\x02DH\x14\x0267\x0f\x04\x14\x01\xf4\x1e\x01\xd0\x1e\xe0\x1e\x02;\x1eK\x1e\x02\x04\x14\x14\x14\x02(\x1e\x14\x14\x1e(\x03\n\v\x01\x1b\x01\x02\x01\x00\xb8\xff\xc0@\"\t\fH\x00\x00K.G\n\x0267\x0f\x04?\x01?\x19''3-$#G\x04\x01\x19\x043\x05\x16\x01\x15\x00??3?\x12\x179\x129/\x113\x11\x12\x179\x01/\xe9\x113/+3]\x12\x179///]]]]\x11\x12\x179\x10\xe9]\x11\x179\x10\xe9]\x10\xe910)\x01'\x0e\x01#\".\x0254>\x027.\x0354>\x0232\x1e\x02\x15\x14\x0e\x02\a\x01>\x017!\x0e\x03\a%\x14\x1e\x023267\x01\x0e\x01\x014.\x02#\"\x0e\x02\x15\x14\x16\x17>\x01\x05\xc3\xfe\x87aP\xc1tx\u00cbL%Da<&5 \x0e=m\x97ZV\x91i<-Lg;\x01\x04#5\x13\x01=\x0f)6F+\xfc\xeb 9M-\x0273\x06\x02\x15\x14\x1e\x02\x17#.\x03R$JqN\xfa\x8d\x90$HjE\xf8NqJ$\x021}\xf3\xe5\xd3]\xc1\xfe2\xf4w\xec\xe2\xd4^Z\xce\xe1\xf0\x00\x00\x01\x00=\xfe\xbc\x02d\x05\xb6\x00\x13\x00\x18@\v\x06\x0e\xf1\v\xf0\x00\x15\x0e\xf8\x05\xf9\x00??\x01\x10\xde\xe9\xec210\x01\x14\x0e\x02\a#>\x0354\x02'3\x1e\x03\x02d$JqN\xf8EjH$\x90\x8d\xfaNqJ$\x021|\xf0\xe1\xceZ^\xd4\xe2\xecw\xf4\x01\xce\xc1]\xd3\xe5\xf3\x00\x00\x01\x00?\x02V\x04\x1d\x06\x14\x00\x0e\x00#@\x14@\x00\x011\x00\x01\x00\x84\x0e\x94\x0e\x02\x0e\x1f\x06\x01\x06\x06\x00\x00\x00?2/]\x01/]\xcd]]10\x01\x03%\x17\x05\x13\a\v\x01'\x13%7\x05\x03\x02\xb0)\x01u!\xfe\xac\xdf\u3709\xec\xdd\xfe\xae'\x01m)\x06\x14\xfe\x90h\xfc\x18\xfe\xd7y\x019\xfe\xc9w\x01)\x1a\xfah\x01p\x00\x00\x00\x01\x00X\x00\xf8\x04\x10\x04\xb0\x00\v\x00 @\x0e\a\x06\t\xaa\x03\x02\x00\v\t\x00\xad\x06\x04\x03\x00/33\xe922\x01/22\xe92210\x01!5!\x113\x11!\x15!\x11#\x01\xc7\xfe\x91\x01o\xdb\x01n\xfe\x92\xdb\x02d\xdb\x01q\xfe\x8f\xdb\xfe\x94\x00\x01\x00?\xfe\xf8\x01\xcb\x00\xee\x00\f\x00V@A\xa0\x0e\xb0\x0e\xe0\x0e\xf0\x0e\x04/\x0e?\x0e\x02\xab\v\xbb\v\x02<\vL\v\x02y\v\x89\v\x99\v\x03\n\v\x1a\v*\v\x03\v\x00\x97&\x056\x05F\x05\x03\x05/\x06?\x06O\x06\x03\x06\x05\x9c\v@\t\fH\v\x00/+\xed\x01/]3]\xed2]]]]]]10%\x0e\x03\a#>\x037!\x01\xcb\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b\x01\x18\xd76z|{8=\x84\x83}5\x00\x00\x01\x00=\x01\xa8\x02V\x02\xa2\x00\x03\x00\x1a@\r\x02\x05\x1f\x05\x01\x80\x00\x01\x00\x00\xbb\x01\xbd\x00?\xe9\x01/]]\x10\xce10\x135!\x15=\x02\x19\x01\xa8\xfa\xfa\x00\x00\x01\x00u\xff\xe5\x01\xd3\x019\x00\x13\x00&@\x19\xb0\x15\xe0\x15\xf0\x15\x03/\x15?\x15\x02\n\x96\x00\x00\x10\x00`\x00\x03\x00\x05\x9b\x0f\x00/\xed\x01/]\xed]]1074>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02u\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x8f/A(\x12\x12(A/-@*\x13\x13*@\x00\x00\x00\x00\x01\x00\x0e\x00\x00\x03D\x05\xb6\x00\x03\x00(@\x0e\x06\x01\x01\t\x03\x01\x03\x00\x10\x00\x00\x05\x01\x02\xb8\xff\xf0\xb3\x02\x01\x00\x03\x00?/\x01/83\x113/8210]]\t\x01!\x01\x03D\xfd\xdf\xfe\xeb\x02!\x05\xb6\xfaJ\x05\xb6\x00\x02\x00?\xff\xec\x04)\x05\xcd\x00\x13\x00!\x00\x1e@\x0f\x1an\x00#\x14n\n\x1dt\x0f\a\x17t\x05\x19\x00?\xe9?\xe9\x01/\xe9\x10\xde\xe910\x01\x14\x02\x0e\x01#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1632654&#\"\x0e\x02\x04)7y\xbf\x87\u007f\xbc|=7x\xbe\x87~\xbc~>\xfdJVjh[[h5I.\x14\x02\u06f1\xfe\xea\xc2ff\xc2\x01\x16\xb1\xb1\x01\x18\xc2gf\xc2\xfe\xe8\xb2\xfa\xfc\xfa\xfc\xfb\xfd@~\xbd\x00\x01\x00\\\x00\x00\x031\x05\xb6\x00\x10\x00%@\x14\x0f\x01\x0e\x0e\a\x00n\x9a\x01\x01 \x01`\x01\x02\x01\x0f\x06\x00\x18\x00??\x01/]]\xe933/\x11310)\x01\x114>\x027\x0e\x03\x0f\x01'\x013\x031\xfe\xcb\x01\x03\x03\x01\x05\x18\x1e \x0f\xa8\x96\x01\xd7\xfe\x03N\x1aIOP!\x06\x18\x1d\x1e\f\x87\xba\x01w\x00\x00\x01\x00N\x00\x00\x04'\x05\xcb\x00!\x00/@\x19!\bn\x19#\x1f\x0f@\x02P\x02`\x02\x03\x02\b \x0e\v\x14\a\x02 \x01\x18\x00?\xc92?\xc93\x129\x01/]33\x10\xde\xe9310)\x015\x01>\x0354&#\"\x06\a'>\x0332\x1e\x02\x15\x14\x0e\x02\x0f\x01\x15!\x04'\xfc+\x01XAjL*YKO\x92P\xa8-bv\x8eXi\xa7v?\x0254.\x02+\x01532>\x0254&#\"\x0e\x02\a'>\x0332\x1e\x02\x03\xee1UsC\xb1\xb6E\x8f\u0653v\xd0Z-dda+VrD\x1d%S\x86bhf\\zI\x1eai0SG;\x18\x9c*ct\x86Ll\xb1~E\x04oLy[=\x10\x06\x16\xab\x91`\xa3xC'(\x01\a\x18$\x19\f :Q0-I3\x1c\xd9!9L+NX\x13\x1d#\x11\xce\x1f4'\x16/Y\x81\x00\x00\x02\x00\x04\x00\x00\x04=\x05\xb6\x00\n\x00\x18\x008@\x1d\t\x00\x02n\v\a\x9a\x03\x01\x00\x03\x01\x03\x03\x1a\x18\x05\x01\x05u\t\x18\x18\x02\x11\a\x06\x02\x18\x00??3\x129/3\xe12\x01/2\x129/]]33\xe92210\x01#\x11!\x11!5\x01!\x113!54>\x047#\x0e\x01\a\x03\x04=\xb0\xfe\xd3\xfd\xa4\x02m\x01\x1c\xb0\xfe#\x01\x02\x03\x03\x03\x01\t\x12-\x1d\xf4\x01/\xfe\xd1\x01/\xd7\x03\xb0\xfci\xf8\r1>B<-\n*^/\xfe\x8e\x00\x00\x01\x00V\xff\xec\x04\x12\x05\xb6\x00(\x00b@#%&\x05&\x15&\x02&\"$\x05! \x12\x18H\x89!\x01{!\x01]!m!\x02!!\x0f\x18n\x05*\x0f\xb8\xff\xc0@\x17\f\x0fH\x0f\x1bt\x04\x00\x14\x00\x02\x00\x00\n%s\"\x06\x15t\x10\n\x19\x00?3\xe9?\xe9\x129/]\xe9\x01/+\x10\xde\xe9\x129/]]]+\x12933]\x11310\x012\x1e\x02\x15\x14\x0e\x02#\".\x02'\x11\x1e\x0332654&#\"\x0e\x02\a'\x13!\x11!\x03>\x01\x02V^\xa2xDJ\x90\u054a7lcY$#\\cd-\x86\x8c\x89\x8f\x1a;94\x13{7\x03\x04\xfe\b\x18 U\x03\xa6:p\xa7lw\xbd\x83F\n\x13\x1e\x14\x01\v\x14#\x19\x0foylq\x06\n\v\x06B\x02\xe9\xfe\xfa\xfe\xe1\a\x0e\x00\x00\x00\x02\x00L\xff\xec\x04+\x05\xc7\x00)\x00;\x00M@/\x05\"\x01\n(\x01\n\x03\x01!\r\x01\r\r7/n =\x157nP\x00`\x00\x02\x002u\x15\x02\x1b\x12\x1b\x02\x1b\x1b\a*t%\x19\x10u\a\a\x00?\xe9?\xe9\x129/]3\xe9\x01/]\xe92\x10\xde\xe9\x129/]10]]]\x134>\x0432\x1e\x02\x17\x15.\x01#\"\x0e\x02\a3>\x0332\x1e\x02\x15\x14\x0e\x02#\".\x02\x052>\x0254&#\"\x0e\x02\x15\x14\x1e\x02L\x17;e\x9b\u0651\x15230\x13&U+\x87\xaef+\x05\f\x149L_;_\x98i8C|\xb0nl\xbc\x8bO\x01\xfc)C1\x1bY[.L6\x1d\x193K\x02mi\u043f\xa4yE\x02\x03\x06\x04\xf7\t\vCx\xa8f$?-\x1a>v\xacow\xbc\x83EM\x9e\xf1\xe5\x1f?`Bk{$:H%3eQ2\x00\x00\x00\x01\x007\x00\x00\x04'\x05\xb4\x00\x06\x00-@\x1a\v\x01\x01\x01\x04\b\u007f\x02\x8f\x02\x9f\x02\x03\x02\x04\x06\x01\x06\x00\x05\x02s\x03\x06\x00\x18\x00??\xe99\x01/3]/]\x10\xce2]103\x01!\x11!\x15\x01\xcf\x02\b\xfd`\x03\xf0\xfd\xeb\x04\xb0\x01\x04\xc2\xfb\x0e\x00\x00\x00\x03\x00H\xff\xec\x04!\x05\xc9\x00'\x00:\x00N\x00\x9c@j\x05\x11\x01\n\x17\x01\x05\x03\x01\n%\x01\b\x1e\x01\a\n\x01\n\x1e#\bJ\x01Jn\xfc\x05\x01\xe9\x05\x01\xc6\x05\xd6\x05\x02\x05\x05\b0\x010n\x0fP\a@\x01@n\xe2#\xf2#\x02\xc9#\xd9#\x02##\a(\x01(nP\x19`\x19\x02\x19\x1e\n\n6\x016\xebE\xfbE\x024EDEdE\x03\aE\x01EE\x00-v\x14\x19;v\x00\a\x00?\xe9?\xe9\x119/]]]\xc9]99\x01/]\xe9]3/]]\xe9]\x10\xde\xe9]3/]]]\xe9]\x1299]]10]]]]\x012\x1e\x02\x15\x14\x0e\x02\a\x1e\x03\x15\x14\x0e\x02#\".\x0254>\x027.\x0354>\x02\x03\x14\x1e\x0232654.\x02/\x01\x0e\x03\x13\"\x0e\x02\x15\x14\x1e\x02\x17>\x0354.\x02\x025[\xa2zH(F`8:oV4H\x82\xb5mv\xb8~A,Lf:1V?%I|\xa2v\x1a3L2ih#7F#\x16,H3\x1c\xcd!9)\x18\x19+9 \x1f8+\x1a\x18*:\x05\xc9,X\x84YBkWD\x1c\x1fL_vI[\x94h86d\x92[Kx`J\x1c\x1fIYlAW\x83Y,\xfb\xbc(C0\x1bcQ*C90\x16\x0e\x163=H\x038\x14&8#*=/%\x12\x10&1>(#8&\x14\x00\x00\x02\x00?\xff\xec\x04\x1f\x05\xc7\x00)\x00;\x00G@*\n\"\x01\x05(\x01\x05\x03\x01'\r\x01\r\r \x157n\x00=/n 2u\x1d\x1b\x01\x06\x1b\x01\x1b\x1b\a*t%\a\x10u\a\x19\x00?\xe9?\xe9\x119/]]\xe9\x01/\xe9\x10\xde\xe92\x119/]10]]]\x01\x14\x0e\x04#\".\x02'5\x1e\x0132>\x027#\x0e\x03#\".\x0254>\x0232\x1e\x02%\"\x0e\x02\x15\x14\x1632>\x0254.\x02\x04\x1f\x17;e\x9b\u0652\x15230\x12%U,\x87\xaef+\x05\r\x148L`;_\x98i8C|\xb1nl\xbc\x8aP\xfe\x04)D1\x1bZ[.L6\x1d\x193K\x03Fi\u047e\xa5xE\x02\x03\x05\x04\xf8\n\vCy\xa8e$>.\x1a>v\xacow\xbc\x83FM\x9e\xf2\xe5\x1e?aBj|$:H%3eQ2\x00\x00\x00\x00\x02\x00u\xff\xe5\x01\xd3\x04s\x00\x13\x00'\x000@\x1f\xb0)\xe0)\xf0)\x03/)?)\x02\x1e\n\x96\x14\x00\x00\x10\x00`\x00\x03\x00#\x9b\x19\x10\x05\x9b\x0f\x00/\xed?\xed\x01/]3\xed2]]1074>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x114>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02u\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x8f/A(\x12\x12(A/-@*\x13\x13*@\x03g/A(\x12\x12(A/-A)\x13\x13)A\x00\x00\x00\x02\x00?\xfe\xf8\x01\xd3\x04s\x00\f\x00 \x00k@P\xab\f\xbb\f\x02<\fL\f\x02y\f\x89\f\x99\f\x03\n\f\x1a\f*\f\x03\f\x01\xa0\"\xb0\"\xe0\"\xf0\"\x04/\"?\"\x02\x17\x96\x00\r\x10\r`\r\x03\r\x01\x97&\x066\x06F\x06\x03\x06/\a?\aO\a\x03\a\x1c\x9b\x12\x10\x06\x9c\f@\t\fH\f\x00/+\xed?\xed\x01/]3]\xed/]\xed]]\x113]]]]10%\x17\x0e\x03\a#>\x037\x034>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01\xbc\x0f\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b/\x1b0@%#?0\x1c\x1c0?#%@0\x1b\xee\x176z|{8=\x84\x83}5\x02\xdb/A(\x12\x12(A/-A)\x13\x13)A\x00\x01\x00X\x00\xcb\x04\x10\x05\x00\x00\x06\x00`@A4\x05D\x05d\x05t\x05\x04\x06\x05\x16\x05\x02\x03\x00\b\x01\x02\x01\x05\x05\x035\x06E\x06\x02\x16\x06&\x06\x02\x06/\x00O\x00\x02\x00:\x04J\x04\x02\x19\x04)\x04\x02\x00\x04\x00\x03\x01 \x030\x03@\x03\xb0\x03\x04\x03\x00/]q33]]/]2]]\x129=/33\x01\x18/\x10\xce210]]%\x015\x01\x15\t\x01\x04\x10\xfcH\x03\xb8\xfd}\x02\x83\xcb\x01\xb6\x8f\x01\xf0\xf0\xfe\xc3\xfe\xe7\x00\x00\x00\x02\x00X\x01\xa2\x04\x10\x04\x00\x00\x03\x00\a\x002@\x1e\a\x02\t\x04\x00I\x04\x01\x04\xad\x90\x05\x01\x05\x05I\x00\x01\x00\xad \x01@\x01\x80\x01\xe0\x01\x04\x01\x00/]\xe9]3/]\xe9]\x01/3\x10\xce210\x135!\x15\x015!\x15X\x03\xb8\xfcH\x03\xb8\x03'\xd9\xd9\xfe{\xdb\xdb\x00\x00\x00\x00\x01\x00X\x00\xcb\x04\x10\x05\x00\x00\x06\x00`@A;\x01K\x01k\x01{\x01\x04\t\x01\x19\x01\x02\x05\b\x03\x06\x05\x04\x01\x01\x035\x00E\x00\x02\x16\x00&\x00\x02\x00/\x06O\x06\x02\x06:\x02J\x02\x02\x19\x02)\x02\x02\x06\x02\x00\x03\x01 \x030\x03@\x03\xb0\x03\x04\x03\x00/]q33]]/]3]]\x129=/33\x01\x18/3\x10\xce10]]\x13\t\x015\x01\x15\x01X\x02\x83\xfd}\x03\xb8\xfcH\x01\xba\x01\x19\x01=\xf0\xfe\x10\x8f\xfeJ\x00\x00\x00\x02\x00\x19\xff\xe5\x03u\x05\xcb\x00'\x00;\x008@\x1e\x03\x1a\x13\x1a\x022\x96(('\x00\x00\x12\vH\x1c=\x12\v\x17\x00-\x9b7\x16\x11\x0eM\x17\x04\x00?\xe93?\xfd\xce\x119\x01/\x10\xde\xe9\x119/\xc93/\xed10]\x0154>\x027>\x0354&#\"\x06\a'>\x0332\x1e\x02\x15\x14\x0e\x02\a\x0e\x03\x1d\x01\x014>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01\b\x15+D0*:$\x10MOE\x9fUf+emp6f\xa4r=\x1c7S7*5\x1e\v\xfe\xd7\x1b0A%#?0\x1c\x1c0?#%A0\x1b\x01\xe5J3SKG&!438%9J:*\xdd\x19-#\x141^\x86V?cUO,!1,/ <\xfe\xaa/A(\x12\x12(A/-@*\x13\x13*@\x00\x02\x00f\xfff\x06\x89\x05\xc9\x00U\x00f\x00U@,V_\x15\x01\x15\x15J-BB-\x00_\n@#\x01##7\x00h7J(Y\x05?\x10O\x10\x02\x10\x10E2Qb\x1a\x1aQ\x04\x0232\x1e\x02\x17\x03\x06\x14\x15\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x15\x14\x1e\x0232>\x027\x15\x0e\x01#\"$&\x0254>\x0432\x04\x16\x12\x01\x14\x1632>\x02?\x01.\x01#\"\x0e\x02\x06\x89-\\\x8b^&C8)\v\x0f\x132>K,S\x81X.>t\xa6g-`YN\x1c\x15\x02\r\x15\x1b\x0f#4\"\x12L\x87\xbam\x99\xe9\x9dQF\x8a\u02848vuq3^\u50b5\xfe\xe3\xc4h6f\x93\xbc\u205e\x01\n\xc1l\xfc>L?*='\x15\x03\f\x146\x1c;R3\x17\x02\xf0_\xba\x93[\x13#/\x1c\x19/$\x159i\x93Yg\xac}E\n\x10\x14\n\xfe]\x16*\x06*6\x1f\f6\\{E\x80\u020aHf\xb7\xfa\x95\x8a\u0551K\x0e\x18\"\x14\xc0*1g\xc2\x01\x19\xb2|\xe3\u00dfq=e\xbd\xfe\xf2\xfe\xdapc'Gc=\xdd\x05\x062Ri\x00\x00\x00\x02\x00\x00\x00\x00\x053\x05\xbc\x00\a\x00\x16\x00\x8d@\f\x06\x06&\x066\x06F\x06v\x06\x05\x06\xb8\xff\xf0@?\x15\x18H\t\x05)\x059\x05I\x05y\x05\x05\x05\x10\x15\x18H\x02\x16\x03\b\x01\x00\x06\x05\x0e\x0e\x04\t\x00\x19\x00\x02\x00\x00\a`\ap\a\x90\a\x04\a\x10\a\a\x18\u007f\x18\x01\x10\x18\x01\x06\x03\x16\x03\x02\x03\x04\xb8\xff\xf0@\x0e\x04\x02_\x16\x16\x1b\x0e\x01\x0e\x05\x03\x04\x00\x12\x00?2?3]9/\xe9\x01/83]]]\x113/8]3]\x129\x1133\x1299\x129910+]+]!\x03!\x03!\x01!\t\x01\x03.\x03'\x0e\x05\a\x03\x03\xfad\xfe\be\xfe\xc7\x01\xdb\x01{\x01\xdd\xfe\x1b^\x06\x18\x1b\x18\x05\x04\r\x11\x12\x10\r\x03]\x01\\\xfe\xa4\x05\xbc\xfaD\x02`\x01@\x12Rcd#\x16\x0254&+\x01\x19\x0132>\x0254.\x02#\xb8\x01\xac\x8a\u040cG\x1e:S67_G)F\x83\xbbv\xfd\xfc\x016\xa1:N0\x15ir\x93\xb6=S3\x16\x165V@\x05\xb6'W\x8dg>lR7\t\n\f-OxVd\x9dm:\x03s\x15*?*TI\xfd\xc5\xfe\x83\x1c4J-)C0\x1a\x00\x00\x00\x00\x01\x00w\xff\xec\x04\xd1\x05\xcb\x00#\x00B@+e\r\x01\n!\x1a!Z!j!\xba!\x05 \x0eg%\xb0%\x01\x9f%\x01`%\x01\x1f%\x01\x05[\x18f$\x00_\x1d\x04\n_\x13\x13\x00?\xe9?\xe9\x01\x10\xf6\xe9]]]]\x10\xe6210\x00]]\x01\"\x0e\x02\x15\x14\x1e\x023267\x11\x0e\x03#\".\x01\x0254\x126$32\x16\x17\a.\x01\x03%Y\x89]0+Y\x8b`Y\xb3i0^bg;\xa9\xf8\xa2NZ\xae\x01\x00\xa6m\xdbddR\xa6\x04\xc9E\x81\xb9su\xb6}A(%\xfe\xfc\x14\x1c\x12\tl\xc4\x01\x14\xa9\xa6\x01\x15\xc8o70\xfc':\x00\x00\x00\x02\x00\xb8\x00\x00\x05#\x05\xb6\x00\f\x00\x17\x00&@\x15\rZ\x00g\x19?\x19\x01\x14Z\x06d\x18\x13_\a\x03\x14_\x05\x12\x00?\xe9?\xe9\x01\x10\xf6\xe9]\x10\xf6\xe910\x01\x14\x02\x06\x04#!\x11!2\x04\x16\x12\x054.\x02+\x01\x11326\x05#e\xbf\xfe\xeb\xb1\xfe\u007f\x01\xac\xa1\x01\x03\xb8c\xfe\xc61]\x87W\x8fr\xc4\xc5\x02\xe9\xb9\xfe\xe9\xbb^\x05\xb6\\\xb5\xfe\xf4\xb8z\xb1t8\xfcH\xf0\x00\x01\x00\xb8\x00\x00\x04\x02\x05\xb6\x00\v\x00F@*\b\x04\x00g\r\x06\nZ\x01d\f\t_\xaf\x06\x01\x88\x06\x01L\x06\x01;\x06\x01\x19\x06\x01\b\x06\x01\x06\x06\n\x05_\x02\x03\n_\x00\x12\x00?\xe9?\xe9\x129/]]]]]]\xe9\x01\x10\xf6\xe92\x10\xe62210)\x01\x11!\x15!\x11!\x15!\x11!\x04\x02\xfc\xb6\x03J\xfd\xec\x01\xef\xfe\x11\x02\x14\x05\xb6\xfe\xfe\xbf\xfe\xfe\x87\x00\x00\x00\x01\x00\xb8\x00\x00\x03\xfe\x05\xb6\x00\t\x00W@:\b\x9f\x03\x01\x03g\v\x1f\v\x8f\v\xaf\v\x03\x06\x00\\\x01d\n\t_\x9f\x06\xaf\x06\xbf\x06\xdf\x06\x04\x88\x06\x01o\x06\x01L\x06\x01;\x06\x01\x19\x06\x01\b\x06\x01\x06\x06\x00\x05_\x02\x03\x00\x12\x00??\xe9\x129/]]]]]]]\xe9\x01\x10\xf6\xe92]\x10\xe6]210)\x01\x11!\x15!\x11!\x15!\x01\xe9\xfe\xcf\x03F\xfd\xeb\x01\xf0\xfe\x10\x05\xb6\xfe\xfe\x87\xfd\x00\x00\x00\x00\x01\x00w\xff\xec\x05'\x05\xcb\x00'\x00D@(''\f%\\\x14\x90\x01\x01\x01)`)p)\x02\x1f)\x01\x1d[\ff('_+\x00\x01\x00\x00\"\x18_\x11\x04\"_\a\x13\x00?\xe9?\xe9\x129/]\xe9\x01\x10\xf6\xe9]]\x10\xde]2\xe9\x129/10\x01!\x11\x0e\x03#\".\x01\x0254\x126$32\x16\x17\a.\x01#\"\x0e\x02\x15\x14\x1e\x023267\x11!\x02\xe3\x02D:v\u007f\x8bN\xa4\xfd\xadZd\xc3\x01\x1d\xb8u\xe0]gD\xab^f\xa3t>+\\\x91eB[(\xfe\xeb\x035\xfd\n\x13\x1f\x15\fa\xbf\x01\x19\xb8\xac\x01\x16\xc3i2(\xf8\".G\x82\xb8ql\xb3\x82H\f\b\x011\x00\x00\x01\x00\xb8\x00\x00\x05\x14\x05\xb6\x00\v\x00G@+\t\x01Z\x00e\r\x8f\r\x01\x00\r\x01\b\x04Z\x05d\f\x03_\x88\b\x01L\b\x01;\b\x01\x19\b\x01\b\b\x01\b\b\n\x06\x03\x05\x00\x12\x00?2?39/]]]]]\xe9\x01\x10\xf6\xe92]]\x10\xf6\xe9210)\x01\x11!\x11!\x11!\x11!\x11!\x05\x14\xfe\xcb\xfe\x0f\xfe\xca\x016\x01\xf1\x015\x02w\xfd\x89\x05\xb6\xfd\xc3\x02=\x00\x00\x00\x00\x01\x00B\x00\x00\x02\xdb\x05\xb6\x00\v\x00;@#\x9f\r\xff\r\x02\r@\r\x10H0\r\x01\b\v\v\nZ\x05\x02\x02\xc0\x03\x01\x03\t\x04_\x06\x03\n\x03_\x00\x12\x00?\xe92?\xe92\x01/]3\x113\xe92\x113]+]10)\x0157\x11'5!\x15\a\x11\x17\x02\xdb\xfdg\xb2\xb2\x02\x99\xb2\xb2\xb0R\x03\xb2R\xb0\xb0R\xfcNR\x00\x00\x00\x01\xff9\xfeR\x01\xee\x05\xb6\x00\x13\x004@#\x06\x11\x16\x11\x02\x04\x04\fZ\x0fe\x15\x1f\x15o\x15\u007f\x15\x8f\x15\xaf\x15\x05\r\x03\a\a\x17\a'\a\x03\a_\x00\x00/\xe9]?\x01]\x10\xf6\xe12/10]\x03\"&'\x11\x1e\x0132>\x025\x11!\x11\x14\x0e\x02\x02Ab\"%Q0.O;!\x016I\x83\xb6\xfeR\r\t\x01\x02\b\f\x141R>\x05\x8b\xfa\u007f~\xb6w8\x00\x01\x00\xb8\x00\x00\x05\x12\x05\xb6\x00\f\x00r@N9\x02y\x02\x02\x1d\x03\x01\t\n\x19\nI\nY\n\x04\t\x01\x19\x019\x01I\x01Y\x01y\x01\x06\n\v\v\x01d\x00\x01\x00\x00\x01\x00\x10\x00\x00\x0ei\x02\x01\x05\f\x15\fE\fU\f\x04\x02\b\f\x03\x04Z\x05d\r$\b\x01\x02\b\x01\n\x06\x03\x05\x01\x12\x00?3?3\x1299]\x01\x10\xf6\xe9\x172]]\x113/8]]33\x11310]]\x00]])\x01\x01\a\x11!\x11!\x117\x01!\x01\x05\x12\xfe\xa0\xfe\xb0t\xfe\xca\x016z\x01N\x01X\xfe-\x02`V\xfd\xf6\x05\xb6\xfd@\xcf\x01\xf1\xfdm\x00\x00\x00\x00\x01\x00\xb8\x00\x00\x04\x02\x05\xb6\x00\x05\x00)@\x19/\x04?\x04\x8f\x04\xaf\x04\x04\x04\a\x1f\a\x01\x03Z\x00d\x06\x01\x03\x03_\x00\x12\x00?\xe9?\x01\x10\xf6\xe9]\x10\xce]103\x11!\x11!\x11\xb8\x016\x02\x14\x05\xb6\xfbJ\xff\x00\x00\x01\x00\xb8\x00\x00\x06\x96\x05\xb6\x00\x1d\x00\x8d\xb5\x10\x18\t\rH\r\xb8\xff\xe0@Y\t\rHG\x1d\x016\x1d\x01\a\x1d\x17\x1d'\x1d\x03I\x00\x01;\x00\x01\t\x00\x19\x00)\x00\x03\x1b\x10\x88\x13\xa8\x13\xf8\x13\x03\x13\x10\n\rH\x13]\x1d\x00\x0e\x0e\v\x12e\x1fX\x02\xb8\x02\x02\x02\r6\nF\n\x02\a\n\x17\n'\n\x03\n^\vd\x1e\x1c\x02\x02\x10\f\x03\v\x0e\x13\x03\x00\x12\x00?\x172?33/3\x01\x10\xf6\xe9]]22]\x10\xf6\x119\x1133\xe9+]2210]]]]]]++!\x01#\x16\x17\x1e\x03\x15\x11!\x11!\x013\x01!\x11!\x114>\x02767#\x01\x03\x04\xfe\xbf\t\x06\x04\x02\x03\x03\x01\xfe\xeb\x01\xa6\x01<\x06\x01P\x01\xa6\xfe\xdf\x01\x02\x03\x01\x04\x03\b\xfe\xa6\x04{\\V%NLF\x1c\xfdX\x05\xb6\xfb\xa2\x04^\xfaJ\x02\xb4\x1aBJL$T[\xfb\x87\x00\x00\x00\x00\x01\x00\xb8\x00\x00\x05\x8b\x05\xb6\x00\x17\x00\x85@,\x01 \x0e\x18H9\x01I\x01\x02\v\x01\x1b\x01+\x01\x03\x0e\x01I\x16\x01\x16\b\t\fH\x16^\x17e\x19\x00\x19\x10\x19 \x19\xb0\x19\xf0\x19\x05\x19\xb8\xff\xc0\xb3\r\x10H\f\xb8\xff\xe0@\x15\x0e\x18H6\fF\f\x02\x04\f\x14\f$\f\x03\x03\fF\t\x01\t\xb8\xff\xf8@\x10\t\fH\t^\nd\x18\x16\x02\v\x03\x0e\n\x00\x12\x00?22?33\x01\x10\xf6\xe9+]22]]++]\x10\xf6\xe9+]22]]+10)\x01\x01#\x16\x17\x1e\x01\x15\x11!\x11!\x013&'.\x035\x11!\x05\x8b\xfew\xfd\xc1\t\x06\x04\x04\x05\xfe\xeb\x01\x87\x02>\x06\x03\x04\x01\x03\x02\x01\x01\x16\x04RMLA\x8f9\xfdP\x05\xb6\xfb\xb9LJ CC>\x19\x02\xb4\x00\x00\x00\x00\x02\x00w\xff\xec\x05\x96\x05\xcd\x00\x13\x00'\x00(@\x17\x1e[\x00g)/)?)\x02\x14[\nf(#_\x0f\x04\x19_\x05\x13\x00?\xe9?\xe9\x01\x10\xf6\xe9]\x10\xf6\xe910\x01\x14\x02\x0e\x01#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x05\x96O\xa2\xf7\xa8\xa8\xf7\xa1OO\xa2\xf7\xa9\xa8\xf6\xa1O\xfc (S~WY\u007fQ''Q~XW\x80S(\x02\u0769\xfe\xea\xc6ll\xc6\x01\x17\xaa\xaa\x01\x15\xc4kk\xc5\xfe\xeb\xabs\xb7\u007fDD\u007f\xb7ss\xb7\x80DD\x80\xb7\x00\x00\x00\x00\x02\x00\xb8\x00\x00\x04m\x05\xb6\x00\b\x00\x17\x00=@&\x06\x16\x01\x04Z\t\x19\x1f\x19?\x19_\x19\x8f\x19\xaf\x19\x05\x00\x10Z\x11d\x18\x00_\x00\x0f\x01\x0f\x0f\x10\b_\x12\x03\x10\x12\x00??\xe9\x119/]\xe9\x01\x10\xf6\xe92]\x10\xde\xe910]\x0132654&+\x01\x05\x14\x0e\x02+\x01\x11!\x11!2\x1e\x02\x01\xee=\x83\x85w\u007fO\x02\u007f:\x85\u0660G\xfe\xca\x01\x96\x8d\u0345@\x03\x06humh\xca`\xb0\x86P\xfd\xf8\x05\xb6?u\xa9\x00\x02\x00w\xfe\xa4\x05\xc1\x05\xcd\x00\x1b\x00/\x00W@8\x16\x05&\x056\x05\x03\x04\x05\x01\x05\b\x12&[\x00g1/1?1\x02\x1c[\x12f0;\aK\a[\a\x03)\a\x01\v\a\x01\a\x06\x10\x06\x05\r+_\x17\x04!_\r\x13\a\x00/?\xe9?\xe9\x129\x01/83]]]\x10\xf6\xe9]\x10\xf6\xe9\x1299]]10\x01\x14\x0e\x02\a\x01!\x01\"\a\x06\"#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x05\x96'OwQ\x01i\xfer\xfe\xf4\a\x06\x05\v\x04\xa8\xf7\xa1OO\xa2\xf7\xa9\xa8\xf6\xa1O\xfc (S~WY\u007fQ''Q~XW\x80S(\x02\xddw\u046c\x86,\xfem\x01J\x01\x01l\xc6\x01\x17\xaa\xaa\x01\x15\xc4kk\xc5\xfe\xeb\xabs\xb7\u007fDD\u007f\xb7ss\xb7\x80DD\x80\xb7\x00\x02\x00\xb8\x00\x00\x05\n\x05\xb6\x00\b\x00\x1e\x00~@P\t\x1e\x01\t\x1d\x01\x05\x0f\x01\x1e\x15\x1a\x04\x01\x04Z\x04\x15D\x15\x02\x15\x0f\x10\x01\x10\x10\x1d\x00\x1c\x01\x1c\x10\x1c\x1c \x1f \x01\x00\nZ\vd\x1f\x15\f\xbb\x00\x01\xa9\x00\x01\x88\x00\x01g\x00\x01L\x00\x01;\x00\x01\b\x00\x01\x00`\t\t\n\b_\f\x03\x1d\n\x12\x00?3?\xe9\x119/\xe9]]]]]]]\x129\x01\x10\xf6\xe92]\x113/8]39/]9]\xe9]\x11310]]]\x0132654&+\x01\x19\x01!\x11! \x04\x15\x14\x0e\x02\a\x16\x17\x1e\x02\x1f\x01!\x01\x01\xeeT\x81px~O\xfe\xca\x01\x90\x01\x19\x01\f(CW0oX&G8\x12\x11\xfe\xa8\xfe\xc3\x03-gdhX\xfdy\xfd\xcf\x05\xb6\xd9\xddKz_G\x18\xb2\x8c\x0254.\x02'.\x0354>\x0232\x1e\x02\x17\a.\x03#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x03\xd9C\x81\xbbyj\xc5T0bee23I-\x15#?Y7.reDAx\xabj5ecd5d-NJG$NS\x197W>K~[2\x01\x96b\x9do<,,\x01 \x17+\"\x14\x17)9\")?74\x1d\x18De\x8fdb\x9bk8\x0e\x1a&\x19\xf1\x15 \x16\vSE%924!(Se\x80\x00\x00\x00\x01\x00)\x00\x00\x04;\x05\xb6\x00\a\x00>@'\xc0\t\xd0\t\x02o\t\x010\t@\t\x02\x0f\t\x01\x84\x06\x01\x06\x06\x00Z\x01\x03\x03@\x01\x90\x01\x02\x01\a\x03_\x04\x03\x00\x12\x00??\xe12\x01/]3/\x10\xe92/]]]]]10)\x01\x11!\x11!\x11!\x02\xcd\xfe\xcb\xfe\x91\x04\x12\xfe\x92\x04\xb4\x01\x02\xfe\xfe\x00\x01\x00\xae\xff\xec\x05\f\x05\xb6\x00\x17\x000@\x1c\t\b\x01\t\x04\x01\x16Z\x01e\x19\u007f\x19\x8f\x19\x02\x0eZ\vd\x18\x13_\x06\x13\f\x00\x03\x00?2?\xe1\x01\x10\xf6\xe9]\x10\xf6\xe910\x00]]\x01\x11\x14\x0e\x02#\".\x025\x11!\x11\x14\x1e\x023265\x11\x05\fE\x8d\u050f\x87\u03cbH\x015 ?^?\x83u\x05\xb6\xfcNr\u0110RM\x8e\xc7z\x03\xae\xfciQsI\"\x98\x99\x03\x95\x00\x00\x00\x00\x01\x00\x00\x00\x00\x04\xe1\x05\xb6\x00\x10\x00X@+\t\x03\x01\x06\x02\x01\x03\x02\v\v\x04\t\x00\x19\x00\x02\x00\x00\x01`\x01p\x01\x90\x01\x04\x01\x10\x01\x01\x12\x0f\x12o\x12\x02\x06\x05\x16\x05\x02\x05\x04\xb8\xff\xf0@\n\x04\x14\v\x01\v\x02\x12\x04\x00\x03\x00?2?3]\x01/83]]\x113/8]3]\x129\x113310]]\x01!\x01!\x01!\x13\x1e\x03\x17>\x037\x03\xa8\x019\xfe8\xfe\xae\xfe9\x019\xf8\x05\x11\x13\x12\x05\x05\x12\x14\x13\x05\x05\xb6\xfaJ\x05\xb6\xfc\x90\x11P``!!`_P\x12\x00\x01\x00\x00\x00\x00\aj\x05\xb6\x006\x01&@m\t5)595I5\x04f%v%\x02'%\x01\x06%\x01i$y$\x02($\x01\t$\x01\x06\x14&\x146\x14F\x14\x04k\x12{\x12\x8b\x12\x03\x12\x10\n\x0eH\v\x12\x01d\x11t\x11\x84\x11\x036\x11F\x11V\x11\x03%\x11\x01\x16\x11\x01\x05\x11\x01k\x01{\x01\x8b\x01\x039\x01I\x01Y\x01\x03*\x01\x01\x19\x01\x01\n\x01\x01d\x00t\x00\x84\x00\x03\x00\xb8\xff\xf0@>\n\x0eH\x04\x00\x01\x01\x00-V%\x86%\x02\x17%\x01%Y$\x89$\x02\x18$\x01$\t\x12\x11\x1c\x1c\t-\x03\x13\x195\x015\x006`6p6\x906\x046\x10668\x0f8\x01\x16\x14\x01\x14\x13\xb8\xff\xf0@&\x135$\x8f\t\x01{\t\x01,\t<\tL\t\x03\x1b\t\x01\n\t\x01\t\x13\x03-\x1c\x14\x1c\x01\x06\x1c\x01\x1c\x12\x12\x00\x12\x00?2\x113]]\x113?3]]]]]33\x01/83]]\x113/8]3]\x12\x179\x1133\x113]]3]]\x113310]+]]]]]]]]]]]]+]]]]]]]]])\x01\x03.\x05'\x0e\x05\a\x03!\x01!\x13\x1e\x05\x17>\x057\x13!\x13\x1e\x05\x17>\x057\x13!\x06\n\xfe\xa0\xb4\x04\v\x0e\x0e\f\t\x02\x02\t\f\r\r\f\x04\xb2\xfe\x9f\xfe\xa0\x011\xa6\x03\v\x0e\x0f\x0e\f\x03\x03\v\f\x0f\f\v\x03\xcb\x01\x10\xcb\x03\v\r\x0e\r\v\x03\x03\v\x0e\x0f\x0e\v\x03\xa6\x011\x02\xd1\x0f6DJF;\x12\x12;EJD8\x10\xfd1\x05\xb6\xfc\xe2\x10=LTPE\x16\x16DMRG7\f\x033\xfc\xcd\f7GRMD\x16\x16EPTL=\x10\x03\x1e\x00\x00\x00\x00\x01\x00\x00\x00\x00\x05\x04\x05\xb6\x00\v\x00|@8\t\t\x19\t\x02\t\n\n\x00\v\b\x05\x02\x02\x04\t\x01\x19\x01\x02\x01\x00\x00`\x00p\x00\x90\x00\x04\x00\x10\x00\x00\r\x80\r\x01o\r\x01\x06\a\x16\a\x02\a\x06\x06\x06\x03\x16\x03\x02\x03\x04\xb8\xff\xf0@\x14\x04\x04\b\x14\b\x02\v\x02\x1b\x02\x02\b\x02\x01\t\x06\x03\x03\x01\x12\x00?3?3\x1299]]\x01/83]3\x113]]]\x113/8]3]\x129\x11333\x113\x113]10)\x01\t\x01!\t\x01!\t\x01!\x01\x05\x04\xfe\x9e\xfe\xd5\xfe\xd5\xfe\xb4\x01\xbc\xfec\x01V\x01\x12\x01\f\x01N\xfe^\x02)\xfd\xd7\x02\xf2\x02\xc4\xfd\xf2\x02\x0e\xfd+\x00\x01\x00\x00\x00\x00\x04\xac\x05\xb6\x00\b\x00q@\x16\x05\b\x01\n\x01\x01\xcf\n\x010\n\xb0\n\x02\x0f\n\x01\b?\a\x01\a\xb8\xff\xf0@\x1f\a\a\x05\x01\xeb\x02\x01\x8d\x02\x01d\x02t\x02\x02\x19\x02\x01\x02\x10\x02\x02\x00\x04Z0\x05\x01\x05\x03\x00\xb8\xff\xe8@\f\t\x11H\x00\x06\x06\x01\x04\x12\b\x01\x03\x00?3?\x129/3+3\x01/]\xe992/8]]]]3\x113/8]3]]]10]]\t\x01!\x01\x11!\x11\x01!\x02V\x01\b\x01N\xfeD\xfe\xcc\xfeD\x01P\x03\\\x02Z\xfc\x83\xfd\xc7\x02/\x03\x87\x00\x00\x00\x01\x001\x00\x00\x04\x1f\x05\xb6\x00\t\x00t@1i\x03\x01\x03\x10\x13\x18H\v\x03\x01\x03\a\a\x00\t@\t`\tp\t\x90\t\xa0\t\xb0\t\a\t\t\v\xaf\v\xcf\v\xef\v\x03P\v\x01O\v\x01f\b\x01\b\xb8\xff\xf0@\x1c\x13\x18H\x04\b\x01\b\x04O\x02\xaf\x02\xbf\x02\x03\x02\x02\n\a\x04_\x05\x03\x02\b_\x01\x12\x00?\xe92?\xe92\x11\x013/]33]+]]]]\x113/]3\x113]+]10)\x015\x01!\x11!\x15\x01!\x04\x1f\xfc\x12\x02k\xfd\xa8\x03\xc8\xfd\x96\x02}\xc9\x03\xed\x01\x00\xc8\xfc\x12\x00\x00\x00\x01\x00\x8f\xfe\xbc\x02s\x05\xb6\x00\a\x00\"@\x13\x04\x00\xf2\x06\xf0\x00\x01\x10\x01\x02\x01\x05\xf7\x02\xf8\x06\xf7\x01\xf9\x00?\xe1?\xe1\x01/]\xe9\xed210\x01!\x11!\x15#\x113\x02s\xfe\x1c\x01\xe4\xe0\xe0\xfe\xbc\x06\xfa\xd3\xfa\xac\x00\x00\x01\x00\f\x00\x00\x03B\x05\xb6\x00\x03\x00(@\x0e\x06\x00\x01\t\x02\x01\x02\x01\x10\x01\x01\x05\x00\x03\xb8\xff\xf0\xb3\x03\x01\x00\x03\x00?/\x01/83\x113/8310]]\t\x01!\x01\x01!\x02!\xfe\xeb\xfd\xdf\x05\xb6\xfaJ\x05\xb6\x00\x01\x003\xfe\xbc\x02\x17\x05\xb6\x00\a\x00 @\x10\x03\x00\xf2\x01\xf0\x06\x06\t\x00\xf7\a\xf9\x03\xf7\x04\xf8\x00?\xe9?\xe9\x11\x013/\xe9\xed210\x173\x11#5!\x11!3\xdf\xdf\x01\xe4\xfe\x1cq\x05T\xd3\xf9\x06\x00\x00\x01\x00\b\x02\b\x04=\x05\xbe\x00\b\x007@\x1e+\x05\x01\x05\b\x15\b\x02\t\x04\x19\x04\x02\t\x01\x01\x02\x01\x05\x05\x04\x03\x03\n\b\x00\x00\x00\x01\x03\x00?3/\x01/2\x113/39=/3310]]]\x00]\x13\x013\x01#\x01\x06\x02\a\b\x01\xb6\x90\x01\xef\xef\xfe\xbeE\x8fD\x02\b\x03\xb6\xfcJ\x02\x83\xa1\xfe\xba\x9c\x00\x00\x00\x01\xff\xfc\xfe\xbc\x03N\xffH\x00\x03\x00\x12\xb6\x00\x00\x05\x01\x01\xb9\x02\x00/\xe9\x01/\x113/10\x01!5!\x03N\xfc\xae\x03R\xfe\xbc\x8c\x00\x00\x00\x00\x01\x01L\x04\xd9\x03P\x06!\x00\r\x00*@\x19E\a\x01\x03\a\x01\f\f\a\x06\x0f\a_\ao\a\x03\a\a\x0f\x00_\x00\x02\x00\x00/]2/]\x01/33/]]10\x01.\x03'5!\x1e\x03\x17\x15\x02\x85\"_\\L\x10\x01V\x10+.0\x15\x04\xd9\x1cSXQ\x1b\x15\"QQL\x1d\x1b\x00\x00\x00\x02\x00V\xff\xec\x03\xfe\x04u\x00\x1f\x00.\x00a@>\x05\x1d\x15\x1d\x02\n\r\x1a\r\x02\n\n\x1a\n\x02@\x18\x01\x18\x18\f\x10\x02.F\x1eU0O0\xbf0\x0200\x01&G0\f\x01\f Q\x10\x10\a:\x17\x01\x17\x14N\x1b\x10\x02)N\a\x16\x00\x15\x00??\xe92?\xe13]\x129/\xe9\x01/]\xe9]]\x10\xf6\xe922\x119/]10]]]!'#\x0e\x03#\".\x02546?\x0154&#\"\x06\a'>\x0132\x16\x15\x11\x01\a\x0e\x03\x15\x14\x1632>\x025\x03);\t!BNa@DtU0\xe4\xe3\xb2PHH\x89EcT\xccp\xd1\xdf\xfe\xd1e=T3\x17D7*H5\x1e\x98-A*\x14+W\x85[\xb2\xa9\t\x06TEB*#\xca/6\xc4\xc8\xfd\x17\x02\x06\x04\x02\x1c/A(F;\x1d9S6\x00\x00\x00\x00\x02\x00\xa0\xff\xec\x04w\x06\x14\x00\x1f\x000\x008@ \x05\a\x01\x05\x03\x01.G\x05W2\x15\x0f&F\x12T1\x13\x00\x12\x15+M\x10\n\x16\x1b M\x00\x10\x00?\xe92?3\xe9??\x01\x10\xf6\xe922\x10\xf6\xe910]]\x012\x1e\x02\x15\x14\x0e\x02#\".\x02'#\a#\x11!\x11\x14\x06\a\x06\a3>\x03\a\"\x0e\x02\a\x15\x14\x1e\x0232654&\x02\xf4V\x8ef99h\x92X8WD3\x15\x153\xe9\x011\x04\x02\x03\x03\f\x156GZ03G,\x14\x02\x13,I6[UU\x04sJ\x92\u060e\x90\u0652J\x18(3\x1c{\x06\x14\xfe\x96!M!''#<-\x1a\xf4%JqK!Q~U,\xad\xa5\xa5\xa5\x00\x00\x00\x01\x00f\xff\xec\x03\xbc\x04s\x00\x1f\x00<@&\n\a\x01\n\x03\x01\r\x00\x1b\x10\x1b\x02\x1b\x1b!\xb0!\x01/!O!o!\x03\x14G\x05V \x11M\n\x10\x17M\x00\x16\x00?\xe9?\xe9\x01\x10\xf6\xe9]]\x113/]310]]\x05\".\x0254>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x163267\x15\x0e\x03\x02qx\xc1\x89IK\x89\xc1vV\xaaKXBz7oddkW\x8eJ%FGM\x14B\x8b\u0657\xa7\xe1\x88:*&\xe8\x1d%\xa9\xa9\xa8\xa0-#\xfe\x12\x1c\x12\t\x00\x00\x02\x00f\xff\xec\x04=\x06\x14\x00\x1f\x000\x008@ \n\a\x01\n\x03\x01\x1a\x15%H\x17U2.G\x05V1\x19\x15\x16\x00\x0f+M\n\x10\x1b M\x00\x16\x00?\xe92?\xe92??\x01\x10\xf6\xe9\x10\xf6\xe92210]]\x05\".\x0254>\x0232\x1e\x02\x173&'.\x015\x11!\x11#'#\x0e\x0372>\x02754.\x02#\"\x06\x15\x14\x16\x01\xe9V\x8ef99i\x92X6ZH9\x16\n\x06\x05\x05\a\x011\xe9;\r\x156GY76L/\x17\x01\x14.N;`Z[\x14J\x91\u060e\x90\u0653J\x19-;#'(\"M!\x01f\xf9\xec\x91\"=,\x1a\xf3%KpK!Q~U,\xad\xa5\xa5\xa5\x00\x00\x00\x00\x02\x00f\xff\xec\x04D\x04s\x00\b\x00)\x00e@A\n\x10\x01\n\f\x01\x8f%\x01%%\x1a\t\x04\x01\x04H\x18W+\xcf+\x010+\x01\x03\a\x1a\x01\x1aF\x0eV*9\x1aI\x1a\x02(\x1a\x01\x1aP\xd9\x03\x01\xc8\x03\x01|\x03\x01\x03\x03\x1f\x00O\x13\x10\x1fN\t\x16\x00?\xe9?\xe9\x129/]]]\xe9]]\x01\x10\xf6\xe9]2]]\x10\xf6\xe9]\x129/]10]]\x01\"\x06\a!.\x03\x03\".\x0254>\x0232\x1e\x02\x1d\x01!\x1e\x0332>\x027\x15\x0e\x03\x02dQk\b\x01\x85\x01\x180H\tx\u0292QJ\x85\xbbro\xb3}C\xfdV\x02%C_=3[VT,(QZh\x03\x9arz3V?$\xfcRF\x8d\u05d1\x93\u0713JC\x82\xbdz\x94@gG&\v\x16!\x16\xec\x15\x1d\x14\t\x00\x00\x00\x00\x01\x00)\x00\x00\x03H\x06\x1f\x00\x19\x00J@,\n\x18\t\x0eH\x00\x00\x10\x10\x1b/\x1b\xaf\x1b\x02\x10\x1b\x01\x18\x02F\x03\a\x03\x05\x05\x00\x03\x10\x03\x02\x03\x01\x05N\a\x18\x0f\x14M\r\x01\x02\x15\x00??\xe9?3\xe12\x01/]3/\x113\x10\xe92]]\x113/9/10+\x01#\x11!\x11#5754>\x0232\x16\x17\a.\x01#\"\x06\x1d\x013\x02\xe5\xe3\xfe\u03e8\xa84`\x88U\\~,H\x1fD.<1\xe3\x03y\xfc\x87\x03y\x93RRk\x8dT#\x1d\x12\xe0\v\x12M\x027.\x0354>\x027.\x0154>\x0232\x1e\x02\x17\x01\x14\x1e\x0232654&+\x01\"\x0e\x02\x13\x14\x1632654&#\"\x04=\xa3\x14\x106j\xa0j\x176\r\x14\x17\x1a*8\x1e\xaeQ\x80Y0L\x97\xe0\x93r\xaar9*FY/\x15)!\x15\x13$6\"Xg8l\xa0h\x1421*\f\xfe\\\x150N9\x9c\x9ebg\x8d\x1b>4#nDEH@?I\x89\x04\\\xa63\"I*U\x8dd7\x05\x03\x11%\x1a\x15\x19\x0f\x05%LuQ_\x99k9+QrH=Z@(\v\t *3\x1c 4-(\x15&\xa8rZ\x8ec4\x05\a\b\x03\xfb\x06\x19/$\x15XJ?*\r 5\x03f[dd[Zj\x00\x00\x01\x00\xa0\x00\x00\x04j\x06\x14\x00\x1d\x006@!\x05\x1b\x15\x1b\x02\x01F\x00U\x1f\x00\x1f0\x1f\x80\x1f\x03\x0f\vF\fT\x1e\x15\x05M\x18\x10\r\x00\f\x00\x15\x00?2??\xe92\x01\x10\xf6\xe92]\x10\xf6\xe910])\x01\x114&#\"\x0e\x02\x15\x11!\x11!\x11\x14\x06\a\x06\a3>\x0132\x1e\x02\x15\x04j\xfe\xcfKN;P0\x14\xfe\xcf\x011\x04\x03\x04\x03\x101\x98`S\x87`4\x02\x8dyy0^\x8aY\xfd\xf2\x06\x14\xfe\xc3*]'.,WM/d\x9bl\x00\x00\x02\x00\x93\x00\x00\x01\xdf\x06\x14\x00\x13\x00\x17\x00/@\x1c\xbf\x19\x010\x19`\x19\x90\x19\x03\n\x14F\x00\x15T\x18\x05S\xdf\x0f\x01\x0f\x0f\x16\x0f\x14\x15\x00??3/]\xed\x01\x10\xf62\xe92]]10\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01!\x11!\x93\x1a-=\"\"<-\x1b\x1b-<\"\"=-\x1a\x01>\xfe\xcf\x011\x05\u007f+9#\x0e\x0e#9+*:#\x0f\x0f#:\xfa\xab\x04^\x00\x00\x02\xff\xae\xfe\x14\x01\xdf\x06\x14\x00\x13\x00'\x00E@,\n\x12\x1a\x12\x02\x14\x04\x04\fF\x1e\x0fU)\xbf)\x010)`)\x90)\x03\x19S\xdf#\x01##\r\x0f\a\a\x17\a'\a\x03\aM\x00\x1b\x00?\xe9]?3/]\xed\x01]]\x10\xf62\xe12/210\x00]\x13\"&'5\x1e\x0132>\x025\x11!\x11\x14\x0e\x02\x034>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02f0f\"\x1f6\"\x19-!\x14\x011'W\x8a6\x1a-=\"\"<-\x1b\x1b-<\"\"=-\x1a\xfe\x14\x0e\v\xf0\n\t\x0f'A3\x04\xaa\xfb)M\x87e:\ak+9#\x0e\x0e#9+*:#\x0f\x0f#:\x00\x01\x00\xa0\x00\x00\x04\xb8\x06\x14\x00\x0e\x00n\xb6\n\x06\x01\f\x02\x01\x04\xb8\xff\xf0\xb3\x12\x17H\x04\xb8\xff\xf0@6\v\x0eH\x05\x04\x15\x04\x02\x04\a\x02\x03\x03\x060\x05\x01$\x05\x01\x00\x05\x10\x05\x02\x05\x10\x05\x05\x10\r\tF\nT\x0f\v\x00\a\x10\x11\x14H\b\a\x01\a\x00\x02\x06\n\x15\x02\x0f\x00??3\x1299]+?\x01\x10\xf6\xe92\x113/8]]]33\x11399]++10]]\x017\x01!\t\x01!\x01\a\x11!\x11!\x11\a\x01\xc5p\x01\x11\x01X\xfel\x01\xae\xfe\xa0\xfe\xf0w\xfe\xcf\x011\x10\x02`\xaa\x01T\xfe\x1b\xfd\x87\x01\xaeR\xfe\xa4\x06\x14\xfdJ\xfe\x00\x00\x01\x00\xa0\x00\x00\x01\xd1\x06\x14\x00\x03\x00 @\x13\xbf\x05\x010\x05`\x05\x90\x05\x03\x00F\x01T\x04\x02\x00\x00\x15\x00??\x01\x10\xf6\xe9]]10)\x01\x11!\x01\xd1\xfe\xcf\x011\x06\x14\x00\x00\x00\x01\x00\xa0\x00\x00\x06\xf0\x04s\x00*\x00q@4\x05 \x15 \x02\x03\x17\x01\x18\x00F\xf6\x01\x01\x99\x01\x01\x86\x01\x01y\x01\x018\x01\x01&\x01\x01\x19\x01\x01\x01\x01\f#F\"U,_,\x01\x0f\vF\fT+\x18\x10\x10\xb8\xff\xe8@\x10\t\rH\x10'\x05M\x1e\x15\x10\r\x0f#\f\x00\x15\x00?22??3\xe922+\x113\x01\x10\xf6\xe92]\x10\xf6\xe9\x119/]]]]]]]\xe9210]])\x01\x114&#\"\x0e\x02\x15\x11!\x113\x173>\x0332\x16\x173>\x0332\x16\x15\x11!\x114&#\"\x06\x15\x04`\xfe\xcfHM:M.\x14\xfe\xcf\xe9)\x11\x18CPZ.s\xa1+\x19\x18DR[.\xb4\xb7\xfe\xceHMm\\\x02\x8dyy0^\x8aY\xfd\xf2\x04^\x8f+>(\x13OU+>(\x13\xc3\xd7\xfd'\x02\x8dyy\xad\xa1\x00\x00\x01\x00\xa0\x00\x00\x04j\x04s\x00\x1a\x00;@$E\x12\x01\x05\x18\x15\x18\x02\x01F\x00U\x1c\x00\x1c0\x1c\x80\x1c\x03\x0f\vF\fT\x1b\x10\x05M\x15\x10\r\x0f\f\x00\x15\x00?2??\xe92\x01\x10\xf6\xe92]\x10\xf6\xe910]\x00])\x01\x114&#\"\x0e\x02\x15\x11!\x113\x173>\x0332\x1e\x02\x15\x04j\xfe\xcfIP

(\x13/d\x9bl\x00\x00\x00\x00\x02\x00f\xff\xec\x04d\x04s\x00\v\x00\x1f\x006@!\x05\x0e\x01\x05\x1e\x01\n\x14\x01\n\x18\x01\x06G\fW!_!\x01\x00G\x16V \tM\x1b\x10\x03M\x11\x16\x00?\xe9?\xe9\x01\x10\xf6\xe9]\x10\xf6\xe910]]]]\x01\x14\x1632654&#\"\x06\x05\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x01\x9e^ji^^ki]\x02\xc6G\x85\xbfwo\xba\x87LG\x85\xbexo\xba\x87L\x021\xa7\xa9\xaa\xa6\xa7\xa5\xa5\xa7\x8c\u0614MM\x94\u060c\x8b\u0613LL\x93\xd8\x00\x00\x02\x00\xa0\xfe\x14\x04w\x04s\x00\x1f\x000\x008@ \x05\x1d\x01\x05\x19\x01.G\x1bW2&\x10\fF\rT1\x11 M\x16\x10\x0e\x0f\f\x1b\x05+M\x00\x16\x00?\xe92???\xe92\x01\x10\xf6\xe922\x10\xf6\xe910]]\x05\".\x02'#\x16\x17\x1e\x01\x15\x11!\x113\x173>\x0332\x1e\x02\x15\x14\x0e\x02\x03\"\x0e\x02\a\x15\x14\x1e\x0232654&\x02\xec7WD4\x15\x10\x04\x04\x03\x05\xfe\xcf\xf8+\x0e\x156GZ7W\x8ef8:i\x91\xb63G,\x14\x02\x13,I6[UU\x14\x18(3\x1c#\x1f\x1a7\x0f\xfe;\x06J\x91\"<-\x1bJ\x92\u060e\x8f\u0653J\x03\x93%JqK!Q~U,\xad\xa5\xa5\xa5\x00\x00\x00\x02\x00f\xfe\x14\x04=\x04s\x00\x10\x000\x008@ \n\x18\x01\n\x14\x01!\x05&F#U2\x0eG\x16V1$\x1b\"\x0f \vM\x1b\x10,\x00M\x11\x16\x00?\xe92?\xe92??\x01\x10\xf6\xe9\x10\xf6\xe92210]]%2>\x02754.\x02#\"\x06\x15\x14\x16\a\".\x0254>\x0232\x1e\x02\x1737!\x11!\x1146767#\x0e\x03\x02Z7K.\x16\x01\x13/M:`Z[\x10W\x8ef89i\x92X8ZI8\x16\b\x18\x01\x02\xfe\xcf\x05\x02\x03\x03\r\x146GZ\xdb%JqK%Q~U,\xad\xa5\xa8\xa6\xefJ\x91\u060e\x8f\u0653K\x19-;#\x8f\xf9\xb6\x01\xd5\x139\x1b !\"=,\x1a\x00\x00\x00\x01\x00\xa0\x00\x00\x03H\x04s\x00\x1a\x00@\xb3\xc0\x06\x01\x06\xb8\xff\xc0@!\t\rH\x06\x06\x1c\xff\x1c\x01F\x15\x01\x15\x11F\x12T\x1b\x13\x0f\x11\x15\x05\x16E\x16U\x16\x03\x16\v\x00\x10\x00?\xc93]??\x01\x10\xf6\xe92]]\x113/+]10\x012\x1e\x02\x17\x11.\x03#\"\x0e\x02\x15\x11!\x113\x173>\x03\x02\xe7\f\x1d\x1b\x17\x06\b\x1c\x1f\x1e\n;cG'\xfe\xcf\xe7-\x0f\x188EW\x04s\x01\x03\x03\x02\xfe\xe2\x02\x04\x03\x01\x1eCmO\xfd\xc7\x04^\xa8+F1\x1b\x00\x00\x00\x00\x01\x00b\xff\xec\x03\x89\x04s\x007\x00c@\x1c\x05\x02\x15\x02\x02\n!\x1a!\x02'\x15\b\t\fH\x15F\x00W9\xcf9\x0109\x01.\xb8\xff\xf8@\x19\t\fH.F\n\x1fV8\x15.\x05+N(\x10\n\rH($\x10\x10N\v\xb8\xff\xf0\xb5\n\rH\v\x05\x16\x00?3+\xe1?3+\xe1\x1299\x01\x10\xf62\xe9+]]\x10\xf6\xe9+310]]\x01\x14\x0e\x02#\".\x02'5\x1e\x0332>\x0254.\x02'.\x0354>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x03\x89@v\xa8h7^TN(*]\\W%):%\x11\r.YKIkE\"7\x0e*L=GrR,\x01LX\x84X,\a\x10\x18\x12\xfc\x15\"\x19\x0e\x0f\x1b%\x15\x15!%/\"!APgGNuN'..\xd8$.,&\x14\x1f!'\x1c\x1f=Nh\x00\x00\x01\x00/\xff\xec\x03\x0e\x05L\x00\x19\x00\\\xb6\n\x18\t\fH\x15\x03\xb8\xff\xc0@4\n\x0fH\x02\x03\x01\x03\x03\x1b\x1f\x1bO\x1b_\x1bo\x1b\x9f\x1b\xdf\x1b\x06\x13\x17F\f\x0e\x0e\x10_\fo\f\xdf\f\xef\f\xff\f\x05\f\x16\x0eN\x12\x10\x13\x0f\x00M\a\x16\x00?\xe9?33\xe92\x01/]33/\x10\xe92]\x113/]+310+%267\x15\x0e\x01#\".\x025\x11#5?\x013\x15!\x15!\x11\x14\x16\x02f-Q*+\u007fKI~\\5\x92\xa8X\xc3\x01\x10\xfe\xf0@\xdf\x14\x0f\xe3\x16\x1d\"U\x8fl\x02\x1b\x81f\xec\xee\xe5\xfd\xe5A>\x00\x00\x00\x00\x01\x00\x9a\xff\xec\x04d\x04^\x00\x1a\x00;@#J\x04\x01\n\n\x01\x01\x18F\x19U\x1c\x00\x1c0\x1c\x80\x1c\x03\x0eF\rT\x1b\x00\n\x01\x01\x01\x12\a\x16\x18\r\x0f\x00?3?\xc92]/\x01\x10\xf6\xe9]\x10\xf6\xe9210]\x00]!'#\x0e\x03#\".\x025\x11!\x11\x14\x1632>\x025\x11!\x11\x03{)\x10\x19ER\\0R\x86`4\x011IP

\x017\x13!\x01\x01\x8b\xfeu\x01?\xb9\x11\x19\x03\x06\x03\x19\x11\xb8\x01@\xfeu\x04^\xfd\x839{15w9\x02}\xfb\xa2\x00\x00\x01\x00\x00\x00\x00\x06s\x04^\x003\x01\x17\xb7\xd63\xe63\xf63\x033\xb8\xff\xf0@\x10\t\x0fH1\b\t\fH\xd5$\xe5$\xf5$\x03$\xb8\xff\xe8@\x10\t\x0fH\xda#\xea#\xfa#\x03#\x18\t\x0fH\x14\xb8\xff\xf8@\x17\t\fH\xd9\x12\xe9\x12\xf9\x12\x03\x12\x10\t\x0fH\xd5\x11\xe5\x11\xf5\x11\x03\x11\xb8\xff\xe8@Q\t\x0fH\xda\x00\xea\x00\xfa\x00\x03\x00\x18\t\x0fH\x98\x12\xa8\x12\x02\x12\x97\x11\xa7\x11\x02\x11\x1a\x97$\xa7$\x02$\x98#\xa8#\x02#\t\x973\xa73\x023\x98\x00\xa8\x00\x02\x00*\x06\x1a\x16\x1a&\x1a\x03\t*\x19*)*\x03*\t\x1a\x03\x1312\xa02\xc02\x022\xb8\xff\xc0@\x11\t\fH2\x1025\x805\x905\x02\x0f5\x01\x14\x13\xb8\xff\xf0@\x1a\x131#\t\t\x19\tI\t\x03\t\x13\x0f+\x06\x1b\x16\x1bF\x1b\x03\x1b\x1b\x00\x12\x15\x00?33/]3?3]33\x01/83]]\x1138+]\x113\x12\x179]]\x113]3]\x113]3]\x113]3]10+]+]+]++]+]++]!\x03.\x03'&'#\x06\a\x0e\x03\a\x03!\x01!\x13\x1e\x03\x173>\x057\x13!\x13\x1e\x03\x173>\x037\x13!\x01\x03\xf6V\x04\r\x10\x11\t\x14\x18\x06\x17\x13\b\x11\x10\r\x04Z\xfe\xb8\xfe\xd3\x01/q\t\x13\x11\x0e\x04\x06\x01\a\n\v\v\t\x03z\x01Pu\x05\x10\x11\f\x01\x06\x03\x0f\x12\x15\tu\x01+\xfe\xcf\x01\x87\x11?OY,gwwh,ZO@\x12\xfe}\x04^\xfe\x11'moc\x1d\x13=FI@1\n\x02\x18\xfd\xe8\x16\\ic\x1c\x19bqp'\x01\xef\xfb\xa2\x00\x00\x00\x01\x00\n\x00\x00\x04X\x04^\x00\v\x00\xfd@[\x05\n\x01\n\b\x01\n\x04\x01\x05\x02\x01\x18\x04\x01\x04\x05\x05\x9a\x00\xaa\x00\xba\x00\xda\x00\xea\x00\x05i\x00\x01Z\x00\x019\x00I\x00\x02\x18\x00(\x00\x02\n\x00\x01F\x06V\x06f\x06\x96\x06\xa6\x06\xb6\x06\xd6\x06\xe6\x06\b\x17\x06'\x067\x06\x03\x06\x06\x01\x06\t\x03\x00\x04\v\x18\b\x01\b\xa0\a\xc0\a\x02\a\xb8\xff\xc0@\x19\t\fH\a\x10\a\a\r\x1f\r/\r\xaf\r\x03\x17\x02\x01\x02\x01\x17\n\x01\n\v\xb8\xff\xf0@\x1b\v\t\x18\x10\x13Hi\t\x01Z\t\x019\tI\t\x02*\t\x01\x19\t\x01\n\t\x01\x03\xb8\xff\xe0@ \x10\x13Hf\x03\x01T\x03\x016\x03F\x03\x02$\x03\x01\x16\x03\x01\x04\x03\x01\t\x03\x01\b\n\x15\x04\x01\x0f\x00?3?3\x1299]]]]]]+]]]]]]+\x01/83]32]]\x113/8+]3]\x12\x179]]]]]]]]]3\x113]10]]]]\t\x01!\x1b\x01!\t\x01!\v\x01!\x01\x85\xfe\x98\x01Z\xba\xbd\x01Z\xfe\x93\x01}\xfe\xa6\xcd\xcd\xfe\xa6\x02;\x02#\xfe\xb0\x01P\xfd\xdd\xfd\xc5\x01j\xfe\x96\x00\x00\x01\x00\x00\xfe\x14\x04P\x04^\x00\x1e\x00\xaa@.\x18\x1e8\x1e\x02\n\x1e\x01\x1e\xf6\x0e\x017\x0e\x01\x16\x0e\x01\x0e\x05\x05\x00\xe9\f\x01\xda\f\x01)\f9\f\x02\x1a\f\x01\t\f\x01\f\xa0\r\xc0\r\x02\r\xb8\xff\xc0@,\t\fH\r\x10\r\r p \x90 \xb0 \xd0 \x04\x1f \x01\x15\x15\xe6\x01\x01\xd5\x01\x01\xa8\x01\x01&\x016\x01\x02\x15\x01\x01\x06\x01\x01\x01\x00\xb8\xff\xf0@\x12\x00\x0e\xe0\x05\x01\x04\x05\x01\x05\x1e\x1e\x1f\x18\x11\x1b\f\x00\x0f\x00?2?\xc9\x113\x113]]3\x01/83]]]]]]3/]]\x113/8+]3]]]]]\x129\x113]]]3]]10\x11!\x13\x1e\x01\x173>\x037\x13!\x01\x0e\x01#\"&'5\x1e\x0132>\x02?\x01\x01N\xb4\x10\x0f\x02\x06\x02\a\n\r\a\xb0\x01P\xfeF>\u05a14L\x1b\x15@#0D1#\r\x13\x04^\xfd\x8b4v/\x178:9\x17\x02u\xfb\x13\xb1\xac\v\x06\xf2\x05\b\x1a/B)8\x00\x01\x007\x00\x00\x03m\x04^\x00\t\x00|@\x17I\x03Y\x03i\x03\x03\x03\x10\x11\x18H\n\x03\x01\x03\a\a\t\x04\x04\x02\t\xb8\xff\xc0@\x1b\t\x11H\t\t\v\xa0\v\xc0\v\x02\u007f\v\x01\v@\v\x0eHF\bV\bf\b\x03\b\xb8\xff\xf0@\x1c\x11\x18H\x05\b\x01\b\xa0\x02\xc0\x02\x02\x02@\r\x12H\x02\a\x04N\x05\x0f\x02\bN\x01\x15\x00?\xe12?\xe12\x01/+]3]+]+]]\x113/+\x129/\x113\x113]+]10)\x015\x01!5!\x15\x01!\x03m\xfc\xca\x01\xc9\xfeV\x03\x04\xfeF\x01\u0374\x02\xc1\xe9\xc6\xfdQ\x00\x00\x00\x00\x01\x00\x1f\xfe\xbc\x02\xd5\x05\xb6\x00(\x00N@2\v(\t\x11H%\x18\t\x11H\x0f!\xf3\x15\x1c\xf0\b\x02\xf40'\x01'\x17\x02\xf6\xcd\x03\x01o\x03\u007f\x03\x8f\x03\x03I\x03\x01\x03\x03\x0e!\xf5\"\xf9\x0f\xf5\x0e\xf8\x00?\xe9?\xe9\x119/]]]\xe99\x01/]\xee3\xe92\xec210++\x004>\x02'\x114>\x023\x15\x0e\x03\x15\x11\x06\a\x15\x1e\x01\a\x11\x14\x1e\x02\x17\x15\".\x025\x11\x01\x1f\x83}>aB!\x02&c\xaa\x83(A-\x18\x06\xe4sz\x03\x18-A(\x83\xaac&\x01oR\xef\x13+D0\x01>JiC \xe1\x01\f\x1f6+\xfe\u057b#\f\x11n^\xfe\xd5+6\x1f\f\x01\xe2 CjJ\x01;\x00\x00\x01\x01\xc7\xfe/\x02\xa2\x06\x0e\x00\x03\x00\x18@\r\x02\xaa0\x03@\x03p\x03\x03\x03\x02\x00\x00\x00?/\x01/]\xe110\x013\x11#\x01\xc7\xdb\xdb\x06\x0e\xf8!\x00\x00\x00\x01\x00\x1f\xfe\xbc\x02\xd5\x05\xb6\x00(\x00R\xb9\x00\x1c\xff\u0633\t\x11H\x02\xb8\xff\xe8@)\t\x11H\x12\v\xf0%\xf4\x18\x1f\x0f\x05\xf3(\x10%\xf6\xcd$\x01o$\u007f$\x8f$\x03I$\x01$$\x06\x18\xf5\x19\xf8\x06\xf5\x05\xf9\x00?\xe9?\xe9\x129/]]]\xe99\x01/\xed332\xee\xe9210++\x05\x14\x0e\x02#5>\x035\x11&675&'\x114.\x02'52\x1e\x02\x15\x11\x06\x1e\x023\x15\"\x06\x15\x01\xd5&c\xaa\x83(@-\x19\x03zr\xe3\x06\x19-@(\x83\xaac&\x01 Ba>}\x83-JjC \xe2\x01\f\x1f6+\x01+^n\x11\f#\xbb\x01++6\x1f\f\x01\xe1 CiJ\xfe\xc20D+\x13\xefRa\x00\x00\x00\x00\x01\x00X\x02'\x04\x10\x03}\x00$\x00\\@\x10\x1c\x1f,\x1f\x02\x1f(\x0e\x13H\x15\f%\f\x02\f\xb8\xff\xe8@\r\x0e\x13H\x1e&\n\x18\xad\n\x00 \x01 \xb8\xff\xc0\xb3\x14\x18H \xb8\xff\xc0@\x13\f\x0fH \x1d\x05\xad?\x0e_\x0e\x02\x0e@\x15\x18H\x0e\x00/+]\xe933/++]3\xe9\x01/\x10\xce10\x00+]+]\x01.\x03#\"\x0e\x02\a5>\x0132\x1e\x02\x17\x1e\x0332>\x027\x15\x06#\".\x02\x02\x10%9/*\x17\x1d><9\x1a3\u007fN\x1e39F0&90*\x16\x1d><9\x19e\x9b\x1e39F\x02h\x10\x16\r\x05\x13!,\x19\xe767\x05\x0e\x19\x14\x10\x15\r\x05\x13 -\x19\xe7m\x05\r\x19\x00\x00\x00\x00\x02\x00u\xfe\x8f\x01\xd3\x04^\x00\x03\x00\x17\x00i@J[\x00\x01\x06\x00\x0e\x01\xb0\x19\xe0\x19\xf0\x19\x03\x1f\x19/\x19?\x19\u007f\x19\x9f\x19\x05\xd7\x02\x01\xc6\x02\x01w\x02\x01\x16\x02f\x02\x02\x03\x02\x01\x02\x00\x04\x01\x04\x96\xd8\x03\x01\xc9\x03\x01x\x03\x01i\x03\x01\x00\x03\x01\x03`\x0e\x01\x0e\x00\t\x9b\x13\x0f\x03\x00/?\xfd\xc6\x01/]3]]]]]\xed]2]]]]]]]]10_]\x133\x13!\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\xa8\xf43\xfe\xa6\x01^\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x02^\xfc1\x05%/A(\x12\x12(A/-A)\x13\x13)A\x00\x00\x00\x00\x01\x00\x8f\xff\xec\x03\xe1\x05\xcb\x00)\x00c\xb1\x0e)\xb8\x01\x02@\x18\v\x00\x00\x06\x13\xaf%\xbf%\xcf%\x03%+\xa0+\xb0+\xc0+\x03\x1en\x06\xb8\xff\xc0@ \t\fH\x06*\x1f*?*\x02!u\x01\x00(\x19v\u007f\f\x8f\f\x9f\f\x03\f\v\x80\x0e\x90\x0e\x02\x0e\x00/]3\xcd]\xe1/\xcd3\xe1\x01]\x10\xd6+\xe1]\x10\xc6]2\x119/3\xe1210\x055.\x0354>\x02753\x15\x1e\x03\x17\a.\x03#\"\x0e\x02\x15\x14\x163267\x15\x0e\x01\a\x15\x02\x1f\\\x94h88i\x94[\xb2&LG?\x18V\x15587\x18B\\;\x1ar\x81L\x8d23|E\x14\xce\rK\x85\u01c9\x8d\u02c8K\r\xac\xa4\x01\v\x10\x14\v\xe2\n\x13\x0f\t(S\u007fW\xab\x9f%\x18\xef\x1d\x1f\x02\xc8\x00\x00\x00\x01\x00R\x00\x00\x04B\x05\xcb\x00&\x00\x9a@j\n$\x1a$*$\x03\v\xe7\x0f\x01\xd6\x0f\x01\xc5\x0f\x01'\x0fW\x0f\x97\x0f\x03\x15\x0f\x01\x0fn!\xb9\x1d\xf9\x1d\x02k\x1d{\x1d\x02:\x1d\x01\x04\r\x01\x1d\r\x1d\r\x15\x1f@\x17`\x17\x02\x17\x03c\x15\x83\x15\x02 \x15@\x15\x02\x04\x15\x01\x15\x0e\x1fw\v\x92 \x01 \x00\x18G\x14\xc7\x14\xd7\x14\x03\x14s\x16\x18\xe9\a\x01\xc8\a\x01\at\x04\x00\a\x00?2\xe1]]?\xe1]2\x119/]3\xe12\x01/]]]3/]3\x1299//]]]]3\xe1]]]]]210]\x012\x16\x17\a.\x01#\"\x06\x1d\x01!\x15!\x15\x14\x0e\x02\a!\x11!5>\x03=\x01#5354>\x02\x02\xa8n\xb3P]Gu?CK\x01N\xfe\xb2\x1b,5\x1b\x02\xa6\xfc\x10*C/\x18\xb2\xb2?o\x99\x05\xcb0\"\xe6\x1d#M_\xc1\u06cf7Q:(\x0e\xfe\xfc\xf8\x12*:R:\x91\xdb\xc3q\x9fd.\x00\x00\x02\x00\\\x00\xfe\x04\f\x04\xaa\x00\"\x006\x00\x96@_\x0132\x16\x177\x17\a\x1e\x01\x15\x14\x06\a\x17\a'\x0e\x01#\"&'\a'7&7\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\xa8\x1c\x19\x81\x94\u007f+f36`/\u007f\x95\x81\x19\x1d\x1c\x1a}\x91\u007f,c68c+}\x92\u007f5\xcf\x1e3D'(F5\x1e\x1e5F('D3\x1e\x02\xd36c,\u007f\x93\u007f\x19\x1c\x1b\x1c\x81\x8f\x81*g68b-}\x91}\x17\x1c\x19\x1a{\x91}[j'E3\x1d\x1d3E'(E3\x1e\x1e3E\x00\x00\x00\x01\x00\b\x00\x00\x04b\x05\xb6\x00\x16\x00\xaf@\x12\x0f\x13\x13\f\x06\x16\x01\x16\x0f\x15O\x15\x9f\x15\xaf\x15\x04\x15\xb8\xff\xf0@<\x15\x15\f\b\x04\x04\t\x01\x01\x01@\x02\xa0\x02\x02\x02\x10\x02\x02\x00\a\x05\x03\x15\x03\x02\x03\vn\n\x14\x01\x14\x10\x00\f@\f\x80\f\x90\f\xa0\f\xd0\f\x06\f\n\x0e\xfa\x0f\a\x0f\x06\x12\xfa\x13\x03\x00\xb8\xff\xd8@\x1c\f\x0fH\a\x00\x01\x00\x13\xdf\x0f\x01\x0f\x13\x1f\x13\x9f\x13\x03\x0f\x13\x0f\x13\x01\v\x12\x16\x01\x03\x00?3?\x1299//]]\x113]+3\x10\xe12\x113\x10\xe12\x01/]33]\xe12]292/8]3]9\x113\x113/8]3]\x129\x11310\x01\x13!\x013\x15#\x153\x15#\x15!5#535#53\x01!\x025\xf4\x019\xfe\x96\xc2\xf5\xf5\xf5\xfe\xe1\xf8\xf8\xf8\xbf\xfe\x9b\x01<\x03\\\x02Z\xfd\x15\xb2\x8a\xb2\xdd\u0772\x8a\xb2\x02\xeb\x00\x00\x00\x00\x02\x01\xc7\xfe/\x02\xa2\x06\x0e\x00\x03\x00\a\x00$@\x13\x02\x06\xaa\x030\a@\ap\a\x03\a\x04\x03\x04\x03\x06\x00\x00\x00?/99//\x01/]3\xe1210\x013\x11#\x113\x11#\x01\xc7\xdb\xdb\xdb\xdb\x06\x0e\xfc\xd1\xfe\u007f\xfc\xd1\x00\x00\x00\x02\x00j\xff\xec\x03\u007f\x06)\x00C\x00V\x00\xc5@\x1f51E1\x02\x161&1\x0220B0\x02\x140$0\x02:\x11J\x11\x02\x19\x11)\x11\x02)\xb8\xff\xe8@\t\t\rH\n\x18\t\x0eH$\xb8\xff\xe0@V\t\rH$H'D\x05 \t\rHR\x05\b\bM\x18M(M\x03M\x9a!!:\x99\x10'XoX\u007fX\x8fX\x03X@\n\rH\x17\x99\b\b\aD\x17D'D\x03D\x9a\x0000\x00\x00\x90\x00\x02\x00?$H\x1c\x05RHRHR\r05\x9d,\x16\x11\x14\x9d\r\x01\x00?\xe12?\xe12\x1199//\x1133\x1133\x01/]3/\x10\xe1]3/\xe1+]\x10\xde2\xe13/\xe1]\x1199+\x11\x1299+10++\x00]]]]]]\x134>\x027.\x0154>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x15\x14\x06\a\x1e\x01\x15\x14\x0e\x02#\"&'5\x1e\x0332>\x0254.\x02'.\x037\x14\x16\x1f\x01>\x0354.\x02'\x0e\x03y\x15%0\x1b?F:k\x95[f\xb0URD\x8dNQJ\x184Q8GuS.E8>?>r\xa3en\xa9F'Z\\Y'8J-\x13\x0f-QBLxR+\xdfqv\x0f\x0f\x1c\x16\r\x154[F\x12 \x19\x0f\x03%,K?2\x12(vKAkL)/%\xbe 3.0\x19*''\x17\x1cDSe>d{%(iJJwT.)&\xcf\x14#\x1b\x10\x12 *\x19\x19'&*\x1c @Qf[?a3\x06\v\x1d$,\x1a 631\x19\a\x1b$,\x00\x00\x02\x00\xf8\x04\xf8\x03\xa6\x06\x04\x00\x13\x00%\x00%@\x14\x1e\x82\x14\x14\n\x82\x00\x19\x05\x8c#\xef\x0f\x01\x80\x0f\xd0\x0f\x02\x0f\x00/]]3\xed2\x01/\xed2/\xed10\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02%4>\x0232\x1e\x02\x15\x14\x0e\x02#\"&\xf8\x16%3\x1d\x1d3&\x17\x17&3\x1d\x1d3%\x16\x01\x93\x16&4\x1e\x1c3'\x17\x17'3\x1c\x01>\xc82\x13\x18H\x01H\xc8$\x04\x00?\xe9]?\xe9]\x1199//]]\x10\xe9\x10\xe9\x01/\xe9]\x10\xde\xe9]\x1199//]]\x113\xe910]]\x01\"\x06\x15\x14\x163267\x15\x0e\x01#\".\x0254>\x0232\x16\x17\a&\x014>\x0432\x1e\x04\x15\x14\x0e\x04#\".\x047\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x03\u007faj`k9\x8499vMk\xa0k64i\x9eiS\x9aDJq\xfc}6a\x8a\xa7\xc0hh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x8aa6\x8e`\xa5\xde\u007f\u007f\u07a5``\xa5\xde\u007f\u007f\u07a5`\x03\U000940c7\x91\x1e\x1d\xbf\x1b\x1eD|\xadjg\xab{D,\"\xa8:\xfe\xe9h\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x89b55b\x89\xa7\xc0h\u007f\u07a5``\xa5\xde\u007f\u007f\u07a5``\xa5\xde\x00\x00\x00\x02\x00/\x02\xf0\x02\x8f\x05\xc7\x00\x1f\x00.\x00\x81\xb9\x00\x1c\xff\xe8@\x0e\t\rH\v\x18\t\rH\a\x18\t\rH\x02\xb8\xff\xe8@D\t\rH\n\x06\x1a\x06\x02\x05\x0f\x15\x0f\x02.\x01\x0f\xe2\x1e0\x0f0\x8f0\xaf0\xbf0\xdf0\xef0\x060@\v\x0fH%\xe2\x16O\t_\t\x02\t@\x11\x15H\t.\xe8\x0f\x0f(\x15\x12\xe6\x19\xde\x01(\xe7\x04\xfc\x00\xfb\x00??\xe92?\xe93\x129/\xe9\x01/+]3\xe9+]\x10\xde\xe922\x00]10]\x01++++\x01'\x0e\x01#\".\x0254>\x02?\x014&#\"\x06\a'>\x0132\x1e\x02\x15\x11\x01\x0e\x03\x15\x14\x1632>\x02=\x01\x02\b\x1f(qD2Q: +QwKZ;6(b4B>\x94[DeB!\xfe\xe6&/\x1b\t&\x1b 3$\x13\x02\xfcn:@\x1b7T9\xfeF\x01=\x03\x14\x1d\"\x12&$\x16'7 $\x00\x02\x00R\x00^\x04\\\x04\x04\x00\x06\x00\r\x00[@2\x03\xeb\x06\xec\x01\x02\x02\x05\x12\x04\x01\x04\x04\n\xeb\r\xec\f\v\v\b/\t_\t\x02\x19\t\x01\t\x0f\r\n\n\x03\v\f\f\x04\x05\xed\t\b\b\x02\x01\xed\x06\x03\xef\x00?3\xed22\x113\xed22\x113\x113\x113\x01\x10\xde]]22\x113\xfd\xe93/]33\x113\xfd\xe910\x13\x01\x17\x03\x13\a\x01%\x01\x17\x03\x13\a\x01R\x015\xdb\xd9\xd9\xdb\xfe\xcb\x01\xfa\x015\xdb\xd9\xd9\xdb\xfe\xcb\x02=\x01\xc7w\xfe\xa4\xfe\xa4w\x01\xc5\x1a\x01\xc7w\xfe\xa4\xfe\xa4w\x01\xc5\x00\x00\x01\x00X\x00\xf8\x04\x10\x03?\x00\x05\x00\x16@\t\x01\xaa\x00\a\x03\x00\x03\xad\x04\x00/\xe93\x01/\x10\xde\xe910%#\x11!5!\x04\x10\xdb\xfd#\x03\xb8\xf8\x01l\xdb\x00\x00\x00\xff\xff\x00=\x01\xa8\x02V\x02\xa2\x12\x06\x00\x10\x00\x00\x00\x04\x00d\xff\xec\x06D\x05\xcb\x00\r\x00\x18\x004\x00H\x00\x8a@W\x06\x03\x00\x0e\b\xc4\t\x12\xc4\x00\x04\x00?\x00\x8f\x00\x02@\t`\t\x80\t\x03\t\x00\t\x00\x19\x18?\x01?\xc3'J\x175\x015\xc3\x19\x05\t\x03\a\xc9\x0e\x18\xc9\n\u007f\t\x8f\t\x02\x00\n\x10\np\n\x80\n\x04\t\x0e\n\n\x0e\t\x03 \x17:\x01:\xc8.\x13\x18D\x01D\xc8 \x04\x00?\xe9]?\xe9]\x11\x179///]]\x10\xe9\x10\xe19\x113\x01/\xe9]\x10\xde\xe9]\x1199//]]\x113\x10\xe9\x10\xe92\x119910\x01\x14\x06\a\x13#\x03#\x11#\x11!2\x16\x0132654.\x02+\x01\x014>\x0432\x1e\x04\x15\x14\x0e\x04#\".\x047\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x04\x85MB\xed\xfe\xb2/\xe5\x01\b\xb6\xa8\xfe\u007f\x1fB9\x0f\x1f/ \x1d\xfd`6a\x8a\xa7\xc0hh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x8aa6\x8e`\xa5\xde\u007f\u007f\u07a5``\xa5\xde\u007f\u007f\u07a5`\x03\x89^n\x1d\xfep\x01R\xfe\xae\x03\x94\x8c\xfe\xf29B#.\x1b\v\xfe\xdfh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x89b55b\x89\xa7\xc0h\u007f\u07a5``\xa5\xde\u007f\u007f\u07a5``\xa5\xde\x00\x00\x01\xff\xfa\x06\x14\x04\x06\x06\xdd\x00\x03\x00\x11\xb6\x00\x05\x01\x01\xbc\x02\xbd\x00?\xe9\x01/\x10\xc610\x01!5!\x04\x06\xfb\xf4\x04\f\x06\x14\xc9\x00\x02\x00\\\x03\x19\x03\x10\x05\xcb\x00\x13\x00'\x00\x1d@\x0e\x14\xaa\x00\x1e\xaa\n)\x19\xae\x0f#\xae\x05\a\x00?\xe9\xd4\xe9\x01\x10\xde\xe9\xd4\xe910\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x027\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\\6^~HH\u007f]66]\u007fHH~^6\xbf\x18*9 9*\x19\x19*9 9*\x18\x04qG~^77^~GH~]55]~H\x1f8*\x19\x19*8\x1f 9+\x19\x19+9\x00\x02\x00X\x00\x00\x04\x10\x04\xee\x00\v\x00\x0f\x00D@(\a\x04\x01\x0e\a\r\x02\a\x06\t\xaa\x02\x03\x00\r\xad\f\v\t\x00\xad\x04\x06\u007f\x03\x8f\x03\xaf\x03\xcf\x03\xff\x03\x05\x03@\t\x0eH\x03\x00/+]33\xe922/\xe9\x01/33\xe922\x113\x11310\x00]\x01!5!\x113\x11!\x15!\x11#\x015!\x15\x01\xc7\xfe\x91\x01o\xdb\x01n\xfe\x92\xdb\xfe\x91\x03\xb8\x02\xa2\xdb\x01q\xfe\x8f\xdb\xfe\x93\xfe\xcb\xdb\xdb\x00\x00\x00\x01\x00/\x02J\x02\xbe\x05\xcb\x00\x1e\x00R\xb9\x00\x15\xff\xe8@3\t\rH\x0e\x10\v\x0eH\b\xe0\x00\x17 \x0f \x1f / _ \xdf \xef \xff \a\x05\x1dE\x1de\x1d\x03\x1d\x0f\xa0\x01\x01\x01\x0e\v\xe4\x12\xde\x02\x1d\xe4\x01\xdd\x00?\xe92?\xe93\x01/]33]]\x10\xde2\xe9\x00+10\x01+\x01!57>\x0354&#\"\x06\a'>\x0132\x1e\x02\x15\x14\x0e\x02\x0f\x01!\x02\xbe\xfdy\xe0.=%\x0f0((W5{A\xa2mBmM+\x196T\x0254&#\"\x06\a'>\x0132\x1e\x02\x02\x9aQY3J1\x18\xb0\xbaL\x84AB\x84IJE\x10&@0p\\4@$\f23/T9e>\x97g>jM,\x04\xe1Ed\x1d\r\n*7B$y\x8b##\xbe(265\x15&\x1d\x12\xa0\x12\x1f'\x15&2&(\x8d/>!\x037!\x15\x0e\x05\a\x01L\x150/*\x10\x01V\v*6>?:\x17\x04\xd9\x1b\x1dLQQ\"\x15\x1218;82\x13\x00\x01\x00\xa0\xfe\x14\x04j\x04^\x00\x1d\x009@\"B\x0f\x01\r\tF\nU\x1f\x00\x1f0\x1f\x80\x1f\x03\x19\x1dF\x1cT\x1e\t\x1c\x0f\x1b\x1b\x0e\x03M\x11\x16\f\x15\x00??\xe12??3\x01\x10\xf6\xe12]\x10\xf6\xe1210]\x01\x14\x1632>\x025\x11!\x11#'#\x0e\x01#\"&'\x16\x17\x1e\x01\x15\x11!\x11!\x01\xd1KQ:N0\x14\x011\xe9+\f#iK6Z\x1c\x02\x03\x02\x03\xfe\xcf\x011\x01\xd1yy0^\x8aY\x02\x0e\xfb\xa2\x96UU.,*+%T$\xfe\xc0\x06J\x00\x00\x00\x00\x01\x00q\xfe\xfc\x04\x8f\x06\x14\x00\x13\x005\xb2\x04\xfd\x05\xb8\xff\xc0@\x17\t\x13H\x05\x05\r\x01\xfd\x00\x15\x00\r\x01\r\b\b\x00\x03\x9e\x12\x00\x05\x00\x00/2?\xe9\x129/\x01/]\x10\xde\xe9\x119/+\xe910\x01#\x11#\x11#\x11\x06#\".\x0254>\x023!\x04\x8f\xa1\xa6\xa2=U_\x9bm\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02u\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x02\xd3/A(\x12\x12(A/-A)\x13\x13)A\x00\x00\x00\x01\xff\xdb\xfe\x14\x01\xa2\x00\x00\x00\x1b\x00K@0\x03(\t\x11H\x17\x15\x14\x14\b\b\x11\x83?\x00\u007f\x00\x8f\x00\xcf\x00\xdf\x00\x05\x00?\x1d\u007f\x1d\x8f\x1d\xcf\x1d\x04\x17\x15\x0f\x14\x1f\x14\x02\x14\x14\x05\x15\x0e\x8d\x05\x00/\xe1/\x129/]\x129\x01]/]\xe13/3\x113310\x00+\x05\x14\x0e\x02#\"&'5\x1e\x0332654&'73\a\x1e\x03\x01\xa2\x1fHwW-H\x1d\x0f%'%\x0f\x1d+J\\N\xc1\x1b\x1f:-\x1c\xfa9Z>!\f\t\xa8\x04\a\x06\x04\x1b#%9\x0e\x9a=\n\"/=\x00\x01\x00\\\x02J\x02H\x05\xb6\x00\x10\x007@$\x0f\x12\x1f\x12/\x12_\x12\xdf\x12\xef\x12\xff\x12\a\x0f\x01\x0e\x0e\a\x00\xe0p\x01\x80\x01\x90\x01\x03\x01\r\a\x0f\xdc\x00\xdd\x00??3\xcd\x01/]\xe933/\x113]10\x01#\x114>\x027\x0e\x03\x0f\x01'%3\x02H\xee\x01\x03\x03\x01\x06\x13\x15\x15\bNm\x01-\xbf\x02J\x01\xbe\x14=>4\f\b\x15\x16\x14\a=\u007f\xeb\x00\x00\x00\x00\x02\x009\x02\xf0\x02\xb8\x05\xc7\x00\x13\x00\x1f\x00Y\xb9\x00\x11\xff\xe8\xb3\t\rH\r\xb8\xff\xe8@5\t\rH\a\x18\t\rH\x03\x18\t\rH\x1a\xe2\x00!\x0f!\x8f!\xaf!\xbf!\xdf!\xef!\x06!@\v\x0eH\x14\xe2O\n_\n\x8f\n\x03\n\x1d\xe6\x0f\xde\x17\xe6\x05\xfc\x00?\xe9?\xe9\x01/]\xe9+]\x10\xde\xe910\x00++++\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x05\x14\x1632654&#\"\x06\x02\xb8-TvJEuU/-SwKDsV0\xfeL7><77<>7\x04\\W\x87]11]\x87WW\x87]00]\x87Wdeeddcc\x00\x00\x00\x02\x00T\x00^\x04^\x04\x04\x00\x06\x00\r\x00]@4\f\v\v\b\t\xec\n\xeb\x05\x04\x13\r\x01\x02\r\x01\x04\r\x03\x02\xec\x03\xeb/\x00_\x00\x02\x16\x00\x01\x00\x0f\r\n\n\x03\v\f\f\x04\x05\xed\t\b\b\x02\x01\xed\x00\x03\xef\x00?3\xed22\x113\xed22\x113\x113\x113\x01\x10\xde]]\xe9\xed\x172/_]\x113\xe9\xed22\x11310\t\x01'\x13\x037\x01\x05\x01'\x13\x037\x01\x04^\xfe\xcb\xdb\xd9\xd9\xdb\x015\xfe\x06\xfe\xcb\xdb\xd9\xd9\xdb\x015\x02#\xfe;w\x01\\\x01\\w\xfe9\x1a\xfe;w\x01\\\x01\\w\xfe9\x00\x00\xff\xff\x00.\x00\x00\x06\x92\x05\xb6\x10'\x00\xd1\x02\xc9\x00\x00\x10&\x00{\xd2\x00\x11\a\x00\xd2\x03\x9c\xfd\xb7\x00*@\x1a\x03\x02\x18\x18\x03\x02\x10\x18`\x18\x02\x18\x00p\x00\x01\x00\x01\x00\x04\x10\x04`\x04\x03\x04\x11]5\x11]5\x11]55\x00?55\xff\xff\x00.\x00\x00\x06\xb4\x05\xb6\x10'\x00\xd1\x02\xc9\x00\x00\x10&\x00{\xd2\x00\x11\a\x00t\x03\xf6\xfd\xb7\x000@\x1f\x02\x16\x18\x02\xaf\x16\x01\x10\x16\x01\x16\x00\x80\x00\x01p\x00\x01D\x00\x01\x00\x01\x00\x04\x10\x04`\x04\x03\x04\x11]5\x11]]]5\x11]]5\x00?5\x00\x00\xff\xff\x00Z\x00\x00\x06\xb0\x05\xc9\x10'\x00\xd1\x03\x10\x00\x00\x10'\x00\xd2\x03\xba\xfd\xb7\x11\x06\x00u\x1f\x00\x00 @\x12\x02\x01\a\x18\x02\x01P\a\x01\a\x00\x80\x00\x010\x00\x01\x00\x11]]5\x11]55\x00?55\x00\x00\x00\x02\x00B\xfey\x03\x9e\x04^\x00'\x00;\x00C@)\f\x1a\x1c\x1a\x022\x96(('\x00\x00\x12\vH\x1c\x00\x12\x10\x12 \x12@\x12P\x12`\x12\x06\x12\v\x17\x00-\x9b7\x0f\x11\x0eM\x17\x00/\xe93?\xfd\xce\x119\x01/]/\xe9\x119/\xc93/\xed10]\x01\x15\x14\x0e\x02\a\x0e\x03\x15\x14\x163267\x17\x0e\x03#\".\x0254>\x027>\x03=\x01\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x02\xae\x15+D0*:$\x10NNE\xa0Tg+fmp6f\xa3r=\x1b8S7)5\x1e\v\x01)\x1b0@%#?0\x1c\x1c0?#%@0\x1b\x02^J3SKF&!438%9J;)\xdd\x1a-\"\x141]\x87U?cUP,!1,0\x1f;\x01V/A(\x12\x12(A/-A)\x13\x13)A\x00\xff\xff\x00\x00\x00\x00\x053\as\x12&\x00$\x00\x00\x11\a\x00C\xff\xf3\x01R\x00\x15\xb4\x02\x17\x05&\x02\xb8\xff\xa8\xb4\x1c#\x04\a%\x01+5\x00+5\x00\xff\xff\x00\x00\x00\x00\x053\as\x12&\x00$\x00\x00\x11\a\x00v\x00\xa2\x01R\x00\x13@\v\x02\x17\x05&\x02V\x17\x1e\x04\a%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x00\x00\x00\x053\as\x12&\x00$\x00\x00\x11\a\x00\xc3\x00N\x01R\x00\x13@\v\x02\x17\x05&\x02\x02\x1e*\x04\a%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x00\x00\x00\x053\a`\x12&\x00$\x00\x00\x11\a\x00\xc5\x00N\x01R\x00\x13@\v\x02\x1a\x05&\x02\x03\x1b)\x04\a%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x00\x00\x00\x053\aV\x12&\x00$\x00\x00\x11\a\x00j\x00L\x01R\x00\x17@\r\x03\x02&\x05&\x03\x02\x01\x175\x04\a%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\x00\x00\x00\x053\a\n\x12&\x00$\x00\x00\x11\x06\x00\xc4LX\x00 @\x114.3\x03\x02\x1c\x1c4\x03\x03\x02\x01!\x17\x04\a%\x01+55\x00?3/55\x11\x129\x00\x02\x00\x00\x00\x00\x06\xe7\x05\xb6\x00\x0f\x00\x13\x00\x8c@%\x05\x04\x01F\x10\x01\x05\x10\x01F\x03\x01\x05\x03\x01\x10\x03\x13\x04\x13\n\x0eZ\x11\x06p\x01\x01\x01\x01\x14\f\b\x0fg\x15\x15\xb8\xff\xc0@.\x0f\x14H\x0f\x15\x01\x04\x14\x05\x02_\x11\x11\r_\xaf\n\x01\x88\n\x01L\n\x01;\n\x01\x19\n\x01\b\n\x01\n\n\x0f\x12\b_\a\x03\x0f_\x04\x00\x12\x00?2\xe1?\xe12\x129/]]]]]]\xe12/\xe1\x01/\x113]+\x10\xe622\x119/]33\xe123\x11\x1299]]]]10])\x01\x11!\x03!\x01!\x15!\x11!\x15!\x11!\x01!\x11#\x06\xe7\xfc\xb7\xfe3\x96\xfe\xc5\x02\x8f\x04X\xfd\xec\x01\xf0\xfe\x10\x02\x14\xfb[\x01\\a\x01\\\xfe\xa4\x05\xb6\xfe\xfe\xbf\xfe\xfe\x87\x01`\x02N\x00\x00\xff\xff\x00w\xfe\x14\x04\xd1\x05\xcb\x12&\x00&\x00\x00\x11\a\x00z\x01\xfc\x00\x00\x00\v\xb6\x01\x16,$\x18 %\x01+5\x00\x00\x00\xff\xff\x00\xb8\x00\x00\x04\x02\as\x12&\x00(\x00\x00\x11\a\x00C\xff\xb7\x01R\x00\x15\xb4\x01\f\x05&\x01\xb8\xff\xa8\xb4\x11\x18\x01\x00%\x01+5\x00+5\x00\xff\xff\x00\xb8\x00\x00\x04\x02\as\x12&\x00(\x00\x00\x11\a\x00v\x00\\\x01R\x00\x13@\v\x01\f\x05&\x01M\f\x13\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xb8\x00\x00\x04\v\as\x12&\x00(\x00\x00\x11\a\x00\xc3\x00\x1f\x01R\x00\x13@\v\x01\f\x05&\x01\x10\x13\x1f\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xb8\x00\x00\x04\x02\aV\x12&\x00(\x00\x00\x11\a\x00j\x00\x19\x01R\x00\x17@\r\x02\x01\x1b\x05&\x02\x01\v\f*\x01\x00%\x01+55\x00+55\x00\x00\x00\xff\xff\x00*\x00\x00\x02\xdb\as\x12&\x00,\x00\x00\x11\a\x00C\xfe\xde\x01R\x00\x15\xb4\x01\f\x05&\x01\xb8\xff\x9e\xb4\x11\x18\x01\x00%\x01+5\x00+5\x00\xff\xff\x00B\x00\x00\x02\xf1\as\x12&\x00,\x00\x00\x11\a\x00v\xff\xa1\x01R\x00\x13@\v\x01\f\x05&\x01`\f\x13\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\xff\xf0\x00\x00\x03,\as\x12&\x00,\x00\x00\x11\a\x00\xc3\xff@\x01R\x00\x13@\v\x01\f\x05&\x01\x00\x13\x1f\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x006\x00\x00\x02\xe4\aV\x12&\x00,\x00\x00\x11\a\x00j\xff>\x01R\x00\x19\xb6\x02\x01\x1b\x05&\x02\x01\xb8\xff\xff\xb4\f*\x01\x00%\x01+55\x00+55\x00\x00\x02\x00/\x00\x00\x05#\x05\xb6\x00\x10\x00\x1f\x00g@B\x11Z\bg!?!\x01X\x1a\x01;\x1a\x01\x1a\x18\x1cZ'\x10\x01\x10\x01\x0ed \x1b\x0f_\x18\xaf\x01\xbf\x01\xdf\x01\x03\x88\x01\x01o\x01\x01L\x01\x01;\x01\x01\x19\x01\x01\b\x01\x01\x01\x01\x02\x1c_\x0e\x12\x17_\x02\x03\x00?\xe1?\xe1\x119/]]]]]]]3\xe12\x01\x10\xf62\xc2]\xf12\xc2]]]\x10\xf6\xe110\x133\x11!2\x04\x16\x12\x15\x14\x02\x06\x04#!\x11#%4.\x02+\x01\x113\x15#\x11326/\x89\x01\xac\xa1\x01\x03\xb8ce\xbf\xfe\xeb\xb1\xfe\u007f\x89\x03\xba1]\x87W\x8f\xed\xedr\xc4\xc5\x03R\x02d\\\xb5\xfe\xf4\xb0\xb9\xfe\xe9\xbb^\x02T\x8dz\xb1t8\xfe\x9a\xfe\xfe\xac\xf0\x00\x00\xff\xff\x00\xb8\x00\x00\x05\x8b\a`\x12&\x001\x00\x00\x11\a\x00\xc5\x00\xc5\x01R\x00\x15\xb4\x01\x1b\x05&\x01\xb8\xff\xf3\xb4\x1c*\n\x00%\x01+5\x00+5\x00\xff\xff\x00w\xff\xec\x05\x96\as\x12&\x002\x00\x00\x11\a\x00C\x00T\x01R\x00\x15\xb4\x02(\x05&\x02\xb8\xff\x9c\xb4-4\n\x00%\x01+5\x00+5\x00\xff\xff\x00w\xff\xec\x05\x96\as\x12&\x002\x00\x00\x11\a\x00v\x01\x02\x01R\x00\x13@\v\x02(\x05&\x02I(/\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00w\xff\xec\x05\x96\as\x12&\x002\x00\x00\x11\a\x00\xc3\x00\xae\x01R\x00\x15\xb4\x02(\x05&\x02\xb8\xff\xf6\xb4/;\n\x00%\x01+5\x00+5\x00\xff\xff\x00w\xff\xec\x05\x96\a`\x12&\x002\x00\x00\x11\a\x00\xc5\x00\xba\x01R\x00\x13@\v\x02+\x05&\x02\x02,:\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00w\xff\xec\x05\x96\aV\x12&\x002\x00\x00\x11\a\x00j\x00\xb4\x01R\x00\x19\xb6\x03\x027\x05&\x03\x02\xb8\xff\xfd\xb4(F\n\x00%\x01+55\x00+55\x00\x00\x01\x00m\x01\f\x03\xfc\x04\x9a\x00\v\x00n@D\xa7\n\x01V\x03\x96\x03\x02\x15\x03%\x035\x03\x03\x06\x03\x01Y\t\x99\t\x02\x1a\t*\t:\t\x03\t\t\x01V\x06\x96\x06\x02\x15\x06%\x065\x06\x03\x06\x06\x01Y\x00\x99\x00\x02\x1a\x00*\x00:\x00\x03\t\x00\x01\x03\xe0\x00\x01\x00\xb8\xff\xe0@\v\x0e\x14H_\x00\u007f\x00\xaf\x00\x03\x00\x00\x19/]+]\x01/10]]]]]]\x00]]]]]]]\t\x017\t\x01\x17\t\x01\a\t\x01'\x01\x98\xfe\u0557\x01-\x011\x9a\xfe\xcf\x01-\x96\xfe\xcf\xfe\u04d5\x02\xd3\x01-\x9a\xfe\xd5\x01+\x96\xfe\xcf\xfe\u0458\x01-\xfe\u0558\x00\x03\x00w\xff\xb4\x05\x96\x05\xfc\x00\x1a\x00$\x00/\x002@\x1b\x1e(\x1b%[\x00g1/1?1\x02\x1b[\rf0\x1d'+ \x12\x04+\x05\x12\x00?\xc1?\xc1\x1199\x01\x10\xf6\xe1]\x10\xf6\xe1\x119910\x01\x14\x02\x0e\x01#\"'\a'7&\x0254\x12>\x0132\x16\x177\x17\a\x16\x12\x05\x14\x17\x01&#\"\x0e\x02\x054'\x01\x1e\x0132>\x02\x05\x96O\xa2\xf7\xa8\xb3\x80H\xa8Ra]O\xa2\xf7\xa9[\x9bAF\xa6P^]\xfc /\x01\xc9EaW\x80S(\x02\xa0+\xfe9\"P0Y\u007fQ'\x02\u0769\xfe\xea\xc6l=u^\x86d\x01(\xbb\xaa\x01\x15\xc4k!\x1fo`\x81c\xfe\u0778\xb4s\x02\xea+D\x80\xb7s\xabt\xfd\x1b\x13\x14D\u007f\xb7\x00\x00\x00\xff\xff\x00\xae\xff\xec\x05\f\as\x12&\x008\x00\x00\x11\a\x00C\x00=\x01R\x00\x15\xb4\x01\x18\x05&\x01\xb8\xff\xae\xb4\x1d$\v\x00%\x01+5\x00+5\x00\xff\xff\x00\xae\xff\xec\x05\f\as\x12&\x008\x00\x00\x11\a\x00v\x00\xee\x01R\x00\x13@\v\x01\x18\x05&\x01_\x18\x1f\v\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xae\xff\xec\x05\f\as\x12&\x008\x00\x00\x11\a\x00\xc3\x00\x8d\x01R\x00\x15\xb4\x01\x18\x05&\x01\xb8\xff\xfe\xb4\x1f+\v\x00%\x01+5\x00+5\x00\xff\xff\x00\xae\xff\xec\x05\f\aV\x12&\x008\x00\x00\x11\a\x00j\x00\x91\x01R\x00\x17@\r\x02\x01'\x05&\x02\x01\x03\x186\v\x00%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\x00\x00\x00\x04\xac\as\x12&\x00<\x00\x00\x11\a\x00v\x00Z\x01R\x00\x13@\v\x01\t\x05&\x01R\t\x10\a\x02%\x01+5\x00+5\x00\x00\x00\x00\x02\x00\xb8\x00\x00\x04m\x05\xb6\x00\x10\x00\x19\x00H@,\x06\x0f\x01\x15Z\x9f\x00\x01\x00g\x1b\x1f\x1b?\x1b_\x1b\x8f\x1b\xaf\x1b\x05\x11\v\aZ\bd\x1a\x19`\v\x11`\x06\v\x06\v\x06\a\t\x03\a\x12\x00??\x1299//\x10\xe1\x10\xe1\x01\x10\xf6\xe122]\x10\xf6]\xe110]\x01\x14\x0e\x02+\x01\x11!\x11!\x1532\x1e\x02\x0132654&+\x01\x04m3u\xbf\x8d\x8b\xfe\xca\x016\xa1|\xb4u9\xfd\x81Tyxjsh\x03\x02^\xac\x84O\xfe\xdb\x05\xb6\xe5By\xab\xfe\xb4izlg\x00\x01\x00\xa0\xff\xec\x05+\x06\x1f\x00C\x00o\xb5<\x18\t\rH\x12\xb8\xff\xe8\xb3\t\rH\x0e\xb8\xff\xe8@7\t\rHF1\x011G\x00\x99\a\x01H\a\x01\aF*\x00*9E \x01 G\x11WE\x80E\x01\x188F9TD\a \x144M?\x019\x15\xe8\x1d\x01\x1dO\x18\x14\x16\x00?3\xe1]??\xe1\x1299\x01\x10\xf6\xf1\xc2]\x10\xf6\xe1]\x1299\x10\xe1]]\x10\xe1]10+++\x01\x14\x0e\x04\x15\x14\x1e\x02\x17\x1e\x03\x15\x14\x06#\"&'5\x1e\x0332654.\x02'.\x0354>\x0454&#\"\x06\x15\x11!\x114>\x0232\x1e\x02\x04\xa4+?K?+\x195R91L5\x1b\xea\xe3b\x91<\x18ELP\"PX\x0e)JI>)dalk\xfe\xcfJ\x89\xc0us\xbc\x85H\x04\xd9@aL:0*\x16\x14\"(3&\x1fAM\\<\xac\xae\x1d\"\xf2\x10\x1f\x18\x0f=>\x1b**1\"$@?E(5N>45>(?Nah\xfb\x98\x04sm\xa1j4+Sz\x00\x00\x00\xff\xff\x00V\xff\xec\x03\xfe\x06!\x12&\x00D\x00\x00\x11\x06\x00C\xa3\x00\x00\x15\xb4\x02/\x11&\x02\xb8\xff\u01f44;\f\x1e%\x01+5\x00+5\x00\x00\x00\xff\xff\x00V\xff\xec\x03\xfe\x06!\x12&\x00D\x00\x00\x11\x06\x00vm\x00\x00\x13@\v\x02/\x11&\x02\x91/6\f\x1e%\x01+5\x00+5\x00\xff\xff\x00V\xff\xec\x03\xfe\x06 \x12&\x00D\x00\x00\x11\x06\x00\xc3\x00\xff\x00\x13@\v\x02/\x11&\x02$6B\f\x1e%\x01+5\x00+5\x00\xff\xff\x00V\xff\xec\x03\xfe\x06\x0e\x12&\x00D\x00\x00\x11\x06\x00\xc5\xff\x00\x00\x13@\v\x022\x11&\x02$3A\f\x1e%\x01+5\x00+5\x00\xff\xff\x00V\xff\xec\x03\xfe\x06\x04\x12&\x00D\x00\x00\x11\x06\x00j\x06\x00\x00\x17@\r\x03\x02>\x11&\x03\x02+/M\f\x1e%\x01+55\x00+55\x00\xff\xff\x00V\xff\xec\x03\xfe\x06\xb2\x12&\x00D\x00\x00\x11\x06\x00\xc4\x00\x00\x00\x17@\r\x03\x024\x11&\x03\x02%9/\f\x1e%\x01+55\x00+55\x00\x00\x03\x00V\xff\xec\x06\xac\x04u\x004\x00C\x00L\x00\x94@^\n\x0e\x01\n\v\x01\x04\x1e\x01\n\x02\x01\x03\x1eG'F\x1155\r*H\x01\tH\x01HH/%WNONoN\x02;G\x19\rVM59'I'\x02('\x01'P\x11\xd9G\xe9G\x02\xc8G\x01|G\x01GG,(D\x01DO \x10\x18(\x15\x01\x15N\x1c\x10>N\b\x16,N/\x00\x16\x00?2\xe1?\xe1?\xe1]3?\xe1]\x129/]]]3\xe9]]2\x01\x10\xf62\xe9]\x10\xf62\xe9]]\x119/3\xe929910\x00]]\x01]]\x05\"&'\x0e\x03#\".\x02546?\x0154&#\"\x06\a'>\x0132\x17632\x1e\x02\x1d\x01!\x1e\x033267\x15\x0e\x03\x01\a\x0e\x03\x15\x14\x1632>\x025\x01\"\x06\a!.\x03\x04\xf4\x83\xd6E+Tb{RD{]6\xe4\xe3\xb2PHH\x89EcT\xccp\xd6m~\xbco\xb3|C\xfdV\x02%C_=^\xafX(QZh\xfd\x9de=T3\x17D7*H5\x1e\x01\xfeRk\b\x01\x85\x01\x18/H\x14ei6M3\x18+W\x85[\xb2\xa9\t\x06TEB*#\xca/6\x83\x81C\x82\xbdz\x94@gG&+-\xec\x15\x1d\x14\t\x02\x1a\x04\x02\x1c/A(F;\x1d9S6\x01\xf0rz3V?$\x00\x00\x00\xff\xff\x00f\xfe\x14\x03\xbc\x04s\x12&\x00F\x00\x00\x11\a\x00z\x01h\x00\x00\x00\x10@\n\x01P(\x01\x15( \x05\r%\x01+]5\x00\x00\xff\xff\x00f\xff\xec\x04D\x06!\x12&\x00H\x00\x00\x11\x06\x00C\xbd\x00\x00\x15\xb4\x02*\x11&\x02\xb8\xff\xb6\xb4/6\x0e\x18%\x01+5\x00+5\x00\x00\x00\xff\xff\x00f\xff\xec\x04D\x06!\x12&\x00H\x00\x00\x11\x06\x00vs\x00\x00\x13@\v\x02*\x11&\x02l*1\x0e\x18%\x01+5\x00+5\x00\xff\xff\x00f\xff\xec\x04D\x06!\x12&\x00H\x00\x00\x11\x06\x00\xc3\x12\x00\x00\x13@\v\x02*\x11&\x02\v1=\x0e\x18%\x01+5\x00+5\x00\xff\xff\x00f\xff\xec\x04D\x06\x04\x12&\x00H\x00\x00\x11\x06\x00j\x12\x00\x00\x17@\r\x03\x029\x11&\x03\x02\f*H\x0e\x18%\x01+55\x00+55\x00\xff\xff\xff\xd4\x00\x00\x01\xd8\x06!\x12&\x00\xc2\x00\x00\x11\a\x00C\xfe\x88\x00\x00\x00\x15\xb4\x01\x04\x11&\x01\xb8\xff\x9e\xb4\t\x10\x01\x00%\x01+5\x00+5\x00\xff\xff\x00\x91\x00\x00\x02\x95\x06!\x12&\x00\xc2\x00\x00\x11\a\x00v\xffE\x00\x00\x00\x13@\v\x01\x04\x11&\x01Z\x04\v\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\xff\x98\x00\x00\x02\xd4\x06!\x12&\x00\xc2\x00\x00\x11\a\x00\xc3\xfe\xe8\x00\x00\x00\x15\xb4\x01\x04\x11&\x01\xb8\xff\xfe\xb4\v\x17\x01\x00%\x01+5\x00+5\x00\xff\xff\xff\xe0\x00\x00\x02\x8e\x06\x04\x12&\x00\xc2\x00\x00\x11\a\x00j\xfe\xe8\x00\x00\x00\x19\xb6\x02\x01\x13\x11&\x02\x01\xb8\xff\xff\xb4\x04\"\x01\x00%\x01+55\x00+55\x00\x00\x02\x00J\xff\xec\x04H\x06#\x00'\x007\x00v@Q\v$\x01\x05\x11\x01\n\x17\x01\n\x1b\x01(G\xcf\x0f\x01\x0fW9\xcb9\x01/9_9\u007f9\x9f9\x040G\xc4\x19\x01\x19V8\xcf8\x01!\b-\x01-N\u007f\x1e\x8f\x1e\x9f\x1e\x03\x1e\x1e\x04\a5\x015N\x14\x16\b_\x04\x01K\x04\x01/\x04\x01\x1b\x04\x01\x04\x01\x00?]]]]3?\xe9]\x119/]\xe9]2\x01]\x10\xf6]\xe9]]\x10\xf6]\xe910]]]]\x01.\x01'7\x1e\x01\x177\x17\a\x1e\x03\x15\x14\x0e\x02#\".\x0254>\x0232\x16\x177.\x01'\a'\x014.\x02#\"\x06\x15\x14\x1e\x02326\x01\xc9\"N*`I\x809\xe2d\xaeHlG$H\x86\xbevo\xba\x87LAu\xa3a`\x88 \x15\x1ceB\xe7e\x01\xfe\x171K3l]\x171L5j\\\x05\x1d\x150\x17\xaa\"E&\x8b\x9ajE\x9c\xb6\xd0y\x8e\u0718OD\x82\xbdzz\xbc\x81C?1\x02X\x9b8\x90\x9c\xfdh/VB'\x8d\x8e?hJ)\xa3\xff\xff\x00\xa0\x00\x00\x04j\x06\x0e\x12&\x00Q\x00\x00\x11\x06\x00\xc53\x00\x00\x15\xb4\x01\x1e\x11&\x01\xb8\xff\xfd\xb4\x1f-\f\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00f\xff\xec\x04d\x06!\x12&\x00R\x00\x00\x11\x06\x00C\xc4\x00\x00\x15\xb4\x02 \x11&\x02\xb8\xff\xad\xb4%,\x16\f%\x01+5\x00+5\x00\x00\x00\xff\xff\x00f\xff\xec\x04d\x06!\x12&\x00R\x00\x00\x11\x06\x00vf\x00\x00\x13@\v\x02 \x11&\x02O '\x16\f%\x01+5\x00+5\x00\xff\xff\x00f\xff\xec\x04d\x06!\x12&\x00R\x00\x00\x11\x06\x00\xc3\x14\x00\x00\x15\xb4\x02 \x11&\x02\xb8\xff\xfd\xb4'3\x16\f%\x01+5\x00+5\x00\x00\x00\xff\xff\x00f\xff\xec\x04d\x06\x0e\x12&\x00R\x00\x00\x11\x06\x00\xc5\x12\x00\x00\x15\xb4\x02#\x11&\x02\xb8\xff\xfc\xb4$2\x16\f%\x01+5\x00+5\x00\x00\x00\xff\xff\x00f\xff\xec\x04d\x06\x04\x12&\x00R\x00\x00\x11\x06\x00j\x12\x00\x00\x19\xb6\x03\x02/\x11&\x03\x02\xb8\xff\xfc\xb4 >\x16\f%\x01+55\x00+55\x00\x00\x00\x00\x03\x00X\x00\xdd\x04\x10\x04\xc7\x00\x03\x00\x17\x00+\x00`@7\x0e\xa0\"\x01\"\x04\xc4\x18\xd4\x18\x02\x18\x18\x01=\x02M\x02}\x02\x8d\x02\x04\v\x02+\x02\x02\x02-\v\x01\x01\x01'\xad\xe0\x1d\x01\x0f\x1d?\x1d_\x1d\xaf\x1d\x04\x1d\t\xad\x90\x13\x01\x13\xb8\xff\xc0\xb6\v\x0fH\x13\x00\xad\x01\x00/\xe9/+]\xe9/]]\xe9\x01/]\x10\xce]]\x119/]3\xcd]210\x135!\x15\x054>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x114>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02X\x03\xb8\xfd\x98\x16&3\x1c\x1c2&\x17\x17&2\x1c\x1c3&\x16\x16&3\x1c\x1c2&\x17\x17&2\x1c\x1c3&\x16\x02d\xdb\xdb\xef*:#\x10\x10#:*(:%\x11\x11%:\x02\xe2*:$\x10\x10$:*(9%\x11\x11%9\x00\x03\x00f\xff\xb4\x04d\x04\x91\x00\x1b\x00#\x00,\x00\xaa@S\xe7'\x01\xd6'\x01w'\x97'\x02#'3'\x02\x14'\x01\xf8&\x01\xe9\x1f\x01\xb8\x1f\x01,\x1f<\x1f\x02\x1a\x1f\x01\n\x10\x01\x05\x02\x01%\x16\x01\xdf\t\x01'\x1f\x1c\b$\x18$8$H$\x04$G\x00W._.\x01\a\x1c\x17\x1c7\x1cG\x1c\x04\x1cG\x0eV-\x1e\xb8\xff\xe0@%\t\x0eH& \t\x0eH\x1e&*\b!\x18!8!H!\x04!M\x13\x10\a*\x17*7*G*\x04*M\x05\x16\x00?\xe9]?\xe9]\x1199++\x01\x10\xf6\xe9]]\x10\xf6\xe9]\x119910\x00]]\x01]]]]]]]]]]]]\x01\x14\x0e\x02#\"&'\a'7.\x0154>\x0232\x16\x177\x17\a\x1e\x01\x05\x14\x17\x01&#\"\x06\x054'\x01\x1e\x01326\x04dG\x85\xbfw9h09\xa2DEOG\x85\xbex>s31\xa0>?F\xfd:\f\x01\x1b(9i]\x01\x8f\x06\xfe\xf4\x11%\x15i^\x021\x8c\u0614M\x14\x12^ZoJ\u06cf\x8b\u0613L\x1a\x17O`bH\u0445VA\x01\xca\x19\xa5\xa7@1\xfeN\b\a\xaa\xff\xff\x00\x9a\xff\xec\x04d\x06!\x12&\x00X\x00\x00\x11\x06\x00C\xc2\x00\x00\x15\xb4\x01\x1b\x11&\x01\xb8\xff\x91\xb4 '\f\x19%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x9a\xff\xec\x04d\x06!\x12&\x00X\x00\x00\x11\a\x00v\x00\x81\x00\x00\x00\x13@\v\x01\x1b\x11&\x01P\x1b\"\f\x19%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x9a\xff\xec\x04d\x06!\x12&\x00X\x00\x00\x11\x06\x00\xc3)\x00\x00\x15\xb4\x01\x1b\x11&\x01\xb8\xff\xf8\xb4\".\f\x19%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x9a\xff\xec\x04d\x06\x04\x12&\x00X\x00\x00\x11\x06\x00j/\x00\x00\x19\xb6\x02\x01*\x11&\x02\x01\xb8\xff\xff\xb4\x1b9\f\x19%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\x00\xfe\x14\x04P\x06!\x12&\x00\\\x00\x00\x11\x06\x00v=\x00\x00\x13@\v\x01\x1f\x11&\x01c\x1f&\x00\r%\x01+5\x00+5\x00\x00\x02\x00\xa0\xfe\x14\x04w\x06\x14\x00$\x005\x008@ \x05\f\x01\x05\b\x013G\nW7+\x1f\x1bF\x1cT6\x1d\x00\x1b\x1b\x140M\x0f\x16\x00%M\x05\x10\x00?\xe12?\xe12??\x01\x10\xf6\xe122\x10\xf6\xe110]]\x01>\x0332\x1e\x02\x15\x14\x0e\x02#\".\x02'#\x16\x17\x1e\x01\x15\x11!\x11!\x11\x14\x06\a\x06\a\x17\"\x0e\x02\a\x15\x14\x1e\x0232654&\x01\xd1\x147HY7V\x8ef98f\x8eW7ZG6\x15\x0e\x03\x04\x03\x04\xfe\xcf\x011\x04\x03\x04\x03\xca3G,\x14\x02\x13,I6[UU\x03\xcd#<-\x1aJ\x92\u060e\x8f\u0653J\x15&2\x1c \x1e\x1a4\x10\xfe;\b\x00\xfey\x18B\x1e#%N%JqK!Q~U,\xad\xa5\xa5\xa5\x00\x00\x00\xff\xff\x00\x00\xfe\x14\x04P\x06\x04\x12&\x00\\\x00\x00\x11\x06\x00j\xda\x00\x00\x17@\r\x02\x01.\x11&\x02\x01\x01\x1f=\x00\r%\x01+55\x00+55\x00\x00\x01\x00\xa0\x00\x00\x01\xd1\x04^\x00\x03\x00 @\x13\xbf\x05\x010\x05`\x05\x90\x05\x03\x00F\x01T\x04\x02\x0f\x01\x15\x00??\x01\x10\xf6\xe9]]10)\x01\x11!\x01\xd1\xfe\xcf\x011\x04^\x00\x00\x00\x01\x00\xb0\x04\xd9\x03\xec\x06!\x00\x14\x006@!\x00\x00\x14\xf0\x14\x02\x14\x14\x06\a\xfb\x03\x01)\x03\x01\x03\x0f\r_\ro\r\x03\r\r\a\x0f\x00_\x00\x02\x00\x00/]22/]3]]\x01/33/]310\x01.\x01'\x0e\x01\a#5>\x037!\x1e\x03\x17\x15\x03!3n46h3\xcb\x1a?A<\x16\x01d\x15\x0232\x1e\x02\a4&#\"\x06\x15\x14\x16326\x03J'E\\67\\A$$A\\75\\E(\x9e6**600*6\x05\xc78Y>!!=Y77X=!!=W8-33--44\x00\x00\x01\x00\xc5\x04\xd7\x03\xd9\x06\x0e\x00\x1b\x00H@0\x11\x90\x12\x01o\x12\x01\x12\x03\x00\x04p\x04\x02\x04\x12H\x00\x01\x00\x8e\x0f\t_\to\t\u007f\t\xdf\t\xef\t\x06\t\tG\x0e\x01\x0e\x8e\x04\x0f\x17_\x17\x02\x17\x00/]3\xe1]3/]\xe1]3\x01/]3/]]310\x01\"\x06\a#>\x0332\x1e\x0232673\x0e\x03#\".\x02\x01\xaa\x1f%\f\x95\x06(AX5)NMK$\x1f$\r\x95\x06)BW4(PLK\x05B56PtL% '!46OtM%!'!\x00\x00\x00\x00\x01\x00R\x01\xb4\x03\xae\x02\x9a\x00\x03\x00\x11\xb6\x02\x05\x00\x00\xba\x01\xbd\x00?\xe9\x01/\x10\xce10\x135!\x15R\x03\\\x01\xb4\xe6\xe6\x00\x00\x00\x01\x00R\x01\xb4\a\xae\x02\x9a\x00\x03\x00\x11\xb6\x02\x05\x00\x00\xba\x01\xbd\x00?\xe9\x01/\x10\xce10\x135!\x15R\a\\\x01\xb4\xe6\xe6\x00\x00\x00\x01\x00\x17\x03\xc1\x01\xa2\x05\xb6\x00\f\x00E@2\x0f\x0e\x1f\x0e/\x0e\x03)\x069\x06I\x06\xb9\x06\x04\x06\a\x97\xa4\f\xb4\f\x02v\f\x86\f\x96\f\x033\fC\f\x02%\f\x01\x06\f\x16\f\x02\f\x01\f\x9c\x06\x03\x00?\xed\x01/3]]]]]\xed2]]10\x13'>\x0373\x0e\x03\a%\x0e\x0e'.4\x19\xdb\x0f\x1d\x1b\x16\b\x03\xc1\x166z|{8=\x84\x83|5\x00\x00\x00\x01\x00\x17\x03\xc1\x01\xa2\x05\xb6\x00\f\x00C@1\x0f\x0e\x1f\x0e/\x0e\x03\xab\f\xbb\f\x02y\f\x89\f\x99\f\x03<\fL\f\x02\n\f\x1a\f*\f\x03\f\x01\x97&\x066\x06F\x06\xb6\x06\x04\x06\a\x06\x9c\f\x03\x00?\xed\x01/3]\xed2]]]]]10\x01\x17\x0e\x03\a#>\x037\x01\x93\x0f\x0e'/3\x19\xdb\x0e\x1d\x1b\x16\b\x05\xb6\x167y}z8<\x84\x84|5\x00\x00\x00\x00\x01\x00?\xfe\xf8\x01\xcb\x00\xee\x00\f\x00V@A\xa0\x0e\xb0\x0e\xe0\x0e\xf0\x0e\x04/\x0e?\x0e\x02\xab\v\xbb\v\x02y\v\x89\v\x99\v\x03<\vL\v\x02\n\v\x1a\v*\v\x03\v\x00\x97&\x056\x05F\x05\x03\x05/\x06?\x06O\x06\x03\x06\x05\x9c\v@\t\fH\v\x00/+\xed\x01/]3]\xed2]]]]]]10%\x0e\x03\a#>\x037!\x01\xcb\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b\x01\x18\xd76z|{8=\x84\x83}5\x00\x00\x02\x00\x17\x03\xc1\x03u\x05\xb6\x00\f\x00\x19\x00x@Z\x0f\x1b\x1f\x1b\x02)\x129\x12I\x12\xb9\x12\x04\x12\x13\x97\xa4\x18\xb4\x18\x023\x18C\x18\x02v\x18\x86\x18\x96\x18\x03\x05\x18\x15\x18%\x18\x03\x18\r)\x059\x05I\x05\xb9\x05\x04\x05\x06\x97\xa4\v\xb4\v\x02v\v\x86\v\x96\v\x033\vC\v\x02\x05\v\x15\v%\v\x03\v\xa0\x00\x01\x00\x18\v\x9c\x12\x05\x03\x00?3\xed2\x01/]3]]]]\xed2]/3]]]]\xed2]]10\x01>\x0373\x0e\x03\a!%>\x0373\x0e\x03\a!\x01\xe9\x0e(.4\x19\xdb\x0f\x1d\x1b\x16\b\xfe\xe8\xfe\x1f\x0e'.4\x19\xdb\x0f\x1d\x1b\x16\b\xfe\xe8\x03\xd76z|{8=\x84\x83|5\x166z|{8=\x84\x83|5\x00\x00\x02\x00\x17\x03\xc1\x03u\x05\xb6\x00\f\x00\x19\x00x@Z\x0f\x1b\x1f\x1b\x02\xab\x18\xbb\x18\x02<\x18L\x18\x02y\x18\x89\x18\x99\x18\x03\n\x18\x1a\x18*\x18\x03\x18\r\x97&\x126\x12F\x12\xb6\x12\x04\x12\xa0\x13\x01\x13\xab\v\xbb\v\x02y\v\x89\v\x99\v\x03<\vL\v\x02\n\v\x1a\v*\v\x03\v\x00\x97&\x056\x05F\x05\xb6\x05\x04\x05\x06\x12\x05\x9c\x18\v\x03\x00?3\xed2\x01/3]\xed2]]]]/]3]\xed2]]]]]10\x01\x0e\x03\a#>\x037!\x05\x0e\x03\a#>\x037!\x01\xa2\x0e'/3\x19\xdb\x0e\x1d\x1b\x16\b\x01\x18\x01\xe2\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b\x01\x18\x05\xa07y}z8<\x84\x84|5\x167y}z8<\x84\x84|5\x00\x00\x02\x00?\xfe\xf8\x03\x9e\x00\xee\x00\f\x00\x19\x00\xa7@\x83\xa0\x1b\xb0\x1b\xc0\x1b\xe0\x1b\xf0\x1b\x05_\x1bo\x1b\u007f\x1b\x03 \x1b0\x1b\x02\xab\x18\xbb\x18\x02y\x18\x89\x18\x99\x18\x03<\x18L\x18\x02\n\x18\x1a\x18*\x18\x03\x18\r\x97&\x126\x12F\x12\xb6\x12\x04\x12O\x13o\x13\u007f\x13\x8f\x13\x04\x10\x13\x01\x13\xab\v\xbb\v\x02y\v\x89\v\x99\v\x03<\vL\v\x02\n\v\x1a\v*\v\x03\v\x00\x97&\x056\x05F\x05\xb6\x05\x04\x05\xc0\x06\x01O\x06_\x06o\x06\x03\x06\x12\x05\x9c\x18\v@\t\fH\v\x00/+3\xed2\x01/]]3]\xed2]]]]/]]3]\xed2]]]]]]]10%\x0e\x03\a#>\x037!\x05\x0e\x03\a#>\x037!\x01\xcb\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b\x01\x18\x01\xe2\x0e'/3\x19\xdc\x0f\x1d\x1b\x16\b\x01\x18\xd76z|{8=\x84\x83}5\x176z|{8=\x84\x83}5\x00\x00\x00\x00\x01\x00b\x01\xae\x02\xa0\x04)\x00\x13\x00G@-`\x15p\x15\x90\x15\xe0\x15\x04\x0f\x15\x1f\x15/\x15O\x15_\x15\x05\x80\n\x01\n`\x00p\x00\x90\x00\x03\x1f\x00\x01\x000\x05\xc0\x05\xd0\x05\xe0\x05\x04\x05\xb8\xff\xc0\xb4\x0f\x13H\x05\x0f\x00/\xcd+]\x01/]]\xcd]]]10\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02b,Mi=;iN--Ni;=iM,\x02\xecVxL##LxVUxM$$Mx\x00\x00\x01\x00R\x00^\x02b\x04\x04\x00\x06\x00+@\x16\x03\xeb\x06\xec\x05\x04\x04\x01\x19\x02\x01\x02\b\x04\x05\xed\x02\x01\xed\x00\x03\xef\x00?3\xed2\xed2\x01\x10\xde]22\x113\xfd\xe910\x13\x01\x17\x03\x13\a\x01R\x015\xdb\xd9\xd9\xdb\xfe\xcb\x02=\x01\xc7w\xfe\xa4\xfe\xa4w\x01\xc5\x00\x00\x00\x00\x01\x00R\x00^\x02b\x04\x04\x00\x06\x00+@\x16\x05\x04\x04\x01\x02\xec\x03\xeb\x16\x06\x01\x06\b\x04\x05\xed\x02\x01\xed\x06\x03\xef\x00?3\xed2\xed2\x01\x10\xde]\xe9\xed22\x11310\t\x01'\x13\x037\x01\x02b\xfe\xcb\xdb\xd9\xd9\xdb\x015\x02#\xfe;w\x01\\\x01\\w\xfe9\x00\x00\x00\x01\xfew\x00\x00\x02\x91\x05\xb6\x00\x03\x00\x1f\xb7\x03\x00\x10\x00\x00\x05\x01\x02\xb8\xff\xf0\xb3\x02\x01\x03\x03\x00?/\x01/83\x113/8210\t\x01#\x01\x02\x91\xfc\xd5\xef\x03+\x05\xb6\xfaJ\x05\xb6\x00\x00\x00\x02\x00\f\x02J\x02\xf6\x05\xbc\x00\n\x00\x15\x00\\@<5\x15E\x15\x02\x0f\x17\x1f\x17/\x17_\x17\xdf\x17\xef\x17\xff\x17\a\t\x006\x02F\x02\x02\x02\xe0\v\a2\x03B\x03\x02\x03\x03\x16\x17\x15\x05@\x14\x18H\x05\x01\x05\xe5\t\x06\x15\x15\x03\x0f\a\xdc\x03\xdd\x00??3\x129/33\xe92\x01/+2\x11\x129/]33\xe9]22]10]\x01#\x15#5!5\x013\x113!5467\x0e\x03\x0f\x01\x02\xf6}\xee\xfe\x81\x01\x81\xec}\xfe\x95\x03\x03\x05\x13\x16\x16\t\u007f\x02\u15d7\x9a\x02A\xfd\u0364*]1\r+-*\x0e\xbf\x00\x00\x01\x00\x00\x00\xd3\x00g\x00\x05\x00U\x00\x04\x00\x02\x00\x10\x00/\x00Z\x00\x00\x01\xcd\x01&\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x86\x01$\x01\xf2\x02\xa2\x03^\x03\x86\x03\xb6\x03\xe4\x04\x1a\x04B\x04\x86\x04\xa0\x04\xd4\x04\xf8\x05>\x05p\x05\xbc\x06:\x06\x82\x06\xf2\al\a\x96\bR\b\xca\t\x1c\t\x84\t\xca\t\xf8\n>\n\xae\vf\v\xda\f\\\f\xb6\f\xf4\r0\rr\r\xd2\x0e\x10\x0eF\x0e\x82\x0e\xda\x0e\xfe\x0fz\x0f\xe8\x10<\x10\x82\x10\xf8\x11l\x11\xe2\x12\x14\x12T\x12\xa2\x13\x88\x13\xe6\x148\x14\x8a\x14\xae\x14\xd2\x14\xf4\x15(\x15@\x15p\x15\xe6\x16J\x16\x98\x16\xfc\x17n\x17\xbc\x18\x9a\x18\xe4\x19$\x19\x82\x19\xdc\x19\xfa\x1ap\x1a\xb8\x1b\x04\x1bh\x1b\xcc\x1c\x18\x1c\x98\x1c\xf0\x1d8\x1d\xa2\x1e\x80\x1f\x1e\x1f\xa6\x1f\xfc ` z \xe0!F!F!\xa4\"\x12\"\x98#6#\xb4#\xda$\xb4$\xfe%\xa4&*&|&\x98&\xa0'L'b'\xaa'\xec(F(\xd6)\x06)T)\x90)\xc4*\x14*P*\xae+\x02+(+R+t+\xea,\x02,\x1a,2,J,d,\x80,\xee-\x02-\x1a-2-J-d-|-\x94-\xac-\xc6...F.^.v.\x8e.\xa6.\xc0/\x18/\x82/\x9a/\xb2/\xca/\xe4/\xfc0J0\xde0\xf61\f1\"181P1h2 262N2d2z2\x922\xaa2\xc22\xda2\xf43\x823\x9a3\xb23\xc83\xe03\xf84\x124\x825 585P5h5\x825\x986\x046\x1c6:6z6\xf67F7\\7r7\xae7\xea8.8\x968\xfe9~9\xc29\xee:\x1a:::\x8e\x00\x01\x00\x00\x00\x01\x00\x00W6\x82\xd7_\x0f<\xf5\x00\x1f\b\x00\x00\x00\x00\x00\xc8\x17O\xfa\x00\x00\x00\x00\xc8\\\x86Y\xfew\xfe\x14\a\xae\as\x00\x01\x00\b\x00\x02\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x02\x14\x00\x00\x02J\x00u\x03\xc7\x00\x85\x05+\x00-\x04h\x00b\a\f\x00?\x05\xc7\x00R\x02!\x00\x85\x02\xb6\x00R\x02\xb6\x00=\x04\\\x00?\x04h\x00X\x02R\x00?\x02\x93\x00=\x02H\x00u\x03N\x00\x0e\x04h\x00?\x04h\x00\\\x04h\x00N\x04h\x009\x04h\x00\x04\x04h\x00V\x04h\x00L\x04h\x007\x04h\x00H\x04h\x00?\x02H\x00u\x02R\x00?\x04h\x00X\x04h\x00X\x04h\x00X\x03\xac\x00\x19\x06\xee\x00f\x053\x00\x00\x05#\x00\xb8\x05\x19\x00w\x05\x9a\x00\xb8\x04{\x00\xb8\x04d\x00\xb8\x05\xcb\x00w\x05\xcd\x00\xb8\x03\x1d\x00B\x02\xa6\xff9\x05\x12\x00\xb8\x04H\x00\xb8\aN\x00\xb8\x06D\x00\xb8\x06\f\x00w\x04\xc9\x00\xb8\x06\f\x00w\x05\n\x00\xb8\x041\x00^\x04d\x00)\x05\xba\x00\xae\x04\xe1\x00\x00\aj\x00\x00\x05\x04\x00\x00\x04\xac\x00\x00\x04P\x001\x02\xa6\x00\x8f\x03N\x00\f\x02\xa6\x003\x04B\x00\b\x03J\xff\xfc\x04\x9e\x01L\x04\x98\x00V\x04\xdd\x00\xa0\x03\xfe\x00f\x04\xdd\x00f\x04\xa6\x00f\x03\x19\x00)\x04j\x00\x14\x05\x04\x00\xa0\x02q\x00\x93\x02q\xff\xae\x04\xb8\x00\xa0\x02q\x00\xa0\a\x89\x00\xa0\x05\x04\x00\xa0\x04\xcb\x00f\x04\xdd\x00\xa0\x04\xdd\x00f\x03y\x00\xa0\x03\xd9\x00b\x03P\x00/\x05\x04\x00\x9a\x04P\x00\x00\x06s\x00\x00\x04b\x00\n\x04P\x00\x00\x03\xa8\x007\x02\xe9\x00\x1f\x04h\x01\xc7\x02\xe9\x00\x1f\x04h\x00X\x02\x14\x00\x00\x02J\x00u\x04h\x00\x8f\x04h\x00R\x04h\x00\\\x04h\x00\b\x04h\x01\xc7\x03\xe3\x00j\x04\x9e\x00\xf8\x06\xa8\x00d\x02\xe7\x00/\x04\xae\x00R\x04h\x00X\x02\x93\x00=\x06\xa8\x00d\x04\x00\xff\xfa\x03m\x00\\\x04h\x00X\x03\b\x00/\x03\b\x00;\x04\x9e\x01L\x05\n\x00\xa0\x05=\x00q\x02H\x00u\x01\xa4\xff\xdb\x03\b\x00\\\x02\xf2\x009\x04\xae\x00T\a\f\x00.\a\f\x00.\a\f\x00Z\x03\xac\x00B\x053\x00\x00\x053\x00\x00\x053\x00\x00\x053\x00\x00\x053\x00\x00\x053\x00\x00\a`\x00\x00\x05\x19\x00w\x04{\x00\xb8\x04{\x00\xb8\x04{\x00\xb8\x04{\x00\xb8\x03\x1d\x00*\x03\x1d\x00B\x03\x1d\xff\xf0\x03\x1d\x006\x05\x9a\x00/\x06D\x00\xb8\x06\f\x00w\x06\f\x00w\x06\f\x00w\x06\f\x00w\x06\f\x00w\x04h\x00m\x06\f\x00w\x05\xba\x00\xae\x05\xba\x00\xae\x05\xba\x00\xae\x05\xba\x00\xae\x04\xac\x00\x00\x04\xc9\x00\xb8\x05s\x00\xa0\x04\x98\x00V\x04\x98\x00V\x04\x98\x00V\x04\x98\x00V\x04\x98\x00V\x04\x98\x00V\a\x0e\x00V\x03\xfe\x00f\x04\xa6\x00f\x04\xa6\x00f\x04\xa6\x00f\x04\xa6\x00f\x02q\xff\xd4\x02q\x00\x91\x02q\xff\x98\x02q\xff\xe0\x04\x9e\x00J\x05\x04\x00\xa0\x04\xcb\x00f\x04\xcb\x00f\x04\xcb\x00f\x04\xcb\x00f\x04\xcb\x00f\x04h\x00X\x04\xcb\x00f\x05\x04\x00\x9a\x05\x04\x00\x9a\x05\x04\x00\x9a\x05\x04\x00\x9a\x04P\x00\x00\x04\xdd\x00\xa0\x04P\x00\x00\x02q\x00\xa0\x04\x9e\x00\xb0\x04\x9e\x01T\x04\x9e\x00\xc5\x04\x00\x00R\b\x00\x00R\x01\xb8\x00\x17\x01\xb8\x00\x17\x02R\x00?\x03\x8b\x00\x17\x03\x8b\x00\x17\x04%\x00?\x03\x02\x00b\x02\xb4\x00R\x02\xb4\x00R\x01\n\xfew\x03\b\x00\f\x00\x01\x00\x00\as\xfe\x14\x00\x00\b\x00\xfew\xfey\a\xae\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x03\x04c\x02\xbc\x00\x05\x00\b\x05\x9a\x053\x00\x00\x01\x1e\x05\x9a\x053\x00\x00\x03\xd0\x00f\x01\xfc\x00\x00\x02\v\b\x06\x03\b\x04\x02\x02\x04\xe0\x00\x02\xef@\x00 [\x00\x00\x00(\x00\x00\x00\x001ASC\x00 \x00 D\x06\x1f\xfe\x14\x00\x84\as\x01\xec \x00\x01\x9f\x00\x00\x00\x00\x04^\x05\xb6\x00\x00\x00 \x00\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x14\x00\x03\x00\x01\x00\x00\x00\x14\x00\x04\x00x\x00\x00\x00\x1a\x00\x10\x00\x03\x00\n\x00~\x00\xff\x011\x02\xc6\x02\xda\x02\xdc \x14 \x1a \x1e \" : D\xff\xff\x00\x00\x00 \x00\xa0\x011\x02\xc6\x02\xda\x02\xdc \x13 \x18 \x1c \" 9 D\xff\xff\xff\xe3\xff\xc2\xff\x91\xfd\xfd\xfd\xea\xfd\xe9\xe0\xb3\xe0\xb0\xe0\xaf\xe0\xac\xe0\x96\xe0\x8d\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#\"!\x1f\x18\x14\x11\x10\x0f\x0e\r\v\n\t\b\a\x06\x05\x04\x03\x02\x01\x00,E#F` \xb0&`\xb0\x04&#HH-,E#F#a \xb0&a\xb0\x04&#HH-,E#F`\xb0 a \xb0F`\xb0\x04&#HH-,E#F#a\xb0 ` \xb0&a\xb0 a\xb0\x04&#HH-,E#F`\xb0@a \xb0f`\xb0\x04&#HH-,E#F#a\xb0@` \xb0&a\xb0@a\xb0\x04&#HH-,\x01\x10 <\x00<-, E# \xb0\xcdD# \xb8\x01ZQX# \xb0\x8dD#Y \xb0\xedQX# \xb0MD#Y \xb0\x04&QX# \xb0\rD#Y!!-, E\x18hD \xb0\x01` E\xb0Fvh\x8aE`D-,\x01\xb1\v\nC#Ce\n-,\x00\xb1\n\vC#C\v-,\x00\xb0(#p\xb1\x01(>\x01\xb0(#p\xb1\x02(E:\xb1\x02\x00\b\r-, E\xb0\x03%Ead\xb0PQXED\x1b!!Y-,I\xb0\x0e#D-, E\xb0\x00C`D-,\x01\xb0\x06C\xb0\aCe\n-, i\xb0@a\xb0\x00\x8b \xb1,\xc0\x8a\x8c\xb8\x10\x00b`+\fd#da\\X\xb0\x03aY-,\x8a\x03E\x8a\x8a\x87\xb0\x11+\xb0)#D\xb0)z\xe4\x18-,Ee\xb0,#DE\xb0+#D-,KRXED\x1b!!Y-,KQXED\x1b!!Y-,\x01\xb0\x05%\x10# \x8a\xf5\x00\xb0\x01`#\xed\xec-,\x01\xb0\x05%\x10# \x8a\xf5\x00\xb0\x01a#\xed\xec-,\x01\xb0\x06%\x10\xf5\x00\xed\xec-,F#F`\x8a\x8aF# F\x8a`\x8aa\xb8\xff\x80b# \x10#\x8a\xb1\f\f\x8apE` \xb0\x00PX\xb0\x01a\xb8\xff\xba\x8b\x1b\xb0F\x8cY\xb0\x10`h\x01:-, E\xb0\x03%FRK\xb0\x13Q[X\xb0\x02%F ha\xb0\x03%\xb0\x03%?#!8\x1b!\x11Y-, E\xb0\x03%FPX\xb0\x02%F ha\xb0\x03%\xb0\x03%?#!8\x1b!\x11Y-,\x00\xb0\aC\xb0\x06C\v-,!!\fd#d\x8b\xb8@\x00b-,!\xb0\x80QX\fd#d\x8b\xb8 \x00b\x1b\xb2\x00@/+Y\xb0\x02`-,!\xb0\xc0QX\fd#d\x8b\xb8\x15Ub\x1b\xb2\x00\x80/+Y\xb0\x02`-,\fd#d\x8b\xb8@\x00b`#!-,KSX\x8a\xb0\x04%Id#Ei\xb0@\x8ba\xb0\x80b\xb0 aj\xb0\x0e#D#\x10\xb0\x0e\xf6\x1b!#\x8a\x12\x11 9/Y-,KSX \xb0\x03%Idi \xb0\x05&\xb0\x06%Id#a\xb0\x80b\xb0 aj\xb0\x0e#D\xb0\x04&\x10\xb0\x0e\xf6\x8a\x10\xb0\x0e#D\xb0\x0e\xf6\xb0\x0e#D\xb0\x0e\xed\x1b\x8a\xb0\x04&\x11\x12 9# 9//Y-,E#E`#E`#E`#vh\x18\xb0\x80b -,\xb0H+-, E\xb0\x00TX\xb0@D E\xb0@aD\x1b!!Y-,E\xb10/E#Ea`\xb0\x01`iD-,KQX\xb0/#p\xb0\x14#B\x1b!!Y-,KQX \xb0\x03%EiSXD\x1b!!Y\x1b!!Y-,E\xb0\x14C\xb0\x00`c\xb0\x01`iD-,\xb0/ED-,E# E\x8a`D-,E#E`D-,K#QX\xb9\x003\xff\xe0\xb14 \x1b\xb33\x004\x00YDD-,\xb0\x16CX\xb0\x03&E\x8aXdf\xb0\x1f`\x1bd\xb0 `f X\x1b!\xb0@Y\xb0\x01aY#XeY\xb0)#D#\x10\xb0)\xe0\x1b!!!!!Y-,\xb0\x02CTXKS#KQZX8\x1b!!Y\x1b!!!!Y-,\xb0\x16CX\xb0\x04%Ed\xb0 `f X\x1b!\xb0@Y\xb0\x01a#X\x1beY\xb0)#D\xb0\x05%\xb0\b%\b X\x02\x1b\x03Y\xb0\x04%\x10\xb0\x05% F\xb0\x04%#B<\xb0\x04%\xb0\a%\b\xb0\a%\x10\xb0\x06% F\xb0\x04%\xb0\x01`#B< X\x01\x1b\x00Y\xb0\x04%\x10\xb0\x05%\xb0)\xe0\xb0) EeD\xb0\a%\x10\xb0\x06%\xb0)\xe0\xb0\x05%\xb0\b%\b X\x02\x1b\x03Y\xb0\x05%\xb0\x03%CH\xb0\x04%\xb0\a%\b\xb0\x06%\xb0\x03%\xb0\x01`CH\x1b!Y!!!!!!!-,\x02\xb0\x04% F\xb0\x04%#B\xb0\x05%\b\xb0\x03%EH!!!!-,\x02\xb0\x03% \xb0\x04%\b\xb0\x02%CH!!!-,E# E\x18 \xb0\x00P X#e#Y#h \xb0@PX!\xb0@Y#XeY\x8a`D-,KS#KQZX E\x8a`D\x1b!!Y-,KTX E\x8a`D\x1b!!Y-,KS#KQZX8\x1b!!Y-,\xb0\x00!KTX8\x1b!!Y-,\xb0\x02CTX\xb0F+\x1b!!!!Y-,\xb0\x02CTX\xb0G+\x1b!!!Y-,\xb0\x02CTX\xb0H+\x1b!!!!Y-,\xb0\x02CTX\xb0I+\x1b!!!Y-, \x8a\b#KS\x8aKQZX#8\x1b!!Y-,\x00\xb0\x02%I\xb0\x00SX \xb0@8\x11\x1b!Y-,\x01F#F`#Fa# \x10 F\x8aa\xb8\xff\x80b\x8a\xb1@@\x8apE`h:-, \x8a#Id\x8a#SX<\x1b!Y-,KRX}\x1bzY-,\xb0\x12\x00K\x01KTB-,\xb1\x02\x00B\xb1#\x01\x88Q\xb1@\x01\x88SZX\xb9\x10\x00\x00 \x88TX\xb2\x02\x01\x02C`BY\xb1$\x01\x88QX\xb9 \x00\x00@\x88TX\xb2\x02\x02\x02C`B\xb1$\x01\x88TX\xb2\x02 \x02C`B\x00K\x01KRX\xb2\x02\b\x02C`BY\x1b\xb9@\x00\x00\x80\x88TX\xb2\x02\x04\x02C`BY\xb9@\x00\x00\x80c\xb8\x01\x00\x88TX\xb2\x02\b\x02C`BY\xb9@\x00\x01\x00c\xb8\x02\x00\x88TX\xb2\x02\x10\x02C`BY\xb9@\x00\x02\x00c\xb8\x04\x00\x88TX\xb2\x02@\x02C`BYYYYY-,E\x18h#KQX# E d\xb0@PX|Yh\x8a`YD-,\xb0\x00\x16\xb0\x02%\xb0\x02%\x01\xb0\x01#>\x00\xb0\x02#>\xb1\x01\x02\x06\f\xb0\n#eB\xb0\v#B\x01\xb0\x01#?\x00\xb0\x02#?\xb1\x01\x02\x06\f\xb0\x06#eB\xb0\a#B\xb0\x01\x16\x01-,z\x8a\x10E#\xf5\x18-\x00\x00\x00@3\t\xf8\x03\xff\x1fP\xf4\x01\x9f\xf3\x010\xf1\x017\xf0G\xf0W\xf0\x03/\xef\x9f\xef\x02@\xedP\xed\xd0\xed\x030\xec\x01%\xeb5\xebU\xebe\xeb\x04W\xe4\x01f\xe1\x01\xb8\xff\xf0\xb3\xe0\x13\x16F\xb8\xff\xf0@?\xe0\v\x0eF\xfc\xfb3\x1f\xdf3\xddU\xde3\xdcU0\xfb@\xfb`\xfb\x03_\xdd\xcf\xdd\x02 \xdd0\xdd\x02\xdc\x03\x19\x1f\xc9\xc8\x19\x1f\xc6\xc53\x1f\xfe\xc2\x19\x1f0\xc0\x01\xbb\xba\x19\x1f@\xb7`\xb7\x80\xb7\x03\xb8\xff\xc0\xb3\xb7\x11\x14F\xb8\xff\u8db4\t\rF\xc0\xb1\x01\xb8\xff\xe8@\xa1\xaf\n\x0eF/\x9c?\x9c\xff\x9c\x03\x8f\x9b\xef\x9b\x02\x9a\x99\x19\x1f\xc0\x97\u0417\x02\x90\x8d\x19\x1f\x1f\x8c/\x8c?\x8c\x03O\x8c\xbf\x8c\u03cc\x03\xbb\x82\x01g\xfa\xa7\xfa\x02Ft\x01&n6n\x02\x1a\x01\x18U\x19\x13\xff\x1f\a\x04\xff\x1f\x06\x03\xff\x1f\xbfg\x01 f\x80f\x90f\x03\x8fe\x9fe\x02 d\xb0d\x02'^7^\x02&]\x01\\Z\x14\x1f[Z\x14\x1f&Z6Z\x02\x133\x12U\x05\x01\x03U\x043\x03U\x0f\x03\x01/\x03\x9f\x03\x02\vW\x1bW+W\xebW\x04\a\x12V\"V2V\xa2V\x04\xafU\x01\xc4T\x01\xb8\xff\xe0@!T\a\fF S\xf0S\x02FO\x017O\x01FN\x017N\x01[\xffk\xff{\xff\x03 \xff\x13\x18F\xb8\xff\xf0\xb7H\t\fFGF\x19\x1f\xb8\xff\xf0@1F\t\fF\x163\x15U\x11\x01\x0fU\x103\x0fU\x02\x01\x00U\x01G\x00U\xaf\x0f\xcf\x0f\x020\x0f\x01o\x00\u007f\x00\xaf\x00\xef\x00\x04\x10\x00\x01\x80\x16\x01\x05\x01\xb8\x01\x90\xb1TS++K\xb8\a\xffRK\xb0\tP[\xb0\x01\x88\xb0%S\xb0\x01\x88\xb0@QZ\xb0\x06\x88\xb0\x00UZ[X\xb1\x01\x01\x8eY\x85\x8d\x8d\x00B\x1dK\xb02SX\xb0`\x1dYK\xb0dSX\xb0@\x1dYK\xb0\x80SX\xb0\x10\x1d\xb1\x16\x00BYssss+++++\x01++++s\x00sssss\x01+sss^s\x00st+++\x01s++ssssss\x00++++\x01s\x00ss\x01s\x00st+\x01s+\x00ss+\x01s+\x00+s+\x01s\x00+\x01+\x00++sss+++\x01++s\x00s\x01ss\x00ss\x01ssss\x00+\x18^\x00\x00\x06\x14\x00\v\x00N\x05\xb6\x00\x17\x00u\x05\xb6\x05\xcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04^\x00\x15\x00{\x00\x00\xff\xec\x00\x00\x00\x00\xff\xec\x00\x00\x00\x00\xff\xec\x00\x00\xfe\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x011\x018\x01\x1f\x01\a\x01L\x00\x00\x00\x00\x00\xf5\x00\xe2\x00\xd9\x00\xcb\x00\xb2\x00\xbf\x01+\x00\xa0\x00\xa0\x00f\x00f\x00\x00\x00\x00\x016\x01?\x01/\x01!\x01\x14\x01\x02\x00\xf6\x00\x8e\x00\x00\x00\x00\x00\xb8\x00\xb8\x00w\x00w\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x016\x01?\x00\x89\x00\x00\x00\x00\x01\x02\x00\xfa\x00\xf0\x00\xe3\x00\xd9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x1a\x00\xf0\x00\x9b\x00\xd3\x01\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\f\x00\xa8\x00\xd3\x00\x8d\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01^\x01}\x01\x17\x00\xf5\x00\xe1\x01T\x01\xf6\x00\xbe\x00\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x01\b\x00\x00\x00\xdb\x00\xce\x01\x00\x00\x00\x01\x14\x00\x00\x00\x00\x00\xfc\x02\xb6\x00\xcf\x03\x96\x00\x00\x00\x8c\x00\xe6\x00\xfa\x00\xc8\x02\x9e\x00\xa8\x00\xb5\x01L\x00\x00\x01y\x00\x8e\x00\xe6\x00\xa8\x00\xa3\x00\x00\x00\x8e\x00\xa8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xb6\x02J\x00\x14\xff\xef\x00\xee\x00\xda\x00\xca\x00\x00\x00\xc4\x00\xaa\x00\xa0\x00\x96\x00x\x00\x00\x00\x00\x017\x02\x10\x01\xd3\x00\x00\x021\x01\b\x02%\x01\xe4\x01\xb6\x01\x00\x00\xe2\x00\xef\x00\xd3\x05\xb6\xfe\xbc\x00\xb2\x02\xfc\xff\xf4\x00\xa2\x01\xa1\x00\xe8\x00U\x00\x9a\x00\xb2\x00\x00\x00\x00\x00\a\x00Z\x00\x03\x00\x01\x04\t\x00\x01\x00\x14\x00\x00\x00\x03\x00\x01\x04\t\x00\x02\x00\b\x00\x14\x00\x03\x00\x01\x04\t\x00\x03\x004\x00\x1c\x00\x03\x00\x01\x04\t\x00\x04\x00\x1e\x00P\x00\x03\x00\x01\x04\t\x00\x05\x00,\x00n\x00\x03\x00\x01\x04\t\x00\x06\x00\x1c\x00\x9a\x00\x03\x00\x01\x04\t\x00\x0e\x00T\x00\xb6\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00B\x00o\x00l\x00d\x00A\x00s\x00c\x00e\x00n\x00d\x00e\x00r\x00 \x00-\x00 \x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00 \x00B\x00o\x00l\x00d\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00 \x00B\x00o\x00l\x00d\x00V\x00e\x00r\x00s\x00i\x00o\x00n\x00 \x001\x00.\x000\x000\x00 \x00b\x00u\x00i\x00l\x00d\x00 \x001\x001\x002\x00D\x00r\x00o\x00i\x00d\x00S\x00a\x00n\x00s\x00-\x00B\x00o\x00l\x00d\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00a\x00p\x00a\x00c\x00h\x00e\x00.\x00o\x00r\x00g\x00/\x00l\x00i\x00c\x00e\x00n\x00s\x00e\x00s\x00/\x00L\x00I\x00C\x00E\x00N\x00S\x00E\x00-\x002\x00.\x000\x00\x02\x00\x00\x00\x00\x00\x00\xfff\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\a\x00\b\x00\t\x00\n\x00\v\x00\f\x00\r\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x1e\x00\x1f\x00 \x00!\x00\"\x00#\x00$\x00%\x00&\x00'\x00(\x00)\x00*\x00+\x00,\x00-\x00.\x00/\x000\x001\x002\x003\x004\x005\x006\x007\x008\x009\x00:\x00;\x00<\x00=\x00>\x00?\x00@\x00A\x00B\x00C\x00D\x00E\x00F\x00G\x00H\x00I\x00J\x00K\x00L\x00M\x00N\x00O\x00P\x00Q\x00R\x00S\x00T\x00U\x00V\x00W\x00X\x00Y\x00Z\x00[\x00\\\x00]\x00^\x00_\x00`\x00a\x00\xac\x00\xa3\x00\x84\x00\x85\x00\xbd\x00\x96\x00\xe8\x00\x86\x00\x8e\x00\x8b\x00\x9d\x00\xa9\x00\xa4\x01\x02\x00\x8a\x01\x03\x00\x83\x00\x93\x00\xf2\x00\xf3\x00\x8d\x00\x97\x00\x88\x00\xc3\x00\xde\x00\xf1\x00\x9e\x00\xaa\x00\xf5\x00\xf4\x00\xf6\x00\xa2\x00\xad\x00\xc9\x00\xc7\x00\xae\x00b\x00c\x00\x90\x00d\x00\xcb\x00e\x00\xc8\x00\xca\x00\xcf\x00\xcc\x00\xcd\x00\xce\x00\xe9\x00f\x00\xd3\x00\xd0\x00\xd1\x00\xaf\x00g\x00\xf0\x00\x91\x00\xd6\x00\xd4\x00\xd5\x00h\x00\xeb\x00\xed\x00\x89\x00j\x00i\x00k\x00m\x00l\x00n\x00\xa0\x00o\x00q\x00p\x00r\x00s\x00u\x00t\x00v\x00w\x00\xea\x00x\x00z\x00y\x00{\x00}\x00|\x00\xb8\x00\xa1\x00\u007f\x00~\x00\x80\x00\x81\x00\xec\x00\xee\x00\xba\x00\xd7\x00\xd8\x00\xdd\x00\xd9\x00\xb2\x00\xb3\x00\xb6\x00\xb7\x00\xc4\x00\xb4\x00\xb5\x00\xc5\x00\x87\x00\xbe\x00\xbf\x00\xbc\x01\x04\auni00AD\toverscore\ffoursuperior\x00\x00\x00\x00\x02\x00\b\x00\x02\xff\xff\x00\x03\x00\x01\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x00\x00\xd1\x00\x01\x00\x00\x00\x01\x00\x00\x00\n\x00\x1e\x00,\x00\x01latn\x00\b\x00\x04\x00\x00\x00\x00\xff\xff\x00\x01\x00\x00\x00\x01kern\x00\b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x04\x00\x02\x00\b\x00\x01\x00\b\x00\x01\x00\xd6\x00\x04\x00\x00\x00f\x01p\x01p\n\xea\x02\"\x11\xdc\x02\"\x02x\x02\xde\rX\x02\xf8\x03R\x0e.\x03\xac\x03\xea\x0e\xf8\x04P\x04\x92\x04\xec\x04\xf2\x06\x1c\x06F\a@\b:\b\xbc\x0e.\n\xea\x10\xea\x10\xea\x10\xf0\x10\xea\t\xce\t\xf4\n\n\n\x10\x10\xea\x10\xea\x110\n\"\x10\xf0\nT\nj\nj\n\x80\n\xb2\n\xc8\n\xea\v\x86\n\xf0\n\xf0\v\x86\f$\f\xba\rX\r\xe4\r\xa2\r\xe4\r\xe4\x0e.\x0e.\x0e.\x0e.\x0el\x0e\x8a\x0e\x8a\x0e\x8a\x0e\x8a\x0e\x8a\x0e\xf8\x0fR\x0fR\x0fR\x0fR\x0f\xa0\x10\xea\x10\xea\x10\xea\x10\xea\x10\xea\x10\xea\x110\x10\xf0\x11\x02\x11\x02\x11\x02\x11\x02\x11\f\x11\x1a\x11\x1a\x11\x1a\x11\x1a\x11\x1a\x110\x11:\x11:\x11:\x11:\x11D\x11\xbe\x11\xdc\x11\xdc\x11\xe2\x11\xe2\x00\x02\x00\x19\x00\x05\x00\x05\x00\x00\x00\n\x00\v\x00\x01\x00\x0f\x00\x11\x00\x03\x00$\x00'\x00\x06\x00)\x00)\x00\n\x00,\x00,\x00\v\x00.\x00/\x00\f\x002\x005\x00\x0e\x007\x00>\x00\x12\x00D\x00F\x00\x1a\x00H\x00K\x00\x1d\x00N\x00N\x00!\x00P\x00R\x00\"\x00U\x00W\x00%\x00Y\x00^\x00(\x00\x82\x00\x87\x00.\x00\x89\x00\x92\x004\x00\x94\x00\x98\x00>\x00\x9a\x00\x9f\x00C\x00\xa2\x00\xad\x00I\x00\xb3\x00\xb8\x00U\x00\xba\x00\xbf\x00[\x00\xc1\x00\xc1\x00a\x00\xc6\x00\xc8\x00b\x00\xcb\x00\xcb\x00e\x00,\x00$\xff\xae\x00,\x00)\x007\x00R\x009\x00R\x00:\x00f\x00;\x00)\x00<\x00R\x00=\x00)\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xd7\x00R\xff\xc3\x00T\xff\xc3\x00W\x00)\x00Y\x00)\x00Z\x00\x14\x00\\\x00)\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xff\\\x00\x8e\x00)\x00\x8f\x00)\x00\x90\x00)\x00\x91\x00)\x00\x9f\x00R\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\xbf\x00)\x00\xc1\x00)\x00\x15\x00&\xff\xc3\x00*\xff\xc3\x002\xff\xc3\x004\xff\xc3\x007\xff\x9a\x008\xff\xd7\x009\xff\x9a\x00:\xff\xae\x00<\xff\x9a\x00\x89\xff\xc3\x00\x94\xff\xc3\x00\x95\xff\xc3\x00\x96\xff\xc3\x00\x97\xff\xc3\x00\x98\xff\xc3\x00\x9a\xff\xc3\x00\x9b\xff\xd7\x00\x9c\xff\xd7\x00\x9d\xff\xd7\x00\x9e\xff\xd7\x00\x9f\xff\x9a\x00\x19\x00\x05\xff\xae\x00\n\xff\xae\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xc9\xff\xae\x00\xcc\xff\xae\x00\x06\x00,\xff\xec\x007\xff\xec\x009\xff\xec\x00;\xff\xec\x00<\xff\xec\x00\x9f\xff\xec\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xec\x00:\xff\xec\x00;\xff\xec\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xc3\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x16\x00\x05\x00=\x00\n\x00=\x00\f\x00)\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\xd7\x009\x00\x14\x00:\x00\x14\x00<\x00\x14\x00@\x00)\x00`\x00)\x00\x82\xff\xd7\x00\x83\xff\xd7\x00\x84\xff\xd7\x00\x85\xff\xd7\x00\x86\xff\xd7\x00\x87\xff\xd7\x00\x88\xff\xc3\x00\x9f\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\x0f\x00\x05\x00)\x00\n\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x19\x00\x05\xff\x9a\x00\n\xff\x9a\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xae\x00:\xff\xc3\x00<\xff\x9a\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xc9\xff\x9a\x00\xcc\xff\x9a\x00\x10\x00\x0f\xff3\x00\x11\xff3\x00$\xff\xae\x00&\xff\xec\x00;\xff\xec\x00<\xff\xec\x00=\xff\xd7\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xffq\x00\x89\xff\xec\x00\x9f\xff\xec\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xc3\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x01\x007\xff\xec\x00J\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x10\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x85\x00&\xff\xc3\x00*\xff\xc3\x002\xff\xc3\x004\xff\xc3\x006\xff\xec\x007\x00\x14\x00D\xff\x85\x00F\xff\x85\x00G\xff\x85\x00H\xff\x85\x00J\xff\x9a\x00P\xff\xae\x00Q\xff\xae\x00R\xff\x85\x00S\xff\xae\x00T\xff\x85\x00U\xff\xae\x00V\xff\x85\x00X\xff\xae\x00Y\xff\xc3\x00Z\xff\xc3\x00[\xff\xc3\x00\\\xff\xc3\x00]\xff\xc3\x00\x82\xff\x85\x00\x83\xff\x85\x00\x84\xff\x85\x00\x85\xff\x85\x00\x86\xff\x85\x00\x87\xff\x85\x00\x88\xffq\x00\x89\xff\xc3\x00\x94\xff\xc3\x00\x95\xff\xc3\x00\x96\xff\xc3\x00\x97\xff\xc3\x00\x98\xff\xc3\x00\x9a\xff\xc3\x00\xa2\xff\x85\x00\xa3\xff\x85\x00\xa4\xff\x85\x00\xa5\xff\x85\x00\xa6\xff\x85\x00\xa7\xff\x85\x00\xa8\xff\x85\x00\xa9\xff\x85\x00\xaa\xff\x85\x00\xab\xff\x85\x00\xac\xff\x85\x00\xad\xff\x85\x00\xb3\xff\xae\x00\xb4\xff\x85\x00\xb5\xff\x85\x00\xb6\xff\x85\x00\xb7\xff\x85\x00\xb8\xff\x85\x00\xba\xff\x85\x00\xbb\xff\xae\x00\xbc\xff\xae\x00\xbd\xff\xae\x00\xbe\xff\xae\x00\xbf\xff\xc3\x00\xc1\xff\xc3\x00\xc6\xff\xae\x00\xc7\xff\x9a\x00\xc9\x00R\x00\xcc\x00R\x00\n\x00\x0f\xff\xd7\x00\x11\xff\xd7\x00$\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00>\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\xc3\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00D\xff\xc3\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xc3\x00P\xff\xd7\x00Q\xff\xd7\x00R\xff\xc3\x00S\xff\xd7\x00T\xff\xc3\x00U\xff\xd7\x00V\xff\xd7\x00X\xff\xd7\x00\x82\xff\xc3\x00\x83\xff\xc3\x00\x84\xff\xc3\x00\x85\xff\xc3\x00\x86\xff\xc3\x00\x87\xff\xc3\x00\x88\xff\x85\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\xc3\x00\xa3\xff\xc3\x00\xa4\xff\xc3\x00\xa5\xff\xc3\x00\xa6\xff\xc3\x00\xa7\xff\xc3\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb3\xff\xd7\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\xbb\xff\xd7\x00\xbc\xff\xd7\x00\xbd\xff\xd7\x00\xbe\xff\xd7\x00\xc9\x00R\x00\xcc\x00R\x00>\x00\x05\x00f\x00\n\x00f\x00\x0f\xff\xae\x00\x11\xff\xae\x00$\xff\xd7\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x00D\xff\xd7\x00F\xff\xd7\x00G\xff\xd7\x00H\xff\xd7\x00J\xff\xec\x00P\xff\xec\x00Q\xff\xec\x00R\xff\xd7\x00S\xff\xec\x00T\xff\xd7\x00U\xff\xec\x00V\xff\xd7\x00X\xff\xec\x00]\xff\xec\x00\x82\xff\xd7\x00\x83\xff\xd7\x00\x84\xff\xd7\x00\x85\xff\xd7\x00\x86\xff\xd7\x00\x87\xff\xd7\x00\x88\xff\xae\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xa2\xff\xd7\x00\xa3\xff\xd7\x00\xa4\xff\xd7\x00\xa5\xff\xd7\x00\xa6\xff\xd7\x00\xa7\xff\xd7\x00\xa8\xff\xd7\x00\xa9\xff\xd7\x00\xaa\xff\xd7\x00\xab\xff\xd7\x00\xac\xff\xd7\x00\xad\xff\xd7\x00\xb3\xff\xec\x00\xb4\xff\xd7\x00\xb5\xff\xd7\x00\xb6\xff\xd7\x00\xb7\xff\xd7\x00\xb8\xff\xd7\x00\xba\xff\xd7\x00\xbb\xff\xec\x00\xbc\xff\xec\x00\xbd\xff\xec\x00\xbe\xff\xec\x00\xc9\x00f\x00\xcc\x00f\x00 \x00\x05\x00)\x00\n\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00F\xff\xec\x00G\xff\xec\x00H\xff\xec\x00R\xff\xec\x00T\xff\xec\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa8\xff\xec\x00\xa9\xff\xec\x00\xaa\xff\xec\x00\xab\xff\xec\x00\xac\xff\xec\x00\xad\xff\xec\x00\xb4\xff\xec\x00\xb5\xff\xec\x00\xb6\xff\xec\x00\xb7\xff\xec\x00\xb8\xff\xec\x00\xba\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00D\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x9a\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x006\xff\xec\x00D\xff\x9a\x00F\xff\x9a\x00G\xff\x9a\x00H\xff\x9a\x00J\xff\x9a\x00P\xff\xc3\x00Q\xff\xc3\x00R\xff\x9a\x00S\xff\xc3\x00T\xff\x9a\x00U\xff\xc3\x00V\xff\xae\x00X\xff\xc3\x00[\xff\xd7\x00\\\xff\xec\x00]\xff\xc3\x00\x82\xff\x9a\x00\x83\xff\x9a\x00\x84\xff\x9a\x00\x85\xff\x9a\x00\x86\xff\x9a\x00\x87\xff\x9a\x00\x88\xffq\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\x9a\x00\xa3\xff\x9a\x00\xa4\xff\x9a\x00\xa5\xff\x9a\x00\xa6\xff\x9a\x00\xa7\xff\x9a\x00\xa8\xff\x9a\x00\xa9\xff\x9a\x00\xaa\xff\x9a\x00\xab\xff\x9a\x00\xac\xff\x9a\x00\xad\xff\x9a\x00\xb3\xff\xc3\x00\xb4\xff\x9a\x00\xb5\xff\x9a\x00\xb6\xff\x9a\x00\xb7\xff\x9a\x00\xb8\xff\x9a\x00\xba\xff\x9a\x00\xbb\xff\xc3\x00\xbc\xff\xc3\x00\xbd\xff\xc3\x00\xbe\xff\xc3\x00\xbf\xff\xec\x00\xc1\xff\xec\x00\xc9\x00R\x00\xcc\x00R\x00\t\x00\x05\x00f\x00\n\x00f\x00Y\x00\x14\x00Z\x00\x14\x00\\\x00\x14\x00\xbf\x00\x14\x00\xc1\x00\x14\x00\xc9\x00f\x00\xcc\x00f\x00\x05\x00\x05\x00)\x00\n\x00)\x00J\x00\x14\x00\xc9\x00)\x00\xcc\x00)\x00\x01\x00\n\xff\xc3\x00\x04\x00\x05\x00)\x00\n\x00)\x00\xc9\x00)\x00\xcc\x00)\x00\f\x00\x05\x00f\x00\n\x00f\x00D\xff\xec\x00J\xff\xec\x00\xa2\xff\xec\x00\xa3\xff\xec\x00\xa4\xff\xec\x00\xa5\xff\xec\x00\xa6\xff\xec\x00\xa7\xff\xec\x00\xc9\x00f\x00\xcc\x00f\x00\x05\x00\x05\x00R\x00\n\x00R\x00W\x00\x14\x00\xc9\x00R\x00\xcc\x00R\x00\x05\x00\x05\x00R\x00\n\x00R\x00I\x00\x14\x00\xc9\x00R\x00\xcc\x00R\x00\f\x00\x05\x00)\x00\n\x00)\x00R\xff\xd7\x00\xa8\xff\xd7\x00\xb4\xff\xd7\x00\xb5\xff\xd7\x00\xb6\xff\xd7\x00\xb7\xff\xd7\x00\xb8\xff\xd7\x00\xba\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x05\x00\x05\x00=\x00\n\x00=\x00I\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\b\x00R\xff\xec\x00\xa8\xff\xec\x00\xb4\xff\xec\x00\xb5\xff\xec\x00\xb6\xff\xec\x00\xb7\xff\xec\x00\xb8\xff\xec\x00\xba\xff\xec\x00\x01\x00-\x00{\x00%\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\x85\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xc3\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00I\xff\xec\x00W\xff\xec\x00Y\xff\xd7\x00Z\xff\xec\x00\\\xff\xd7\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xd7\x00\xc1\xff\xd7\x00\xc9\xff\xae\x00\xcc\xff\xae\x00'\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\x85\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xc3\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00I\xff\xec\x00W\xff\xec\x00Y\xff\xd7\x00Z\xff\xec\x00\\\xff\xd7\x00\x82\xff\xd7\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xd7\x00\xc1\xff\xd7\x00\xc9\xff\xae\x00\xcc\xff\xae\x00%\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\u007f\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xd7\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00W\xff\xe5\x00Y\xff\xd5\x00Z\xff\xe5\x00\\\xff\xdb\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xdb\x00\xc1\xff\xdb\x00\xc9\xff\xae\x00\xcc\xff\xae\x00'\x00\x05\xfff\x00\n\xfff\x00\r\xff\u007f\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xd7\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00W\xff\xe5\x00Y\xff\xd5\x00Z\xff\xe5\x00\\\xff\xdb\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xdb\x00\xc1\xff\xdb\x00\xc8\xfff\x00\xc9\xff\xae\x00\xcb\xfff\x00\xcc\xff\xae\x00\x12\x00\x05\x00)\x00\n\x00)\x00\f\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00@\x00)\x00`\x00)\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x10\x00\x05\x00)\x00\n\x00)\x00\x10\xff\xd7\x00&\xff\xec\x002\xff\xec\x004\xff\xec\x00\x89\xff\xec\x00\x8b\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\x12\x00\x05\x00)\x00\n\x00)\x00\x10\xff\xd7\x00&\xff\xec\x002\xff\xec\x004\xff\xec\x00\x84\xff\xec\x00\x89\xff\xec\x00\x8a\xff\xec\x00\x8f\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\x0f\x00\x05\x00)\x00\n\x00)\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\a\x00$\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x1b\x00\f\xff\xd7\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x00-\xff\xf6\x006\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00@\xff\xd7\x00`\xff\xd7\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x13\x00\x0f\xff\xd7\x00\x11\xff\xd7\x00$\xff\xec\x000\xff\xec\x00=\xff\xec\x00D\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\xa2\xff\xec\x00\xa3\xff\xec\x00\xa4\xff\xec\x00\xa5\xff\xec\x00\xa6\xff\xec\x00\xa7\xff\xec\x00R\x00\x05\x00R\x00\t\xff\xc3\x00\n\x00R\x00\f\x00=\x00\r\x00)\x00\x0f\xff\x9a\x00\x10\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x9a\x00&\xff\xd7\x00*\xff\xd7\x00-\xff\xbe\x000\xff\xc3\x002\xff\xd7\x004\xff\xd7\x006\xff\xec\x007\x00'\x009\x00)\x00:\x00\x14\x00@\x00=\x00D\xff\x9a\x00F\xff\x9a\x00G\xff\x9a\x00H\xff\x9a\x00I\xff\xe5\x00J\xff\x9a\x00P\xff\xc3\x00Q\xff\xc3\x00R\xff\x9a\x00S\xff\xc3\x00T\xff\x9a\x00U\xff\xc3\x00V\xff\xae\x00X\xff\xc3\x00Y\xff\xd7\x00Z\xff\xec\x00[\xff\xd7\x00\\\xff\xec\x00]\xff\xc3\x00`\x00=\x00\x82\xff\x9a\x00\x83\xff\x9a\x00\x84\xff\x9a\x00\x85\xff\x9a\x00\x86\xff\x9a\x00\x87\xff\x9a\x00\x88\xffq\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\x9a\x00\xa3\xff\x9a\x00\xa4\xff\x9a\x00\xa5\xff\x9a\x00\xa6\xff\x9a\x00\xa7\xff\x9a\x00\xa8\xff\x9a\x00\xa9\xff\x9a\x00\xaa\xff\x9a\x00\xab\xff\x9a\x00\xac\xff\x9a\x00\xad\xff\x9a\x00\xb3\xff\xc3\x00\xb4\xff\x9a\x00\xb5\xff\x9a\x00\xb6\xff\x9a\x00\xb7\xff\x9a\x00\xb8\xff\x9a\x00\xba\xff\x9a\x00\xbb\xff\xc3\x00\xbc\xff\xc3\x00\xbd\xff\xc3\x00\xbe\xff\xc3\x00\xbf\xff\xec\x00\xc1\xff\xec\x00\xc9\x00R\x00\xcc\x00R\x00\x01\x00\n\xff\xd7\x00\x04\x00\x05\x00=\x00\n\x00=\x00\xc9\x00=\x00\xcc\x00=\x00\x02\x00\x05\xff\x98\x00\n\xff\xd7\x00\x03\x00\x05\xff\x98\x00\n\xff\xd7\x00\xcc\xff\xd7\x00\x05\x00\x05\xffo\x00\n\xffo\x00I\xff\xdb\x00[\xff\xd7\x00]\xff\xec\x00\x02\x00[\xff\xd7\x00]\xff\xec\x00\x02\x00\x05\xff\xbe\x00\n\xff\xbe\x00\x1e\x00\x05\x00=\x00\n\x00=\x00\x0f\xff\xbe\x00\x11\xff\xbe\x00\"\xff\xb4\x00F\xff\xf6\x00G\xff\xf6\x00H\xff\xf6\x00I\x00\x14\x00J\xff\xf6\x00R\xff\xf6\x00T\xff\xf6\x00W\x00\x06\x00\xa8\xff\xf6\x00\xa9\xff\xf6\x00\xaa\xff\xf6\x00\xab\xff\xf6\x00\xac\xff\xf6\x00\xad\xff\xf6\x00\xb4\xff\xf6\x00\xb5\xff\xf6\x00\xb6\xff\xf6\x00\xb7\xff\xf6\x00\xb8\xff\xf6\x00\xba\xff\xf6\x00\xc9\x00=\x00\xca\xff\x8d\x00\xcc\x00=\x00\xcd\xff\x8d\x00\xd0\x00\f\x00\a\x00\x05\x00=\x00\n\x00=\x00\x0f\xff\xbe\x00\x11\xff\xbe\x00I\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\x01\x007\xff\x9a\x00)\x00$\xff\xae\x00,\x00)\x007\x00R\x009\x00R\x00:\x00f\x00;\x00)\x00<\x00R\x00=\x00)\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xd7\x00R\xff\xc3\x00T\xff\xc3\x00W\x00)\x00Y\x00)\x00Z\x00\x14\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xff\\\x00\x8e\x00)\x00\x8f\x00)\x00\x90\x00)\x00\x91\x00)\x00\x9f\x00R\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\x01\x00\x00\x00\n\x00\n\x00\n\x00\x00") + +func third_partySwaggerUiFontsDroidSansV6Latin700TtfBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6Latin700Ttf, nil +} + +func third_partySwaggerUiFontsDroidSansV6Latin700Ttf() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6Latin700TtfBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-700.ttf", size: 40516, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6Latin700Woff = []byte("wOFF\x00\x01\x00\x00\x00\x00e\x88\x00\x11\x00\x00\x00\x00\x9eD\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00GDEF\x00\x00\x01\x80\x00\x00\x00\x16\x00\x00\x00\x16\x00\x10\x00\xd2GPOS\x00\x00\x01\x98\x00\x00\x06$\x00\x00\x12\xc0\xf2ZM^GSUB\x00\x00\a\xbc\x00\x00\x00\f\x00\x00\x00\f\x00\x15\x00\nOS/2\x00\x00\a\xc8\x00\x00\x00`\x00\x00\x00`\xa2\t\xb7\x96cmap\x00\x00\b(\x00\x00\x00j\x00\x00\x00\x8cmag\xdacvt \x00\x00\b\x94\x00\x00\x01\x01\x00\x00\x02\x06K\xe2RQfpgm\x00\x00\t\x98\x00\x00\x04'\x00\x00\a\x05s\xd3#\xb0gasp\x00\x00\r\xc0\x00\x00\x00\f\x00\x00\x00\f\x00\a\x00\aglyf\x00\x00\r\xcc\x00\x00O~\x00\x00u\x1c}]p\bhead\x00\x00]L\x00\x00\x003\x00\x00\x006\xf5\xcd \xd7hhea\x00\x00]\x80\x00\x00\x00\x1f\x00\x00\x00$\r\x9b\x05ahmtx\x00\x00]\xa0\x00\x00\x01\xed\x00\x00\x03L\x9f\xc7I\xb4loca\x00\x00_\x90\x00\x00\x01\xa8\x00\x00\x01\xa8da\x83\"maxp\x00\x00a8\x00\x00\x00 \x00\x00\x00 \x03\x17\x02\x14name\x00\x00aX\x00\x00\x00\xb8\x00\x00\x01d\x19w4\x0fpost\x00\x00b\x10\x00\x00\x01Y\x00\x00\x01\xe7\xa2\xc2\x0f;prep\x00\x00cl\x00\x00\x02\x1c\x00\x00\x02beq\u058a\x00\x01\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x00\x00\xd1\x00\x01\x00\x00x\x01<\xcc\x03\xac\x1cQ\x14\x80\xe1\u007f\xb0\x1a\xed\xdcF\xb5m\u06f6m\xdb\x0ek\x86\xb5\x19\xa7\xb6m\xc6\rj\x04\u0573\xc2}g\x99\xef\xf2\b\r\xb0\xa8LC\xb4\x85\xd3V.&\x8c\t\x10\x8b\xa1\x01\u0682Y\xcb%\x06\xc9\x1f&\xba\xfc\xb4\xc4\xfe ?\x98\xad-\u0556Z\u007f\xf4\xea\xea\x93^]_\xab\u007fq\xc7\xea%\xc6p\xaf\xb1q\xd6\xf8\u3558C\xcd\xdd\xe6?3/X1\xd8;\xd45\xdc>|\xd7kl\xfd\xf1\xe3r\xfc?\x91\xf7\x91\x02\u02f2\xfc\xf8_5\xb5\xaa\xfb9\xd6Hk\xbeXo]\xb6^Z\u007f\xec\xadV\x8e\x95couj:\xb7\u0771\xee/\xf7\xb4\xec_^\u3505\xde\u038c\x92\xe8\xf0\x94\x932-C5\xf5s\x94\x9e\xe2\xa8\xf2\x19MU\xfb\x94\x9e\xea\xbe\xfa$~\xa8\x1f\xe8\x94# \xc0\xc2F#\x8a\u00a0&u\bROX4\x146\x8di\x82CsZ\xe1\u0446\u0394\xa1'\xbd)O_\x06P\x89\xc1\xa2\x1aC\x19NuF1\x86Z\x8cc2u\xd9\xc86\x1a\xb3\x83\u0774d/\a\xe9\xccaN\u0403\u04dc\xa3\x1fW\xb8)\u0577y\xc0\x04\x1e\x89i<\xe7%\xd3y#f\u0450\x9a\xb1\xf3r\u05a3\r\xc3i'\xbb=\xb3\xe9 \xff\x8e\f\xa7\xb4\x1a\xbb\x86\x8e\xe3Z\x03\x00\x85\xd13A\x89XF\xa5\xbajj\x82\x1f\x06\xb3\xc5Z\xe3\xd4QO\x03\x8d4\xb1 :;X\xa6~9+X\xc9vc7\x1b\xa3\x85V\xdah\xa7\x83N\xba\u8987^\xfa\x19\xd1\xef ?\n\xfe\xec\xe8\xef\xfc\x9fGy\"\xba)xRfS\u0129\xce8]\\\xa8|\rkY\xc7z6\xb0\x89\xcd\xdana+\xdb\u062e\xbd\xfb\xa3g\x84?G\xbf\t\xfe\xce\xffy\x94'\xa2\r\xc1\x93\xe2\x14=\xa7j\x1d\x1b\xdd\xf1\x1a\u05b2\x8e\xf5l`\x13\x9b\xd9\xc2V\xb6a\xf4\xe0\xa4q?d|\xf0\xcf\u0608Fc\x1a\xd3\xd9\u038f\x83t\xe3g\xf2GG\xb1V~O\x11\xa7\x86-\xcf\x043\xc4Z\uaa27\x81F\x9aX\xa0\xfd2q9+X\x19\x1b\xf9\x8c\x91\u01f9\x8f\x11\xd2\xcc^\xbal2\xf9\xbd\xdf\u007fT;\xc5\u075b\xcat\x9eV6\x9fZ\xe5u\xd4\xd3@#M8C\xb0]\xbb\x93\xc6\xfa\x90t#[\xbb\xfcY\xed\xdf\xf9?\x8f\xb2\x905\xace\x1d\xeb\xd9\xc0&Nj\xff!f\\\x1e\x11\x92\xcf\xf8\u06ee\xfe\xf0\xad\xcd8\x1f\x92\xe1\x8a\x1f\t2\xb1\u039d)\x9cusy&\u015a}\xc9\x19S\u07d93\x97\xee\x8cx\xabwfTl%\x14\x9a\u0152 B\xfa\xf7\xf9^u\u007f\x1a\x12\xd6\xfa\xe3z<\xe1\x1ed\xab\xcb%\x8f|\n\xf5)\x92y1%\x8eK\xc52\xb1\\\xac\x10\xab\xc4j\xfdk\x98\xc5l\xe6P\xab\xae\x8ez\x1ah\xa4\t3\x90\xf2\x19\u06a5\xcdn\xf6\xb0\x97}\uc9d9\x16Zi\xa3\x9d\x0e>p\xfeN\xb1\x8bnz\u895f\x01u\x83\f1\u0308\xf1\x0fr\xcc\xef\xe3\xae\ub939\xf9\x90H\x90n\xd62\xf9c\xaa\xd9V?3\x9c\u04eb\xd7\xfb\u1115\x9a\xad\xec\xaa7\x1cE\u028b)\xf1\xbbT,\x13\xcb\xc5\n\xaa\xa8u\\G=\r4\xd2\xc4\x02\u05d2j\xe5\xef\xd2f7{\xd8\xcb>\xf6\x93\xecM\xf8\x81>\xc9\u0786\x03\xea\x06\x19b\x98\xf8\x1c\xb9r\xef\xef\b\xe9f/\x13Oy\xc2\x13\x96\xad,\x97<\xf2)TVD1%\x8eK\xc52\xb1\\\x8c]\xb58\x87\xe4o\x86\xb7S>\xa1\xbb\xb4\xd9\xcd\x1e\xf6\xb2\x8f\xfd4\xd3B+m\xb4\xd3\xc1\a\xfat\x8a]t\xd3C/\xfd\f\xa8\x1bd\x88aN\xba\xd6\x0f\xf9m\u04b7Q\xaeVy\xe4SB\x19\xa9\xeeS\xb3\xfa\x16Zi\xa3\x9d\x0e:\u989b\x1ez\xe9'\xfeF\xcbN\xb2\xea6%d\xf4\xb8^\xd9\xcas\xc9#\x9fB\x8a\xdc\xd9bJ\xfc.\x15\xcb\xc4r\xb1\xc2\xfcV\x89\xb3\xf4\x9d\xado\xec\xc9UWG=\r4\u0484'7\xf5*\xd4f7{\xd8\xcb>\xf6\xd3L\v\xad\xb4\xd1N\a\x1f8W\xa7\xd8E7=\xf4\xd2\u03c0\xbaA\x86\x18fDn\a\x89\xaf\xc6I\xe1j\xac\xf6\u03aaa6#\x1c$~\xe7\u0185w\xaePi|6G\x05\x11#\x8e\x8d\u05c5\xe5i\xe1\x98\xd9\xceT\xc8.v\xb3\x87\xbd\xecc?\xe1\xf8\xe1}\xa94~<\xb7\u02e5\x05W\x94\xa6\x85\xe7+\xb9\xb4>\x93\xad\xc30\x9fq\xe1\xf7\xb5\xe0\x8ao\xe3\xc4\xd8JkN\xbej\\\u07ff\x82W\x82?\x85\xfb\x8e\xc9\xde\x1e\xe9\xd6\u042f\xf9\xbd+\xbf\x91}\xc8\f;\xb5\x02e\x95T+\xab\x11g\x8b7\xfb\xb5\x1c\xd1\xe7 \xf1}\xca_\xae\x97\x95\xdc\xe7\xdeRf\xb5w \xbb+\xe7\xec\x8d+\xb2;s3\xd9\xc9\xec\xa2\u033e\x92\xd9E\x99]\xb8\xf9\xac\xf49\u0215sf]\xf2 duB\x1e2\vN\x8b\x1f\x8aY\xe1\xbaNK|C\x86;\xbf\x1b\u0677e\x84#e\\\xba\xb6\xf0\x9a\x16\xb28y\xbe\xe1\bYIG\xa8g!\x8bX~\x03#\x85;\u0404\xa7e\xe1\r\xf4\x9e\x90r\x1f\xf1\x8b -z&a\xef\xf7\xaf\xe8\xb7\xc1\xe3)\xf6\x80O\x8b\xf3I\xb1;I\xb2K\xbf\xf5]f\xea\x91\u007fp\u056e\xe9\xbf\xcc ;\xf5HI\u07e9\u079bL\x92[DL\xb3f'\x9b\xc9p\xe7\x9a\xf8\xcd3c\xc3\xcez\xf8\xaao\xdf\x13\x9e\x96)\xdaM\x8d\xfd\xd51#\xe1[X`\xf5\xdf\xc0\xf70|\xb3\\\xf9]\x9co\xbc\x87\xe1\xdb\xe8\xfb\xe6\x8cc\xe3_\x8f\xf0\xcb1\xda{dC\xacnL\xf8\xebC\xc69z!\x88P\xe0\xf9v\u0141\x1d\x99\xd6\xe1/\xf5\xc3A\x84_\x87c\xa6;\xca\xe4\xf7\xd1\xce \xd7\xca\xcd#\x1f_\xaa\xa0P,\xa1\x8cJ\u007f\x996\x8b-\xb4\xd2F;\x1dt\xd2E7=\xf4\u048f|\x83S\u0465\xb1\x9c?\x12?\xb5\x1a&$\x9c9\xfc&\xe2\xef\x1d\xf3\xf2\xb7;\xf1\x1f\x87\xbb\xfd\u07c6\xef\x00\xe8\x11\x93\xb0\x00\x01\x00\x00\x00\n\x00\n\x00\n\x00\x00\x00\x03\x04c\x02\xbc\x00\x05\x00\b\x05\x9a\x053\x00\x00\x01\x1e\x05\x9a\x053\x00\x00\x03\xd0\x00f\x01\xfc\x00\x00\x02\v\b\x06\x03\b\x04\x02\x02\x04\xe0\x00\x02\xef@\x00 [\x00\x00\x00(\x00\x00\x00\x001ASC\x00 \x00 D\x06\x1f\xfe\x14\x00\x84\as\x01\xec \x00\x01\x9f\x00\x00\x00\x00\x04^\x05\xb6\x00\x00\x00 \x00\x02x\x01c```\x02bf \x16\x01\x92\x8c`\x9a\x85\xa1\x02HK1\b\x00E\xb8\x18\xea\x18\xfe3\x1a2\x1dc\xba\xc5tGADAJANAI\xc1J\xc1\xe5\xff\u007f\xa0\x1a\x05\x86\x05p9a\x05\t\x05\x19\xa0\x9c%H\xee\xff\xe3\xff\x87\xfeO\xfc\xfb\xf7\ufaff/\x1fl~\xb0\xe1\xc1\xfa\ak\x1eL{\xd0\v\xb4\x01'\x00\x00;\x03#\xf4\x00\x00x\x01\xad\x8a#`.P\x18@\xcfw\x9fm[\xe5iF[\x1e\xd3V\xff\xb8\x1ef\xf4\xb9\xcd6\xdal\xdb*C\x99m[m\xf69\xf7~\xbe\xfd\x92\aX\xdd\xca\xe2\r\xf6\xb7\xb2n5\xb2\x1fnjx\x85+lO\xc0\xfe\xb8\xf5\x92k\xe5.\x00\xa2#\xc6\xf2E\xee\x88\x05\x00\x8b\xf4\xd1I=i\x14\xcb\x1f\xa2v\xb5\xdd\x15\x10C1\x11-\xf9&/E\xb1\x84\x1f\x009\xbb:\uee8f\xbd;<\x01D\xb1\xc6\f\xfdtr\f\xf2\x9e\x19Bi\x97\x17\xfbf\x0fI\xa2\x1d_\xb2\xf7\xcd4\xe2.oX\xa4W\xace\x89\"j8\x9en\xb9\xbb\x17i\x12@^\x02\xb0\xa1\xb2h\xbe\x11\x00\xf80\xc4\x1a5*\x82$2\xc5\x02\xc4\x19?\x86H\"\x16\xf0#\x89sp+K\x99\xf1r{\x9a)\xba\xa8\x03*H!\x8a\x00\x9c\x00\xc4H=\x95vP:rW\xfd\x92\x01\xc9\x12\xe8c\x9a\xf6[Y[\x05\xa4\xa9\x8d\xed\x05b$\x9a\x11l\b!m\a\x1aUO\x85\x00\x00\x00x\x01uSG\x93\xdbF\x13\x1d\x80Q\x19Td\x15\xbe\xcf\x1e\xb8\xc5U\"\x95s\x84I\fDZ\x91AU\x039\x01\x9b\x8a\xeb\xd3^\x9c\u04de\x1cf\xe5\xff\u0490/\\\x9f\xf4\a\xfc\x1b\x1c\x8f\xde\xe3\xfa*\xf7\f\x01e1\xf6{\xdd\xfdf\xe6\xf5\xc0\x17\x91\xbc7\x1a\x0e\xfaw\xef\u073eu\xf3\xc6;\xbd\xee\xf5P\x04\x9d\xf6\xdb\xfe\xb5\xabW._\xbax\xe1\xfc\xb9\xb3gN\x1c?v\xb4\xd5U.\xbeP\xe9\x9bJJ\xe5\xb4\xe5\xf0\xcb\xecr\xab\xc9\x05p\xfc5\x00>\xb1\xee\xf7%\xc5?\x05\x10q\\7\xf1-\x1dS\x87\x01\xdb\bx\x1eupQ\x1f\a\x1c\xad\x98\v\f?\x19+\x11\a\xa4\x97n\xd9\u0701\xce\xc2\xe6V\x93\xa5\x9b\xb7P\xb8\x85\"<\b\u02e9u\xf0\xaae\x02\xfb\xa0\xb8\x98\u06ac\xbaM/\x8b\x85\x86H\xe6\xf1n_\x8a\xc0\xf5\xbc\xa8\xd5\xec\xe1v\bL\x8au\x8c$\x96;X1\x92|Io\x9d\xad\xf2\xb4\xf9H=\x988l6>\xb2u\x1e\xe6\x93\xf7$\x16\x12\xeaU\x05\xa1\xd4\xf7X;\x82\x87 \xc0C_\xfc]\xa7\x93/`\x13\x02\x81G\xb4\xea\x8d\xc1\x93un<]\xd2\xc2R\xc3\x01\xae6\x18\x1d\a\xd6\xffy\x9eI2\xa6\xdcp6\x98\x0eC\xb2W\xa9\x10x\xa8b\x95L\x1e\xaf\xcc\x02w@\xa5[\xb7\xaaeA\x0e\xb3\xbb\x12-\xe2\u007fYu1|\x10\xa1\x13\x8f\xad\x8b\xd9a\xc3\xc1\r\xdc\xd5\u007fW\xa2\xdd\b\xf98!\x86>\xd7\xc0;\xefz\xb5(\xaf\xb9\xfb\xba4##\xb0\xac=\xf5<}\xf0\u0549\xcff\t\xe0J_N1g\xb3\xeeC\xe6\x1f;\x12\xa1\x1d\xeb\u0323<\xb3\xe7\x9e\u03ac\xe4\x99'\xed1xd\xc6P*,6z\xf3 \xc8\xe3\xd5\x04Wf\x91'\x1f\xe9Q\x80\x83\xdb\xffu=P;k\xfc\u00b1\xc8\xd4r,P\xed\x12\xc7\xd2\f\x96u\u05f3\rtSt\x8br4\xa0`\xfa\xb7\xee*J\xd4v\xf2\v@2ZG\x80\x88\xb3\xcf'\xe3:\t\xf0V\x13\xbbG\xa6\xa3\x1fI\xf4\x03\n\xfc$\x9b\x91H\x8f\x1f\xa3\x8e$\xa6\x11-\x05f|x\f\x96q7\xb4\xf3y\x9am\x89\xa5\xa14-Y\x1b\xee\xee \x8b\xe7\xb2.<&\x02\"\x81\v\x15\x9b@\xc4Z\v\xfar\x8d\x9dz\xfc{z\x9a\xbb?\x9fb\xa7Y\x14\xe8\xe2\xbd\x1d\x89\x85\x19\xa1\xe4\xfc\"\xbe\x19\xbb\xf3\xc8\xe3E.]\x0f\xfd\x88\x06\x1c\x81\\\x88\xf0\x90q\xe8\xd0\ufd1cgVD\xbb3\x927\x86p\xa3\u007f_\x9e7\x1b\xc9\x13$G\x1e\x8b\x17d@\xbaS\x19\xbarXmT\xb9\xb4\xddBD\x85\x0e\x11<\xa4\x00\u0697\xe9\x17+\x8d*}\x1d,OY:\x11%\xb8\xb4\\\x96W\xd36\xf0\x10\x17\vAVG\xf8yQ\x02\x85F\xa7\x9b\xab\x955$\x9dN\xd7\xf5\"o\xfaj5mJ\xf3la\xea\xa8jS\xbbY\x8ab\x8eE\xe2l\x92\u0454\xf1\xb2\xae\xef<\x97\xb0\x00\x11\x8c9\xfaw%\x9d\xcd\xd8c\\\xce\xcc0\x9eg\xb3\x1a=\x87r\xb3\fB\xe6QZ\x83\xdcL\f\x8f\x10z\x06_'\xfc\f\ucf90\xee\xe5i\xae\xaapc\xa8\xb48d\x82\x8cv\xdeC\xa6\xaf\xb0\u007f\xbe\xe6j\xca\xd2\xcf3\x84\tp\x87\x87\xd3\xe7Y\xa5\xbe\xaf\x9f\xe5\xf1E-\x02\xbdy\x05Cy\xd9T\xdf\x18\u022f\xdd/(\xc0\x9d\xec\x86uc\xd4n5S\x9b\xb5S\xb0~\u89fe\xf5\xc3\xf0\xbe\\s\x18\xe3?\x8c\xe4C\u06f2;q;J\xf7SN\xaeq\xc6|\xc3\u069a%\xd2\x00\xae\x81V\x1a\x10\xa8\x9azw\xcdgl\xc5d\x8b\x860xnb1\xc3Us\xcebs\x13{\xca99g\x13W\x9cr\xbe\xe1\xf4\x8b\xa6T\x1f\x93\xc7\x12\xb8\xe0\xf3z>_Ec\x15G\x81v{/9B\x1f\v-\xb8J\xee\xc0\xd5\u0532\xcb[q3,\xb4q\v\xb45\u007fM\xf3\u05e6|Y\xf3\x15h\xa3\xb5\xd7j5\xbfP\x8e\x80\x8dz\xeb?v\xf0\xf3\xb7\x00\x00\x00\x00\x02\x00\b\x00\x02\xff\xff\x00\x03x\x01\x8c|\t|\x13\u05f5\xf7=\xf7\u03a2}_-k\xb3,\u0276lK\x96l\u02f2\xb1%\xc0\x1b\xc66`\xc0\x80A\xb6\x03f\xdf\xf7\x10\x02&%)%ib\xb2\xbc\xecih^K\b\xd9H\x9aR\u06a4M\u04ac4_B\xf3\xe5\xa5)\x8f\x97\x12\xd2f\xe1e\xa3yiK\x88=|\xf7\x8elL\xc8\ubbdfd\u034cF\xd6\xe8\xec\xe7\u007f\u03f9w\x10F\x9b/|\x00o\xf1G\x10Av\x94\xcdL:\xec|\xcfy\xd6I\xbc\u03a83\xed\x1ct\xde\xef\xe4\xdf!\xf02\x81\xad\x04ld\t\xc1\x84\x00\xd1\xdd\xfeG\f\xc70\\\x89a9\x06\xec\xe3\x00q\xfd\x1c\xe6@y\x8f\x19\x13\x94\x8e\x8e\xbc\x01\xd1\xec\xfaD\x96>>\x8bgs\x8f\x8a\x18\x04\x88\x1f*\x1bp\"\xee\xc1V\x8b\x0e\a\n\xca1\xec\xff*\x01=\xd2\x03\xaeX&\x18H\xc7\xf2\xf3c\xe9@0\x13s\xc1\a\xe4\xcd\xf3'\xa2\x13\x8bL\xa6\xa2\x89\u0472L\x89\xd9\\\x92A\bat\x1d9@&\xc9\xf4\x8a(\x9a\xc9\xe3\xee\x14Ee\x9f\x12\u041d\x88\x18\bV\x10\x01\x01}\x88\x84\u0491HD\xb3\t\x88\xf6fOgM\xa9\xe8iJ\x01\xa1$\xd0\x17\xdc[\xfcR1\xfe5\xdd\xf0GF\xceb\x03{\xb1k\x97!\xc4I\xfcS\u0205\xbc\xe8\xf5\xcc.B\xf2\xf2\x1c6\x8f[\xe4\x04\xbb]p\"\xe08\xfe\x89\xaf\x1c0\xdd\x01\x0e\x87\xdf\xea\xcdWpJ\x8b\u0164\u05e99\xf3\x13\xaa~\x03\x18\f\x1a\x8d\xf2\x1b\x15\xf4\xab\u05a9\xb0*\x1fZ\xb5\xa0}L\xa3\xe04^\xf4\x11\xfd\xf41\xa3\xd3j\xfcJ\x03\x1fh\xe0\x16\r\xcc\xd2@L\x93\xd1\xe0O\x8c\xdf\x18\xf1}F\x98o\x84\xb4q\x9a\x11k\x8c\x1a#o7\v*\x1eE\x13\xe9\x84)\x95\x8aF\xb3c\x0fc\"a8\x93\x8d\xc7\xc7\xf6@?\xa2lRF\r\x9f\xdaSq\xa3\u025e2\xd27Y\xf6&1\xfa.\x11\xa5\x9c\x8b~+\xe5\xdc\x1c`\xaf*\u007f\x92\xbe\xcc\t\x92`/+\x9fH\x06\xc8GQ\xc0\xd2;\x1d\xff\xd5\xf9\xdb\xf6w\xda>\akt\x18\xfc\x1d';^\xee|\xa7\xf3\xec\x88\xfb\xc5\u82e4\xfd\xe37\xa4\x15p;{\xbd\xf1\xf1\x9bp\x87\xb4\x9c\xbd\xde\xfc\xf8cD\x1f\x04-\xbc\xb0\x97\v\n\x16\x94@\x13\xd0d\xf4F\xa69T\x9e\td\xbe\xc9@:\x03\x99Z\xc1\xfc\x95\b\x1f\x8a\x80D\x83\x18\x13\x89(z\u0515\xae\xcaH\xe5\xf6\xca\x1b*\xf9\xcab=\x9a\x860j\xe2\xea-\xf5\x85\xf5\x9b\uabed\xe7\xebu\xfb<\xfb=\xd8s\xf4\xc2s\x99\xb4Z\xdf\xea)+\x9981\x94\xb2X\xca3G2\xb0\x97^\xd3\x1c\nft\x96\xd6`0\xe0\veB\xd3C\xbbB\x87C\xbc>\x04\xa1Z\x9d\u066c\x98.\xf6\x8bX\x14\xf9\x8c\x02\x14(\xcadDegd;v\x1c1\x9aR\xb20\x8d\xf2\x93\x1aI$\x9b8\x965\xfc)\x1b?\x965\xa6\xe8?\u0477\xf1\x04\xfb\x17\u00f18\x15\x1f5W\xd1\x1a\xa8*'a\xa3\x87\u060d\xa1p9\x84\xcbI\x15\xb5\xe6dU\xc2\xea\x01\xbbHO\x18\xed\x1e\xc2W\x96\u3c35\x01\xc0b\xb3W\xe9\x80\vV-\xbfw\xc9\xdeI\xeb\x16\u038b\x94,Z\xb1\xbaR\xa1T\x18\x84\xf9?\x98_\x96Zqg\xdf\xde9G\x06\x16O\xbc\xb1!\xdcwSo\xb9\xf4\x966?\u2b6b\x91\xee\xa8LU'\xe1\xd8\xd4]\xfd\r\xaa\u05cfa\x8d\xcdk\x06\x855\xe4\xb5\x11h \x1c\x11p\xa0\xbdwC\xeb\xd4\xed\xf3S\xca\xfb\xee\xe0\x8b\"\xff\x9dW\xccK'u\x81\xb6\x05\x1b\xba\x1c\x85\x1e\xa7nX9\x01\xdf\x14M[\xcf\b1\xa6\x1b\x1e\xa5/|.\xbc\u03bf\x86T\u0203\n\xa8\x95OD\xf7\xfd\xbc\u00a1\u0536\xa6\x8f^\xf88\xa3\xa3\a\xb5\xec]\x15\xdb\xe4\xb3S\x85\xf4\xc0\xc1\u0799\x8b\xe8F\u01ce\x02O\xd5\xfc\xbc|^\x01\x14x\xbb}\xe0\xf3{\r\xfe\xa3\x17\xcef\x02^\xbf\xd7o-~\xaa|\xb2\xf0\x94\xfa\xe7\xe8)k\xe4H\xfd/BG\x12\xce\x02\xc1O\x8e\x18~\xa18\x92'\xa2\xf4\x99\xe13\xd14\xdbB\x94n\f\u007f:#\x1buM\x8d1\x91\xa5\u007f\x86\xe13\x151\x14\x81H\x04E\xe8\x96m,\xb6D\xbc\xba\xaa2P \U00023062j4p(!\x00\xe6\u007f\xfe1\u0515\xc5+\xa2\xfd\xf12x\xba\xb8\xfb\xda\xf9\xb3\xaf\x99SZ4\xfb{=\u077b\xe7\x96\xe1{\x86\xdf\xfe\x82D\xd6}\xfb\x1fv\xd1\u007f\x98\x95\xfb\a\x0e\r\xee\xb8z\xd7\xf9\xed;V=\xb2%\x9d\xde\xf2\u022aU\x87674l>\x04\xad\xe7\xdb\xf8#\xc3x\xec\u04c7\u0667\x0f\x8f}\xcal\xbf\xeb\u00a7\xfc\vT\xbee(\x85\xa6\xa0\xfb3\x13\xc3-E\u0175{kqm\xab\xa7%PH\xaf\x1cj\xfc~#nl\xb5\xe0\ua91e\xb3\xc0W\x1e\xf8\xbd\xe7=\x0f\xae\xf3L\xf5`\xceb\xb1\xe0\"\x8f\xc5\xe2)\"*5\xb8\x00\x03bf_\xa0\u0534\"4\xb5\xbcE%\u007f+\rig8\x9c(+\f\xb4p\xe0\xe4\x12\xbc\r\xac(\x9dN\xa4\xa9\x97\xd3\xf0f\x94\u075d\n\xd8H\xcd;\x91\xa5\xc7\xd1\\\xdc`\xa7i\xac0\xca[\x03\x15u1\x84u0&\xb4$\xb3\xe2\xf1\x98,B\x03$\xfd:\"\x06-\x1ez\x92\u06a1\x0e\x80\x9at\xa0@\x87\xad\u0524\x1b\x80\u007fA\xdas\xc5\xf4\xe77]\xf9\xc2\r\xed\xc1\xc6+&\x84\xaa|\xba\xfa\xd5w\xf4t\u07fc|BY\xfb\xd2:\xe0\x02Uf\xa8\xd7\x17W7G\x86?\xf1\xa5:\xca&,\x89H\xaf%j\xa0\xd5\xe2/\xb6\xda\u0282\xf6\xf2\xa2\x8ei\x03\u0249\x13V\u07d5\xed\u0636pza\xf9\xec\x993\xcb:\xb7\xcf)/\x99\xb1\xb5\xbdi\xe3\u00ae\x80\xf4\u0564[\xdaR;\aw\xa6\xae+m\x8e\xe5y\U000e1b64\x1f\xef\xf0F\xf2\xb5\x1aW\x99\xbfrAy\xe9\\\x04,\x17\xc0\xbdr.\x88e\xc6\x00\xbc\"\xdd\fkO\xc2\x1a\u9593x\xe0$\xac\x97\x86NJ\xb71\u06a5s\xf0\x1a\xfa\x1ciPwf\xe2~\xdda\xdd{\xba\xb3:.\xaaK\xeb\xf0\xc3\xea\xa7\xd5x\x82\xba]\x8d\xb7\xa9\xf7\xaa\xefRS\x0f\xc9S\x97\xa8\x89\x1a\xdd\x11\xe2\xab\xf9f\x9e\xf0Q!-L\x13\x88\xc0\u07eb\xceP\x97Q\xa3h\xe43\xcagb\x14{0v\x83:\u0084\x9a\xf4\xc3k\xbap4\xe1\xfc/\xbd\xdbeS\x80\xe3\x9d\uaaee\xde^S\u007f\xed\xee\x1dU\xb2~\xe0 \xee\xc6\x0f \x82\xf22Z\xcc{y\u0605\x00\xa1\xa7\xe1\xd74\x86\xb1Tkx\x83j\xbf\xcao\xad\xc7N8x\xfe\xc1~\xfe\b\vb\b\xd3\\\xf0)W\u033fN\xe9\xf5#OF\x9f\xb7\x06\x05,kT\xeeMz\u047e\x89wR>\x19\xa7,F3[\xc4r\xa0\x00\x1a)L\r@\x89\x06\x13?\x1a{C,\"p\xc5\xc9m\xcf\xee\x19|\xe6\xea\xfa\u457f\u0673\xf3\x99\x9d\r#m\xdd+\x96\u035f\xbf\xacjJ\xb9\x05\x9f|B\xfa\xef\xdf.Y\xf2[\xb0=\xf1\x048~\xbbt\xc9o\xa5\x8f\x9fpec\u06fe\xb7\xafO\xaeZ4\xaf0\xb0`\xd1@\xd9\xf7\u007f\xb8w(\xaf.Ui\u079e$\x9c\xa4p\xf8f\x93\x03\xb5\xeb\x1e\\\xb5\xf5\u05fb\x9bUf\x8f\x05\u0516\x80S\xbfv\u06ea\xf5\x82J-L\xc2g\xa4\xf3\xd2i\x91\x19\x1bF\ud53f\b\xff\n*\xa6\xd6\u0591\x89\xf2\x05\xa0*\x02\x15\x01\xbf\x16\xb4\xdadt\x8d\xaf\u079a\\3\x9d\xc6*\x8c\u26ed\xd8era\x97K,\xd9\x14t\x1a6\x8b\f\xbf\xe5\x18J\xb0\x18x&>\xca\x133\xb1\xac\x99\n\x9e\x99\x8e\xddZ\x0e2\v\x89q?a\f\xf2\xe3V\u01b2e\xbb\xbdn\xf1='n\xb6\xc6\x131shvd\xcfcK\"\xbc\u0192j\xef\xab\xeb\xbbsy\xcd\xe4\xab\x0f\xafY\xf5\xcc\r\xd3`\xb8xr\x85k\xde\xfc\xf2\xf6j\xb731\x15\xaf^\xfe\xfbg\u007f\xb2\xad\t\x13\x81\xfb\x87R=\xf9\u0283K\n\xd3ey\r[\x1eY\xbb\xf5\x99\xddM\x1d?\xfa\xeb\a\xdet\xff\xa4\x95\xdb\vk[\x83\x89\xc53\xe2\xb2\u007f%e\xbf\u007f\n\t\xa8,\x93\xa7\x06\x00N1\x88\x87\xf0\xfd\x98`N\x00\x01\xf1x#\xc9E\x18\xe6=\x89l\x94\x06\xf78e*\x01T\aV8\x8e\x15#\xfd\xe4\xec\xc8'\xdca\xe0~\xfb\r\x93#A\xadT\x8e~\xfe\x18\n\xa3Z\x1aW\xee\u036c\xe0\x8d\xa0\xb2\x03O@\x15\x04\x85\aD\x15\xa8<\x01E\x1b\xb4\xad\x19\xe6\xe1\f\x0f/\xf3\u007f\xe01\xcf+b\x10[\xa3\x9f.f \xb3\xe6\xfd\xc0\x97\x01|,p\x82\xb9\xb3X\x04Ek\xa6;\xfb\x9d\xd8\xe9Q\xa9\xaa\xa1\xfa\x93\xa6o\x9apeSc\xd3@\x13\x11\x9b\xa0\xa9\t\x95m\xb18\ubda0\x9c\x12r#\x93c\xd9T\x8a)\"\x9b`\xaeO\a-\xf2\x11;\xa4\xb0:\x9b\xd3K\x16\xc6\x00\x9d\x87\xb0\xddep\x8f\xe4\xd0\x1d\v\x05Q\xd0\x11\xf3\xa8z\xec\r\x84\x9d\xc2U\xf3\x1f\xb8\xaa\xb5\xa8\xb9\xbf\xa6vmwe\xeb\xf7~\xbez\xcb\u045d\x13K\u06d7\xd4Vt\xa7\x83S\xae~`K^\xa2=\xbe|Y \xd9\x1c\xb0\x95\xb6&\xf2_\xf7\xa7\x8a\x1d\xceH\xca\u7b49\xe49Jj\xf9c\xa5s\xaf\x9d7i\xe5\x9c\xc6|o{\u07d6)\xf3o[VS=p\xcb\xfc\xa9W\xf6\xb7\xe5{\xa7\xcc[5q\xce\xeey\xa5\xdff\xba\xcd\x1d?\xfa\xf2\x03O\xfa\x8aI+\xae\xbe\xc4t\xc7j2\xdcFdFa\x8al\xbd\x87\x8b\xdf+>[L\xa2\xc5\xe9b\xecQ\xddn\x19\xc3\x15\x81{\x9c\x86\x1c\xb6H\u02c0\x87\xe1\x9d\xef\xe2\v\xe3\xbf\xc2\x1b\xff\n\u007f\x90\xa5\x17OL,6\x9b\x8b'2\x1ae\xcc\xc6h\xd4 \x1fZ\x99\x99\xfe\xb0\xe6i\r\x9e\xa0i\xd7\xe0m\x9a\xbd\x9a\xbb4D\xa5\xc9\u04d4h\x88\x06\xf6\x17\x1c.x\xaf\xe0l\x01\x17-H\x17`\xfb\xedHk\xd0\xf6k\x89\x16\xee\b\t\xd5B\xb3@\x84\xa8\x98\x16\xa7\x89D\u033f\xc7d\x10\xee\xd50\x10\xa7a .=\n\xe3d\xe0dL\x8cB9\xfb(\x96#\x97\xf1\x05\xcf\xe8/\xc1v\xd1\u02f9\xfa\xdc>\x8e\xf5\xf0\xc9\xcb9b\x98\xf65\xce\xc0#$\xa0\xfe\xcc\xc4J\xbe\x91\x1f\xe07\xf1\x9c\xc0\xdbxL\x90\x020\xf0<\xa9\x12\x9a\x04l\x13B\x02\x16\xa2r\u0162\x96k\u3c13+\xe6XN#\xe0#1\x92!\x87\tG\x10\xab\u007fQ\x8a\xa3Y\xaa\x13S\xaa\x9e\xa2bpDi\x84a\xb6\x17\x84*\xb0*\x813\f\xb7\x92\xa3#;\xf0\xee\xd7\xe0\xc8\x10\x9c=+\xbd }$\xcbv.<@\xf15\x92k\\\xf1\x8cG\xc4J\x0eM\xe1\x80{t\x1fO\u0258\x82\x00=\xea\x83\f\xec\x82\xf7\x80\x03$\x87\x02\xb6\x81h\x82\xfd\x82\x8cP\x81\xbe\u64a3\xec\x17H\xf8\xc4\ti\xfb\u0253\b\xa1\xcb\xf9\xac\x83\xa9\xb0\x12\xb6\x03\xa7\x04'`^A\x04\x9e\x03 U\xa8\ta\x1b\n!\x8c\xa2\x14Zc\xa1\x16\xb7a\xec\xc4\xc5\x18\v\xf8\x9f\xf0\x99\x18\u74d1\xc1\xf84+\x19\xa30\x17\xef\x1e\xd9\xc1H\x81_\x81\x13\xea\xcfJ\x86!\xa9M\xe6\xd3y\xe1\x03\xb2\x99b\xa00\xaa\xa38\xc0C\xf2\xccy8~{QQ\x18!\x93\xba5\xbf\u07a4\xb6\xa3\xb2{\x926\xa3\xae\xc3\xce!\x8av\xd2#o\x18i\uc8ceL\xfd\xf8X\"\xfa\x19\xfd\x19\x90\xe3\xda\xff\x06\xd4D\x1dq\xc3w*\x8e\nk\xa41VR[h\xe8\x98\xd6t\xff\xec%\x91\u016b\xd7U/\xf9\u0246\xfa\xfc\xe4\xccdI\x95G-\xbd\xe3\x8aM\x1c7\x9d\x89\xac\x18\u0656\x989\xb5%\xe4\xafL\xd4\x04Sm\xb5%\xef:\xcb\x02\x96\x8a\xde\xefw\xa7\x17\u035eV\xea\xaf(\x8d\xfa&H\x87.\x87\xed\x18-\xb9\xb0D\xd8K\xf3\xc5l\xb4\x04\xcd\u0394v\xf7Y\xc1jm+\x9b4\xa9\f\xf5\xa92\x01\b\x04\x92hY\xb2\xadh\x1e\x9f6L3`\x83\xa1)>ca^\xde\fnB\x13\x8a\x1eKS\x16\r\xc7(\xa3\xac\x16\x05\xd1\xe7\ro\xe4\x8e\r'\x9e\x8b\x1aY\x06~\x9eA\xf4Q qY\xf4\xb2\x13\xc1\xc2\"\xfaX\xf8\x1aK\xc0r\xa4\xb32T_\x18\xc2Ur\xf2\xe6l&\xc8\u01794\u44b8\xb0\xb7l\xc1\r\xbd\xa1\xc95\xc5j\xbd9\xde0\xb5t\xe65s\xcb\x1b6\x1dXZ\xd6?\xaf3\u07ca\xb5V\x97>PY`j\xdf\xf3\xab\xd5w\x9d\xb9oF\xf3\xf5\xbf\xbb\xb6f\xcb\xe6\xf5\x89\xde\x0f\xbe\xf7s\xe9\xcf/.\xab^r\xeb3\xef_\xf3#P=\xbfj\xb8\xa1=]R\x1f\xb6\x12\x8d\xa5:\xbf\xae+a\xc7g\xfb~u\xeb|s \x9a\xef\x8c\x16ZS\xcbo\x9d\xb7\xf4\x91\x1dM*\x83E%em%BI\xb5WS\xbd`{\u04eeW\xafo]\xf2\x8b\xf3\xffv\xfd\xdb7O\xd59\n,\u03d5T,\xfd-8\x9f\xbc\xfa\xcf/\u073f\xbe~\xf1\xaf\xa5/\xa5\xff\\\xb7(\u0732\xa8\xfe]^\x88w-\x97\xed\x89>\xf8\x04\xff\f\x12\x91\r\u0758\xd1\bB.\xc2l\x11x\x81\x15\xab\xd2VG\xab\x92/\xe6S\xfc\x14~\x1b\xcf\xf3\x06\xfa\x1e\u06c8\x02\x90\xc0\xebt\x9c\x129\xd95h\xe1p\x9d\xb8O\xe4D\x83(:\x06\x1d`p\x80@l\x04\x13\x8e]C\xc7\xe1>\x9b\u0365\x03\x1dO8dB\xe9x:\x91MEiz\xa9a\x01\x8a\x8d\xbd\xa8+\x98h\u0755Un\xe9_E,\x92\x8dd\xfd\x84>\xc1\xaf\x04BK\x88:^$\xe4\xfc\x80\xa4X,\xbd\x02'\xa9\xfb\xbd+\xb9z\x05\x87\xcb\xc1sZ\xa3\u0260%YX \xfd\x84\u007f\xe6|#\ue1cc\xa9k\xd1@\xc06ar\xe3\x84r\xb5\xf4\x9c\x8cC\x8e\"\xc4\x1d\xa1x\u054e\nP\x14m\u0274\vf\bq\xc0s\x10R\x83\xba\xd0\xe9\x01O\x8f 8K\xa0\xa4\u01f8\xb4\xc2[\x01\x8e\xc2\x1e\xfb@L\x1d\xe8\u007f\xda\x01\x0f9\xe0\a\x0eX\xea\x80v\a\xd49\xc0\xe9\x00\x05\xabg\xa3\xc2>\x9b\xa9\xa0\x0f\x91\x8bpo\xf4A\xe1\x91\xe1\xefg\xe2Y\xba\xa1a\x86\x81\x8cQ\xe8\xe7\x1fs3\xeb(\xc6\xf0\xc3\xe8\xa0\"\x02N\xb8hyG\xe1\x91\xeb\u007f\xff\xc3\x16O\xed\xcc\xead_Kq\xf3\ue9f7\x8c\fC\xf5\x8fk;c\xd6\xe5\x1bn=R?3a\xb3Uug\xf8#\xe197.mX\u0555T\xaa4e\u04ee\xec\x1e\xb8ou-\xd9h-I\x97\u031a2\xf2\x92\xb4;\xbf\xb2\xad\xacxr,/\x17\u01f6RL\xf0&\x8d\x1d\x014)\x13Y\xac\x05\x95?\xcf\xdf\xe3_\xe1\xff\x95\x9f\xf7\xe9\x96\x06\x0f\a\xe1\xfe \xf4\a\xc1\x1b\x04~\xbecI!\xeass\xaa>\xb3Yf\x8fq\xc4x3|H\xc3%\xa2`\xe0\xa2{T'\x8d:26\xe6\xad.L\xc4m\xac\xb4K\x82\xf3\xf6fc\x91y7\xf4\xcf\xfb\xd9\xf2X\xef\u00a5u\x0f\x9d{\xa0\xb3\xe71@\aV\x9f\x1c\x18\xe8:\xc0\x1dk\xba\xe6\x97\x1b7\x1f\xd91\xb1((\r[\xf2M\xcaU/\x82\xe5\xa1\x03`}um26\x1c\xaee\xf6\xc9\xf4\xc6\a\xa8\xde4Ts\xa1\x8cU\u06c3\x96\xd2.\vXz\x84\x01\x87\xb9O$\x96>\xde4N\x1f}\xc9cp\x81\vPH\xca\xfc\x94\x97\x87nFJ%\x1fX\xfc\xac\xf4\xc9\x13\xd2 <\xf2c G\x17I/Wd\xf7\xcc\x19\xda\xf0\xe2K\xf8\xcc/\xa53O\xf7\xf2G\x16\xfc\\\xfa\xea\xe8UOl\xaa\x19n=\x8b@\xb6\x19L\u007f[\x8d\x9a3%\n\x0e-\xd5\n\xaa\x1e\x18\xd0(\xfb\x1e\x17\xe0\a\x02\xb4\vP'\x80S\x00\x05+\x17\xa9\xf8>LT}\xc8\xf4mk\x90\t\x8bS\xa9\xc5\xd9\xf0\x98Uur/\x0e\x0f\x1f!m#\x9f\xc2\x17\x92\x11[\xf8#\x92\xf4\xac$\xedA(\xf7\xbbD\xa2\xbf\xab\xa4\xe3\xdcZ\xc5\xfd\x04\xc8R\xb5W=\xa4~\\M\x04\xb4\x00\x06T\u02be\xfb\x85\u01c5g\x85S\x02G\xc9X{9%\x88Q\xc2\xe8\x18#c\x9c\x0e\xaa\xbe\xec\xb7\b\x813\xd2q\xd2<\xf2\t\xd0\x1c\u00c8\xd83r\xd1V\xf8\xb0\x9cg\x1a3E\xe1\xb0&\xb8\xc0\xb2\x0f\x00\x8a\xfb\x8b\xd7\x15co1\xb8\xe7k\x96\x14\x85\xfb\"\b\x10*p\xf4\x19\xb9\x82>\xd1|\x91\xf3\x9c6\xe4\xe6\x00{\xcfjZ\xff\x9b\x8d\x04.\xb5!?\xfe3n\xac\xdd2xC\xe7OF\x1e\xed\x19x\x01\xdcG7\xbf\x97]\xda\xf8p\xef\x92\u007f\xdf\xd4\x10Yp\xf3\xe2I\xf3\x8b\xa4OH\u0548\xca\xec\xb5j\xaex\x16\x9cG\x1f\x01\xdb\v\xcb\xe3E\xe7\n\xca[\xbewt\xfd\xaa\x9f}\xafU\xa3\x80\x8aQ\x19\xf2\x16Yw-\x99\x88\x12z\xd0b\xed\x90\x16\x90\x16\x14\\\x0f?\xa0!}?P@\xbb\x02\xea\x14\xe0T\x80\x82\xfd\xa9\x04\u008fF\xa7T\xf4R\x911\xab\x1a\x95\xd9\u0613\xb7H\xafIz\xe9wP\r\u007f\x85*\xbcud/\xad\x89\xbe\x80\xebs\xb2\x9b\x84\x10>)\xffv]&p\xbf\xf6\x82\x16k3ZCk\x8c\xfe\xb8Z\xad\xea\xe11~\x8e\x00Qr}\x02Q\x91\x9c\xc1\xc4\xe9\x1fCn\xc6\x04\xc5\xdb\t\x1a\xfd\xe4ZJ\xd2\x18\xa6\x98D4\xda\xf1\u0251\xa5O>\x89\xefz\xf2\xc9\xc3]\xe4\u026e\u00c7\xbb\x86;\xbb\xd8o]HI]\xf0\xb9\\\x1f\xad\xcc\x04\x04\xa3\u03489N\u04e3_l\xf5Z\xd7Z\a\xadC\xd6\u01ed\xbc\x96\x88\xa2]\f\x8bD\xecC\x88\x86\xa34P\x96N\u01e9Z\xb2D.r\xe4\"\x0fe\x8c\x86$\"ui\x95\x80\x15\x1aKEW\x03\u007f\xc3\xf9\xc1\x9dG\xb6\u058c\xca\xd7$\xfb\xe5\x86Lg\no\xc3\xd8M@\xa9r\xaa\xa6\xa8\xe6\xa9dl\x94\x82)0\x0f\xb6\x81\xa0R\xaba\x80\xd9\t\xb0\xe2\x9bn9\x06^c\xd54ifk8z]\xc2\xf4\xa1-T\xd0\xdf\x00\xa6\x02\xa0\xe2\xc8\xf5\xf0\xb2L\xfc\xf6\xf8h\x86\u0232\xce\x13\x8b\xa24\xf6\x14\x03\x88\xb2\"\x92\xe0\a\xde$\xed\x97\x0eob\u02b8\n:a\xaeT\x86\xfb\xbbG\xfeN\x15\x929\x0e\u007f\x1dY\x8d\x10\xba\u0117yT\x9cqF\xb947\xc4=\xceq\x9c\xe8\x15\x81\xf4\xa0\x01\x01\b\x19u\xdd\\ y\x83\x8dk\xe5\xdf8\n\xd5\xcc?\xbfi\xbb0z\x1d\xe1vz\x1d7\xba\xf1\xe7\x06\xd6\xe4\xd1\x1e\xbd\xf0^f\x1e=hqC\xb5\x1bD\xb7\xdd\x1dv\x93)\b\xea\x10\xb0\xf4X\x8c\x88\xcb\xf0\x03\xf3A\xf3931\x1bT\xb4?\x94u#\x9dNmZ\uc74b\x8fb\x8c\xb5\u056af\x15\x16UvUXET\xbd\xea\x01O>\xc6\x06\rQ\xeb\u0332\x13\xdb\xe3\xac+\x9b\xc8yT\x9c%\x15#K\x95g\"\xf4\r\x93\a{D\"~\b\xd8\xec4\xa90\x92A\x1e\x90\xcbu\xbf\xead\x00\b'=\xab\x148L\bH\x9f\xc0\x01\x98 \xc0t8 \x9d\x02L\x80#\n\xe9\x00\xb7}Aw\xb0\xb3\xbd9\u007fd.\xe5\xf3\x01\xae\xf7|\x1b~*oR[{\xe1\xac\xf9\xdf\xec\xb9(?\xfe\x069\u007f^\x97)\x05\x9f\xce\xd1\xca\xf4\x8bY\xef%\x02D\aSl`S\xd0Q\x88\xad\u05fe\u0609\x9c\x06\xa7\xcfy\x98v\xc5y'-\xfc\xfc\x8c\x1a\xbf\x86\x89\xc9J\xbfV\xadi\xd6`Nc\xd1\x14j\b\xd14+Ay\xf4\u00b9\x8c\x81~U\u066b\x1ap\u0630\x9a\xe8T\xb2\x1f2\xbe\x19\u05ccQ\xc6bv\xfc\x98y\x87\xcc0\x8c2\x1cb\xadE\xea\x977H[G\x9e\xa7\xccr\xde\xfc\xdd,\xf3\xddJ\xefe\xf0\x91\xbf}\xda\x03\xff8x\xf0\x1f?\x9eF\xf7\x0f\x1d\xfc\xfb\x8f\xa7\r\xfb\x8af\xee\x9c3opF8\x87AT\xb2\xdc=hgf\xba\xd2\x03J7\xf0z\xf0X\xf38\xaa\x02\xce\xdah\xc5V=\x9b\xcb\xe0F\xf9\x90o\xc8\xcf\xf7y}\x80T=\xea\x01\x9a\xa8\x9eF\xf0\x10\x82\x1f X\x8a\xa0]\x0e\v\n\x04\xa8_\xa9T)\xfa4\u012d\x92\xe3\x1dS\u0459l\xeea\u02a1\xc7Q`LU\x97\xa2\x03\xd5\\\xec\x1bW\x9c\x93\xb9\xb8\x8f\x93\xc1$\xf5\x03\xec\x05?\xc0\u7ceeYw\xe5\xceiTq\xfb\xc0\t\x9a\xa2\xc9sbk\xe7\x86ZjLF\xe9\xa0\xf4\x02)[:\xb0l\xee\u0236\x91\xe3\xfc\x91\x13\xefN\xbd\xaa\xaf\xc5\xf1\xe4\x0f'l\xe8q\xe5\xe3\n\xd9\xc7{/|JN\U0002fc4el\xa6LE\xf2\b\xe6}V\x1f\xb6)!l^\x80\x96\xd6y\xeb\xd2u\xf7\u05d1\xd8\x02\xa5{Im\xcc\u0317\xf5\x15\x15p\xba>%o\x96+\xb8\t\xa67Jz\x9c\xeaP:\x93@2\xe6\x85\xefV\xd2\xc3\xe3\xfdS\n\x02(*\x10\xe4B\x9a\x87\x90\x13\x93\xafyz\u06ca\x97f\xc5\x16.^\x1cOL)\xb3\x06\xd2\xf3\x92\xe5\x1b\x167N\xbc\xf2\xe1\x15U\x8b\x17\rT\r\x94u\xb6\xb5\x14v\xcet&\xe74L\xdd9?\x0e\xb7/\xbco\xed\x84R\x1a\x91\xec\x91\x02\x8b\xbd8UP\x9cNV\xba\x1d\x8d\x8b\x87\x06\x16\u07b3\xb2F\x97\x17r\xfe\xd5\uace9g6\x05S\xf1J\u007f\xd1\xcc\u017bd^\x8b\x11\xe2\xea\xa8NE\u0510\t?\xa7\xfc\xbd\x12\xafUBL\x99Qb\xbd\x12\xae\x95QT\x0f\x10\x92\xa1\x92\xc4 \x92>.\a\xa8N\xcbY:j8\x13\xcfA\x84qX\x80_\xa7\x90\xe0f\xce$\xdd\xc2=\x05X\x92\x10\xa0\xc7h\\\xd1\xc813\x96\xc9W*@\u0241\xad\a\x16;\a\xa9\xb7b]\x8f\x9a!X\xc1\xacA\x84\x81\x8e\xd3\u3845\xa1k\xe3X\x05\x92^{\xb4\xf2h\xe45M7\xfe\xc7\u041e\xe37\xb4B\x95/\u075b\u07bd\x99\xf6\xd8;7\xbc\xb8\xaf\xab\xe3\xa6W\xae\"\x8f\r/\x9f\xb1qJ\xc1\x9dw\x91\u007f\x93c6\xdbp\xa7\xe5^\xd1\\\x8a\x81\b\b\x18\bV\xab\xc7Fm\xd0\x0f\xeb({\x1c\x18\x00Lz\xd3Z\x13\x96K7\xbc\x9f\x82g\xa4E\xd0\r&\xd0@\xa7\u050b\x8bG\xde\xc1_\xe2\x17G\xbe\u013a\x91\u0228\x8f<\"\xc7\xf6\xf5\x19\x1b\xaf`\x86r\\\x051\xd5a\x15\u05ab@\x91\x16Ad\x94yE\x91\x87O0\u0708a\x00ob\x85=\xc0\x06\x8c\x11\xd7\x13\xe3\x81'\x88\xcd\x00\xd2(\x8d\xadH\x10\x803)\x800\xaaY\x0f.\x92`}\x87T\x9c\x92\u02f4\x9f\xa3\x9b\x1e\x8d5\x9b\xa9{\x83\x1fw\x83\x82R\xd7(\xfd\x1f\xa9\x11\xa6\x93\x05\xb8gx\xf7\xc8+8Jr\xe3\xc1\nJ\xa3W\x1e\x0fn\xcaT,'@\ffG\xab\x9a\xeeE\x11\u0448\u056f\\\xa7\u0727\u072f<\xac\x14\x95J:H<\xae\xfeBM\xa6\xaba\x9a\x1a\x96(@\xc1\xc8\u03e7_\xe0\xe817\r?\x8e\x9f\xc5\x04c\x95\xc8\xf5\xf1\x04+\xfa`l\xf8a\x84\x04k\xe4\xe6L\xce\u020e\xc7\a\"\xb9\x06\x8f\x9f\xf3\x0e\x9b\xf0\u0291\x83\xe4\u0551\xdb\xf1\x8ec\xe43@\xaf\x0e\x9bd\x1a\x87\xa4g\xf0F9\x9e\x16d\xcc\x1c\xfaR8\x8b\xc0\x00\x18\xf8\u007f\xe0s\xc2?\x80\xce\xd78\x9d>\xcdD\xf1\x19\x05\xad\xf2\xe5\x02\xc6\x04\xde(\xe5\xc3_\xde{OzF8\xff\xd6\xf9G\xd8u4\b\x91I\x17{\xf6\b\x94\x180\vP<\"\xacgO\xbe\u0773O\x8c\x89\x91\xca\xd0/}2rj\xb4g\x0f(A\xe9\xb1\xcb\xf4\xf82\x06\x82\xbe\x84\xb3\x82\xa0D\xff\x10\xbf&\xff\xe0\xce\xc9P\x8e\xf1+ScO\x18\x03U\x94\xa2\u0129S\xf0\x17)\u007f=?\ubb6f\x05F\x8b\x02+\xb8z\xfe7H\x81\x92\x19O\x84A\x1b\xab\x02+9'\x87\x95 W\xb79BT\n\xc6>S7%*\u03a6\x0e\xb2\x8an.Y\xa3\xac\x19\x12\x10\x00\x01\x8b\n8\xb2\x0f\xbe\xf8B\xfaM\xd3P#V\x90#\xc3mx\xf7\x8f\xa5_\xdd+\x8f\u11a5gH\xe7\x85VD\x90\xe9\bB<\xc0/1b\xe51z\xb5\xdcl\x10\xd29\xfc\x18\xa13m~(\xfb\x1b\xb4s'\xc8t\xc1\x8f\xb4\xa8$\xe3l\x12\x81\x88\xa0\u0448\x82^\xec\x13\u05f2\x89\x82z\xd4\xc7\xe2{4+\xcf^\x91'\xf0\xd1\xeb\x94\x13:\x98\xa4\x81\u068a\xaf+\xe8[\xd0n\x80nC\xa4V\xa0\x11d\xe9W\xd3\x028\xc1\xeb\xaf|~\uf529{\x9f\xdf\xd2}h\xea\xdcIW%\xd7\x0e\f\xac\x9csS[\xb0\xb9\xa5\xc32\xe9\x86\x13w\x1a\xa9\x8c\x15\xa8\x18-\xceLT\x19@\xa5\x81!\x8a\x1d\x82yJ\x0e\xb8V\u01dc\xc8\xf1\b\xc4\"@\xc4<\xc8k\xd6u\x97\xa4\xf2\xa6\xe4\xe1\"\xfaf\xfa\t\x02\xaf\x12\xb8\x9a\x00!^4\xcdl\xf0v*m\xe3\x85B\xe6\x15\xb2&r\u0566\xec\xd8d\x01\xa0\xae\xe0/'\xe4\x12\xde\xdd\xe0\xcfAiY%\x033V*\xe0:p\xc4Z\x95W\xfe\xee\x96\x19m\xd7=\xbda\xed\xcfvL\x1e\xe9\xc6\xc1\xc9}\xf5\x89\xf9\u0773J\x8bf\xf4,#wo\xb8*\u045d.\x1c\xeej\xbe\xf1\x9d\x9bo\xfd\xaf[\xdb&\u007f\xef\xd7W\u0756Y\xda\x12R\xdb\xfc\xb6O\xadn\x8b\x12\x8d\xe1b\xd2*x\x91\x13\xb5eJU\x0e\xa5\xae\x15!\x83\xc1\x15u=\xee\xc2\x06\x178p3\x11\t\xcf\xcb3\x05\t\xf0\x9d\xa2Co\xe9\xd0\x02\x96\xfd<\x9d\x18\xc5\xc7\xc6\x04E\u0232Y\xb1\xe2_\x04\x02LUU\xc9o[\x96\x1b\x12\xf8\x83?K\xc7\x0f\x1e\xac\xec\xff\xc1\xec\x05;K[\xbd\x8d\xe5\x13*\xfeL\xb6\r\xef!\xdbn\xed\xeaZy\u3b00\xdb\xf4\x9e\xda\xd41\xa1\x99\xd5\xf0-\x92\x85\xab\xa7\U0009f23aP\x16=\x93\xb9\x86\x17\xadbP$,@\x05\u0744wZ\x9dA'Q\x05\xf2\x02%\x01\xa2\xaa\x02U*/U\x92\"\x95>Z\x9d\xa9\xd4&\x15\xf3`^+\xcf\xcfl3\xb0\x86w\xdf\xe3}\x10\xeb\x03q&\xcclM\x96\xf8\x94\xa6\xd6\x12C4\x9a\x9c4-\xd8\x17\\\x1b$\xc1\xa0!\xe9K\u0192$Y\xc9\xe3\x89\u0704\xee\xa9*P\xa9\xac\v&\x18ZZ\xa0e\xba\xcf5\xb5\x13:\xad\xb4\xe5\x94M\x9f\u03a6\xe5\x96\xd31\n\xe6\x18\xf7\xf4\x882~,\x151\x9c\x19\u0364\u01e8>\xe5\xa9\x06\x91\xb1\x82\rX\xc5\xf1YF:`\x01\xa2\x8eE\x91\xefL<`;\xb8h\xf7p1\x90DX\xfd\xdd<>\xb3\x8c\xab\xffw\x8b\xa1z\xc5\xfe\x15\xf6j\xad\u015eWR\xe3yl\u01aey\xb1\xf6;\u07bbu\u00e1\r\xa9\x92\xe6yQk\xb1\xdfj.\xac.\x98\xbb\xb4f\xd5\xfee\x96xE\x89FZ`\x8du\xa6\xee\xfd\xd1\u00a57\xba\x1a*\x03k\x1a\x9bZ3\xe9){\xb9\x05\a\x12\x05SJf\xdf8\x90\xe4\x891\x98gu\xea\xf9`\xfb\xe6\x19}w\xadLEflh\xad\xef\xc9\x14\xa9\x95\xbe\x92D\xbe\xaf\xb2\xac\xc8\x1a:\xb8\xa1\xe7\xa6E\x95\xbc\xa8 \xdf\b\xacE5\xb7-]\xa2\xf5U\x91%\xf3\a\x06\xe6\xf7\xac`v\xb5\x1f!n\x05\x8d\x01nT\x9d\xf1\xf3.\xab\vC3\x9a\xedE\u0798w\x97\x97\xe8\xd5\u035aY\x1e+\xdf\xe10h\x91\x86%\x8d8K\x1b\x17\xbb(Tl\xc5`\x1c\x9d\x14c\xf4\x8f\xc7W\x90\xfb\x94\xdc\n\xe9\xf8\xd4\u03ba\xe91\x8bt\x9c\xc6S\xc2\x11C\u015d\xfd3\xf7\xf4W\xe2\x1b\xb7m\x8b\xf5^?o\xe4K\x1a@_(\u0246\xcbK\xe7tD\a\xeeY\xc5\xfc\xf9V\x84\xe0\x14\xa5\u024c\xec(\x9a\xc9\u007f\xd6\t1:\xb1d\x1f5!K3\xb2\xcer\xf03O\xb1B\x8aMo\x91g\r\u04de\xba<\xba\x95\xa7\f\x98/\xef\x91R\xa2n\xcd+\xab/(\x98P\xe6r\x95M((\xa8/\u02c3\x06F\x0f?\x18I\x05t\xba@*RR\x1b\xd0\xeb\x03\xb5\xe7\x1f\xe6z\x11\xc2\x17\x1e\x93,\xa3\xbf\x1fFM\xd4\xdbLy&L!\xb0\xa6\u0663\x9f]\xfcl1\xc4h\xb5}_1q\xce<\xc5\xfa\x9eZ\xfdX\x15\xb7\x03\xb9h\xe8\xc8\xe6(b\x01#N\x8b\xb9rW\xc6L\xad\xa9\xea[\xe5\xdc\xcb[\xfeKbK\n\xbc\xd5\x05\xce2\xbf\x05*\xc2s\xae\xaf\xbe\x9cf\u0262S\x9fU)\xf5\xe1\x89\t\xee\xd07\xc5\x1d{\x16\u05ca+/c`T\x9fG\u5e73k\x8e\xa8\x04\xd0`\xe0\x18>3\xd9[\xd9>S\xad\u05b5\xf2\x9c\x95\u00dc\x88\t\x11b<\x14\xf2\x80x\x03\x8f\xe9\x8b7h\x95\u036aYz5\x12\rFK\xabB\x04\x11aAe\xc5z\x94\xceA\xfdH.\xbf\xcah9W\xf9e'e\uf064\x8c\xf0G\v\xc0\"\xbc\xb4\x0e\x8c0WZ\x05\x8f\xd12\xf0\u066dL\xe0\x06\xdc\u007f\bfI\xae\x91=\xf0X\x97\xf4\x13\xc12\xd2&\x8d\xda \xbcIi&\x14\x13\x9a\x9f\xe5!\xc6\xf7\xf3\xfbx\x82\x9aa\x16\x87\x11\xb3:\xf9g\xc7F\xf5\xf0&\xbb\x18\xfd\xff\xd1\xef\ngi\xec)\xa1\xe3\x84J\xb9,B\xec\xe0@\xcd\u007f\a\xb8\v\xe0\xfb\x00\xdb\x00j\x00B\xf2h\x13@\x13h.\x98]\xdaW\n\xb2eG\x1c\x06\x03\x1b!\x18h 2\x84\xf9\x0e\x8f\u0560\xd5\arvN\r\x9dM\u038b\x18\x13\x17\xad\xdd8\u07b4a\xa9\xef\u06e6\x9f\xb0\xcb\xf3\xc5l\xa3;vJ\x86LV\xae_:\xde\xdaQ\xdbQN\x9d\xe0L\xb1\xd11yzO\xf9\xc6\x1fG\x9c\x8e\u01ae\xf9\xe5O\xfdBz\xa3\xb5c\xf5\x82q\u007f\xe0z\x87\"\rE\xe6i\xb3\xd9\xf6\x85wF\xc2\xec\xa3G\u007f|\xd1W)\xafy\xa8.S\xd8d\x02\xdeau\xc8\ue68f\xf2c\xf9\xbb\xf2s\xee\xea2\xf0\x1d\x8c\x8f\xff\xdd]\xd1\xffJ\xf5\xa8\xafN\x99>azt\x94\u0326\xae\x05\xb1\xae\xef3O\xbd\x8c2\xe6\xa5\xe3yw\x80\u04a3F^9z\xe8\x80\xf7\x80\xca\x02*\a\b-\x9a9\xfe>?\xa0\x16[\xb7O\xd9\xe12\x90\x0e\xa3\xed\xb2J\xad\x1co\xc7#\xe5w\x17@\xfc\xa8w\xc5\xf2\xde\u0795\u02f3\xf8\xe5\x96\xeb\x9e\u077a\xf6W{\xda[\xae\xfb\u0355l\x8f+\x1e|\xe8\u0401\a\u007f\xfa\xd3\a\u007f\xf8\xc7\xdb::n\xfb\xe3\x0fo\xf8\xe3\xad\xed\xed\xb7\xfeQ\u018e4\x1fm\xa5t\x8daG7\xf0N\x8a\x1d]s\xe2!\x83\xa6Y;\xab\xc2\xe8\xeb\xb0\x19tz\x8d\x8b\x8f\x8c\xe1\x1a&\xa7oaG\x9eaF\xb9\x94\xfdm91\u07fd\f;~\x9a\x9c\xd3Xi5p\x1c\xe1\xa5\xe3\xe7\":\x86\x19\x93snZRS\xbb\xfc\xe6#\x97bG\v\x83\x8c\x01o^R/\xd5\tm73\xf7f`r\x88\"\x1dr\xebe\u0611\xc9w4\xaf\x1aF\xf1\x99\x83\t\xd7\u03c7\x9a\x03\xb3\xe3:*\u060aBW\x81\u07a7\xa6\xd2-E\x1d\xc6\u007f\x82\u03c2\xdf\x06a\xe2\xb7\xe0ZR\xeeGT\xb3v\x84\x8e\xe0\x9e\xe4\xd4r\x1b\x98\xa3\x1d\xb5\x14\x83\x19\x18\x03\f\xac\xd5\xf4L\xa9\xb1)\x1c\x80\xa5\xe3<&Dk\xa1\u071dd\xc4\x06s\xc4\x1e<\xf0\x05\x83k\x94\x89\xa9\f\xae\r}}\x04\xde6\xa7\\>?\x83kc>JZe\xbb\xcd\xfc\xec9\x01\x046\xe7\xd4O]N\x10\xf2/\xe4C\xb3\x95J\x98\"z\x97Yo\xb4\xf2\xb6&\xdbl\x1b\xb1\xa9\x19\xa4?\x96\xc8\xca\u030cB\x166\xe6\x05F\xb6\xb1\x9c|\xcb~\xf1G\x1a\xb7\xcb.(\xf2\xbd\x1eU\u0762\x96\xb0t\xfc\xa32\xbd\xa3\xa6i\x0e\xb7\x11\b\xc1\xd2\xfb\x98#\xe0\x99\xbcz\xda\xc8+\\\xef\xc1Hs\x85+\x87\xa9\x16Rl\xbe\x97\u0495D\x8b2\xf9<\xb6b\xcc:\xef8le\r\x13k3\x9a\x93:\x9e\x82X\n\xcaY'\xc4I\u03d57\xab\xbc\xdd5\xd6r>\xd2Y\xc4ZFE\x85\x06C\xa7\x9a\xc6\u055f\xd37j\x9ej \x119\xcd^c\x05\u05c8\f\x1b#\x89\xf1\x8a+\x9b\xa5wY\xc9u\x1c{\x8dW\\\xf7f\xb6\x1c\\\x96\xec\x9d\xd5YT\x92]0'X\\\x1b4j\xcb\xe7M\x9d\xb2\xb2\xa9`\u009a{\xfa\x06\x9e\xa2#\xc5\xeb\x9b\x1a\x92\xba\x92\xf6\xfa\x96\r]\xa5\xd0>\xf7\u06b9\xa5\xa2\xc1a\x1a\xb6\x168uzW\xd0j\xf5\a\xa3\x05\xfe\x89\u04d7\xb6tn\xee\f\x97\x97\xff\xb1\xb0\xbc4d\xf1\xfa\xc3\xf9\xde\xfa\xcee\x8c\xff(\xe5_\u01f7#'ZpD\xe5`<\x13\xa6\x9aJ\x95\xbe\x153@\xec\U000ba9b9\xfa\\k]\xf7\xbbN\xb9\x04\xb3\xbdY\xa3\xd3\x19\xfa4k5\xa74_h.hx\x8dM\xd7i2\x98\xf5\xa8C\x94};\x91\xc85K\xe5:\xac\f\xb0\x18\u7460\xfd\xfc\x83\x91\x0f&6\xe4\xf4u\xb7\x1coz\xe5\xf8\x17h\xe3@\xa5\x02p4;/\x86?\x1d\xf5m\x17\xa2'\xc1$\xda\x1cZ=\xab\xf5\x1c\x8bg\xa3c!\x87\xf9\x03\xbad\\kdD\x8c\xe5d\xb2\xbd\xd8\xe0\x1c\vzP\x91\v\x85P1\x14\xa9g!\xef\xeeU\xf8\xc4\xc8\xc6\\$\u013ao\x1e\xb8X\u01ddN\xe9\u0462\xdb3^Ak\xd3Vk\x97h\xb7h\x8fh_\xd6~\xa8\xfd\xbbVyB\rj\xd6@\xfb\x03\x96\x176\u022b\xa0X\x8d7\x85\x96\xa3m\xe8\x97\xe8\x18:\x83\xbeFJ-+N\xa9\xf7k\x9e\xd3`\r\x93\xbf\x8dM\x1a4h4\xfau\xfa}\xfa\xc3\xfa\xdf\xeb9\xaf\x1e0\xb0+hA\rz\x9b\x00\xf2\xb4_\x16\u07b3\xd9\xf4%\x85\xcbH61V\x01\x8e\xb0z\x91\\\x91\x04\xea\"@+\x91\x007H\x9b!\xfdK\xa3\x93\b\xc4i<\n\x19i3\xd7;\xb2;\xb5\xbd\xa2jk\n\xef`L\xc9<\t\x1b)O\t\xb0\xff\xe2\x0f\x89\x0f\x13\u007fO\x90\x04\xfbe\x83R\xdfZ\xc1\xfc\xe2\xed\xc2\x0f\n\xffVH\nY\xded'\xff3\xf0\u07c1\xf3\x01\x12p\xd0c\vs\x14;\xfd\xa7\x13\xa63\xa6\xafYA\x98\x9e|\xdb\xf8\x81\xf1oFbd_\x98\xc1\xbe\x80\xfe\x1b\x9dG\x04\xb1/\xdci:h\u00a6;\x8c\x0f\x1a\xb11\xef\x8e\xc2\a\vq\u1741\x83\x01\x1cP\u0791x0\x81\x13w\xa2\x83\b\xa3\x12!\u03d6\x17\xca#\xca\x12gIq\t)Q\xe6\x11sE|\u007f\xfc\xb98\x8e3\x81\x19\xe9/\xc6\r\xf1\xaa]U\xfb\xaa\xb0\xbej\xb4\x10\x9cg\xae\b\xb0\xa2\xe7\x14%Q\x9a\xf5\x11\xc1es5\xbb\x88\u02c5L\xd6\xd1\xf5\xb4\xe9\xc4%e\u07da\b\xdd\u0411\x02;\xce&.\u0670YO\xf2st\xe3g\xf3\x9eB\xe1\x80 \xea\x88HF\xab\xec\x89\u046a/;\"L\xd8\xe4\xef\u075c\xd6`TZ\x1c\x82\u076c0\x1a\xb4\\\x8ftTz\v\xa2\xeb\x95f\xa3\x8e\x13@\xa4\xedw%\xb9\n\xa6o\xe6\rF\r\bDo\xb2*7C\x84b\x9b=\xc6\xf4\xb4y\xa5K\xb7n]V\xda3-c\x92vp\xbd\x921\xbcz\xed\"\xb7\xb9\xbeyJ\xa6B\x85\x1d#\x1f\xdb\x16,_\x94\xef\\\xb8~]\x18\xbe\x18\xb5G\x15B\xdc\\\xaa;5\x1a\xc9\xcc\xe7U\xa0R\x80\x8a\x03\x1e\x83\x83\x03\x8e\xe7\xefF\x87\u042f\x10\x13?\xbf\x1cA\x0f\x02\xb6\xc2\x0f;P\x11\xc2*\x04\xcdB\xb7\xb0D\xb8]8 \x1c\x11\xfe |((\xecBXH\nD\x10@P\x12\u0129\x1d\nP\xec\x17\x9f\x13\xb1\xc8d\xce\xc2!\x9bV\xa6\xf5j\xa3\xda\u01f5\u010e\x01\x83\x9d\xfe\xa6\x9a\xc9\u07a5V:\f\xe6\xd6\xe5J\xe8QB\x8a\xaa\x00\x97(\xc1)\x17\xe2\tk8\xfb\xe8\x87K\b\xcc\"PM\x9a\t.$`c=oP\x12P\xa8\xac\x1c\xe8\u01cb\u02d7T\xdb#\xb9Bs\xfc\xa2\xb1g\x99\xbe\xc6\x1e\xb9b3;R\x82\xdf%\x83Q5\xf8\xe1:\xe9N\xe8\xf9\u056f\xa1G\xba\x15vH\a^\u007f]:\x80\xebp@:\f\xd3G\xde\x1dy\tVH\xb7\xcbv/Yd_\xf6\xa0C\x99r\x87\xa7\u0183U\x1e\xf0\xfc]\aI\x1d\xd8\xd8\x149\x1e\x9d\xd1\xc0\u007fj\xa0X\x93\xd2\xe0<\r(5\xa0\u066f}N\x8b\xb5L\x1c\xa5T\x1cZ\x83V\xeb[\xe7\xdb\xe7;\xec\xfb\xbd\x8f\xf3\xfa\xc0j\xfd\x10\xe0m\x80\x83\f\u007fV\x03\xb6\x02\b\x00\x80\x98\x84LH\xf7\x1e\x0f\xac/\xeb\xf1x\x1dF\x97\x06\xe9\x19Z;f\xcc5\x1d\x18\xa7\xa3lE\xc7\xd9e\x0f\xe6\xe0\xec4C\xc3F\xe6\xdec\x16G#\xec\xf8(#\r\xd0\xf9\x94A\x8f\x05,\xaa\xb4\"\xe5Ujn\xf8\u00cf+\xdb]\xd6L \xd6X\x11\u041a\xa9\xeb\xdfP\xb9%j\xaf\xa9M\xd9\xf1\xe6o\xccO<\xa2\x16\xbe\xe4\x15y\xd1I\xc55\xb95\ad5\x95\x87\x92\xf6\x0e\xecS\xc8<\xb2\x9c\x10b0:ZUr}[\xc9qX\xc9\x18w\xd1\xe2:\xadn\xefW?\xa7\u01834\xdee\xe8\x00\xa3Y\u046dX\xa2 \xb9\n7\xfd\n\xcf,\a?\x871\xcehM\xadX\xe4:y=Vt\x82\x15\u047e\x9d\u073ac\xcc1\xf7\x92\xd3<[\x01\xfa\xad\x1aw\x15\xabq\x93\xd5\u00ff\x83cR7\xe1\xa4fx\xfd)\xfc\xfc\x99\x97Gf\xe4\xf2\x82\x97\u0594\u07d6\u05fctf\xe2\xea\"JQ\xd0A7z\xff\xffX\xf3\xcf*\xf0W\xb10\x84\xed\xf8\xef\xaf\x13XK\x06\xc9\x10!SXv\xd3\xf9\xffV\xf0\xb5\xfeo\xbas\xe33\xebs\xab\x8f>\xa7i\x8c\xad_\x8cDP(PE\x85\x19\x96\xe7\x9d[u\xc4j\x14\xd8*$\xd1\u0232\xb4UN!\xe0\u077d\xa3\xe1\x8aI~\x1cZthw\xd1\xc42\x87\xf0\x97\x8dW\x11G\xd9\u0122\u0747\x16\x85`m\xd7\x17f:G\x17\x1a\u0696O\xf6\x9d\x06\x8d\xb7:\"\xbd\xfdt@c\\\xd3+\xbd\x1d\xa9\xf6j\xe0}\xdf\xe4\x15mP\x87\x10\xc0+R\x14? \xe8Xl\xcch\xf1!61y\x1d!\x04#$\x97\u05b3l\xd9\u007f\x82\xad=6\x83\xc5\xe2he\xfb\x8cY\xa3o\xf5\xf9\xdc\xfc\xa3i]\x9f\x0e\xeb2VG\xab\x0eE#\xf2r\xbbHD^\xee\xc3&r#fd\x90\x83\x8fbU\xaeJa\x1f+\xdb\t\f\x14`C0\x15-\xb1\xbb\x1b&\xa4\xf2\x12\x83\x9d\x9eD\xaa9\x16J\xc5Jl\xec\x8cs\xf1=\xec\x04^f\xb0iy\xb3\xbf\xd4\xf9Qu\x92\xd79-\x06+}\xeb+s~\xb4\x9a\xd7:G\xd7=HC\xf0\x16\xd7+\u07cbby\xa6m>\x02\x01\xe9\xe0\u007f\xb9%\x05\x86\x971l\xc5@\xd1\x10\xc6\x04\x03F\x1cp\xb7\xff\x91\xc01\x02W\x12X\x9e[J\xd6OC\x10\xa2\xf7\xa4\xd0\x13\x14M\x8f\xbc\f\xd1\xd1h\xf0\x19\xabL\x8e-\r\xed\u02da\x134\x10\\6\x8c:\xf8UB:\x00\xbd\x97/\"\xc0\xbd\xc3\x15|\xf0\xbb\xcb!X\u03c8\xe2\xc2\xd3\xfck\xa8\x18-zBW|\x14p\u01a1FH0?\x1e|6x\x9c\x96\xe0\"\xfb#\x87#\xcfE\x88g\x8d\f\xe5}4\xf6\t%^:\xb9\x15\xfb7\x03*rn\x19\xd4\fi\xee\xd7\x10\x8dz\x97n\x1f\xd5\x06\xa2\u053e\x9e=\x1d}=q\x1a\xb2\x86?DNg\r/g\xe3Fy%\\E\x8c\xaf\xba\xe4\xee\x03\xc4.\xe6\xb4s\xb1\xbc\r\xa2\x15{\x17\xd0U75\xcbo\x9b\xffd\xa8\xbd%\xed\xe8\xb6V\xd5$\x1d\x93\x16\xd4\xe5m\xb8\xa6\xfd\xc6x\xe2\xea&\xcb\x1b\u06a9\u05fd\xb2\xf7\xc6\xd7~0U\xfb\xc8O@m\xb0\xa8\xdfW\x99\xf5\u02a2\x99\x83s\x1e\xbe?\xe8\xf8\xc2\xed\u016f\xe6\xd6E#\xc4M\xa2\xbc\x85\xd0\u0759\x15\xaa\u00bc\u0092B\xa2\xfeH\x0f\u007f\xd0\xc3Kz\b\xeb\xe7\xe8\xef\xd0\x13\xab\x1e\xf4k\xfc\xbft\u007f\xed\xc6+\xdd\xdb\u0778\xd6\r\x9c\x16\xdcZ\xb7\xd6\xea\xcd\xd8\xfb\xed\xd8N\x16Yw[\xb1\u03da\xb1b\xce\nV\x9dw\xab\xfa\x16j\x92>\xe4h\xb1\xbcby\xc7B,\x1bm\x8e3\"\xbc*\x82\xb8\x89C\"\x8d\xed\xa7\xb3\xac$)\xf7Wr\xe5X9\xb6_\xbc)\x06=)\xab\x91\x81T\xb8\xa4\x16K\xa1\xb2<\x99\x84-\x10l \xf5\x10\xa8J0i\xe1\x83k~6=\u06f29=y*tJO\xbaJ\xab\\\xf8\xc0\xb0\xa1dr\xd4\xf1\xe4\x93\xe9\xb5w\xf1\xaf\xc5\n>t\a:\xfa\x9e?9\x94\x9cQ[\xa4\x93\x86\u03d9Jj\xbbjo>\xf9\xc2\xfa\xfb\a\u0299\x8d.@\x12\xa7\xe1\x0e\xa1\x02TM\x11l\xdf\x04\u007f\xbb\x9f:\xf5d+N\xe8'\xeb\xf1\x04\xd2N\xf0\x04O\xbb\aOp\xb4;pB3Y\x83\x13\xc2d\x01\xdbt~\xe2\x11\x1c\x1a\xab^\xaf\x11\b\x87\xca\x0e\x99|\\\xe0\xd0~t\x18\xfd\x1e\x11\xe4\xb5k\x04*B\xbf\xc3\xe3\xf1\x13\x81S\x16=\xe6\xd2\xf2\xf1\u01d4(z\xfa\xe5\xf8\u007f\x9d\x96;\xeb\xb9\xe7\xcbL\n\xdf=\xc9\nf\xf4\x01lc\xa6\x83\xd3p\xd2.w\x9d\xecI\xbb\\\x9c\x15X\xb9-\x97\xed\xc4p2\x94\xbcl\xca\xd1\xc1|\xe75\xb7\rF\x96$\xaa\xfb\xa3\x83\xffv\x8d\u04dd\x9f\xb7\xe3\xe6\xc1\xd2E\xd55\x8b\";n\x19\xac:\xeeI4\x86\x8b\x9a\xab<\x9e\xaa\xe6\xa2pc\u0083\u07ea^T:x\xeb\xa03\u07d5\u007f\xcd\xd05%K\xabk\x16\x96\xed\xb8y\x87=\u07d9\xb7\xfd\xe6\x1d\xf3W\x84\x9b\x12nw\xa2)\\\u0514\xf0x\x12M\xb2\x1d)\x10\xe2\x16\u04b8kC\x8fgLz\xb3Y#\xd8\xc0\xa6\xb7N\xb3\xdeOgvrV\x96\xfa&X\xad\x1a\x05\xc7)\x01 \x83\xf7c,7\xa6E\x9eX\t&\xea5*\vX\fH\x93\xd1\xec\xd2\xec\xd3\xec\xd7\xfc^#hT\xba\xf3zQ/\x98\u039bY\xe3\xfa\x8f\x99|\x1a\xd4D\x04\xc8\xcc\u029df\xaf\xf9~3\u045b\xf5fP\x9blc\x8dl\xd9vX\xaeL\x18N\u01cdl\x03r\xb3\xf8t<\x1b\x97\x9b\u06c9,\x93\xecxW\x9e\xa6\x10\x1a\"\x12\u0580\x95\xbd\xfcU\u051c\xd8\v\xfc\xb8\xea+HI\xb7\xff\xf6o\u007f\xfb\x9bt\xfa\u0739s\xcfJ\xf7\xc0\x04\xd6\xf2\x1e\xb1>y\xfd\x93\xef\xbeK7\xf8\x139\xb6]\x92\xa7DT\x981c\xe1\x10\x89\x89\x19q\x9dHDV\xe3\x15\xe4|\xc5H\x03\xd9\xd4sY\xcb8\x9a\xb9X\xee\x1a~S\x1a\x1c~S\x8e\x93+h\xac\x19\x14\x8a\xd1d\u050d^\xcax\xab*\x9a*\xb0\xad\"T\x81\xe3\xb1I1l\x89\x15\xc6p\xad\xb1\u0348\x9d\xc6b#.fI@I+\ar\x03\xa4\x90!\xc9n\xfa\xae\xb05\xdc\u0233fB\x17\xafPt8:\x8a:H\xc7\xdd~\u007f\xed]\x86\xf0\u0735s\a\xe7\x0e\xcd%s3t\x84n\xbfK\xa1\x10\x1b\xed\x8d\xe1F\xd2x7\x8a\xc5\x10\xda\xc7V\u007f\x15\xb6\xe6\xf3]\xad\xf4\xa9\x8dU\xddWj3Z\xee\xd3\xc2(212.\xe4\x89 \x89\xdc\xfc\xa2\xd3ts:Bg\xeb\xc5O\u04c3,\xfd\x15\x1ai\\\xcfG5\xa8\x1dm\xcbL\u02f3@\x9e\x01\u020by\xaa\xb4\n\xf4&0\xa9L*\xb7c2L~!\xd2iOA\xea\x05\xb7pL\x8b\x8e\xd9\a\xe9\xfc\xf3\xfb\xb5\x04\xd9\rv\x9f}\x9d}\x97}\x9f]\xd0\u06b5\xf6B\x1at\x1a^\x8d\x9b\x1d\xad\xd0\xfaj!\xc7\n\xfb\xf4\u03d8\xf38\xc3\x19\x03E\x14\xb9\x05\xab\xc61'\u0335\x9c/\xe9\xccB\xe0\u04aem\br\v\x8c9kn\xb9&wy\xe0\"\x83W\xac\xe8_\x99\xba6\x95\xda\u04b1r\xff\xca\xea\xca\xe5?Z>\xf3\xee\u01b6\xf5\xc3;\xaa\xaf\xb8\xfe\xc1\xe7\x96-{\xee\xc1\ubbe8\xbe\xf4\xf8\xa6\xfe\x9f\xfeip\xf0O?\xed\x1f\u06d3/o\u06fd\xe7f\x8f\xfbY\x97\xa7\xf1\xeaGW,}x{ci\xc1\xc1Z\xe9\xcce\xdf\u077b\xb0\xaaj\xe1^z<\xfeey/\xfbd\x14\x9f\xc5C\xfc+\xf2<\x83k\x18\xaa\xcc\xddXG\xed\xa0\x1b\x91md\x80\xd9\xc8\xfcP\xc8\x130\xaf\xb7\xeaq9\xe8\xdf\xf7\xc4\xf4\xb1\xa1\xd8\xe3t\xea\xc1\xa9\xd8\x171!\x96Q\xeb[\x83\xef\u06e6)\xfb\x94X\x991Z[\x95\xe5\x1f\xeb\xf5EV\u04c7\xce?A\xd1G\xdc0\xfa&7\v\xe1L\"7\t\x81\x015\xe6\\\xb4t)\xcfR\x84\b}\\z\x8b\x974\x8cOC\x90a(\\\x9c\x86P\x0fX\xe1-Z\xdf\x18\x9fQ\xeb\x8b\xcc\xd8:\xb5\xa7\xae\xbaha\u5906\xdb\xe67.\x9e\xe4\x97>\fE]\u0290\u02d7(4\xe3\xe15\xb5\x19WrVj\xc2\xcc*\x17\u01e5\xab\v\\{|\xf1p\xcb\xe2\x06\xa9\x19\xea\x89\xc5]`\n\x15\xda\xc2I_!\xc2\x14/\xf4r\v8\x0e\tH\x8b\xe6g\xe2\xe4\x13\xe1S\xc0\x987q\xc0q\xaaO\xb4\x9fj\xd4jE\x941\xe8T\x82R\xafU\xa9\x88Z\xa3\xe1\xf8\u03d4\n\x05\x86\xcf\x04\xf2\x05JS?\x88\x1bs\x1b\xf6\x04\xba\xfa\"\xcb\u078c\x9c\x91'\xf6\xb0\x03\xea!`'f\x11\x82\xb9]\x17T\x9d3G H\xa7xQiz\x11Q\x0f@C\b\xb3iM\xbb\x94D\x89\x94\xc8\xe9HC\xfa\x85p\x9b\xbd\n\xaa^p\xf2J\"\x1e\xd39\x8e\xa9\x06\x95CJ\x8cT\x06\xd5:\xd5.\x15\xa7\u0529T:%\xf1\xd9k\xa1\xf6\xd5r\xb3\xa3\x11\x1a_\xf5]\xf4&{*:\xeaN\xa7in\xfa\x8eG17c1\x98M9\x16Dv\xc7/#\xe5$n\x83\xd1\x05\xdf\x11\xf8W>\xc5]\xd71\xe93\xe9\xc9\xe8\a\xa08rP\x1a\xf4NJ\xe9\xbdQ\x9f{\xa4\xff\xff\u07e3\xf6\xf6\xaeqK\xeb\xa0Kz\x8c\xdc\xf6C\xe9\xcb\u0524@\xb9K-\x9d\xfa\xffv(\xb8p^\xb0p\x82\xf0.\"\xc8x\x04\xf1\x00\xcf\xe0\xdcMX\f/\xe7\xa6\x11q\xc27_q\x1a\xc1r\x8ca2\xe2$\x06\xaa\x03\xd6{tgt\x96C\xc8sHU\xec|L\x1fx\x8cg+\xe7\xff\xe3\f\xb5\x1f\xba\xfdnL\xbd\x9c\xf5\x05\u057d;[[\a\xb3\xd5\xd5\xd9\xc1\xd6\u059d\xbd\xd5\xcf:JR>_\x8a\xc6\xf7\xdc\xde\xc1\xado\xd9\u065bL\xf6\xeeli\u0759\xad\xaa\xca\xeel\xf5\u05b0Ok\xbc\xbeT\xc4\u9324\xd8\xfa]\x848\x03\xf79R#=[q$r\xa0\x13\xb5\x98\xdd(\a\x13\xa4}T\xc3\xee\x95\xc3\tlT\xfd89N.\x10\x9edhj&\x88\xf92\xeb\x9f1\xb7f\a\xb2\xf13d\xf7\xad\xbb\u8c11\xfd%w\u0491n&G\xf1\x03\xa3w\u04f9UzM^\xe8\v(\x8a\xdb\xf0o\xa8L\xa8\x8f\x15\x15\u0369\xda>\xf1\x81\u0553VwD\x9c\u0573&,\x87~\xdcv\xf0d\u0664\xea\xa8+TT\x1c\xbd3\xd5\xeaOg\xeb\xcbgt\u036b\xee\x93i\xae\xc3)|\x84?\x86*\xd0m\xbfD\xaa\v\x1f\xff\x8c\x92\x1c;\xca\xf6T:\f\x1d2\xe0B\x90\u06ed\x0f\x9cF\xc8vZ\x99\xd0'\xbc\x89h\xa2/q*\xf1E\xe2BB,\u0667\xdfO\x13i\x95\xa1\xc90\xdb@B\x06(f\f\x93\xa5\xf9[\xf3\xf7\xe4\x93\xfc\x0f\x8f\xbba\x99\xfbJ\xf7\x0f(\xa7nsq\u80f2?\x99?0hN}\xeb^*\xd9\x14-\xa9\xc8c\xc5\xdc\rU\xe8YS\x0e\xab0\u007f\xb2\xcax\xe4b\u0468\xfa\xb2\xbb\xa9\x8c\x8b\x03\xdf=c^\xa2\xad\xc2q\xf8W\xed\xd7N\x9ct\ud536&C(\x13[\xb7\xa02S\xa8\x89'\xa2\xb3R\x8b\x1b\xeeX\u06b0\xa2\xa3\x94;\xdd4\xe0\u05aaJ\x92\x93\n\xb7\xdd\x10\b\xfc\xa6\x88^\xd4\x1ar\x9b\xf6\x9b\xbcak(\x1e*\xba1\xda\xe0\x9f\xd0}\xe9\\9=*\xca8\x049\xb3\x88\x02\xfa'S\xe5\xa8\x191]U\xb1\xdb\x1eYu\xbc\b\xed\xd6X\xb4\xc4\x00\xdd\xea\x92\xea\x86t\xad\x9d;\xe1r\xb7\u03d8Q`5U\xd4\xd4\xd5\xc4\xcd\b\xe4\x1e\xe0\n\xae\x17\xb9Q*S0I\x0f\xac\xb3}qZ\x83\xd3\u075c?\u02e3\xcc\u05fb\\:\u0598\xd4X\xd9\x14r\xd6\xf1\x05\xb6\x00+\xcb6,\xfd\x8cw\a\xd8|&`\xa2\x1a_\xdb\xf2\xe6\xd4\x19t\u0767\x05*\xceD4\x81\xe5S\xab{\xf21\xc1\x84\xb5\xa6\xe1\xcd\xf1F\xc1\xed\xb3g\x97\x97\x96D\x82\xb3\n\xa5\u7136\xdc\xf8z\xbd4\xcc\r\xc9\xf3\v\xaa\x9e\xe4Fx\xf9\x16,Js+\xcfka\x04Y\x91\x16\xb4\n\x05\"?2!\x9eJ .\xd7f\xa8\x12s+\xc5#g\xe4\xdb\u0170\xa7p\x11^\xf8\xb9\xa1\x1f\x1fx\xa0~v\xdf=\xab'L\xdcz`\x00/\x90\x86\x85\xe9_\x1f&\tSb\xcbs?\xbc\xf5\xa5+\xe3\xf2\xfd\x9dp1\xbcEv\xe4\xee\xef4~O\xa7K\xef\xf44z\u007f'\xb6\n\x9e\xc1\xb6\u007fu\xbf\x05\xfc\xd6w\v\bp\xe1\xa4d\x01V\x91v\xa1\xa9\x99\x18a\xf58\xbb\xd5bQ(\x8c\xbb\xd3h\x10\r\xa1\xe3\xe8\x14e-\xed\x1et\x0f\xb9\x8f\xbb9\xbbUo\xf1Z\xb0\xc5\xc2[u7\xf2t\x98\x18e\xd6kJ\x01%\x82\xa2l\x06\xbeY\u51bf\x145\xb3\xbek8\x99\x10=\x04\x1e\xf0\xb6n\x9dS\xd6\xea\xd6\a\xc3A\xbd;\u04b6\xa0\xf3y\x97\xb7\xb6,\xff|\xaa\xa7\xc1\xafQ\x1e\xe4D\x81s\x05\x82)\xdd\xdd\xf5\xaa\x82h=\x02\xb4\x80\u0193Vy\xfe}2S\xa87yMQS\x9f\xe9\x94\xe9\v\xd3\x05\x93\x98\xbbu\xd3{\xeb`\x17\xec\x03\x02ZQ\xff_\x88\u018et\xe2u\x88\x8e\u07bc)\xcb40~\xf7\xa6`\x02\xb7~\x0e\x84\x80`\xb6Z\x15\x9d\xab\xa1\xecY\xdc\x06\xbf\xb1\xd47Tj\x14V\x9bE\xac\x1f\u030d\x9bP\x8a\u2aa3\x14W\x99\x91\x17\xcd\xfb%2\u6882\x96\x81\xa9\xaa1hE\xd8&\xef}\xe4\xd7\xfb\x87\xfc\x8f\xfb\x9f\xf5\x9f\xf2\u007f\xe1\x17\xfc\xac\xacjy\u007f\x9a\xaaO5\xa4\"*\xf7\x87\xfa?\xd9?\xe4\x87Goq\x95\u0341&&$\xfa\xb8\xbc\xfe\xc3_\xd2b\xc7G\xcbfmik\xda<;Z6s\xeb\xd4\u018d\xdd1\xa9=\xd90!\x99\x9c\u0410\xe4\x16\xcc\u0653\xad`ko\xe9>\x16\xa3\xfb\x81\u014b\a\x06\x16-\x92i\x9fEqP\xef(\x0e\xcaf*\x19\xecQ~\xaa\xfa\x84\xe7\xccZ\xc0Z\xe0\xb4\x04\u007fJ>\x892\xb7\xb5!@\xdfAB\xe8\x9f!\xa13\x9f\xd9\xe3\xd1>\x06\x9f\xe5\xf3\x151\xb6\xaa\x85$\x81\xcf\xedh\xeb\xe35\x06\x80\xa0J\x12\u018ep@\xaa\xdb\n\v`\xc1V)\x957~(c\x9ar\x84\x84[\xf8#\x860z\x13\x1fC\xc8\x10B\xdb\xff/2\x8a\xe8\xff\x92{G\xfe_mW\x01\xd7V\xb2\xee\xe7\x9b#!B\\\x0e\x04H\x80\x84\x84\x04\x1a $!hh\vI\xbb\x10\xb8\x15\u02b2@ho\x95\x15\xf6\xf7\xbae\xdd]\xbb\xbdR[wo\xf7wo\u07baw{\xdd\xdd\xdd\u0775\x8473\xe7pHi\x9e\xbf\x87D\xe0?sf\xe6\xfb\xce\xe4K\xbe\xef\xff?/\xa2P\xaa\x92\u00d2\xc4a\xb34#a\t]\x88\x00\x01}\x81\x9b\xe19\xde2\x15\x93\u007fb\xa8/\x16S\xfa\u0297\xe8\xeb\"\xee/\xa4/\xa2f\x82\x9d\x12>\xee\x04\xb3\x13\x9c\xe8\x1a\x04\xa4\xb7\xb5gt8\xc5nh\x97l|\x13\xa4\xcf\u714f\xd3>93\xe93@F\xf6\xca\u008b\x16\x11\xed\xf3 \xe4MY1h$\f\xa3\x1a\xd0\xd0.[\x10 \xd2\\\x1d\x15\xb3\xc5\xea\u00a5\xdc\xfd\xfc4\u04daX\x93j4TV\x9d\xa65\x81\xacf\xab\u05da\xb2\x8eZg\xac\xa2\xa2;a\xa2\xba\x13(\xa2\xcaNLE\x8ae'\x14\x85\t\u534bkY\u007f!A?qZ\xe9P\xf8\u0612\xecD6;\xf0\xe0\xa6]\xe1\x9dTv\xe2\x91\u007f\xe9qwlL4\x12\xd9\th<\xf3\xc3F*;1\xb8$;\xd1\xd5\xf8\xed\xca\xe6:;\xf1\xb5\xcdDvb\x94\xcaN\xb4x\xba`l\xe5f\xb2\xb8(\xeb h\xf6Z\x1b\x90\x0f\u0475_\xb3\xf8G\u0600\x1cy\xec\x12\x1a\xc8\u06d0'\xf3U\xf5\xbc\xc6\x0f\xe1\x18\"?%\xf0\xf3\xe8a\x82\xb7\xa5\xf4\xac\xc1\x98\xabf\x19\x8dJ\xe1O\xa0l\x11\x1e\u05c4J\xe2gT\xfcI\x15_I\U0001cef1$~L\xc5\u03e2!\x82w\xa5\xca9L\u01398\f\xae\x98\u070269\xad\x8dNi#\xa2w\x87\u0189g\x90\x0f\u07e3\x1c\xae\xaaj\xe7H\xabZ\x97\u048a\x16\xb8\xc7b\x16kR\u058c\x10\u007fJ\xf65\x13\xb2\xa1;R~\x81\x87A3\bf\x18\xe4@\xe0\xc0\xcc\xd9x\x9b\xce8a\x11/\x04\x00\xb0\x1b\xcaL\xbb\x1c\x0e\xfa\xe2\xb3\xcad\u03d8\x1c\xc0\xdb\x05\x9c\xb3X\xcas\xc7up\x8b\x0e\x86t\u0425\x83\n\x1d\x94\xd1\nK\x93\xb5,\xa7\xe1L9Y(\x82p\x06\xdaT\n;)r\xfb>\xd0}1L\xd9\xf4\xec\xf3M\xf2\xa9O\u0522\xa4\xef\xe4\x1aA\xaa\x19\xa1r\uc07c\xa0\x8a?=\xf5b!z\xb0p\x12\xef\xe7\xc7\x17~Ey\xee\xd8\xfe\xcfs`r+S\x8cPx\xf70\x83\xb3lM..\u0629F\x02Y\x93\x06\xb6\x8e\x97\xc1)\x84\x90\xfe\x05p6\xf9$/[r\x86c|bf\u03e0\xe2//2\u007f\x01\x83\xd0\x00\xd4_,\x12 \xc5B\xa5\xf0\xf3hR\xb6'k0l\xb0)\xe8\xe2\xfe\xf5E\xf8\x13\xc8S\x847\xdb<%\xf0X3\xa6\xe2gQ\x85l\u007f\fn\xe20\xa07\x84\x00\xad\xb0\u007f\x88\xf2\xd4\xd91\x9a\xe49\x14\xbeS<\x87\xfbW\u0381\xf2\xda\u007f_\x84\x9f_|\xa8hL3+\xe7\xb0\xf8;\x84\xb8\xa6\"\xfc\x89\xc5T\x11\x1e\x9d1\x878\xe9\xffG\x9a1\x15?\xbb\xd8K\xf0\x15/\xc8S #Z\u032f\x98\x05F\x11E\x1f\u008c\x14Am)wM\xd0\xedW9\xd2\xees\xcaw\xb6T\a\xc2^+\x1f\xa6Z&o\xf7\xbdmae]\u07e7\xdeF\x1e\xaa\\s\x96\x86\xa0$h5M\xe1$Dh\x17\xb0*K\xa1=\x00,'\xaf\xb0\xce?|M\xe6\xc9\r[\xa7(\a\xfa\x9c{\xfa\a\x1f\x1f\x9d\x9e:\xe5\x8d\xc0\xc7\a\xb62\x02\xf4\x83\xe1B\xb2n\xb4\x85\x92\xa2\x15\x06z\u03fe\u96f6C\xf0U\u0184\xae\xf5\xcc\xcd\\\xfb\xde\u00b7_\xca\xef\u017f\b\x13\x1a\xf4\xdeg.Zp\xdb\xec\x84\x18-\u06cdq[\x99_t(~\xd7#\xfb\xa9\xc4\xfc\xf4X\xbe\u06a7W-]\x02?\x8f~#\xfb\x05k\x90\x93<*\xbat\xff'\u041d\xc5\xfd\x17\xf2\x9ep\x89\xfe\xc7T\xfc,:\xb0\xb4\xff\x05\xe8\xe6\xc1Iq\xfd\xca\xfd\x8fq\xff\xd81\xba\x951M(c\u0492\x83l\u041a5X\x1dS1\xff\u078c*P&\xd5$\x9a\xc01\xf1\x00\x02\xb4\xcb\xedq\xf7\xb9s\xee\xfd\x84$!X\xf4\x9a\x89\xb2\xed\x95\x153z\u02cc\xa8'\xdf\x1a-\xa7!f\x95\x93(\xe6\uf6ffOM\xcbt\x1ch\xa2}\nT\x06\xbe\x83\x06=*\xc1\x9b??\xba\xef\xcd;o\xa7\xb2\x16\x0f]\x91\u07d7\\\xb8v\u04e5\x97\xcc\xee\xdd\xcd\xe1\xe9go\x18)\x10}\x91\x1f\xaf\xbe\xf4\x99B~\xcfe\xe7\xedB@yLBX\xf4\x10;\xcc\xfdk7\x8d\xed\xad/\xc9a\xbf\x91\x86\xfd\t\xf2`\xb0\x15Z\xd3\xe8\x88\x062\x1a\xd0\f\x86P(9\xe0\x05o\u06b2e\xe0\x9a\x01\x90:\x06\x93\x9b\xd6j\xbc\xf6\xf6\xe1>H:~V\r\xd5#\x92\x9d\x16\x1a\x12vC\x9fRg\xf8\xfbw\xa8GR\x1e\x83\x99\xe4\x10\xc9ok\x8b\xfc>\x80_N;\x14\xbdsR\xeb\x0ey\xf9M\x01+U\x96C;\xfe\xd1p\xdfY}\xe1\x8a\u0606d\xebP\xcc\xfd\x8b\x1fn;\xd0-\r\f\x8d\u058d\x8e\x1b\x1b\xd7w\xf7m\x8e9\x1b{\xd7\xf56n\xdfz\u07b9\x85\u03ee\xbf\xf5\xad}{_\xbb1\xc3\u007f=\xb5u\xa8\x93\xe4\xc8\xedu\xc1h\x83\xa7\u007fx\xb2\xfb\xd9c\xd5u\u007f0{$SO\xaf;\x14j\xad\xf3\xa5\xfa\x06\x82\xb1lo{\xac7\u0617\u077a\xfb\x9f\x87\xf9\xbd\xe7?4\xdb\x1e\xdex\x99ls\xc6m\x13k\x89\xcd\u05f2\x98g\xcd#\x88\xeef\x11\v\xdd\xcd>\x9ao\xef2\xd4(6/\x8d\x9f?\x1fQ\x0fa\r\x0eD\xe2*z\x19\xebU\xb1'\u0422\x8a\xf5\xc5W\x97\xc0\x1aU\xec\xc9E\xb9\xdf6\x8a\x8d\xf6\x97\xc0\xf2*vVDrd\xd7ki\xe0p82,\xa3)\xbc\b\xff!\x15\xff.R\xf0\xed\x14O\xea\x0e\x8a\xf1\x88\xa3x\xf1Y~\x1fj'\xde3\x84>\x90\x9a\xd6\x19A\xa7\a\xbe\x06t\x18\xb8\x9at`\xd0\x12\x8b\x95\x872\xa0\xcd@&\x13\xf1o\u024ed\u7cb8+]Q>6\x1cK\x06\xd6\x05p0\x00\x81Q\xcb\xd7\xd3?O\u33e5\xe1\x8a4\xa4\xd3M\xc1\xb5\xb0v\xc4k\x96\x82\x0epd\xab\u033d\xd92gS6\x82\x9c,\xae#\xdfSQ\xf2+GwQ*m\xa2H\a\u041b)\x9a\xb4\xffy\x1b\xdd\xfb\x10\xcb\xd0\n\x94&S\x9a%\u82ab\xb4(\x85\xa8VL\x1aT\x18T\xfc\x9f\xae\xff\xca@x\u04f6\xcb7\xac\xbd|*^L\x1e\xfc\xca\xf9W\xbd6\xf7\xe1+\x96(S\xd3\xc7\xc7)aj\xe1\xbe\"B!\x146\xc8,\xabH\u01becO|8*\xadd\x17^\u007f\xad\u02a7\n736\x15\xae,\xe6\x1a\xc2\xefd\xfe\x15\xf3)ZoM\xb9z\xc4>\x83J\x8c\xb9\x1b!dN\xe9`4\b\x8e\xa0W('\u664a1,\xe3\x9c1\xff\xcb\xc8\xfe\xfa:\xf3\xd7\x10\xf3\xd7\x17\xf2\x91\xb8QR\xfd\xb5\x14~~/\xf3+\xd6\xe0\xbcP\xab\x8a.\x85=a]\xc6\xea[{J`y\x15;kU|*I}\xca\x10\xca0\xb4\ua0cb_B\b\xbe\xc6\xfa~G\x89-oAt\xe4\xc0[\xe4\xd8Rk>-\xb6<\x80\x10\xfe`\x11~~q\x00\xb1\u0470\x06\x13\xbc~Ely\x98\xe0\xbfT\x84?Q\xf8Yq\xff\x85\xbc\xdeU\xdc\xff\xe2\xf7\b\xfe.\x91W\xf1\xb3\fOcK\x9bE\x89-\xf9\xba\x15\xb1\xe5z2\xe7\x8cX\x8f\x02(\x81\xe6S\xef\xd1\xfb@\x16\xaf\u0579!\x98\xfe\xac\tL[\x92\x9fLB$\x99K^\x9d| \u0277\xa4\u07ed\x80\x8a\xb1\x8e\xcfv@mY34g\xaf\xae\xd9_\xf3@\rWS\xc3kb\x10\xcb\u069de9\x1e\xce\xe2!\u0083\x9b\a\x1eP\x1f\x8b0Y\xba\x8f\x12c\u06e8.\x13\xb9g\xb7\noa\x15\x04\x125\xe0J\xb8V\xa8\u04b2\x00\x80\xfcS\x13\x00\xb9\xe6^\xe1\t\xc0\xc7\ubca1\x99u\xd7$\u007f\xb0\xfdX\u6f34/s\xd3\x1b\xf3\x94\xc8\u043f\uf46d3\xb7x\x1dU;V\xfft\a\x14\\\xadgE\u03dbr\x91\xcdwv\x92\xd0\xe7Z\\O\xd7\r4\xdc~tv\xe0\xde\x17>w\xe9]\xdf:<\xb2\x96\xf8\xf3e\xaf]\xbb\x86\x04(\xe3\xf7t\xdc}\xef\xc2\xee\xc8\xd8\xea\xc0\x9dw\xf5\xed^\xdf\xf8\b\xb1\x17\u3230\xfd\xeb=\xf2\xfe\x15e\xab_\xc3V\u007f!\xefi6\xa03\xfcr;\xb3\xd7\x06\u064f\xdfe~\xece~\xfc\\\xde\xdf\xe44\xfc\x87\xf8\xf9\x9d\xcc\x1bX\x83\x11o@E\x97\u009e\xb0\xab}\u04f1\x04\xa2%\xfb6\xaa\xf8\x93V\x86\xafg\xf8Sy_[I<\xaf\xe2\xa9\xef\xd3\b5B]\x9f\xb6\xf0\xf6\xb2\x16jl\x8184\x8e\xbe\u035b\xf9\x8f\xb2\xba\xac0\x9aI%\x8c\x0f\xd6A\x1d\xff\xae\xf4%\tK\x12\xf4\xe0a|%\xbe\x13\xf3z\x1c\xc6\x187\xeb\x01 \xf0\xdc\xf7\xaa\xc1T\xddW\x9d\xab>^\xcdWk\x9f\xbb\xdb\x066\xf2\xbe\xf9\x05\x92\u07b4\xa1\xe7\x00E~N+\xcdde^\xaaPE\u0746V<)\xfa\xa5\xc2\u007f\xa2bK\xb4M\x17\x0e;\x1b\xa2UUm4\x03\xdeVU\x15mp\xae|\x8e\xb7\u007f\xf3\x9b\xbf%4/\xb3\xb9\xbe3\x14$t\x00\x8b\xbf\x13\xff\x80~\bc\xf6\x91?$\xe9\x1f\x92\x88#k\x92\xe7\xb7\xf3\a\x90\x1b\u0563&R\u02fa\xf1\xa7\x01\xf8J\x00.\x0e\x1c\n\xe0\xfa@4\x80\xed\x01\xf8[\x03\xfc\xdc\x03/y\xa0\xc9\xd3\xed\xc1\x95\x1e\u0419A\xc0\xe0w\xc2w\xb5\x10\xf0T\x95\xf9$_\x87/\xe3\xe3}i\xb4eUn\x15h\xaa\\U\x89\xaat\x15_\x956\x8e5\xd7\u0430\xdcO\xf2\x18\r^rS\xd3\x10*\xab\x95j;j3\xb5|\xed\xb0\u036c\t\xb9B\x89P:\u0107\x86\x05\xe7r\xd6<\x1c\x96)\\\xf4\u01a2\xbe~\xa8_\u02c24\x9a\x80Z<\xa1T\xfc(\xa1\xb4\xb8\x14I\xc7\xf9\xed\x94\x0e\x94\xdc\u0752|x\xed\xc0\b\xa5\x04\xf5\ue376>\xd8\xdb7\xb8\xd0i\x00w0\xb9g\n\xf6\x8b\x85?Y\xfc\x8e=\u04f8\x952\x84\xec\xd6\u9279\xf5\xdf\xdcOYB\x95\xae\x91\x99m\x99\xcf\xdf8\xd6\x0f\x9f\xa8x\xec\x89Tk![\xa6y\x9a\xf8\xd3Q\xd5_\xc7\xe5s\xe1\x1dv\xee\xb8\u0679s \xef\r\x18*\x8a\xfd\xaf\x18\xaf\u0129\xd7*{#m2\xea\xae\xfb\x8f\xf0\xf4|h,\xea\xffo\xf9\xbaU%\U0007c29f\x8d\xc8;chigt'Y\x8b\xe2\u0619\xd51\xb3cL\xca\xe7g\x8f<\"\x0f9\xc8{=\r\xa8\\9\x82\u0293\x12\xed\u0207b\x8c'e\x00\xa1\f\xa2i\u0756D\xd8\xe3&\x19\x92x5r\xbb\xed-\xc3&'\xf2\x0f\vf\xa5&\xa6\xafO\x0e\x94\xc9\r+x(VI/\xa6L)\\P\xd7\xe9d)\xf8\xbc=\x919;A\x99\xe0\x1d;\xef\u0692\x98H\xc7Id\xc0s\xfc\x12C\xf4\x13\u0144)\xee\u04d4V\xbf\u0111r\x90s\xc1[S\xd9n.t\x95\xa1\u00a5\xd2\xea\x9az\u007fv%mJ]\x03^]\x83\xd9o \xf9\x1d\xc7*\xbap\xe0\xe9A\xe5\uaaa9\xfcC~\xba4\xff\xd0\x04\xa5\xf9\x87\x04O\xdb>O\xf2X\xbf\x12k\x91\x9d2\xe0\x10\xb2\xff\x8e&2D\xcd?9h\xe4\x803\x95\xe7\xca\xe7\x88@tyQB\xab\x8d\xe6\xe3\x14\xfd\x87(\xd5\u007f\xa0\x05\x0e\x1aZf\x9b`2\x10\\m\xf4\x82\xf6\xf8\xee\xe8'+\xfb\xfa\xbb\x9d\xb0\xdd\xd1\xdd\xdf_\xc1\u007f\xbdn\xac\xa3c\xacN\xces-kB\x90\x11~\x95[/~\x88\xe5\x14\x0e\xbd\x8c\xac\xacV\u00da1H\u498c\u07b0Z\x8d\n\xf2\xc0^F\xaag\xed7\x98\b0\x87\xdedI\x18\x11UR\xc6F+\xf9G\xe5\r#\xba9\x1dF:\xd0=\xe9\x82#.p\x95\x19I\xdef\xbf\xc9\xe41\xe5Ls&\u0794\xb2\xb92\xa6'\xaa\xe1`5T\xd3Vz\xf2\xff\xea\xfd&!'`\x81\u030bTEM})\xcc\xee 2E\xee\xbfD~[[Je$4\xed\r\xaa\x80\x01\xb7>00\x19OL\xf6\xfb|\xfd\x93\x89\xd8\xe4@\xf0\xfex(\x14oi\t\u0145\x8fv\x9c\xdd[[\xdbsv\"1\xdeC\xee\xb7t4G\xa3\xcd\xcd\xed\xedt\xddO\x92y\u007f]4\"7\u02a4Z,w[a\xce\nV\x0e\xf1\x17\xf2\x98\xb7f\b\xe0.\x13\xa9\u0298\xd3^\xad\xfd\xae\xf6\xb7ZQ\xabM\x1b\xc1x\x17or\xe5\\\u0605h]\x1a\xad\xbe$723\x9cZ\x82\x86\xa4\xf5\xb27\u04c05*\u01f5\xf0\xb4\xc7o\xf8\xa0\x18\xec\x1f\x8f5f\x87\xcf\xf2y|\xe5\x1f\x14\x1bWoi\x0f\x8e\x0e\x9d%\xac\x8e\xc5G/\x1a\xf2{\x03\xb5\xed\U000512c6\xfd\xb5\x81Z\xe5\xfa;\x90\xe7\x8e\xe1\xa3,\xe7\x8f\x05\x84^\x01%\xe7\xaf\\ve\x037\t\xf9\x9f\xfcd\t\xab\xf9\x0f\xb1\x9ae\xac\x8b{\x1b\x1ef\xfa\x8e\x03\xa96\x93\xd1c\x8c\x18\xb9F1)\xae\x13_\x16yQs\xe8QC\u0780\xe7\r7\x19\x0e\x1a8V\xb2\xe97\x80hp\x1a\xb0\x01\f\xf7\x8a\x1c\xa2B\xe4J\xe9\xb0\u0317\x0e\xf4rt\xaa\x1a\xbf\xd1\x18X\xd5^\xf1M&9\u03bd\xed\\\x92\x18\xbf\"\xb6\xe2\xb8kR\xad\xcaq\x99P\xba\xa2\x91\xce\xf4\xd2U\xa1tE\x0f\xfd\x05:$\"\x83\xae\x1c\x96\x1eR\xb9~\u0792\xf29\xbc_V:\xff\xa6\x91\x1eVx\xc1\x99\xb8\xf4\xca\xcb:\xbao\xb8\x81\x1d\xf6?\xbd\x9e\x8ez)\x1dvY\x9d\xff\xbf\xeb\xe9`:\u007fn\x1f\x9b\u007f\x05\xba$5ar{\u0738\u045a\xb4\xae\xb3\xbel\u5b76C\x8fJy\tG\xa55\x12\x9e\x97n\x92\x0eJ\x1c%\xe7\xfa%N*\x97E\x9a_\x16xA<\xf4\xa8>\xaf\xc7\xf3\xfa\x9b\xf4\a\xf5\\T\xbfF\x8f\x05\xbdC\xef'C~\x10\x01\x92\xf4\xf7Z\x05\x8ee\xc9\xe8\x18\x15\x1bE\xa2\xcb\xc6\x02\xc5V\xb5\xfe\xa5\a\xf0scP\xb5Z\xe1g\x05\x8f1P\xf4\x94\xfb\xea\xb2\x15O3h\xe9\xf9<#\xbd*\xc9\u017e\x97J\xb7JG$N'UJ!:\x87C\r\u05b8u\xd0\xfa\x02\x99\xea\x836\xb0\xfd\xa7+\xff\x02\x9d\xadU\xb8W\xd2+\xf3Q\x8d\x1f\x99*v\x83\xa5\xb5\x17T#<\\\xe4\x0e \xc1\x0fN\xb3\x89\xf0\xe0\xb2{\x14y\x8a\xa2\xe1\xcf\xdd\xcf\xfc\xa4\x02=\x91\xba\xfeA\xf7\xf3\xee\xb7\xdc\xdfs\xff\xce-P\x02\xe3\xd5n\xce\xebna3T'\xc7&Zj\x86#\xb69\xdb\u0576\xfd6\xde\xfc_\x9d*!\xb5\x8e\x889qN\xe4\u0624U_\x93-\xa9\xceX}\xb8\xd2\xf5\x84\xd2>\u0226_\xda%]\xcb\x0f\x15.+\x1c\xc3\x0f\xf2\x8d\u0206\u04a9\xe6\x19\u01c5\x8e\xbbIV\x9f79<\x8e\b)J\xce9\x84kt\xa0\x93\u017e8\x0f\xc1\xb7\bo\t\xf4\x02c<-?\u021bH\xf5\x81\tE>\x1df{\xf7\xa7\xa7J))lk\x1a\xde\xd3\u04f5'\xdb\u071c\xdd\xd3\u0573g\xb8\t\xffj\uc4a1\xfa\xfa\xa1K\xc66_2\xec\xf3\r_\"\xd7\xd7O\xe3m,O\x1cN9i\xb5\x9c\xc0\xf3@U\xb9\xcaH*\xb8(\x0fLV\x86\xaa\x10\xb7\x9dV\xfd\xb6\xa1T\xb1\x1bBg\xf4K\xfb\xa4\xe9f\xa7\b\xa2\u04afxZ\xbf+r\xc9x[\xa9\xd41\xed\xb7p1B\xf8\x00\u04f5\xf2\xbcx\xfaE\xa8\xb8\x15\x17\xa1\xa2\x97\xeb\xc3\a\u0605\xf7\x145+\xeaw\x06\xbc\x1e\xffEx\r\u9403\xb0V\xbac\x8e\x01\a6\xb9<\xae\x88+\xe7\xfa\xae\ubdeeE\x97F\x8b\xe2x\x10c\xfc=\xbd\xa6\x8d[\xcda\x8es\xba\x1cB\x8aPW\x04\x10~\xac\x15\x1d\x0e\u03a4\xf9\x16\xf7m\xe5\xf2@2\x8b6\xdc\xc6t\xf1\xc9\x13\xb2H\xac\x16\xb2\xdeA\u0530b\x10e\xd7\b\x8a\xb3\xda\x03\xfc\x97+\u007fS\xb8\x16\xae\xfd\u0555\x85\x0fr\x9c`s:\xb5W\xe3\xef\x1f:t\x14\xf7/|\xfa\xd1\xd0Tky\xb89d|\x13\xfd\x1b=\xe5s@\x00\x00x\x01c`d`\x00\xe1p\xb3\xa6\xeb\xf1\xfc6_\x19\xe49\x18@\xe0\x84\xb8\xff/0\x1d\xd3\x16\xf9\xaf\xfc\x9f\b\xfb:\xf6b\xa0:\x0e\x06&\x90(\x00:\xfe\v\x9b\x00x\x01c`d``/\xfe'\xc2\xc0\xc0\xc1\xf0\xaf\xfc_%\xfb:\xa0\b*\xb8\f\x00\x80\x88\x06\v\x00x\x01m\x92C\xb4\x1eA\x14\x84\xeb\xef\xbe\xfd\xcf\u0136m\u06f6m\xdb\xf66\xb6m\u06d8\x93u\x8cUl\xdb\xd9\u0119\u050d\x93\xf7\xe6\x9c\xefT\u3daa\xc6\u01cfO\xd5$'u1\xc2\x1e\xc7\x04\x97\x0f\x05\xa47\xbaz\xf1Q\xc9\x1dGS\x93\x05\x13\xccA4%\x15\xa4=*q\xae\xb5i\x8aJf\x1e*\x98\xda\\\xd3\x10\t9V\x89\xb4'\rI\x19\"\xa4%\xa9OJ\x91\u06a4\x92\xd6\xebZ\xdd\xe3\x17v;\xd2D_\xa2\xa7+\x06\xb8l\b\\\x1a\x8crK\x11\xc88\u049d\xfd\xd3\xec\x9fE`3\xa0\xaa\xd9\x18\x96qI9^\x1b\x81\xd7\x10A\xb4:\x89\x8fQr\U00087eb8\x9c+\x82\x8e\\\x97\xc7\x1d\xc6N\xb9\x03x}\x01'\x80l'\x8dQ\xc4l\xc4,\xde9>\xb5\x98T\x85o\ub19fee\xa4\xbe,\xe6}o`\xb5\xfd\x8a\x9er\x83lDO\x9b\x06y\xa4/\x92s\xfdj3\x04\xf3\u0310p\xa7\x04\xda\xc6jo\nV\ube1c\xd6z*\xd7\xd81\\\u007f\x05]mc\x14\xe2\xdcR\x9e\x87\xe80@\xba\"\xae\xb6\xedf\x942O\x90IzG\x8e\xffP\xb4\xfe\xe5=\u06f3HS\u049e\xf8Zc\uf86f\xac\xc4\xfb\xe8ft7\x8fPHv\xa2\xa9\xaeQ\xefuL\x10~\xb4\x03\xb4\x9e>\xfa(D\xca\xe9[\xe8\xc3jW\x01C\xd4\xef\xc8\xfa\xf0\x1a\xc7\u06db\xb7(\xc3\xf5\u0359kA\x85\xb4\xa5\xf7U\xd5\xf7\xd8\xf0:\x03\x9a\x85\xe6\xf07\xcc!/\xa9j3\x84\xaf\xa9%\x99U\xa1_9\xfc\x0f\xef5@U\xb3\xf8\x1b\xcdB3s\u00f0Z}\x8f\r/!Zj\x16\xb2\xf1_\x98\xc1y\xfa?\x87\xba\x98\u0726?u\u007f\xe5\x10\x03\xfa\xa2\xaaY\xfc\x8df\xa1\x99\xa9j\x96\xdcc7}kN=*@S\x9fD\x02\xa4R\xf4\u007f\xb5\u04d0J\x91\x1cl\x1bt5\xfb\xd1T\x89\xc4\xfd:\x8a\xde\xc6\xff\x06\x00\x9b\xb5\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x86\x01$\x01\xf2\x02\xa2\x03^\x03\x86\x03\xb6\x03\xe4\x04\x1a\x04B\x04\x86\x04\xa0\x04\xd4\x04\xf8\x05>\x05p\x05\xbc\x06:\x06\x82\x06\xf2\al\a\x96\bR\b\xca\t\x1c\t\x84\t\xca\t\xf8\n>\n\xae\vf\v\xda\f\\\f\xb6\f\xf4\r0\rr\r\xd2\x0e\x10\x0eF\x0e\x82\x0e\xda\x0e\xfe\x0fz\x0f\xe8\x10<\x10\x82\x10\xf8\x11l\x11\xe2\x12\x14\x12T\x12\xa2\x13\x88\x13\xe6\x148\x14\x8a\x14\xae\x14\xd2\x14\xf4\x15(\x15@\x15p\x15\xe6\x16J\x16\x98\x16\xfc\x17n\x17\xbc\x18\x9a\x18\xe4\x19$\x19\x82\x19\xdc\x19\xfa\x1ap\x1a\xb8\x1b\x04\x1bh\x1b\xcc\x1c\x18\x1c\x98\x1c\xf0\x1d8\x1d\xa2\x1e\x80\x1f\x1e\x1f\xa6\x1f\xfc ` z \xe0!F!F!\xa4\"\x12\"\x98#6#\xb4#\xda$\xb4$\xfe%\xa4&*&|&\x98&\xa0'L'b'\xaa'\xec(F(\xd6)\x06)T)\x90)\xc4*\x14*P*\xae+\x02+(+R+t+\xea,\x02,\x1a,2,J,d,\x80,\xee-\x02-\x1a-2-J-d-|-\x94-\xac-\xc6...F.^.v.\x8e.\xa6.\xc0/\x18/\x82/\x9a/\xb2/\xca/\xe4/\xfc0J0\xde0\xf61\f1\"181P1h2 262N2d2z2\x922\xaa2\xc22\xda2\xf43\x823\x9a3\xb23\xc83\xe03\xf84\x124\x825 585P5h5\x825\x986\x046\x1c6:6z6\xf67F7\\7r7\xae7\xea8.8\x968\xfe9~9\xc29\xee:\x1a:::\x8e\x00\x01\x00\x00\x00\xd3\x00g\x00\x05\x00U\x00\x04\x00\x02\x00\x10\x00/\x00Z\x00\x00\x01\xcd\x01&\x00\x03\x00\x01x\x01}\xcf\x03nd\x01\x18\x00\xe0o\xed\x8d&\\\xbd\x18cD\x1b-k\xbb\x8d\xc66\xef\u0483\xf4z\xe5\xcb\v\x8a\xdf\x06\xde8\xf3\u00b3\x97\xef<\x13#\xb4\x9f{+\x16\xda/\x14|\r\ud5fe\xdb\t\xedW\x12\xfa\xa1\xfd\xdaW\xe7\xa1\xfd\u0641\v\xff\x8c\r\xb4T\x05\xf6\x95\xf4M\xfc1\xd0U\xf5\xdbDEM_U\xcdX )x\xb0#\x88z\x9e\xce\x1e\xa9\x19\x9bh\x19\xe8\vd\xa5dd\x04\xcafZ\xba\xaa\xb7\u046c\x9chR4'\x19\xcdi\x9a\x9a\x1a\xfa)-mq\x8b)%C%\x15M5)\x03c\ri]\xad\xf0\x8b\x89\x9a\x89\xb4\r\xab\xfe\xfao\u02fe\xff\x92rR2W\xe4\xf41\xa3x\x01l\xc1\x83\x01\x03A\x00\x00\xb0\xf4k\u06f6\x8d\x91n\xe1\x0e\xd4.\xf0\x89\b\xf8\x05A\x9c/\x12\"I)i\x19Y9y\x05E%e\x15U5u\rM-m\x1d]=}\x03C#c\x13S3s\vK+k\x1b[;{\aG'g\x17W7w\x0fO/o\x9f\u007fA\xf0\xb0\x05\x05\x00\x00\x00p2?fo\u0676\xed\xb5\xbd\x9b\xf5\xb2]\x97l\u06f6\xf92\xcf\xf9\xe5s3\x9ah\xaa\x99\xe6Zh\xa9\x95\xd6\xdah\xab\x9d\xf6:\u8a13\u03ba\u8a9b\xeez\u8a57\xde\xfa\u8adf\xfe\x06\x18h\x90\xc1\x86\x18j\x98\xe1F\x18i\x94\xd1\xc6\x18k\x9c\xfd\xb6\x99m\x8e\v\xd6\xfah\xae\xa5\x16\xd9`\x8f\xed5jZX\xa3\x96YV\xf9\xe5\xb7%\u0599\xef\x9a\x0f~\xdah\xaf\xbf\xfe\xf8g\xab\x03\xee\xb8\u5820\x90\xe5\xc2\ue278\xed\xaeG\xee{\xe0\xa1O\xa2\x9ez\xec\x89Cb~X\xe1\x85g\x9e\x8b\xfb\xe2\x9b\x05\x92\x12R2\u04b26\xcb)\xc8+*\xa9(\xab\x1a\xef\xb3\t&\x99h\xb2\xa9\xa68m\x8b\u9999a\xa6\xaf\xbe;\xeb\xa5W\xde{\xed\xa8cN:\xe5\xba\xe3N\xb8a\x9e\x8b.9_\xa3v\xbdJ6\x11\b\xb4\xeb\xd8 W\x8d\x14K\xa1\\1\xd28\x9a\xab\x14K\x95|\xa4\x98\xc8\x15\xff\x03@\xec\xfe\x80k\xde\rx\xd7\xf4\x8eHo\xa1\xcd\x1b\xff\x1b\xfef\xc2\x1b\x9d\xf2\x14&>\x82S\xe2\xe3\u04476'\xd3xM\xe8aa\t\xfb\xfb\xc7K\x1fx\xef\xf1\xfb\u07bb\\\xfaS\xf3g\xf4\x1f2\xea^\xf6\x1e\xf6\u0713\xee\u1ee4\x94\u07beUJo\\\xf7\xd2\xffWJ\xa9t\t\u039e)\xa55'G\x9f\\v\x92\x9c\x12\x97\x8e\x9e\xb4\u0635Z/O\x1c\xcb/f\x972\xa0\x895{\xd3\x05%\xac\u06ce\xd0\x0e\xb1\x83$\xb7\u007f\u060e\xb7m-\xa5\x9767m\u01a9x)\xa5\xb1n\xb1P\x8c\xf4\x8f]\x8cec\xe4\xec\n\x98\xf4\xfb\xf0o\xcc\xe6C\u06d9\x81\x99\xb8\f\u073c\xd4&\xa8Q'\xa8A[\xee\xe2$\xf0L\\615\x91$'\uc780=\xe3\xd5\xf1\xb8\xdd\xc8\xe0H\xdcv\x04\f\x1fj\xa7\xc34l;40\x14\u06fcV\xae\a\xc2u^\xc2M\x04\xba\x91\xdd\x04\x17*\xe5J'\u53623Z\xa3-\xa3\xd5\xd1}Q]\x9a\u00f5\x886\xe5\u00da\x16\x11c\x11\xf3\xc8\x1fe\xcc\xfaC\xb0?\xb0~\x10\xec\a\xc3\xc44\xb1P\x10\x8f\xb0\xb9s':\xd9#\xbf\x88\x85Y)\u035d\xab;\xd3\x14\xa7\xd7\xc1-`\xe2f\xaf\x89c@\x1c\u0088\xa7MY\x13\x96L0\v-Ei\xf4\x01\xe9\xcc\b\x969A\x0f\xa7 \x95\x89\u021d:\xf5>e\x14\x83z\xab\xf9\x03\x86\xa9\xb0Nm#\xe7h\xcd\xc0\xa1\xaaa\x9d\x8a\xf8\xd0a\x833\x00\x89!\xab\xe3qTW\xd9[\xad\x96\a\xab\xa3+\x87\xf4V\xc7kBMNX\xa6\t\xe6\u028c\x13\xd55W(&$\x00\x041\fl]\x9c\x87\x18\xba\xdfD\xd7?;\x13 \x0f\x99kPTkS\xa3:\xd8\xcfX\x1e\x13\xa6\xaa8e\xb4\xe5C\x8f\x11\xa3\xd24a9J\x01b:\x99\xe3\u07dfF\u0597") + +func third_partySwaggerUiFontsDroidSansV6Latin700WoffBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6Latin700Woff, nil +} + +func third_partySwaggerUiFontsDroidSansV6Latin700Woff() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6Latin700WoffBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-700.woff", size: 25992, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6Latin700Woff2 = []byte("wOF2\x00\x01\x00\x00\x00\x00,\xd8\x00\x0e\x00\x00\x00\x00[D\x00\x00,\x81\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x16\x1b\xa5@\x1c\f\x06`\x00\x81\f\x11\f\n\xfb@\xe6n\x016\x02$\x03\x86L\v\x83(\x00\x04 \x05\x82d\a\x83g\x1bXN%\u3615\xb8\x1d @Um\xc2(J\")\xc9\xfe\xff[\x02\x1d2\x84\xa2)\xa0\xf3O$\u0084\x15\u0444i\x86&:\x10\xb3\x16\xf3\xcc3i^\xe7&\x96\xf4\xb2j\b\x93\x8f<\xb4\xb2G\xd9\u053f\xc2$n\xfdK\a}\u2123\xd75\u007fC\x93\xba)m\xcd\xc2\xc1e\x8d6\u0155$\x824\xe9#;\x9d\v]>\x05\xa2\xd5?\xfaQ\xad\x169\xda\xd7\r\xa5\x84'|W\xfa4\x1aY\x06L\x9cp\x19(\xe0\xb6_i\xf7\xca\xc0{[\xf8$\xc2\xd5\x10l\xb3\x9b\x99`$\xa2\"!\x12VQ%\x02\x92\x82\x05\xa8\xa8\x18\xd13z\x9b\x9bK}{.\x8a\xb9\u029f\xeb\xcfm\xef\"\xe2c\xdf\xea\x9c\ry\x19+\xe7\x17F\u0388\xabp\x97X0\xb7\xb9\xdc\x1c9\xbc\xd2\xccC&\xf4d\x1f\xe2B\x81\xe7\u007f\xbf\xe1\xf1\xfb\x1e\x8a\xa0\xc5ni\xc6`0\xb48XX\u02fb\x01phS\xa5U\x1f\x06\x90_!\x9a\x10o\x9a\xb2\x19\xa6`\x19\xbee\x9bu*\u0470\xf6\xef\xb7yT*S\x8f\xed\xd3\xf2RP\xb1'\x93d\x05\xf0\x0f\xfd\xfb\xf7\xa4\xc2&5*?\xdd\x14\xa8t\xb1\xde\x1c\x81K\xe5\x95\x03\xdc\f|\xfe6\xbc[:\xff\x93l\x87\xb4\xab\xc0\a\xec\xe1:\xae:\xdb\x1bx\xc0\xa1\x03\xb6\x1d5\xeb6\x99\xeb>\"\u016f(\xaf\x01\x02\x0e\xea\u03bfNs\x95\f\a\x18\xe0\xe9\x8a8L\xbd\x9b \xf9\v\x80\xb3\x87\xb3\xadf\x8d\xc6lN\x97\x15\xaa\xaa\x13JV\xd8BN\x139\xf2\xed\xc3\xe0\xb0jj:\xedoL}\x1f^M\xc7\xe6R\xbb\x8cAC\x11\rA\x04DD\xe2\x1f\xb39\x06\xc8yd\xa5\x80^\xde\xc2<\xbe\x94\xd9\tf\xcd\x01OE\x11\xb0@\x01B Z\xcd\xfeoY\x99\xa3\x90\x89\"\xac\xc1\xec\x1bT\xc5\xd3LI5\xda^\v\xbcy\xe7C'5\xe3~!\x1f_\xad\xe8\b\xb1K\xf6u\xf9U\x055\xaao\xf5s\xe4\x151\x16\xd2\x1a\x13\x1f/C\xd2\xd75\x18?2+\xb9\x9e\xfc\x9a\x8a\xa9\x8b\x01\x1a\xbc\a\xaf\xfbT\xbc\xe5\xa7\xfeZ\xd2\xfd\xe9\xa5\xf4u\u0595~\fbv\x1a\x92\a\xe4G\v\xf9\xfe\xb4\x98\u0093O\xcb\x10\xb4C\u007f\xf4n\xfbZ\x89N\xdaQ\u007f\xb3W\x83O\xfaFv\u4393\xb7\xad\xd3}x6O5\xef\x8d<\xde\ta\x12\xa6_\a)\x19\x86\x8a\x06c\xe6%\b3\x16J6Y\xb1\xe8\x8f[\xb388lX\x9ap\xecX\x81\x04\x9c\xa0\xc1\xc0\x03\x16\\\xbc\xe1'\xab\xed\x87\xc0\n\x10\x81\x93\x90\t\xa4\x90\x0e\xa9M\xb7\x10=F\x85Yg\xa3\x04\x13\xb6\xa3\x9a\xb2\v\xdb\x01\xcb$\x8e:E\xe9L\x92\xcdr\xd1%jW.\xce\x16,\u088bQ\"\x89D\xa3\xe11r\xc4B\x89#\x12\x9f'\xc62\x01+q\"\x82(\x86 \x83\xa2H\xa9 T\x90\xdan;\xe8\u0429Kwv\xed\xcfA(C\x86\x8dd\xb7\x13\x99\xdf\x05\x8bvZ\xb2\xcbA\x87\x18\x1c\xb6\xech8\x05\xe5\xcc\xceP\x88E#\n\xbb9r\xa2\x12\r!\xe6\u01a5\x9e]\a\xd6\xdb`\xdcF\x13as\xb6\xd8j\xdb\xec\xf6\xd1\xcdl\xd6\n\x02\xa2hDa\x1f\x8b\xf6Z|uVY+\xeb91\x14k\xac\xe0v\x0eS[\xb3\xb2\xf5\xddb\a\xdd,=v><\xa2\x91 h\x87\x811\xb1\xb2\x9c\x11\\\u13c9N\xca\x15\x1f\u0255\x1e\xf9UljBI%-\xb4\x9dv\x1d:u\xe9\xeeH_\xd1}\xd2\xd4\xf9\x06\x996c\u059cy\v\x16\xed\xb4dW\xf6\xc0=x\x0e18l\xd9\xd1p\xec\x1ew\xc2\xc9pj\u03ec|\xf1~;+D\xae\xaa'U\xc1\x11\xea\a(\xfaY\x12\xd4\xf9\x80*\x97\xae\x95F\x1az\x84w\xbb\xba\x82\b\xbd\xdcxJ<\xdd\xed\x92H#\xb7\x18UU\xd5\xfac\xf5q\n\xf9\u01b4\x19\xb3\xe6*y\xc1\x97;\x10O\xb8\xf2\xb1\x1c\u03c9\x9ct\xa8\x8ezZR\x9bf\x9a-\xd6\xc1\x1f\xe9\\\x89\x16\x06`b\xfd\t\xa7\x82\n+JJ\u0151T\xe2q\xd3\xd4]\xc9+\xd4_\xe7\\\x9d\xa9|\x93\xe9\xccd6s\x99\xcfB\x16\xb33K\u0655\x03=\x98\xfd\u0621\x18r8\xcb9\x9ac=\xde\x13\x89\x93iE\x8e\xab\xb8\x1e\xcc\x13\xdd\xce(\xb3,\xc9ZR\xd5WG\xdf7\u07c5.vg\x97\xbaK\x18\x92d\xa97\xab\x03X\xd7\xe2\x0e\x9f\xe2C\xfd\"\u048b\U000ea28a\u0696\xd3b\xbd\"\"\xb2>\x95-PDDDDDDEDDDOUc\x81\xa5\x96\xb8\xd1rR\x01\x12%\x8cB\x9c\xc2\xd3g@\xb4\xb6\u0474\xe0\x10:\x8a\xbc~\x8d45!\xe7\xa4\u0486\xdf8\xadVk\xca7a\xba3o\xcev\xce*JS\x9d\x142\xde\x1d\xb1\x1e \x1c\xcc.m\xba\xea\x89l\xb3\x92\r\u6894\xa6\xa1u!;,\x16\x16VVw\xdeb\xae_c1\xf5\x02c\x8e\x9bm3\xf6\xd6\xe5\x83\v\xb8\x97\xea3\x06\t\xf1b\xb1\u0242\"\xa9\x85*\xf4\xcea\xa0\xbc\xfeT\xce$F\x19,H\xa0\u05cf\x95.\xd4\xd3n\x13\xec!u\x1d\xfc\xfd\xe4\x80\x06n\xff\xee\xe3}\xb9\x0e\xbd\x9c\u007f\xff\b4~\xe9\x11*^\xb9m\xa5\xa5\x93M/g\xe3\x1d\xf3\xa8\xaf\uf62dt\xe0\xd2s\x90+G\x1f\xda\xd3>Qs\xe6\xa3s\xeaup\xe8\xf5FJ}qy(\xfa|\x84\xa3\f\xda\xc3X\xdf<\x86\x18\xf5d\xb3yd\xdc7\x81\xfd\x8e\xbf\xaa\xc4\u007f\xa7I\u0274\xf1\x8a\x91I\x85\b}\x9e#\xcc\n\\\x17;GL\xf0-\x0e\x83\u0438T\xf2\xa7\x85\xc8c\x8e[\xa6^\xf3\xac\x8d\xd5\u062e(\xea8\x84\xbb\xd3\xd8/|\xf4\xfa@\xd8kp:H4\u052a\xe3\xf9$\xf1a\xf0\xd5\xd9\xefP\x98{\x95\x87B\xe2\xff/S|X<\xbdF\x1aB['p\xe4A\xe3\xb4\x11\x97_ri\xfc\x96\xae\u01b4\xe0\xd9\xf08\xfb%\xad\xb4\x85FiryY\xa1\u0487_\xb4/DG\x94\x85\xffc|3\xb1\x12\x1b\x04\xe7\x96(\x8a!\u0258\xb9\x05,\xc4E\xb0\u04d2]\x0e:\xc4\xe0\xb0eG[\xa2\x8e_\xfe#n\xbc\x96[\u079eo\xb2\xe1;\xb5\v\x87\xec\x9aU\xfa\xc2G}\xb7\xe1W\xfd\x9d\x06\xea{W\xf0)\x1c\xc5\xd2\xc8\x13L\xc5=\u0461\xf7\u0715\xbf\x8c\xf8\xcdi\x1a\xe6\x1f\x90,\x8el\xac\"\xfa\x11\xf2\xe3\x9a\xc0v\x01\xb0 \x00\x96Zk\x1b*\x80\x01\x9b\xf3\x19\xf9\x0e[:|\xf9\xf4vN\xb0\xe6j\x00\xe8\xeem\x000'F\x80%\v\xb4[\u05a0\x87\u02c4C\x00L\xc6\x01cR\x8e\xe2\u007fC\x90\x8b\xf2\x8b\u071d\x13\u0096#N\xb9\xe73\x04\xe6\x9c\x1d\xe43\x9cYs\xa0\xda5\x0e\x9f\u6e5c\xfb\xbf\xae\xef\x9b\xff\xd7rK\xf6\xca\x1eY\x92\r2\xc0\xddE\xb0\x15b$D\x94\xf0\xf0*\x80\xb9\t\xc0\xc7\xd0\xecv5\xea\x18\xf6$`>c\x80O%\x16'\xbcCp\x97\x1cb\xde\xd2\xd2%\x8am\x1e\x1a\x87w4\xa5\x8bO4'\x8a\xb3\xa7\xa1\x9d/F\x9e\x1a;1H\xea-\x85p\xf1\x99\x97\x1f\x1b\x1e\xe9\xdci\xc1y\xedj\xc0\x92\x17\xc7l\xae\x1dY\xa7@\x92\x9bC\xa59\x90\u05bfh\xab&S5,1\xcfZm\xe5\u2043B\xda\u0626\xd87\b\xa4t\x9c\xfb\xe8\xdb-\xb4pf#\xc7b\x1a\x03!\u011b\xe8q\a\xdaW\x13\xdbO\xccl\xe7-\xac\xf3t\xc1\u0726-\xccf\x9f\b\xb8\xf6S\x1d\x91\xcb\u028e[\xb3\t,\xd3X\xe3D\xcb9+X\xc3\xee\xe0\xfaM\xbe7\x99O\xcb\xf7!6YdJ\x00\x993M\xd9m\xdb.\n\xcb}S\x94\xa2\xe63 \v\xaff\xa8\f\x93u\xcf6\x1b\x0e\xc0\xd8\xdcGe6\xf5\xf0\xc0\x81\xc9\x1cK'#`\x90\"0o{\xa8\xc4p\xacl\xa6\xa4\xd6MB\xbb+\xcb\x05\x85\xed\u007f\xe0X\xce\xd7\x18\xd06\xf0R\x93\xe2\xf1\xc1h\xbd\xb9\xee\x18R\xaaM\x03\x8eS~\xb6\u05f2}\x82\xc4^\xbf\xfb\x92y\xf7\xb4&\x134U\xc1W\x16\x9fA\u05e9E\x89\xc8&\xab\xa5\xea\xaa\x1d\xfc\xac\f\x89\x05\xce\xe0\xc00\u02e8qo\xe1\xacvw\xbbn{\u00ddb*\xcev\x02\x15\x8c\xd1\xe4c\xe9p~\x1a\xc3]\x9aKC\xa7oo\x82\x17\xbee{\xed\u01a7W\xc1\xa2\x16\xa6\x92\r\xf3M\x152\u007fM\xd0r\xb3\x1f;1IR\xbd\x1a\u8c3c\xf8\xe0\xfd\x1a\x86P\xcb\xfb\x16\x97?\t>\xf8V\xdd4\xb0\xe8h*\x82\u06a5\xb7r%-\u077eNn\xdc<\v\x16\xeb\x03\xca\xccN\v,\xaa\xaf\xb7w\xc1\x03F\x84\xd8\x03\x19\x05Z\x06\x89\xea\xa5+\xb8k\b\xf5\xf9`\xa6\xe17\xebak\xce\xcc6\xfb\x1a\xd9U\x0e\x83vh\xbe\x95\xca\":\xc2y\xb4\xa9\xdc\xc2\n\x18\xf56\x8b\xb5\x88}\b\x8d}\xe5\u07a2\x16|Y=QD\x17\x84\xcc\xc1\xba Jq\xe2\xd6y\xba\xae\xf2\u00f6ZY\xa5m\x11`\xe5\xea<| \xe3t\xeeC\xe0\x80\x18J\x803\xab\x0fJ\xbe\x16\x06\x82r6\xf8\t\xf2\x9fi\xcf\n\xef\xf4\xe3\xed'G\xbbe\x14\xce+\x8di\xfc\u0232-\xbc\x96\xceB^]\x12\xb2\x97M5\u0351\xec\u0185:\xa7\x85\xd35\xd1\xf5\x13\xdcw\x90S\xb3\xe5\xeb;^\xb8.\xc1f\\]\xb8\x1f#\xc9>}~\u013e\xee\xf3\u0732\xa7\x0f\xa5}e\xb7\x06q7\x8bw\xbd\xa2&\a\xb4\xb0\xf7\xf5\x1b\u007f\xa8E\x05\x15yU\u0366\xfbM\xc4\x06\xc3\xcd\xe3\n\xd8\x1b\xf7\xdee\x9f\xb8a\u0712T\xbb\xff\x1a\xae s\xb3\u055b\xbb>\xbc\xd6\v[\x16t\xf6bD\xfc\x82\x10\xbc&\x14!\xa7\x83\xe6^(k\u4ab4\xb8~\xb8\xbb\x9b\xaaT\xc2\x00\x056\xff\x10\x94\r\xe0N\xad\xbf\xfe\xc4\x04\x0e\xdb\xdd\xd67>\xf8\xc1\xb0\xe9r\xf2;\x8a\xbe\xbb\x97\x8b\x00\xc0\x027\x0f>\x06\x8cx\xe9\x93#u>5\xd1\u0243]\x8e~\xd3\xeb;\xfd`-\xa7\x8e\xa9\xdcu^f\x90\xbd\u0324\x17\x19`e\xbevg\x18.\xeb\a\xbf\x1c\u07a1\xf3\t\x94\x9a\xe3\xab\a\u007fM]\xd7\xc2I\xaf\xb9\x9b$$\uc531\x8d9\xb0\xaa.,^E\x1b\xbc\u0590\xec\x115\xe2g*\xaf'6\x9e\xa3\xc2\u035c\x8a}\xddnI87\xc1\xe6\xe1\xe4\x00\x1dA\xf8\xcdZ\x82G\xc1\xcdY)\x9e\xb7\t\xadB\x8d\xf2\xb8*\xaf\xb0\xfe\xd8L*\xdeK\x0e\xda\u007f\xf6\x12**]-:\xa7\xbd\x06o\xa5\xc79\xae\x94\xd1\x14B\xac\x80\x9f\x0f\xeaC\xaap\xaf\xe9\x19\x9c\x1c\x14\xbd\nt\u03e7\x1b\u04b4\xb9\xa3\x84\x8b\x15\xa76\xa0\xb1d\x1f\x82{\x85D\xe1<\x9d\x1b\x8fM\x96\x05\u0162\xab\xb23!\x93\xf6\xd0V\xadR\xf3\xa8^\u00a1u@(\"\x0f\xe3'o~\xe9;f\x9a ]\x10~\xbe\x8e\xf1E\xbd4\xd4l\xed\xe5\xc1x\xcc\xe6\xff>$\xfb(\xab\u01a6G\x88\xd9\xdf\xf8\xf5\xc4\v\xc0\xe1\xd9}\xe6U=\xb7\xed%\xb7\xdb/*\x99\x81\xd8\x1b\x9f\xb0\u007f\xf3A0\xf0.iw\xa5\xa3%\xef\x80e\x8b\xf3\xed\a\xa0K8\xd6\x03Nv\xa5\x01\xe3\x0f\xdc\xfa\xf4)V\xf4\xd4\xf6X\xa6\x00\xc6d&Vi\xd6L\xd4\t\u06e2\x17\"F\xef\xb9\xd8\xca'\x9b^v\x80\xd2\xfdtt\xbf\xc7\xdd>w\u0132\xd8\u04f9\x01\xfb9\xca\x1b\b\x95?$\x12\x80\x14\xafH\xf4 PB\xa8\x81!\xa6E%\xd4\xfb\xfa\x99'US\x13\xa1\xcd1\xc8Z:d6\xd4B\xba;a\x14\n\xe3Xdv(\xe2\xf5\xfc\xa7\xd2\xee\xe4\x0e&\xb6\xd0\xde\x1c\xf2I\u0631\x10\xb7\xd7k\xd2b\xb9\xff\xa2\xedi3*Zs3\x83\xc1Q\x9cr\x05\x98\xb5\xe7\xbc\x1b\x86\xf6\xe4\xab\xfd\xb6\xfd?SrB\xa1\xcfa\xc5\xf4C\x0f\xddGC,\xc2\x108\x1f\xa6\x97\xea\u0401g\x10(\x1f\xd24[\xdb\xec\x1c@y] 4W%\xd5\xfeq\xf6V\xa0\x04\xf89\t>\xa2U\xc4\xc9%\xb0\xa7\u05dei\x13.\xf9\x95\x81*\x8f\x1f\xbd\u007f\x19U\u007f\xf0\xa1\xb6%0U\xd7kc[\xbc7\xa1\x83\x8bU\xde=\x870\x84\x14\x8b7\xb8\x154/\x83b\xe8cD\xd2\x10z\xd1@\xee\x93\xea\xe4\x84=\xc5VR\xa2K\xdc\x18a\txl9\xaa\xfd is\xb1\xbbc:\xd4\x1fm\xb2\x85\xae^\xf2\x1d$z>o\xed[\xab+\xa9@]\xe8k\xfa\x15\xec\xa3j{D\x0e\xdb\x14\x91\xf4\x03iwkq\x03\xb76\xd8\xd2>\xe3\xaeI\xe8\x16\xb2\xd9\a)\xaf\xc7\xc3\xeeuc\u063cr=#c\x976n\x1a\u07f8\xc7\x17\x8aa\x94T\xc6jg{\xca\xe1\xf1\xb9A(\xd5\xe0G\xbc~TF\x85\xeegzf\\\xd8A:\xb97\xee\x1e\xa7\xa0\xfb\xb2J\xb8y\x1aa\x9a\xd0\x18\x05\f\u06b3\xd7`\xdb\xca>\xc1\xe9\u035e\x9d$\x1e\x8c\xe6\"\x0fx\xf2\x12&\xab#\\:\xcdqm\xe7\u0771L%d:}\x15\xef\x05i6\xd4\xc7hnc_\x96\xa8\xf6\u011b\xc5\xd7N\xf3\xe4\xae\"\x00Kb\x8b\xe3\xb19\xaa\u0472tu\xb3>\xac\x96\xc9C\x18\u007f\x18!\xb4\xb1)\xb2=6C\xcb\xf1\xb3\xebS\xe2\x0f\xc1A\xb4\xaf\xb1\x06\x1d\xfe\xffg\x86\x11\u007f\xfa\x94\xe0Jb[W\xe5\xfd\n8\xb1I'\xee\xd8\xea\xadq9\x1c)CG\xa6\"\xbb\xb8pc\xfd\xa8\x8e\xccn\t\u0324nZ\xbb\xfd\xbc\x02\aCp\xf6n\xe3\xd0j(It}w\xb7E\xde\xd8\xedY\xf8\xc5rCc\xf5\xb5\x95;M\x95\xfdGW.\xcc\xf4m\u052cJ\xb4\x04\xdf\x1c\x1a\x90\x17_\xc3\u0234\x9fk\x88\xef\xd3\xfd\xe3\xbb7o\xe6\r\x90\x1d\xaa\x17\xdeI\x0e\xe0\u0630w\xe3\x01+\x9f\xdb\xd3*N\x15\xef\xb0\xf1\x89\x82Pq\xe84\x9brah\x82;\xae\x98o\x821X\x95\x17\xf8\xa1~\xe6\xae\xf1C\x93\t\x8b\x9e\x98\x82\xf3\xc6;50\xcd\x1d\xf5[\r%\x04\xba!\x80/\xd8cQyr\x8eFR6\x8c\xdc\xf7>&\xff\xf2\x9d\t\xecB\xac\xec{\x17\xe1i\xd1\xce|@\x9b\x9f\xaai\xf5\xc5;/\x1c@\xd5>+\xfdh\xe6\xec\xdeq\xeau\xbe\xbc*\xc1\xb0\x17\xbc\xb1\xa9\xcet\xb8X\xe0\xf1\x18L\xd2\xde\xc8\xce\x1c\a&\xf3A\xf8\xb0\x8a\xf7\xaa[4\xe9m_YW\xf8\xc6\u0154\xce\xd2\xd5\xce\u027d`\x9fh\x0e\xccJ]1\xdd\x0e\xea\r\u007fi\xfeE\x10Z\x8cFU\x13\v\xbcAMr\xa8\xc0#\\R\xa3;]C\xec\xc8\xeb4\xbf\x8b\xb1\aXaV\u0299\x01I\x89\u0102\x91{\xd5:\x04\x86-\"\xed\xe2\xf9@\vX\x83\xa8\x8c\xe6\x01\x1b=y\x98\x11\x19\xfa\xc2\x06\xccC>\x8bg\x85\xd7\xe8\xd9!\a\xc3\xe0/JB\xb7_/\xb7\x85\xfd#&\xf5M\xf3\xc1\fx\u01ad$\x86\x9d\xcf\u074f\x8bf\xb5]\xb5\x84B:\xae\xea\x82}\xde\xfb~\xf2K\xa7\u6104\x12*\xbc\x1c\x8a\xa5\xbd\xd3q&\xbd>\xaa\xcc\xc0mM\x85U\xe9\xa3H7\xea\xdbc\u05deT#\x9a\x96\b\xf8\xb5k\x89\xb5\xcd+\x99\x10\xdd\xe7&\xcc.\xb0\x10\xb6\x9afq\u614dP]\xdd\u075b\xcf\u0361n\xf1\xe0&\xab8\xf8\xe0nhKC{\u0319\xa1j\x97\x91\xa6\x95\xcb8\xdb\x01\xe7HT.\xd2\xe3\u0232\x0f\xecPK>\xd1Q\x80od\xc4+Kf\xb1\x1d,,\xfaK\va<\u0168c)\xfb\x01\x99\xc6\x1a\\\x0e\xe5\x8b\xfe\xd0\u05ae\xa5j\xe7V\x0fRR1\xa34\x16\xee\xf9\u034c\x1db\x9e\xfd\xb1\x13\x8d\xeb\u007f\u055a\x99\x06\xf0\x18\x0e\u05f4\xfb\xd9\xc0{c5\xfa\x8a3\xfaa&)\xea\x92z\u0123!Y\xb4K\xf1\x85W1w\xb3\"\xf3\xb2\x1fs\x98N\xc0\xef\x00\xb7\xa9\u018c\xb1\xffD\x9c\xcc\u0560\x19K\xf1f\xa5N\u06ad;\xe7\x90\x1c\u046cAz\xfe\xec\xb6\xd4\xf9Iw\xb92=\xc8\xe4T\x94\xdd(\xdb\u075e\xb4jE\xfb\xf6\xb5l>u-\x1ck\xa2n`\xad\x06\x02\xa4v\x17\f\xfcX\x94\xd7 ,\"\xff9\xa1\x93\xbcW#\x1fe\x1fYuI!\x9f\x8b\u015c\x1a\x18\xc3\u01c1\xe5B\xec\v7n\x80\xe1$\x89\xc60A\xc5y\u020d\xc7,\xf4l\x9e\xd8\u0774\x970LM\\\xe4\fCHL\x12\x11\x10j\xec+o\xc5\\\u0269[\x97\xf4\x80\xad\xf2\x0f\xfc\xff3\xf4\x93w\x9fT\xe8\xb3 \x9c\a\xe9\x8fO\xf3\xf9?\xfa\u00d3\x84\u00de\xfa\xf3\xb1\u007f\xe0\xe7?\xef\x06\xee\x17\fH\xfb\v\u035e\xd8F\n\x12\xcay!/\x8c\xae\xa3x\xeb\xef&\xad?\xcb]\u007f\x8b\xbd\xfe\xfdu\xe8o\xa3\u007f\xbe\xf3\xe3mX\u034c\x8bI\x1bn\x9d\xef\xe3w\x8f_\x9c\x0f\x19\xe6\x00E\xb8\xc2\rk\xd6el\x8e\u03f6\xbc\u05b3B^Sl\x9d\x05\x95\xfbLY\xacS\a\xe6\xf9\xe8\xa1\u0104\xb2\xf6\xb2\u07c4\xa9\xf0nnjZp)\x8b\x1bU\x97\x97:\x1e\x95n\xb1\xb5g\\jr(H\x83\u05be\"\xb9\xf7#\u007f\f,L\x87\x0f\xb0\u04d4\xd8\xd2`\xa1\u06f9\x13\xf3\xef\xfe\x99\xaf\xd7\r\xe0\x12:^I\x8a\x81\xf3A\xd0\x1c\xdc@$\x84\u0537\xfc\x95I\f\xae;\u06a0G\xee\x94T\xb6'(%-\t\xd2J\xccN\xbd>hA\\\xd1\x1a\x9f*m\x8b\x97U\x04/L0\x89\x87\f\x1f\xf0\x9a\u034d\xffc\xd2,\xaa\x9aU\x8bWMy_\x02\x15\x1e\xd4fj\x92#N\x93*j\xce\xc6\xf6\xea\xb9\x1b\u04d2\x02j\xa8Y\x99\xc9\a\xd2\xc2\u013e\"[\x11\x96\x1fW\xa7\x97n\xc0\xa6J\x87Q:Al\x15\x8f\x1e\\\xc6\xcd\xca\x11N\x19[\xc3\xc9a#N\xec\xf8\x97\xc8\xc6\xf0&z\xe3\xf2\u007fS\xfd\xeb\u0435\xfe\xd3\u007f%\xa9J\xbeg?\xf5\xff\fr\xcd \xc8\xe2\x8a\\\xd8\xdf)\xae\xf7\x91\x8fk6G\xad\x8dxSu\x17)tG\xfc\xa9\xcfE\x16\x83\x8b\x8b\u016b\u0165\xab\xa5E\xabE\xfaUpY\xfd\x84\xa8\r\xa9'\xd6u\xdf}\xeb\xd5\xee\xd1\x06m\xa8p\x03qs\u007f\xb9\xff\x05v\a-F\x1eF7\xc0\xa1\x06(\xfe\x13\x00\xa0\x8c\xae\ue2c0\u059c9\x99\xdd\xdd|,\xbb\xfeL\x1ct\u07fe\b\xd7\xea3'r\xba\x9b\x8ee7\x9e\x89w=\xb4\xef/\xc9\xdf\xf9\xba\xd4?\xff\xf9w\xe7\u007ft\xe1\xacDl\xa3\xf3q@\b\xe7{\x00\x96\x11\xdf(\x19\u042b\xef\xfe\xfbf\xaek\xfd\x91\x9f\xab\xfe\x03\x99?\u0752\x95\x91\xe8y\x95\xdcbT9\x95#\x17r\x93G\x92\x92\x99s\x17/eq*\xa3\a\xe0\xf2\xbc\xd9\xe8\xca\xfc\x84\xf1\fi\xec\x96\xdc\rk\xd7%\xf1\xf6\xec\xb5\x13\x83\x84\xa7\xc5<|\x8d8\xb5,\x8ebo\xb6\x17zhq$\x9365X}\x9b2Vu\x03\xa1\b2\xffV\xe3\xafq\u02f4\xc6HK}\xa9\xd1^\x02<6\x80%\"vz\xaauwrT\xb50V\x947\x17\xc3\u03d4\xe5\xe1EN\f\xaf\xa9\x92\xcd\u05f6\xa9C\xcb\x11\x9dP\x9e~oH\xa3\x9c\xd6\x02\xa8\xdf\xe1\xf6\xe2\xb08\xd5-\xc4\x0f{\xbd\xc6\xf7\xde\xfbj\v\xbc\x8d\u0218`KK\xf7\xe0\xb4\xeb_JA\xa0f6}2\xba\xba\x98:\xab\xaff\x1f\x1fj\xfb\x91\xde\x1bY`\xa9v\x92{\x87Z\xfb+\xe1j7\x8d\x1d\xb6\xab\xaf\xa8V\xbf\xb6d\xc8c\xa6'&\xb0\x8e\x1c\xf1\xd2\xc4\ucaeb\xcf\xefb[\xc0\xd5\xe7\xb9\u07089\xa9\xfdf\xa2\xe66m\x04\xea\b\xff\xcd\xff\x0f\xb9\xd8\n\u04fd\x8b\x92]\x8d\x9e3\u0276\t\x1d\xe4\x06\xa7\xbb\xc7f\x8c\xc7\xeb*#w\x16WS\x8e\u0577\xed\xa1\x15\xe9\x8f\xf1z\xb7\xf2?\xfe\xfd\x19\x8a\xe2c\xe7\x91A)\x90\xd7)C\xb8\xfe\n/f`\xa8\x9b\x96(\xe0\x10\xc0\x8d\xa4\x8e\xbd;L>\x9e\xf5\x13\u007f\x06\xa9\x92\x15\xe5$\xa6V\xc6lWP\x82\xf2\xe9\xd2\fj\xfd\xb6\"\xae$=\xb4\x92\xadd\x8e\xb5\xe6\x1e\x8c,\xac:\x1c\u07a8!\x8d(\xb9\x98jnF6{\xb3\x9d\x84\x95 \x0f( \xcbXm\xf5\xf2I\x8c\xb9\x96\x86t\xa7\xe0\xb8\x1e\u013c\\\xb5\x10\r\xa7\xe8\xe8\xb8\xc0\xb4CLb\xb0'\xd3\xe6\x87(\xbf\xf6\xcej\u007ft\xff\xee\x8eO\x1f*wlE\xfaW\xaf\x1f\x03\xe4/\x8c<\x97\x9b1'\xb4\xd3\x13\u0577i\xa3PG\xf8\xaf\xce_\xd9b\xab\xe0\xee]\x94\xec\x1a\u026e\x9e\xd66\xb4\x91\x8b\xcd\x18\xb3\x97\x9e\u06735\xf9\xd3(\xaa\xf7T3)\xf9\x8azW\xcc\xd33\x97@,\xe6\xeb\u0351\u007f\x9dL\x02\xc7\xde=7\xf5e\n\xf9\x85\xb21\x19\\\xa9m5\f-\xff\x1f?\x1e\x17\xd7\xe6\x06L\u06c3\xee,\xdf9\x03v\xae.\xaf\x02\u06516\xb7\xb6\xb8\x8f\x15\xa0\xf2\xa95\x00\xf3\xa7\x9cP\x88\b\u03612~\x1b\x1e#\xfe\x11\x18\xcdc'\u04f7E\x8bQ\xd9w\xe7\xb5\xc1zx\xb1sD\xce7\xf8\u04b4\xb8Ni\xa2\xa7:B,\xe2\x17\f\x93Vw\xc3\u2412\xb6\x17'9\x8a/\x90\x9c\\\xec\x8f\x17\xdd\xe8\u01cc\xe0#\xca\xd1\xde\xd4t\x04\u0169lp\xa7=\xd2\xe7\a\x0e$8\xa5%J\xa6\u00ce*r\xe3w\x967\xcc\xd0r\xb1\x19\x96r\xfb$\xe7#\x90)(\xda\f}\x81\xbf\xd3\xde?\xdcO\xe9XGo\xe1~\xdb\xd5s\x84Y\xb8\xe9e\xf6\x16\x83\xe0\xcf\xf5\xbd\xf4\x1f{\x86W8\x1dQ\x95\xb6\x15\xae%~\xfe\xa7\xd3PO\xf1m\x87\xbcr\u039d\xc9u\xdb\xdf\x10\xfe8\xfb\xec\xe8\xb6c%\x8f\xe2Z\xb7YjO\x1f/\xb0\x8d\xf3C\x94p\u0549\xe8\x8b\b\x06D\x1dl}7L\xe2\x15+$\x10\x85.:\xf0\x97F\xf9U\xab\x8c\xf6>t\xbc\xde\xfb\xa7\xe3O3\xd2\x12\x85\xaeB\x0f\xb5\xab\x86\x12~\u0141\xe2H\xfd\xfb\x1aZ\x95\b\xac;\rK\xbd7\x10}RF\u007fn\x82wA\xb4P\x14!\xb7*H\x0ff\xf0\x91\xd5R-}K\x9b\xfeht\x95\x89\xb3\xa6|2&\t\xf2'\x1f-\u05b1\xca\xc6b\x1b\r\xf1\"O\u007f(\x1b\x8b\x82R\x92%\xee$@\x14\xaf(\xd6\xd2T-\xb8\xe5\xf2J\xf4!yC/)S\xb1?H\x17`\xf2%\xcd3\xcb1\xc7\"v\u13c2\xc9sI\xce\v\xb3\n\u022eo\xff/J\x15\xfe\x12\xa1\xc1i\xfe\x16\"f\xa2\x81\x88\xf8\xea\x88\xd6\xe5\xe4QH\u06beV`jX\x9a4R\x1e>\xa8\xb6\x8e>\\\x87\u07eb*\uf294\r-\x97\x9d?\xff\x01\x18qj\x02r\xfe\x83\x90?\xfc\xf7\xa1\x16\x02^\x15\u007f~\xd11\xfe\x83\xd6~\xfc\xf7'\nB\xc3i\xbf\x8fV\xfa4Az\xad\xf9\xd3\xffd.\x9dT\xb8-/i\xa0g\xcfz\xe9\x96+\x1f\x10TA9\u007fP\xfd\x16\xb1\xe99S\x8c\xf2\xd6\xf8\u00e5z\xf4~e\xeb03\x9b\x92j]M\x80\x02!\t\x84W\u007f\xaa\x8eh\xceoD\xfc\xa7\xf8p\xb0z\xb2w\x9fp\u007f\xf3{\xf3(\xc1\x9a]\xe4,\x1b7#\xa6\xc0\x1a\x1f\xc2w\xde\x01\x13&\x00\xd3>\xda8Z\x9bX\x87\u06aa\x0eE\x02!\fd&g\x94K\xac\x1a\br\xba\xf6z\xd2G\xf9\xf7\xa3`\xb9`1@\x00\xf8\x11K\xd8zKS\xa5\xb1\x04b\x94d\xc4\x05t\xafy\xe8~\xe5\xac\xf3\xf9t3\xa8I\xfa\xec\xc7C\xe3w\xd0\x03\x90\u05f0\x8d\xb8\xc6\xc6)F\xa9\x16\xd0\xe9Z \xdf\vz\xfc\u007f\x15Y\x9a\xf2\x8c\xb9\xc6$\x93\xc1\xe8\xbd_\x90\xba\xfd\x9f2\xcd\x0e\x89\x94moDYC\xb1u?\xe8\x02\x14\xea{\v|\xe8\xe4\x85\xdf\v\xe6\xe7\xfd\x80\xed\xb8\xc0wY\\\xe4C&\xcf\xfd\x9e\xbf0\xff[\xfe\x8e\xf3|H\x02\xd8Y\x1ed\x1055Re\x8a&\xaa\xa0\ta(/\x8f\x87H\xd0\xdcH\x95\u02da\xa9\xa2\xe6 \x03\xf0yb\x16\xdf\u0791[YX\x95\u06dc\u0734\x92\x19\xbd\xa7\xa3\xf3v\xf2\x0e\xa6\xc5\xe9t\xd80p5\xa1\xa3\"q\xbe\x9d/c\u0548\x9b\xfc\x9dU\x9d\x02\x8cnt\u041am. Y\x9bt\x18\x1c+n-\xce\xd1\xea\xaaeM\xc9\u0744\x9b\xdf\xceaw\xeb\xdb\xf7\xb8A\xb5\x94t)\u33e2}\xb2>%\xa34R\xe1a-\x8f\u00c3\xf8\x91\rj\u0296\x96\xa2\xa3\xb1\xb5\xf9\xe71)\x18\xd8\xefYh\xad\x9f\u0599\x18\xcar\xb9\u0102\xa3B\x9e\xcbC\xf5\xb7J\xa9Z-uP\xab&MT\xe7/F\xe6\x87km\xd5\xee\x9a@\x96\xe6\xe3\xf9$_6\x94a\x15\xc0\x17\x89\xe8\x81k\xb3\xa4\xa179A\x8d\xa2T-\xa1\x19\\+?Xl\xe4dT\x04\x04\x17\f\xfb\xcbh\xe7\xfa\x87~\x10\x0eu_\xe7\xf5\x0e0/\xd6\xed\x0e\x1f\x17\xfa\x96%\xb0\xd2\xfc\x12\xdb+\xc67\xad\a1\x9d\x86h/\x0f.\xf2\xaa4D\u06f7\x97\x90\x1c\x92\x9d2\x1c3H\xa4h\xe7\x9c\xee\x94L\x06\x99;\xfaIm9'u\xb4\xb5\xb6\xe5O\xfe\b\x025*s\x05\xdf\xf3\\ct\x18n\xee`\xb7\x00\xf8\xbe_A\x1cx'\a\x97\xde!\xbey\xdf\b\u02a8O\x81\xd9_O\u007fx\bL\xc5.r\x82F\b\"\xb1\xe4\xc1n\u0783\x1f\xaaN\ub039\xb9\xa7\xc60\xec\xf3\xc5\xf0\x81\xdcF\xdb1H\xa7n\x06a\x8fh\xa2~\x11@\x8a\xefx\xa6\x8b\x942\xae\xe0/\xa8\xf4\x13Z\x80\x15\xe0\xb8\x93\xe2\x19\xe2BB2\xa81\x91h\xa6\x17\xcb[\x14\x01p\xb4r\xe9\x00;{$\xea\xd6\xe0p\xd4\xed\u0711\x11\xb64\xd5J\x02M\x81\x1dz[!\xf0R8\xe7Z\x80\x90\x94\xda'\xb5\x84\xda\xf9\xb19\xa1\xa8 \xb4?#\xa5\x1b.Q5z\xedc>xMu\f\x89\xc3\xf3\xe2\x18O\x00\xf5G\xd5\xec\x14\x91`\xcfBK\xc2\xfb\xf34\xdb#\xf2]\xc5g\xf1Z\x0f\xe8\xc6m\x15>\xbb\x85\xcd\x01r.\xaeB\x98\xc1\u0778!\xffA\xd4X\xd9\x02\xbaT\x10U\u028aG)\xe8\x89\xf2\xa0\u05ec!K\x8a\x17\xcc?N\x06\x91\x05\xe6\u0315\xa5F\x0e\x14\xa8\xb7\x87\xea \x10\xb3\xf1\xfd\x1e\xb4\xbf\xdc\xf9_\x92 \xd1[\xb6\xca8\x89Y\xa8\xdc\x01\u03fb\x89\x01fOr\x94T\r\x9d\x95\xa8Q\xa6&\xe4\xb1{@>a\xa0\x96S\u00cfM\xc6\xe1\u049c{\x14v=\xf4\u00cb\x10\x8f6V!\xe21\x0ex\xe98/3\xa5+$C\x13:\xa1\a\x96\xe1\u0358\x8dg\xaf\xc1\xe1'\xce\xcec\xd0\vgO\xc2\xe1\xd7\xcfnr~&!\xa4\x13@\xf6\x1b|\xb6\xad\xc7\xc7Wr\xb8\xfbu3gR\xe8\"\xe1V\x12\xa2K\xaa\xed\x896\xce-\xf8J\x1c\xe0\xfcl\xf1\x82C\x8a|\xec\u9b9aL\xfb]UBU\xa75\x06\xfb\u007f\x81\xe7M\x00\x99B]\x9cY\x93\x14\xc3\xc3a\u00e5\xbfB\x0e:\xd6Q\u24c3\x14N!\xe5;\xe6\xb2\xc6\xeeu\xd4xaP\xea\xcb\xe6\xa0\xe1\xec\xad;D\u06aaB\xe5\u04a4D\x19\xac\x1aA\x9cG\b\x1b\xa2Q\xd6)\x9d\xf0\xa2Ni\xfcl\xc5\u03e5\xcd\xe7\xe7\xa5-\xcc\xdeQO\x17\u4a66/\xcc\xf63nu\x8c\x9d\xe4U\x17\x1f\xe1u\x8dqo\xf5\xf7\x153FOpk\x12\xb8]\xa3V\xf0&4\u04a0\x95D\xae\x031\x01\u0170\xbf f\x13\xceW\xf4\xb0\x1d\xf9\xda\xec\x11)\xb3~,R\x18\x8a6\xbf}\x1cf[k\xc6\f<\xa0\xe2\x97HN\x00\x96\r-\x01\x9c@ru\x88\x98\x87\x89\xb1\xbe\xea\xf9\xd4\x19\xfb\xf7\x8d\xa8\x86I;N\xe0\u0223\x14\xac\xe0:\x91\x85\xeb\xa0QgJ\xc2O\xce,\x0f\x1c\u0316p\xfd\xf7Y\xe1\x0eB*\xcamNO\xa9\x85>\xa5\a\x1e\u07f4\x8aU{3(\b}r4!\xfdE\xf0\x9c}]$\x9d\x86\x97z\x80\xa8\x11\x9e<\xb1\xbdR6\x87\xd1E\xa6\x99\xa5\xd8'\xb9\x96\xfe\xb3N\xe5\xa7t\x93\xda\x06\xa2\xb6qL\xa0\xd0\xd3?\xcaC8~,X>\x89\x96\xec\x97\xc3\xe4\xc7V\x14&M 2\xb4\a\xb0\xe9X\xe5-\xae\u007f\x0f\x96\x9eP\x80\x80\xdc\x1f\xe6\"\xae0|J\xe3\x84I\x98\\\x90}\x1f+p\xde\xf6d\xa6\u024b\xcbn\xf4S\x8a\xc3\x06\xf5\x9e\xa3\xads\u06727\xe7\xde;7\xb9\xf3\xed:W\xef\xef\xf7\xf6m|\x11\xd8\x14\xc1\xf7\t\x18\xa0\xbb}\xc9\xe8\xf8g\x9d\u02dfp\xa7\xfa\u05fe\xd0\xea7\xfb\x04\xf4\xd3\xdd\xc0\\\xdaw*\xf0\x1b=\n\\\x8c\x0f\x97>\xce\u05d56c\x9c\u070e\u020b=\x03\x91\x97u\xddc\x9cT\x9b\xa5\xfd\xd3\x02\xae\x15\xc3\xfeI\x9d\xe4\x11\x9b\u04a4s\xa3(\x83bD\xeeM\xb2\x9d\xa5\xdbZy\xfd\x01\xae\x1f\x82\xeb}hk.\x01t\u7562\xfd\xb8d?\xd53\x86W\x05<\x91\xca\xe1e\x9c\xe1\xaf\xf2\x87\"=\x04G\x98\xbbfM>~=\x97\x82z\xe5*\x8c\x19\u067f\xba\xff\\i\u00b6\"\xcdF,\x98\xfb>\xc2S\xdd\xd7\xd246\xda\xd44\x9f\xed\x19\x1a\x91\xe1\xf1\xa6\xa9e\xdd`KK\x8fWND\x94g\u0596\x86\x86\xe1\xe1\xa6\x06\x83\xda3\"J\xed\xb6\xd0P7R\x18<,\xf5z^\x907\rN\xf5\nB\u04bd(\u07b4\x0f\xc1\xe5(tod\x10\xd5\x1b>\b\xf0OQ}QD\xe7\xbd>\xbb\xff\xb7\xde\xdf|\xfe{\xbe\xf7\xbe\xee\xff\xda[uJ\xfb:\xae\xcfE\xdcj+\xfc\xfe\x00\xf3\xb1\xc0`\b\x87\xffi\xf2\x05\xbd\x92K\x8e\xce\xcf\xe7\xaeC*s\xf6\x84\x88\x03\x84'\xa8\xbe\xfdD\xbe\x90\x8d\u017b\xd7F\b\x10U\f\xcf\n\xaaH\x84\xd5&hiu\x15\xb7\x12t\x1cN|Ui\xca\x146\xbbh\x1eI\x0f\xbc\xa1Q\xc0\x95\x1er\xfb\xa0(\xb6\xe3\r\x94\xbb\xfb\xf3\v\x02\x14\u0653\xeb[\x9d(\x14\xa0\xb3\xef\xa7&\x96dV\x12\x9f\xbd>\x9er\xc5\x03F'\xa6\xe2\xe9n.\u007f\xb5\xbf\x01\xf6\x9d\x8d\xfe\"\x12\xce\xdb\x1b'P\xfb\u00f3\x04oAI\xc2Q?\u007f\x91 \xd1\xc7\v\x97\xb9\xe7\x05\x91\x89\xf3\x8a\x13\x92A\xe4\x97\xcf{\u5375wg\f\x17D\xb7{\xf7\x9f\xea\xad\xf4N*\xd8N\u036f\x0f_\xca\xcf\r]\xd4\xd5m\xa5\xe6\xa5l\xc2P\xfd\xd8s%\xd1Q\x04W]\xf8\xa9\xcc\u065e\x9e\xd9\xccS\xe1:]v\x9d\xcd\xec\xe9\u025c\r?\xa5{8c\xedl\u05a90c\xd8M<\x10\xf9\x1b\xc8m\u03b87=}/\xa3\xb9\xd9{\x9a\x9e\u03b8\xd7\\|\x01\x01\xf3\xbf}\nkK\x12iD\x81\xc7\x06\u07d4\xe88\xb4H\x10V\xe5\xc11V\x18'\xceD \xb3\xfcb\xc8]\x0f\xc6\bJ\x9a\x16Af\xc0\xb4\tG\xdd\xe3DO\x96Z\x9d\x10)\x9e\xb0\xc0\b\x04,\x00\b\xe3\xc2.\xfeRu[Y\xc4l\x16v\xfeO\xf7\xc2_\xbb\x00\x19|]\xd5\xdf[]\x06\xac\x94\x9et^!\xd9\xeb\xed\xd0\u007f\xfb\x848\u0473u\x16\x86\xb9\xbe\x16[_\xcaZ\x8a\xff\xbb\u05efa\xde\xdba\xa7\x15))\ab\xb3b\x03L\u03d72\xc3\x1b\xd3\xd2\x1a#X\xac\xa6\bU\xdau\r\x93e?*US\x18\x8b\xd5\x18\x96\xa6\xc2\xefI\xa6o\xf5\xa6\xb50\xd8\xdaM\u077e\x9b\x99xk\x98\xa8\x01\x17-\xdf\xee1\x166\x13v\xee:\x9c\x9c`w\xcf?\xf8\xe5n\x1c\x99\xfe\xde\x13\xf1\a\x12)E\xf2\xeb\xc6IQ\x93\xccB\x8a\x1e\xc6K@\xab\xe2C\xdc\x04\xe1\xc2\x14\xf9!]z&@M?\xa2\v4r/[\x14\x1be\xe6J\x0e\xa8\xdd\xd3{\x94\xd7\x0e'\xc1O\x92\x83\xda\tl\x0e-<\x1c\xfa\x9b\xea\x13\xbed\x87*\xecS\x82\x01\x8ap\f\u0165\x04vk\xfb\xefo\x88\xcfM\u0203\xf1b1\x12\x009\u007f\u01d3\x87\xe3\x86\bP\x82OR\xe8\xe4\xb0\xec\x97\x17#jp\xd3=\xb7\xa7\tc\x92bK\u007f\x85^o\x03\x17\xeb\xc4\xdc\b\x05\xf6\x98;\x1ab\x94\x12@\x9a\xc1\x02\x10\x00\xeb\x93\xc9$0\x13\xcc\xe2\u03ec\xa9\xd03\x92\x8c\t\xa2\xbe2\xf6T\xff\x18\xe9|U\xf5\fA\xab\x02\x15\xdf{\x8d\x17\xd9\xe4\x9f\xd1>\nf|\x15L\x86eZ_\x9a\u007f\xc2\u0226\xda{/\xfa\a\xb2\xa3\x94\xb6I\x9b\xce,\xbd\x1a\xb9~\x1c0\xd9\xefOBl\xb0\xfe\u05b2\x00:\xb5*)N\xdf\x14\xfc\xfa\x14\xc0t\xa8d\xc1])\xaaJ<\x87^\x81\x17\xabB\xbad\xc5HD\xaa*\x1c\x97V\x86\x93\xa8p]\a\xa4\xda\bmB\\\x12\xaa\x8cP\xc7%\xd0\x06\xd0\x1f\xfb\x87\x9d7\x1ct\u044c\xe6-\x94\x81]i\xdf'\xd0\xd2\xfd&\xb1\xf9\xf4\xed1)\u021c\xbb\v\u0661\xf2\u00e6.\xa7\x8a\xeb\x92$z\xa8#\x13\x92\vZR\xf6\xf8\xc6:\x95-pQ\t`\xab\xae\xadW\xc6\"\u007f3\xc8\u05ef\t\x1f\xff\xfb\xa9_\x8e0S\xc5\xcf\x02F_D=\xdas\u079c\xbd\xeb\xe0\x06qO\uc381\xf5oM\u03bb\xff\u0789\xd7\xc0\x11\x8c\u007f\x8f\x0e\u07b0)\x18\x8dGoZ\x8f\xc7\a\x87\xac\x1f\u07db\x05\xa3\u05cd\xaf\xffn\xe2@s\x1c\xb3b.M\u0619\xa9Q\x05\x1d[\x8f\xdd\v\xe5\x04\x8c\xe4C/\x9a\xc9HnIS\xab\xe0\t`\xf9`H\u0665W4t\xd6m_\xdb\xcbv\xa2\xcb/>uJv\u01af\u052e\a0~0J'\xee\xach?\xc9\x1f\xe8\v<\xaf\xfd\u007f\xe1\xb3\u0246\x03\u429a\xa8\xc5&\xae\xb8\xb6ZW\xa7\xcf\xcb)\xd7\x01\x0e\xed\x0e\t\x9d\x99\xc0\xe5D\u007fXp\x81\xb42\x85\xc4N;.)\x8c\u784c[z\xb5\xeb\x89z\xd8k\xdf\xe7f\x9a\x0f\xd75\xd9\x0e.\x90\xc5%x\xde\xe9a\xe3\xf7=\x11'\xf2\xa14d82\xe9\x1e+\xf4\xc7\x01d\xa2&)K\x9f\x9f\xa9\xd3\x11\xca\v\xd9;\xd6\xe6\x9d\n\xad,?\x86\xee\x101kA2\t\xd2\xfe\x93\x96\xa6\x9bI\xe1e\x11\xeb\\E\xb4:\xb4J\x1a\xbe\u0290\xfd\xacokl9\xbe\u011eB}}\xfan\xb4,\xf8r\xa9j\xf7UH\xf9\xbf\x1fD\vw\xfc\xfd\x8b\xdek\xbd7$\t\xb7!c\x81\xe5\xd7L\xeb|\u052b\u0674+\x8fI+\xd8\xcc8\xe4\u007f\xa3v\x90\xb9\xda9~\x82_U|\x84\xda\xd5\xca=^WG:V\xd12E\xc9\xca\xecN\xf8H\xf6\x94i'\u0211\u03c7\xb4\x9b\xff\x1d\u01f9H\xf0d\x0e\"T\xaf\xea\x1fLt\xc9\u0173\xb9\xc8\xf0|\xe5\x14\x90i\xc6z\xec\xb9\xef\xd1\n\x11\xce\xcb\xcbW\x94\x87F\xe6\x89\x1d\xbc\xbc`b\xc5c\xb4\"\xa5\x8c\xa7ht\xf5r\xc0\xa0\x10\xa2\u02db\x8a\xceu\xfe\x14\x956\xa9\xa0\x16\xd1\xd8\xfc_\x86\x16\x99\xd1&\x94\xb9#\xf0\xfc\xed\x19\xf1Y\tL\xfa\xcd\v\x1dRk\x92\xc7JM\xf4\xc2T98K\x12X\xef3g@\x17\xab\xfd\x01o\xe7k\xc4\x02f\xb0\xdc=\xf2\x8ck\xd6P\xe4\xed\xec\xd1\xe7\xbbQ\x16\xa9\x800\x02\x85\\;\\<*\xd4\xe1\x02\x01X\x00B\xb7\x9b1\x19K\fXI\xbag\xbe[\xc0GJ\x84\xdc\xf1+\x94D\xcar%~W<\xb7$pI\x82X\x81PK\xdeFR\r\xca\xed\xf7\x04a3\xdfF!\xe4\xb4x%,\"\u0483\x90\xe2\xfc\u5451\xfe2R\x9c\x12\x16\x19\x1eO&-.H\xba5\x12+B\xa3EX\xec\x17<:\x05x\xccP|i\x87\u059b&\a\x95\x93\xb8\xb2\x80pT\x92/\x0f\xc1\x81\x05\xf8\x86^Xo\xcaG\x96\x93y\u04800d2\x8c\xbb\xa7\t\x10\x1ex\xaez\xbe\x95W\x9e\x06\u03c9Q\xcao5uA\xd4b\xebC\xeb\xbaW\xbf\x8f\x18\xbe\xbe\x02\xb8\x87\x1b\x9e\xfd\x8c\xa8\ti \xd6v\xaf\xae\x12T\xed\u03bf\xc1\xbe'\x9f\xb1[?\x05\xb1\xae\xd9\xed!\x94\xdf\xd4\u0740G\xe0\x8er\xb7G\xd0\xf2\x84\xbbo\x9c\xb7\xb2\x94G.\xe0\x17d\xbd\x91b\xaay\\\x1d<>\xd6\xe7K\xe2\x06WK%\xe7K\xe2\xe9\xfcc\xe3\xb7\xc4\xe3a\xaag\xc2\xd5A\x16|\xfa*CA\r?a\xf9\xde\x06\xbf=l\x1c\u007f?\xde<\xd1Bz\x1b\xdaX0\x8d6R\xc1xh\x95b\xa0\xe9d\xeb\x8fS\x04j@\xbd\x80\xf2\x9d\xac@=\xbfR\xff\n\xb5\a\xaf\xd8-\xff\xb7\t)\a\xd9\xdf9K/~o\x8f\x16\x83D\xe0\xe09p\x9a_\t\xa0\xbea\x9d\xf0\xab\x11\xdd\xea\xf7\x98\xd2\xef\xb3\xf9\xe4\x83\xf4\x0e\x9e\x14\x81\xd1Mw\xcc\b \xf1\x8c\xc3\xcc?\xc0#y\xab\x1f\xd6\"\xddU\x88\xc0}\x0eH\xeepW\a\xeb\xaf3\xbc\xaf\xdf\v\xd7\xea\xf7\u00da\xc9]X\x9d'\b\xa8\x1e\xa8\x89\xab\xae\x83\x18\xf4{\xc6H\xbf\xcf]\xfa\x03\x1eK\xee8\xc8Gqp\x8f\a\xfd\x1e\xef\t\xdc\u03c4\xe4\x8e\x11>\x8eJ\x9d\xca\xd2\xd4S\xb1\xce\xf5|\xe8\xf4\x0eL\xef\x13\xd2\a\x01\x9d.\x1a3\n\xcfP\xadZ\u01f18\xba=\x89tz\xb3t\xfac\xd4\x1d\u007fV\xa5\x8b\xac\xbd#p_\x0f\xf4\xfb\u00ef\xb4\x1d'\x14J\xb5\x8cZ\xb4\xc8:\xa3\xb7:\xbdi:\xfdVg0\x86\ua693\xb3\x99\x9eC\xa0\xe3Uh\x85\xb8H\u007f!4\xa6[B\xad\xd2\u9b76z\xf7\x0e\x8f\n\x83}\xfa\xe8\x0f\xaf\xbe\u0e2e\x00X\xcd\u030btL\x11\x02\x88\xces\x86\x1c\u007f\x00O\xfd\xa4\xdc\xe3V\x00\xdc2\xbe<\xd1fj\xa5\xe1\xac\x18\x19B\xf4;w\x85G\x00*4v\x90\x93\x15/\xb8=4@\xdeE\x14\xc0~>_~\x02\xbb\xa8 \x02\xd0gu\xd22\xc0\x9d\xce{Vu\xf8\xae7\xe0JNC\xa2\xd4n\xdc\xc6\x05 E\x13\xf4\x0e\x84I\xb74\xff\x17\xf9!-Lk\xa75\xb9\xfc~r\x86\x10{\\\xcb\t\x84\xa2\u047a\x80\xe4&\xe1\a\xf3\x16\x9a4\x02\x90\v\x85p\t\xe0\xaf\xe1\x1f\x19\xcfB\xc65\x00\xedxCZ^\xcb\xe2$\xa7\xebRM\xb8\xcc\x05\x10M@\xc5H\x80(\u011b\xfc\x17\x9c\xf8\xb8f\x89\x8d\xd6\u02f0\x8f\xfb\x9d9b\x00\xf0\xe2\x84\xe4\u007f\xc0\xb2\xebI;\r\xf5\u0487\xdf\xed\u02ed!F,\xc1\b\xb2?\x04\x10S\x83\xd5:\xfe\u02de\xf1\xaf\xc60\x17\xa4}\xb8s\x1b\xab\xb4\xdfr\xa2\u00c0U\x1d\xb5\xb7a\r\xf7-[\x8b\x1f\x9db\x00\xb9\x81xUI$'\xc8E$\x931\xe2\x85E/\xf2\u0655!\t\xa9R\xc4\xc7x4n\x82Kq\x1e\x1e\u0270\xea!-d\x83\xec4\xbe\x13v\t\xf7\xe8=\xd3\\(\xc0\xcd\u00f2s\xa7\xdaM\xb0\xac\xf5\t\xa6\x15\u0715\"v-\x80\xf5\x86\"\xb3\xa1\xba\x9dH\x18K\xe6\xf9\x96#\x1a\xaa\xb5aDW\xf2Q\xce\xeaAQ\x02\u9a85rG\u066d\x8f\xc0w\x80S\xd0;\x00\xba%\x82\xcc2$.\xb2\x81\xe8C\x95\xc2\xc2n\x9c\xfft\x9b\xe1\xd5F\xa4z\x8fk\xec\u007fLK\x12\xa6\xe9\xec\xa0\xd6\x1d\x94\xe6\x838\x13\xae\x91Rc\xab*w\xe9\xf2G\xf1\x0e\xdf\x03$\xe5\xe9\x15Z\xe6\x1az\xc1\u05b2\xca\ufc37\x15\xc0A\xf0\xcbT\x00D\xb3\x00\u075b\xd5G\xaf\xf6\x16\"\xe5\x15s\xa8n\xfa6/$W;@h\b\xf3\"\x152\x16\xf5q\xd8't\xba\x8d\xaf\xd1\xaampt\xe0\x10\xa0}\x81\x1c\xea\xc1.\x85@\xea\xcb,\x00\xf4h\xd1m\xecU\x19\x12\xe7\xc1/(`\xeb\x18\xb0\xb5Y\xc6\x15C[\xb5\xda>\\A\xd0\xc0\x8f\xa6F\xec-\a\x11\xc1\xa3b\xac\x86#\xb4 \xc7\xdc7x\xf5\x98\xda\u0384\xa8q\xa9\xc0|\x80\xf8\xbb=\xb3\xb7\xf3\xdbl\xb5\xcbhAZ*\xe2\xbf\xec\x03p\x8e\xb5\xac\xd79jv\xc19\u03a2E\xe7D\xa6N<\x18\xa5m\r\xb4\xb2\xe2<-,%\xab\xa8\x9cR\xac\u05d2\x9334\xd9E\xf2\xec2\x18\x16;\xa5\u0381m\u68c6\x95\xf2@\xe5wbq\xd1F\"\x84\xe0\x9f\bj\u0515y\x1bHX\x95@\xe4Bg#\xb1\xa2\xae\xe2\u9312\x18\x9c\xbaZ\n\xc9*\xc1\xb7F\xa3\xcb\x0e).\xcb\xc5\xe9\xf3$\xc0\xcb\u00d5\xe3xl*\x9d\x9f\xb2-\xc1\x12\x05\xa0\xbc\xdeQ\x12N\xcec\xf8W\vCX\u0289\xf8\x1b6\xf9\xdd\u0517O\xaeP\xaa\u050eN\xce\x10\xa8\x8b\xab\x9b\xbb\x87\xa7\x97\xb7\x8f/\xcc\x0f\xee\x1f\x10\x88\bB\xa2\u0418`l\b\x0e/\xf3]\b\r\v\x8f\x88\x8c\x8a\x8e\x89\x8d\x8bOH\xfc\x89\xff\u06dbB\xa5\xd1\x19L\x16\x9b\xc3\xe5%\xf1\x93\x05BQ\x8aX\"\x95\xc9\x15\xa9JUZ:\x11\x19\x99YK\xbe\u0461\xd3\t\x1b\xbc\xec2\xa8\xcfV\v\xa6\x13\xce\xfa\x8d\xf9\xfce\xc0\xb8\xb5\xce\xdd\xff\xb4\u0362\xdf~\xfd\xfd\xff~\x85^\xf9v7\xb5f\x98\xf6?}=\u0757.\u07f8z\xed\xfa\xab\x9c\x1fn~\xb7G\xee\xc7\x11?\xff\xf8\x93\xee\u037b\x1e\xf9y\x05\x85\xfa\xa2\x1d\x8aKK\xac\xe1\x8dPYQU\xfd\xba\xa6\xae\xb6\xbe\xb1a\u0664\xe6\xa6\x16\xad\u07be?\xea\xd6\xed{w\xf6;\xc0\xe0\xb0\xf3\a\x1dr\xa1\xdbI\xa7\x1cO\xf7\xa2<<\x9eL\xb3|Ve\x97\x95k\x8a\u02f2mNqeYye\xc9i\xce+.\x03\x00") + +func third_partySwaggerUiFontsDroidSansV6Latin700Woff2Bytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6Latin700Woff2, nil +} + +func third_partySwaggerUiFontsDroidSansV6Latin700Woff2() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6Latin700Woff2Bytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-700.woff2", size: 11480, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6LatinRegularEot = []byte("\xf8U\x00\x00\x1eU\x00\x00\x02\x00\x02\x00\x04\x00\x00\x00\x02\v\x06\x06\x03\b\x04\x02\x02\x04\x01\x00\x90\x01\x00\x00\b\x00LP\xef\x02\x00\xe0[ \x00@(\x00\x00\x00\x00\x00\x00\x00\x9f\x01\x00 \x00\x00\x00\x00%\x83\xbcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00\x00\x00\x0e\x00R\x00e\x00g\x00u\x00l\x00a\x00r\x00\x00\x00,\x00V\x00e\x00r\x00s\x00i\x00o\x00n\x00 \x001\x00.\x000\x000\x00 \x00b\x00u\x00i\x00l\x00d\x00 \x001\x001\x003\x00\x00\x00\x14\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00\x00\x00\x00\x00BSGP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00w\xa8\x009\x1e\x00NV\x00-\xd4\x12\xcd\xe9\x8a\xc8`\xd8W\xc9hKropq\"U:b,/\x962\xd9\xe3\xdb\xd3\xf0\xe0\xc6g@\x9e\xba\xd6$@6\xa4\x92\x9f\x83\xec\x03\x8a;\"\xf1\xa5\xb1\x18\xe0[E\xc7LFM\xad#^S[\xaf\xd0\u03cb^>\x17\x1eZb\x91b\x92`x\xba)\xecQ,V\xd6\xc3<\xf0\x04\x96[\x9aU\x90\x83\xa4jmC\xccRQ\x98\xd6h\x92_\xa9\"\xc7\xfc\xc9\xe5\xech]\xa1,\u0395IV\x9e\xca_\xb2\x02\xb9\x92\xa3\xb3\xbb\xb2\xb5\x99\x06\x16\x8e\xfaP\x80\xa0\x9ek\x85fb\xe9\xa3\xf5PA\u0221\xa3\xed\u02f9\\\xac*\xb8\x1e;\x02T\x1d\xfa\xaa\xc0\xf3'\xeaSg\x1fS\x11&\xc00\x06\xc1\f]E\xdd\xd9rY\xb9sE.y\u045d\xf6]Xt5\x93\xa9\xfc\xe6l\xb1e\x06\x95\xa1\x10\xfa\x1d!LM\xe3\xd8m\xa3m\x0e$/re\xecV\xafP\xc1u\xe7O\x9d \x86\x129h\xa6\xe28v\xa96j\xbc\xb8\u044a\xcf(iV\xb7\x88\xb4+\xdc(\x86\a\xc8\xd6|\xdc\xea\u007f\xaa\xfc\x9e\x90~\x99\xb6r\xaaT\xceC\xf7\xe6\u0755\v\xdc\uf863t3}\x05M\x96\xaaT\xf8D\xfc\x8eS\xbe\x14\x89\xc0J*+\xc9\xc4;\x90\xce\xcd\x02\x040\a7\r\xd0\xc0\xd3\xcd\x14\xa5\x8a\x87h\b;\xb9\xedJ\x1aj\u0124\xc8\x1c*h\x86\x17\x91\x1a4\xa3%\x8c\n\x84\x91\x1en3\xccq\xaa/\x1d\xb8\x12\xdaV\x97\xe1\xec\xf0\xb0\x05,\xfb\x98\x19S^\x03\x03\x98\xd3\vG\x15\x89\x8f\x18PM\x1a^K,\xe5oe\xba\n\xc9\xdcEa+\x81\xc9\x06\x88\x1b\xf8\ay\xb6Ef\x14\x005\x84\u050d6\x13P+\x9a\xb0\x9a\x90lr\x843\x1c\x9a\xa9,15R\xfeR\x84I_\f\xb1\xedI\xfb\nYh.\xf8S.\x81[\xe3\x8aX\x88\x1d{aK\x16\x85\x8e\x06\x99\xcc\x1b}\x91KI\xca=sn3\xa8atJ\x01\",Q\xd2\xf7\x98\xa0\x06\x9fD\tf\u0114Rr\x15\xdds\xd1HD\xd0\xc7\x13hc\u0212#\xb0\x00\xc6c\xc29\xe650\"\x19|\xe3\u07a0\xa7\x0e\x1fu\n[\x1cN3+\x89\xf1K\x86Y\x82D\xc0~`ja\x81\xa7\x89\x848\xe5\xe5\x98\x03V\x02K9K\r*\xccyT\x94S\x96)\xeb\x0fE\x9d\t\r\\\x17\xbc\x17\xdc\x17\xfc\x05\x9a\x1c4\x81\xc0\xe3[\x0eX\t\f*\xd62\x8f\x02N\x12V\x11\x9c40\xa7\xdd&7\xdeAnf\xb5\xe60\xb5\xc3\x16\vF\x01e\x82\xbc\x0681\xa0R\xdb\u009a\x00\xa6(di\x1be\xa0@,\xcb.\x81v\x00n\x84C^#\x8b\xceb\x80\x8e\x943l\xaf\xc2_ +\xc7\x0e\x02\\\xb7\x18.0\x9ca\xb9\x9a\xe3\x13\xd8\xcf\xcf+\x1c\xba\x81\xb5sl4S\xa1\xa3Ze\xc3\x0f\xc3\xfb\x95\x98\x03`d\x18\aq/\xe8\u00f4\x8e\xe3\xd7B\x1f}~\xf0d\xa0B8M\x1e\xf5\xa3F\r\x1a=a\xd8\x0e\xc4h\xfe\x05A]B5\x10T}6\x19\x87\x17\x8b\xa0\xf7,)\x99\xdf8'\xdas\x98\xb0w\xad\xc8\x17\x84\x91\b\x06.\x1e\xc0\x9f\xac\x1e\tvH \xfd\xe1\xf0\f\xa0eC,\x12Y\xa4\x05\x87\x10\x13\xc4C2$\x18\xf4\x1c:\xb66\xbe\f\bF\u00d4\x18@\xec\ad!\xad\x85\u04ad\xfe\xa3\u007f\xf7\xf0\x8b\v\b\"\xce|@A\xbd\xfa\xa2\xe3\x84\x1cth\n\xdd^\xe9\x8aq:b\x90\x03\xe6\x82\x01\x1a\xc2,\x1a\xc2\u0524h\x18G\xa0\xb1\x1c\xe8\nTF\x19\xa7\xd1k\xbdD1\xaa~D4K\x89\x18e\u010d\x0e\xd8\f\x8d\xd7\x15\x00\x194<\xb32p[\xa7\xbb\x1cL\xa2\x95y\x0f\x81\xbcr\xa5\x10\u0725M\xfc\x8a\x8co\x1aG\x17^5\xde\x05\x9c),\xf4\xaf\xb6\xfe\x97\xf4_\u026d\xe7~{\xf7\xcf\xfc\xffl\x92v\x95\xa1q\xaa\xdd\xff\xd8\x17h\u07616\x9c\xdb\xc6\xdev\xf5\xb7\xbd\x11Hzsm]\xf2;\xec\u07e6\xff!\xa9|\x97\xfde\fN#;\xb9\x18\xc6\xe3g\xa5\xa7\x9a\xe4)\xc4%6V\x12H\x82\x9e\x17#6\x15\x18\x8aC\xb7\xb8\x19\xcd\u0133C\x0e\t\x89xN=,\x89\n\x9ec\x94\x88Q\x84\x86I\x91\x11bM\x88\x91$yi\x88OHN\x86\xe3\xceL\xe4\xeeG\x92\xfd\xf3\"\aA\u05e4\xfd7\xea?U\xfb\x8e\xba\b\x90\x04\xb3.\x87Q!\v\xbar\xf7\xbf\x91\xcb\xfa\xba\n\xb7!FL\x93?r\x90\x18\xc1K\xfb\x84 \x88\xceP\x02\xd2\x1c\x81\xc8_\x89\xf8\xd0\xebo\xec\xfc\x87F\x8d|4j\xd1\xe2\x05\xaey\x04\x84F\xec\u0321P*@`^W8\xb9\xc9\xcents\xab\x95\\\xac\xa5u,/Z\xf6/\u06f9i\"\u0697\x14\xba\xbd\xab\x04\xa7\xc2\x16)O\xaa\x02\\\xc7\x12\x98+.\xbcn\x04\x18\xec\x83V0a\x15\xc4\xc5k\xd6\bAdPb\x83T\x1c\xb2\v#\x01\xc0\xa1\x05\b\xa8Id\u0371\xecA/\x02\x93C\xe9\xe4( 3vjD\xe4\x85xZ\x86+r\x81K\v\xfa9\x8f@\xbc\\\x91(\xf4\x91\n\xf9p\xe3k\v3$l\a\xadaL\xcc\xcaVegRU%RU\x12L\xd3\xeah\x12\xa0e\x03\xa8 \xc1&\n9\xa3\x9b9\u00dd6\xf3x9+\x028\xd0\xe7\x8e|\xea\r\xe4\xd2\xcc&\x82\xb6\x98P\xe5\x0f\xc1\xc7^\"\u07aa\x88[\xa4\xb1\xc1\x93w\xf1_\b\xec\xe8\xf0\x0f\x05h\xacB\xcc\xd5{\xb8\x1a\xbc\xad\xaa\xdb\f\xcdXo10\xea\xfd\xd0\x14\x8a\xec\v&\x92\xbc\xc6\xc49\x87\u018dc\x98X\x9d\x91\u065d\xa1\xda\xfa\xfbI\xd9!\x0eO\xbd'\xd4\x1f{c\xac\xa8]\xf4\x8f:\x1b\xf7a\u007f\x8c\xa21\xf3\u03bd\x0f\b\xe6\x8a\x11^[\x13\a\x13\f&n\x97\a\xde\xc0\x03y\x10\"\x01r\xf3\x93v\x16i\x13\xa8.\v\x93\xb4\xf6O\x91\x90\x8a\xbd\x96\x8bS\x17\xb3SR@\xdb\xd0\x063P\xe3\x05\x8c\x97A\x92\xcb\u056c\xf1I\xa3\x99\x03\x860\xe7\xd6b\xfdX\x17\x8dm0\x842\xeeK\xab\x03\x1e\fzD\x8eC:O\x8c\xb9\x03\xe4W\xc1\xa4<\x1eh\nMj\a'\x86?\f\x9f\x89\xc5\xe4\xa1\xf8\x11\xfezh\xba\vf\xc7\x00\xfa\x93\x01{\xfcxk\xbe\xfb\"Pn\x02\xd9\u042c\x96\x18k\x12\t\xf7\xa5\xe8\xe9\u007f)X%6\x1a\x82d\xa6\xd1\nU \xf2YXEE\x8f\u01e2\f \x86A_\x931B0`\xd4\xfbWm\xb3\t\u007f\xabO;a\xa2\x8aNu,\t\xa6/kn\"\xab\u06b7\xec\x9dj\xcduI\xadQ!\xe4\u013f8\x9a\xae9$\xe2A\xfb\xe0\xc1B\xf5a\xc1M\x12\xd9mnU1d\xb1c\xe6+-\x15\xb5\x19\xfe\x8c\xf7\xe2hCd\xbef\x12\x05K\xf3\x83\x9e\u02b2\xd0p\x80\xa3\xe8C\x12\xa1\x11\x89FJ(\x1b\x155\x8a^0d\x18\fRLi\vd\x19\x11Nu%\x1cJ&&\x8c\v\xb5\x05-\u007f\xa2\x01\x99\x96\xad`\x9c\x99{!&\x1f\x16\x03\u0182Jp\u01b9h\uf0b3\xab\xfcl\u063cM\xef\x1e\xaf-\x1e\xbf\xca\xea\xcdGB\xddL%\xc7\x1c\xc3[-'I\x9d\x00tONV\xc9JH&\x15\x0f\xa6o\u007f\x1d\xbb\xab\xe7\x87y\xc9\x04\x96\xe8\xef'\xd4\u05f5YF\xa1\x15p\vq\xd1g\xa6\x84?Q,\x95<\xb6\xa1G\xd8\x02\x91\x9c\x97\xcc?\x9cpM\xb9R%~\u007fJ\xa7M\xa4\xa1H\x0f\x9e\xed\xa8\xf3\\\x8aZ\u06b0&\x02\xb6\x1b\x9b\xf61u\xaf\x14>`\xd5r\xf13\u07e9\x83k\x14\x151`\xb1~\v\xdfqZ\xba\x8b\x85\xe0(LC\xe3\xc3\xe6\x046\x9c\x1c\x12\x06\xe2s\b\xc5.\xa8\f\xaexi\xf4r]\x16S\xaa\xc7\xf4)\xc7P\t\xf0g\xa3\x88\xdd\xe1\xe9<\b\xd3Z\xae\xf7\x92k\f\"\x97\xc5\x18\xddb!V\xedH\u01d2\xa52\xfd\x83\xfbaE\x160A\xf1`\xad\xea>^\x81\xfd|d\f\xa0\xe2A\x9a\x9f8\xc0\u1604t\xd0\x0f\x8e\a\xc8\xd80q\x81\xb13\xc33s+\xe7\x02E_\xa8!\a\xa8)\x10R\xf8\x19\xd8\xea\xcf\xd91\x85\xe5)\x90\xe6~\b:u:\xe5\r\xdd\xfb\xceu\x15\xf0\t\x05\x96)\x0181T(\xadb\xc6\xfe\xac\x8c\t\xf7\u0524\xa2\x1c\x99\x18\xdd\xe9\xa1 \x14f\x10\x92\x04\xc6Z\x0f\xc5\xcfU\x84|x\xda$f\xfaDK\u0266\x81(o\xa4G\x1eD:\u007f\x13\x83\xedH\fiz\u0268@1\xac\xacZa\x80\u02e3\x05\t\xfb9R\x92\x99<\x80\x8e1J\x10\xf8\xb4%\x06L\xbc\x81\x11a\x0eLD\x98\xc6&\xe8\rg\xca((\xd2\r\x89F\x9f\n+0j-\x88\x06'\xa6\xb0%\xd0,\x02\xa4\xc3)Q\xb7U\x12U%\x03\n+T8@\x89\xb0\xf3L\x98\x87\x11\u02b1!S\x190\x0f\xd5\xd5\xe6\xd2V\xfe\xa5 l\xa71\"e\xac\xf6\x04\xa7\u06433H\x11\x8a\xf1\xe8?r\xd0kw\f\x93\xa9\x01\x11U\x9b#\xe5Me\x9aJ\xb9\x9cJ\xac\xfa\x10\x0ek0\xc52\xa0j\fHABy\b\"%F\ua1eb\xe6\x9e}\xbb~\xc4\x05B\xfaN\xb9\xc9\xf0nG0\x91\xe3aR\u0639`\xcfD\x01\xe9>\x8d\u071d\xa0N\xd0\xed\xd6\xd1m*\xd0\u00ad\x95@\xb6\xb1\x80D-\xa6,j\x9c\xb7\x86\x9eEF\xb8@\xfe\tC0\xf9\nkL5K\u0552\xc9J\x9e\vTB\xc8\xf1\xe4&\xe4.\x8e\x92\x1e\x98\xa1\xcd\xc5\xd8\x06\xdbv\x03\xb7\xa0\xd9!\x0e\x017\tp\xd2{\v\x8a\xca\x13\xc5S\xb3\x01\xf7P\xabRMGS\xc78a\xdaE\x12\xe2\xa5D#\a\xbb\xe0U\x10\x9c@P\x98;LH\xb1\xf8\x18\x1e\xc8^\xcc^\x85\x8d\x16\xb4Q\xf9\x17O\xc1\xc8\x1dT2sN\xa1\a\xa8\x12\xae\xca\ri\xfd\x1ej\u0214O&h\x04R\x00\x8ai\x1c\xa2\x97\u035f\xf5\x93\xa5\x15\xfd\x9dD\x16\xa1\xb7\x90\xde\b\r\f\xd3\xc6_X\x19\xa4\x861\x93\xbdi\u0419\xb35\x15\x02\xd4\x04\xc7\xfd\x12\xba\xbb-\xecN\x16\xc3\x1cZ8H\xfb\x94n\x91\x132&a\xb1\x18\xf9\x9c\xe6t\xf6\xf1Y\xa8\x95\x9c\xc7\xce\r\xc2\xe3@E3\xacc9:\xd3W\xd0~6\x12\x89\b\u07b8\xa8\xeeD6#y\v-\xa7\x98\x92\x88\u6d55 !\x15J\xa6\x93Wb\xb0\x93`V\xc7:\x16\xed\xa5m\xa3\xf1\xec\xe8f&\xf9\x118O8\xf4\xa2 \x19\xc5\x12\x92\xc3@\xf8\xc0\xf2\x88\xe2\x1d\u031c\xbc\x9dH\x8a\x11\xcf\x04`\b\xed\xe1\x99\u039a\u00b1\x92\x97\xa0\t9\xbaQBw\xd4\nM)\x84uQJ\xd5\x02\x99`4I\xe9]\xa1<\xa9\u0705\xbe\xab\x83\xdaK\xbc\x9d.\"d\bM\xb0\xab\xe2\u01b0\xf5-C\u0147\xf5\\\xb2\x13\a\xaa6{\vu\xd8(\x17\x02L$\x95(\x83\xdd2\xac\xd1G\x1a8\xa2\xf9$#\x13\x18R\xb0\u01850M\xcam\xda\xc5H$\xa8\u04d0\xfan\xd9(\x13\xf6\x85\x19*\xb9\xa0\xe1%\xab0\xea/E\x19\xb9O\xfc\x94\x02A\x1c\u05b8\x14\x99*4%0[\xb0&Z\u2c9d\xf8z\x17\x85K\x1a6\x9cTn\u0629\xe8\v\x94\x9dp\v\u8ade\x1e\x93\x06h\x19\xe2\xa0\xea.\xe5\xf6$\x85$je|A'\xbc\xd5\xfe\xc8\xf2\a!fF\xdd\u04bb\x91;\x95(\x1c\xa9\xa6p\x13W\x87\x12W9!\x8e\x95v\x17G\n\xadQ\xa0\xc8Z]\xf4\xec\xd6H\xf98\xa8\x98\x1c\u0265.B\x88\xcd\xe36\x97\xdb\xe2j\x8ci\x06\xeb_\xb1\xd1P\xc8X']\xf4D\xd2N\xf7g\xf9#\xcf\xcf\x05e\x97\u007f4\x91\xd5\x03)\xbc\x811 %13i:f\xb2\xb2S\x13=\x02\x02\xda3\x0em\r\xf5bb\xec\x8c\xc2\u05a7\xe0\x88\xd1<\x86\x83hf`\xd3\xdc&\u012a^8 \xbbf\xddP&trHG\xe6{3\u060f\xaeisu\xe5L\xe6/\xa6c\xa3\xb3I\xdbV'\xael=\x99\xddz\xeau\xae\xf6\x9b\u06a4\xaa\xf6\b\u0494^k\x138\u0553,\x04MS+\xa3\xf9\xeefj\x8e^K\x99j\xa6\rOt\xa6\x1b\b\xcf&*.\xcd72\f\x94\xcau$\n\xaay\xaf\xdat\xb2\xf8\xac\x00k\"\xa3\a\xccT\xac\x03`\xca\xd8M\x8a\xe7s\x06\\+}\xeal\x91\xae\x82wM\x93\u053aRh)|\xa9\x1dQ\xb5\a\xbc2Q\xb3Zg\xe9Bw#K]Du\xa8\xa1\xc6n\x18\x0f\xf6\x804\xb6\xe1\xb3\x13\u015c\x10\x87*)\xd1\xd3\xd2E\xed\x88\r\v\x12\xb3nt\f^\xca\x04\xf7#\xe8\x19\xac0\x85\v<6\xba\x81\xael(\xb4\xcb2\xbelB\x1cC \x95\xbc\x9d{v\x12 \xaaR\xb2\x83I\xf0\xe8&\xbe\xf3F\x85VIuN+\x9b\xa7\xb5\x10\x153\x95\xd1[\xf0\xd6}\x05V\xf4\x18\xe8\xd8\x18\xb7*$\x13\x03\xb3CA\r\v=\x19o\xfa\xcch7\xf8\x8cEYY\xe8\xed\xf0\x83\xb2\xcd\u0317+\xcdg\x83`\u07d8\xd6\xe4\xb6\xdajTI\xed\u05acL\xab7\x01\xe9\xc0G\u01a0F3P:H#[\xc10\xe9\b\xffY0\f%0\xbeN\xfb\xf5U\xbf\xc8\x06\xc79\x82\x15\x83:x\xe7Ic\xa4)\x89\x03lZ98\x06\u03b0f\xe11V\xa6\xadJ j\xe2\xa3QU6y\\\xfc\u067f\xa3\xc3nJ;dN\u6e49\x89\xf5\x9c\xf7\xc4^\u03ae\xf2\xcb\xed\xe8\xc64\x9fg\x8a\x9eR\r\xe6\xcc7\x18y1$\u05e0D\f\xedx\x8c;\xb7\x86G+\x86\re\xf9\b\u0542\xb3\xcb2\x0f$\x8d\x10\xa6\xd4Ph1\xa0\x1e\\\xdb\x13z0\xb3A!NX\xd0\x13\xb6\x15\x1fN\xa27K\v\x80\xb6\v\x9c9\xba\xf7\x1a\x84%u\u0448\u49c1`\xd8\xd6?\x8b\xccO\xd2\xc60'?m,\x8ec7\xcc\xef\x04\"R\x18s\xac\x13\xbe\xc4`\x1d\u0231\xa9\x89 \xd7\xe0\x99N\xe6s\x89\xc0;Y\x1fC\x96\xc4\xf4\xb1\xfb\x95\x88(\xe7\xdd\x1d\xf2\x10&@\xc2\x1e!D\u00b4\x8f\f\u04d4\xe7\x90Np'I\xfb:>\x98\xd2h\xa5&\x86\xd3\xe8I\uc910\x02\xe6\b\x15Evg\xa6\xc0Y\xe65\f\x17Q\x9a\x82\x95\b0\x0fn\xfet\x1f\ub186Y(\x8da5\x86\x9f\xe9g\xff\xab\xfd\xfeHp\xc8V\xfao\xb1\b\u00c2\x961\f8\a\x92b\xfc.J\x9cWb\xf0\xdf\xea\u03cb\x86\xfe,\xa7\u01d3\u063c\x93\x8a\t\x1d\x83\n\x1e\x0e\xa0\u04ae\x035\xd32\xac0\xa3<\"\xa7\xc4c\xeen\xf8\u00f4x\xc38\x19\u007fgX\x84\xde?\xde\xf9X\x9dPL\xdcK\nlC\u0415\u58e6\xb6\xfeJ\x0e\x85=\xb1q0R\x9df\x9e\x90\xbfM\xacL\x94\xdeX\x0fa_\u0736\xf6L\x80\xff\x80\u0270\x1e\xa9\xf5\x93b\xa3\x03U\xe8?o\xb8H[\x88\xab\x10PN\xec\x87\"+\xdb<\xa7%\x11<8gBY \xb0Kr\xd8^z*\xb3\u01eeA\u007f\x03\xd0,C\xd7\x15F\x91\xfc\u00e4\x05\xfc\u0b07\xf1<\xc4\x05a\x1d\xa1\x994S\xacuQP\xdc1\xc1rp\x9d}\xcd\xf1\xfb\x9f\x89r@\x17\xe4y\xc0\xddM\xd8\xc3\"\x80\xf7\xd2\xeb\xa3\xc7c)\x15cc\xd6>\x94\x16\xd6\x11%d\x13S\x82\x1d\\\xb2%\xf7\":`\v\xb27X\xabl\x16\xb29\xb4T\x02\xba\xbc\x12\xc07\x98\xb7\x1d\xe5\xd21,l4`\x9b\x83\xdf\xd7~S*J\x89\x10\x15#W\xdc\x04#\xab\x98\xda\xf3\nf\xe5\xb3=\xfc\x12!L9\xb1\vD)\xc0\xb1O\x10\x14\x04\x1f\x05\xa9\x84\xb9\xe9\x12\u05944+\u00a1\f\x9aA\xb0\x19\xf0j\u0659l\u0440\xb1#\xe4\x14\xf2\xfb?\x1b\x9c\xb5|\xee\\k\u00ea\xde\u05f4W4od\fu\x85Y\xaa\r'\x95=2UZ\xc6`q\xf33\xab#\xb1\u6005\x1b@\u04ea\xfa\xe4\x9cN\xf5c\xf6\u040c@\v\x94\u0317M^GS\xc2\xf5=\x12\xb7\x9f\x103)\xc8@\x1c\xf6\x12r\x88\xa3\xdfQ\u072a\xacIU\x16\v\x86\xd1B5\n\x82\u036b\xc9\xfe\vaQ\x83Xq0\x91h\x05\xd0\xe5M\x18\xae+\x8ah\xe8\xe0z8\xd5g.\x98\x06\xd6\xff\f\x01\xa1j=\xbf[4\x9a\xc2gz}\xcfg\x06\x14\x86k\xa7\xa7\xf0\x05\xf1TM\xf5v\x05f\x90\xf0\x84\xc7|\xb3\xd4!\xe9\xd6.\xa4g\x8e\x0e\xd1\xfe0\xa2m\xd3\u0201\x12SR\x8d\xec\xc8*v\x1bQ\x80fU\xfa\x1c\xbd\xe6\\\x93\U000a24a9\xa7\xea5h\x92\x18\x98\x1c\xd5\x05\x0fN\x8f\\.C\xaaCF\xc1$jZ*\x9e\xcd,q\x89\xbdmR\xc7+/C+\x86\x01e\x9d\x8a\xb3\xd1\x0e\xa1\x8c\xbb\x14\xb9\x02`m\xb4\a&\x87\xba\xe2^\n\xdf\n\x9e\xd0\u046eU\x1b\xbfp\"\xa1d\xbd\xd1U\xd2\xc7g\u0457>1\xe2\xf6\t\xf0\xa9\xddG\xb2\xac\xd0\xf5\ua3be\x96\x97\xae:\x96\x00\x17\xaf\xfe\x83\"\x8b*\x9b\xc42\xaau\x8a\x84?m\xec\x9c\x18\u0293'\x1e\xc4\xe4\xe4\xaf\u04d0\x9aNA\x1dA\x18\xa4a.\xbd0\xd2F\u0164\x04kz\xa59\xed\xa71\u0160\xf6\x19\xcfo\xee\x9d\n\xf1\xab\xf9\xc3\x10r\xbe\x1cLW\x9c\xc5\xcf]\xba2\xae2+\x81\xad\xdbr\xa9\r\x11\xa8\x84\v\xe0\x97\xf1\xfeM\xda.\x9d\x80\xee\xb6\xf5\xbcW\x05\xa7\x98\x85\x02[\x94\x95\x00\xad\xe2\x15\x92\xa2\x8f\xb8Z\x05\xb6\xa0n_\x915\xc3@,\x8d\xee\xda%\x91\xa4\\\xa8@p\xdbD\xb2!\xb5\\\xdd\xee7\x93xb]u\u0582\x8a\xe7\f\xb8$n\xb5\xdc\x1d\xbd5b&\x1ch~A\xea{\x01>\x8cP\xbdO\xbe\xb7^w\x80k\xca\f\u847edr\x99\x1c\x13\u03d6C\u049cp\x9e\xe9-\xce?6E\x13\x94oj\xb9L\u0343\x03I\x995p\x05k\xd8b\u06c72\x1eJ\xa4\xb9\xdc4\xe6I\xf5\u0659w\xddXb\x0eF\u07af\xa8\xc9\xee!\x02u\xc2\r\xb5\x04\"\x88\xc1\x95o_\r\x87E\xf0f\xf4\x913\xe8\x13A@\xab\xbf\xcdvr\x84\xc9\v9%\v\xe6z\xd8$-6\xd8\xe0&?\x02\x16\x9eh\xa5:\x10\xe2\t\x10\xa2$\xe6\xa4\x02R@\x1d\xdb@\x1cV@WwH\x14hF\xf5\xb6\x89\x86\x1e\u06e7\xd6\xcbH\x14A\xd8K\fY\xde0]\xca\xf3\x1c2?\xe4\\wM(\xa2\x0e\xc0\x8a9Tp\xef@t\xe8\xfa\xa4[\xd9>t\x83\xa9PgF\u00fbCk\xc6\xd5\x1b\x98a\x8b\u0533@\xe4*\xfa\vV>\vp\t\xf1T=H*\xb7\x96\xa1\x12m4\x9b\x88Qi\x94\x8e\xf1@\x8c\xd8:\x9e\xdc\x11\xe2\xf1\xba\x00v\x9e\"\xa2\x95\xfd\xefi\xe0^h\u04aa\x04*\xba\xdb\xca'\xba=\xedB\x0e0eL\u075b\xe6\x83Y1=\b\xafn\x0e\x90G\x9d\xd0j\xc0\xdb`\xae\x11\x06\xb0\xec[\xc6:Aa\a\xeeo\x06\x01G3M\xa1a\xf6\xea\xf1/^\u0332\u01ec\x9b5\x93\xc6\xf2@$\x90Q\x80\xb9\xbd\xc9\x12\b\xf0\xcfX\x95uvT\x00\x88ih\x8f\xec\x89\b\x88j5(6x\xf6\a\x98\xe0\x06\xad\xd4c\t8ru\x98\x0e,$=<\u6dfd\x98_XE\xddo\xe7\x02F\x8b\xba\xfe{\x8b^\xf3\x90\x06\xbf\x17U\x9f\xa1`;Q\u90c8x\xe4\x87\x1bY\xfe?\a0r\xae\x9c\x10\xf9\x9b\x9aX!\xa5\xb1\x1d@M\x9c\x84\u0726dU\x81 \x1e\x1a\xae\x9cp`\xa7\x0212\xbe\xf4\x86\u04df,]_\xeb\xce6\x04\u024c\xff,\xe7L\"\tR*\xc1~\x06y&\xa7\xbc\xc5K\x16L\xc0\x130\xdb(y\xed\x13\xb1\u007f\xa9\xa30_\x85\x93RV\xee1\xbf\vF\xa0\x1d\xf4*;\x01\xa4@;\xb4`]\xbe\u3368RB\n@C\xb26\xac\x19^\x85\x9a\x9a\u0644\xc5\xd0qE\x17A\xed\xce3W\xa8\x9b<\xc5\u01d8\x05/\xcd\x16\x88x\xd7bN)r\xf9\xce\xe4\xa2E=x\xaaU\xb8\xa43\x11\x96\xc1\x15\xd3\x11>E\x8d\x81\xff\x10\x1b/4\x90\xcc\xc3\xe7K2\x88\x87]1\xce\xdfN\x1f}G\xb2X\x8c>\x99\xdcc\xf1L\xccA\xcctz\x9c\xe9F\xee\x8b\xde1G\u03c6\x04\xfc\xea\x10\xa5\xe6\x1fY\x04J\xed\x06\xda\xf3#\x96\xf3y\nQKC\xc2\xc0\xe6(\x8f~\n\xfb\xff\rhTAbr\x8e9,'=\xd0\xd2T\xd5x\xa9NT,?\xa3\xe7'\xea\xa2\xees>`0~@N\x94\xa3\x12\x9e\xed\x86\u3026H9n\x9cjJ\x1f\x1dqP\xc6\x17/\x0f\x99\x18U.%\xd0\xc9\xccH\xd0oJGd:\x18\xb2\xe7^\x88\xeb\x83\xec\x0e\x1a\xdbY#\xb0`\xad\xb8V<\xaa\x93\xb9M\xaf\x10\f\x9b\x9c\a\xe6\r\x12\x13o`\x03\xe4kdZ\xeeCX\x94a\xe4!)\x12\xeab\xc3y\x90\x82\xc3lRJ\xe9\xf2;\x16\u07eaD/\u04a3\x91-\xc7E\xb0\xb3\x94B\x18vf\xd4CZ\x88\xf4\xfc?K\xc5\r\xdb\xdcP\x0f<\x93\xce\x11\x91\x1bU\x84\xd6g\xb9\x86M\xc20\xe5\xf0\r\xc0My\xcb\x0e\x9c\xf3\x83\x18f\x87\x80ia\xfd\bE\x89\u042a!q\xb3+\u024d\xb9\xa9\x9b\xe3\x94\xd4\xf99b~\xadQ`\xea\x9b\xec\x86O\xda\xc34\u0098}T\u0546?Sh]q\x87b\x89\xa0\x80J\xb1\\Qy\x05\x17j.\x05\x13\x1f\xd6\x03\b\u007f>\xb9u\xfb\x01\xf0\xf9Lm\ufe4d\xfd\xbc\xa5T\xa4\xaf2\x1c\x02\xed\u063f\xa4/d\u067fPV\xbdJPW\x1cHX7\xdfhUr\xf1\x06\xb9\xd4i\xcd\xc1\x10\xbaT\x83\x80\n\xfbI\x12\xc3\u039bG\x1a\x84\x94\x9e\u068d\a\xa1\xdc\xd1}\u0712\xc4f\n\xb0w\xbeC\xad\xa6\xe1v'RR\xa5D\xbd\xbe0\xd5\x03\"/2\x81~\x94\t\x96PP\u0089\x8a\xca\xe8\xa0\xe0l\xab\xfc\x9cd\xf21z\x05\x1e\xa4\xb3\x1c\xc1\xf4\xe2\xdck\x1b8\xa3\xbf\xca5pB\xb3yc\xab\xa9j\x19\xe1X!\xbb\xf6\x14;'s\x8e\u01ce\x81\u0196\u0176\x1fe\x8cJy\x1b\vo\xb8@\x85I\x0f>\xe5\x19\xf0\xe37\x9f\xf6\x9e \xd8`^\x847|i\xfc\xabj\x00\xd3\xd7\x16Q\xf9\xcf\xd59\xf5\x1e\x99\x84\x0f\xb6#\xa9\xf3\x12P`\xffq\xf4\f\xa3\x9dm\x1f6\xa8\xc1\v\x19\xf7\xeb\x8b\x00X\xfea\xa3(\xc3\xfd=\xb2\x84)D\x88\xe7\xc9#\x1d&\x87H\x1ca\te\x13G[\x18\xc5\u0281\x17\xc0\u01a6g\x94X\xdf\x1d\xc1rZ\xaf\x87a\x8ee\xcb\x10\xfcf\x14`\xb0g$\x8e\xe3D\xeeRQPG\xd4}\u00d8\x86\xc9i\x912\u0179\u04e9\"\xdd,\xd8\xeb\x95`\xd6\xea6t\xf2\xb8\x1cU\xb6\xea=o\n\x8c\xac\xfe\x1f\xfe\x8d\x85E\x06#\x0eQn\x1eH\xe3#\xc5\xec\xdeI\x1aJz\xca_\x10\xe8\b\u0706r\x92\x02]\x15\x01\xa6E\x998\xa6\x19\xf4G\x0e!\xd71D-7\xcdt\x11\xd7\x13aXj\x8ds\x1b\xf8k$\x91 q\x998R \x88\xa7eq\xac\xdb\x03\x9ae\xb5\xa6^\xc5\a4\r\x1e\xdet&\xfc\xf1\xb5\xaeN\x1b(\x97c=|;p\x97\"T\xd1z\xae\xe4\u0204h\xb40N\xf1\x0f\x92\tq\x19h\xe1\x85\x16\xba\xa3\xe1\x06\xd2%\xda\x13y\xa9\x0fw\x03\v\xff`(\xa4w\xa4\x88\x19\xab\xb1p^A\xac\xf5&\u05ac\tx3\xb3\x8c\x15\xbb{\b\xdc?r\x0e\xa386\x19{(/~\xa19\xf4\xc8\xc7Zr\xc9\xc7\xdc\u0aaeSi\x8f\xf85\xe9\xfdf\u02b6\x89>@jag\x13z\xe9nCv\xac\x9b\x145\x15\xe6\u05b6\x8bC\xe9\xb1}\xa0)'\xbb^8\xdbl\xa5\x82\xac\xe7\x97\x16hS\x8a\x8c\t\x99\x14$\x13e7]\x15m\xc2Mo\xe8;\xd6\xe6'\xdeQ\x16'N\xe0*\xe6\xcd6Oj\xf7\xf4\xb80\xb8j\xb8\xa7W\xd7\u05a1\xaed\xb2\x98\xb9\xc5t\x06[\x9c\x93\xbd\xba\xca\x14\xd1\x14-\xa8\x06qQ\xe8\xf0\x9eu\x13\xb9\x92v\xa4\x88\xc5\u044ee\x9b\xa9\xd8\xf8\x91\xc1\xbd\x8b\n\xd0!-\x1f\u0253o\x12Cva\xff?;!\xb4p\xe2\u007fs#\u068f\u02d8\xbdx6\x19\xe6\x82\xf7l\xd5\xf1{\xff\xc8I\x92\u0754\x95\xde\x03;\xf6\x90\xb8\xa8r\xf5+n\xbb\xb9%\a\t\xa6\x03T\f\t\x12\xb8\xec\x8aN\xca#\xb0\xaf\x92*A!\x9e'\xfc>:[!l\u05f6H\xa4LY\xd9\xeb\xb9\f\x82\x9d\xef\x18e\x9f\x8d\xad5\xb8\x19=\x96\xf4\x11\x862\u41c4\xab\x11\x9b}t\xfdz9\f\xca\x00M\"eh\xc0\xecRI\xc5d\xf1]1\x96/B\x15S@\xe7\x02\x84\r\x91\xfa\xc9\xff\rj\xec\xe3\xb8H57\x8e\xda\x0fT[\xa3\x13\xf9T>\xe9y\x05\xf5`vF\xed\xa7:\xc5^\xf5\xb5\x03\x11\x8b\a\x96\x1c\x88nXI\xdb,\xbf:\xe0\x10@\x87\xc7E\xc6\x02e\\\n\x8f\x13\u02a0\x99k\xd3cQ\xc94$\x87\xe7\x18\xfc\x92\xd9\u007f\x18'`\x92Z\xb4\xbe\xcd\xef\f8\xb4i)&\xb0[\xa9\"k\x85\xb5\xb2P\xedCy!C\xe9C\xbb\x01[\x1b\xc0\xdep\xa0\x9b\xc5wR\x0f\xa3\x83\xe9\xfbK9/\xc1D\r\xbb\xb2N\x86\xac\x9b\xad\xd41\x0f\xca\xdc\x19\xect\x15EiP\xea@T\xb1\x86\xa0\xdd\xe4\u07ed\xc1fD7\xf7\xce3\x8c\xbaP#\xa6\x89\xa8\xafJ\xcf\xee\xa5\xd7}I)Q\x8e\x89\xde\x12\xc0\x0f<\xb64\xaa\xffC\xa25\xa0\xf2\xa7M\x92\x90D\x10\x82\x17-\xa3\a\x82]\xc2Xe\x02\xef\xe8\x89\x02\xb5\xfa\u024c\x16\f\u03den\u00c3[\u0483r\xe8xw5N\u06028\x80\x81\x00\x00)\x9a\x95Wn\xbf\xc4\xc4\u0186\xe2\xae\x1c\x8c\xaeYuZ\xb9\xe2\x9b\xe6\x81\x0e\xc9)hm\x12\xfb\xb7d$s\xce\t6\x85\xe8\xfc\u191a)\x91\xea\xa1\f\xfc\xb3\x85@\x8d\b\x14\xef/\xa5\xdc\xd6^\x17\xe0\xcdn\xbc\x10\x99\x1a\xe4p\xd2\xe6\x06\xb2\xc2^>\xf4\x04;AD(\x98\xf0\xbe\x86CF\u030b^\xe7p\xcf5\x12J\xc1g\x10i\x97U\x1a\x10I\x8a\xcc\xcam\xc5\xee\xaf\xedt\fB\xfd\u007f\xcb\x14|\u0696L\xe5k\xb3\x15\x05\x8a\xbb3\xd2\xf4\xa8W\x94\xce\x11\x0fR\x11\xbdm\xc9\xc7\r\u0436J\x8cb\x10\f\xdd\xfeX\xdc`\xfd\xe5|\xa6\xfd\n\x86Y\x15\xbc\xca`\x86\xa0\b\xd4=\xa2\xcaF\x1b\xa6\xa3Ta\xf4\xd8S@\u0151%\xee\x9dI\xa0(\xe7vT\x01\xa9\xd8>d\x84qLX\xbdA+\x10\x01\xcaXY\xef\u076b\x9a7B\xd2+\xac\x92V\x94\xa4\x87\x02\xa8d\u0285i\xb0:5\x9d\x1f \xad7\x81amP\x90\x1ez[\xc1n\xfc\xc8\xd5\xe0>\x01\x8a\xcevd\xaf(\xfb\xb0\xc8\xd8F\xccS\xa6i\x85\xeac\xb2\x9anr\xa5\u0203\x8ez\u029a\xc4S\x95\xcdq\xbc6h\u00e2\x99\xb8\x9cp\x98\xeb:\xd1\x04[\x83-V\xb1Z\x94\x93\x8a\u0658\xa9,K\xef\x00K\xdb+\u038cl>8^\xd2;D\xe4\xa1\f\x98\xf2\xb0:|r\x95\xebK\x11\xb5\xe9h&\x16\xea\x1c\xe9\x1e\x90\x19\x8f\ag#\xb5\x8d\xbeM\x88\xe9\x86\xee\xb5\x10\xaeW0TL\xa9\xcd;K\xb9\x95\t\xb7\xda\a\xca.C\x0ep\x12\x15\xd7U,\xf9\x1b6\xc1\x1f\x0f\xa7\xec\xc1J\xcf\u050a\xc0\x00\xe0\xde\xc49r\x8a+\xbc\x12\"\xe6\x1dm\xe1\x1d\x8b\xa7\xd5\xc1\x8e6KF\xb5%\xab<\x90x\xfd*\xce\xf2D\xe1\xe8\xb5\xd1FY\x12Vx\xe2\x80\x1dT\xa5_|\a\x8dt\xd0a\xf4\xd0\a\u065e\x86\x183C\x0e\u02dc\xfc}\x97\u01c6=\x18\xa4\xdc\x1c!\xc1\x0e\x12-\\\xd2\x1b\xa0\x83\r9\x1d\x94\xc8\x14$\x8d\x10\n\xf5\x17[\x9b\xeb\xf8\x06\xfa\x14\x11&Mpp=\xb3D\xb8\xd8\"25&` ]\x1f~\x99\xc3<\xfeY\x9e\x898\xe5\xe22\xc0\x06&\x86\v\x84\xb8\x17TZ/G(^\xaf\x8b\xa0\xe1\xd8\xe2\xb8\x1f\xb2\x80\x8fG\v\xa8\x91\xff\xbb]\x9a\xb5\xe2\x98\\\x1c\x0f\x8cw\x1ei\x182x\xad\xac\xcd\xd6\xcf:\x00\u059e\xe1+\xab\xfa\xdf\x15\x04\xd6\xd7\xe2\xa2J\x90\xe6\tw\x10*M\xb8\xbe\xb4\x9171Nt\xc6DF<\x02\n\xb5\u0121U (\x13\n\x13T\xa8\x84\xb8\xf5uA\x91U\xf4UB?\xe0%\x9e\x8d7\xff|\x05\x14\tn\xc7I\xda\xe3\r\x0e\u05af\xc5j=\u051d\x87\x88\xa8\xc8a\xea\xfc\xea\xbep\xea\xd6C\xef\xe9\v\xe9\xa8\u0546b\x88U\xae2^\u048e$\x06\xec\x99\x01k\x11\xaf|\"\xeb\xd5'\xb1\x11\x13(\xb8\xfd\xac\x0fV\x10z\u02b6\xc1\xf1o*&\xb6\xec\xb52\xee\xecW4A/\xd1\f!\xc8H[\xe1[\xb5\x06\xd4\u0537\x8fs\x90\xb9\xfb1\x01\x18\x9cQ\x19\x80\xc3H+\u00e6-}\x05\x80\xe1\x02sP\x06\xd5\v\xd6_\xcf\x17\xd0r\xdeN\x11\xb6B\x8b\x02\xfef\x89}~c\x82\xf87\xb8\xad\xb0&5,\xb4>3\xdb\xeeo\x81*\xceK\xb4%e\xd2q\x17n\xff\x15\xa5\xb2\u0492\x8e\xfb\x03\xc3\xef\x9cj5\xab\xd4\xfa\xe0\xc51B\xff\xf7\xbd\x0e\x10\x90\xd4|Vf\xbb\xa8\xc1\x96}\xa0\xa7:\x9e\x8c\xc4HVF\r\xe3P\xa8\xf7 \\-\xa5J\xd5\u009b\xe5\xc8\xed\x85\u0289\xd3\x11N!R\xab\x01H\xf2\xba\x15\x1fV\xb0\xc8\u0626\x00\x1e\xbf:v7CJ\x1b\x8dS0[\x96*I\x88\x89\xbd\x04V\n\xa1\x83\x98t\xe2\xcc~|\xab\xca\xdf\xf3{H\x81H\xf5\xa7%\xb1\x1a\xd2d\xd8\x03\xb1\xd4\x05:\x02\xb4\tiw\x88\xab\xab\xbc\x84:\xa4\xb21,\x18\x06\xc6\xcf-\x81\xdf#\xec}\u01e8\x83\x9du\r\x87\xb2>\xbc\u0371\x83\xe4\xdd\xf7\x11\x94\x17\xb3\x8f7\xf6\x0e\n\x9e\x15\xde\xe2\x03\x13{A\xae_\x8e\x9ds\x10M\xb1][&&C`*pQ\xfei\x14\xf6X@\u019fM\x1c\x92&A\xc6q\x844\xbb\xc7\xeb\x14\xc8R\xcc/\xbd3\xa0\xb3\x1f\x99i\x93\xa2\xd3\r\u009d\x11I\u034bW\"\xa7\xd5\"\xd5z\xe5\xcdk\u04cc@\xf3\xd4\xf0\u04a1\xae\xf1R\xa6\x956\x10\xffX\xa9\xc2j\x8f\xa4da\xe0\xcf\u03d2A\xcc\xc8D\"K\x1c\xbf\x1e\x16E\xf4NjSU\u01aa\t\x9a8\xe7o\xe5x,\x83i\xd8\x14\x13\a\x1b\xe3,\xa9OI1{\x14T\x9a:\xbc+\xb0\xcd\x15SP\xa7\xceP\x80J\xcf\v\xc0\x12c9\xf8y\xa2\u0783m\xd4_ \xafU\xb68\x87G\x92\xb0\xc2\x1d)Y\fQ\x03\"\xb10\x85\aD\x8d\x06\xc3\xe95.\x13\x8c\xf4\xa8%\xa9\x9fY\xfa+\xf4\xd5\x10\x1e(>\xb9\xf1/-\x19\x8a\x1e'\"\r\xcdK\x8f\xaf\xa4\xc9\t\x91\x97\x8b\x1fm\x82\x9d':\xd7U\x8f\xe9\xa7\x01p\xa6{\x85`\xf2\xeaRM\x18\u007f\xb7\xc1h!\xb8|\x05\x84\x17\"\x1e\b\x1b\x1e\xc8\x04\xc9\xc0\xb8\x12\u2a82X/g\xb8\u007fw\xa42(\\\xe8\xabr\xa1\xea\x98\xf7\nf\xb2F\xc3/\x1d\xb9\x1c\x8a\aY\nQ\xc8^\u025b\xe3 6X\xa9n\xea\xb1L\xe8@A\xc7X\f\x8a\x05Ib{\u02b0E\x8d\xae0@{\xe6\xf3W\x1d\xc8^M\x00\t\xb7\xae\x82\xee\x8aQ \x92\xecw\xd9\r;\x96\x1f%M\xe1\x96\x10!\xfd'\x1c\xf2\xc2L\xbb\x83D\xdb\xd0*\xa9\u0255:K\xd6\x01\xe4XMz\u056b\xf3\x0e}\xc96\x80\x87\x84\xbcD8\xb4\\\xa2R<\"/\x17E\xc21\x00\u1a55\x1a$\xf9\xd16\xd7\xf8gI\x94\xbe\x9b\xbdc\x1d\xf9OB\xb4g\ax\u074dr\xc1\x86v\xc0\f3\r\u0289\\$f\x83\x91\xe2\x1c:lQ<\t\xcf\x00\xebF\x8fW\x11b1\xa6(\x84B\xeb\xdb\x19A\xecl(\x89\x01\x85\xb8\xae\x966w\xf6A\xc0\xd8\xc8\xc5(\u0269\xea5\xf9=\x05\xcb\xe0Q\u01f4\x9c\xfb\x17JN\xc4G\xd0e\x1c1H\u0311\x8eL\xdcF\xcec\x8c\x87790\xf6\x92C\x10\x8eM\xebZ\xcfY\xac\x12\x9cR\xd7\xe5\xe9\xf0\xb8pq\xed\x00Vy\xfdns\xb1\xc3V\x8d\xf5|F\xcd\xfbtI\xd7\xc9N0\xc8\xf9\xb4\xfd\xa6G\u0185\xab@\xd7\xd1s\x81\xc1\xd8H\xc4\xe2\xcf\x0f\x919$\x9d\x8a\xe2\x1c\x01\xe3\x9bb\v\xa2\xd7\x19 \xf2x\xa3g\x9b\u0385\xcf_]\\[\xf0\xb6\x8d\xe8\x06\xfc\x8b\x0e\xf0\aR\x1e\x94\xfa\x1bn\xdaq\x9b\xea\xbb\xf1\x1ea\xa2{\xff\xc1\x83\xd2\v4\xadJ&\x19\xae\xfc\xae\xed\x01\xa4:\xc4\xe6\xc2\t\x0e@U\xfa\xca\xfdL{\xae\xa75CxF\xc7 \x8c7\x96r\xc0\x8d\xf9\x9dh\x86\xf2\xf3N\xf0{\xe9\x9c\u07b09\f\x87\x11\xa2\\>b\x95bH\x17\x82\x01D\xd2v\\P-\x81\r\xb6\x15\uf125\xee\x01\xb6W\xa1\xf6t\xab\x15\f5\x94\n\x15#t\x91%\x8c\xc0\x8e\x12}\xc2\x0e$\xe0\x91\xe5\x10\xdeg{P\x90X\xfd&`F\xa0\xbb\x89\xb3\xba\x84\x1b.\x066\xb49\xa2'\x94'T\x81\u05e1X`\u0434\n\xf2@,\xdf}\x8f\x10\xc3z\xa8&\n\xf1\x9ak8?Z\xac\xf3\xa7\xcf\xc5\x16\xf2R\xf1\x02L\xf3k\x19\x10\xebps\x02]bY\u007f\xf6\xd6\r!\xba3-\x8fT\xaf\xad\r\x13^?\x1f\xba\xb43\u06f4|}\xe0\\\xf9\xefG\u056f&d\xf2\xce\r\xc36\xda.\xf9\xbd\xbe\x00\xf4A\xf5n9\x96lr\xcd\"*L\xeb\x86\xfe\xc7C\x1c)\xa6bf/\f\xd0\xc53\x04\x87\x81\v\x97\x11c\x1f\xa0\xe7 \xa6Uu\xdf\x05\xe5\xae\u051aM\x8fT%\xe4\x9b\xeb\u011b\x90\xc2\xe1'C\xc2\x05\x94\x01\x1bh/\bL\xbf\x83\x88w&\xff0\xea\x14?n\xda*\x95\xee\xa2\\\xd3\xffB\xb2\x12\xf1#\x05u_\t\xa2I\u8665\xc7k|\x82\x19\xd8\xe2\u0672\xc9\xcc\xcd\b\x0f\rL\x0f/t\xe6_\x86&\xbb\xf0\x04$\x1a\x88\x9dq;'\xd4\x05\x8eI\x02h\xe4<\xd0\x18\xa4lrP\xa2\x11:\xd8.\bk\xd1\xf8\xc7>p\x15\xa2^2\xf0\\\x12O\x99\xc6<\x80u\xf8\xd0%\b\x04!\xbe\xcd\x1f\x88\x94J\xd9\xfa2l\x1c\xd7\xf6\xf2\x87F0\"\xc0\xa4\x83\xe8\x90T\x9d\xc4\x15Z\xc9\xd0s\xf9\xfc\x9e\xe9B8Z\xba\x0f)2\x82h\x1b\x19\xb20H\xceFbud\xa7\x89\xa3\x83\v\x88\xf1{\xc4\\M]X\bP\xa8,o\xaae\xbfc]\xa9\x8b\x88\xab\xa2BY\xdeR$\xdeo\xda\f@p\x9c-\xf6\x02\xcf\x0e\a\x81\xaa\xb0\uf23cDg\xe2\x96\xc8<\xd1vPk\xc4T\x8b\xc8\xe1|\xed\x1a\xac\x96\xae\xfd\x0fd\xde\xd8\xd7\x02\x1av\x96\xa7Z|\b\xa8\blGF@\x10ro\xe1p\xb0\x96\f\x94y\xb1\u17a3\r\x02\xf5\xbb\xd6G\x00?6;K\x91\xa8\xa2\u02edN)(^\xcc\x1b\x16\x11!\xc3aE\xba\xdb\n\xe1J\xe2\xc2\x03\ue4ce\x89\x0e>\xa8\x8e0\f\x97\xec\x1f_\x9b\xaa0O[\xce\xe0\xc4\x15\u007f\"\xc7\xd0\a\xffU\xb0.G\xf1:Q\xa4f\U00087098s,J\xbe\xa1\xe2h\x10\xec\xf8\xb0\x88\x96\x84\x84\xa2\xff\x96\xaf\x823S\xcd#\xc4Uw:\u0396\x8a\u070b\xed\xa6\xaf\x9cD\xe38\xf3YU\xc8\xd1O\xc2\xe00H\u964ep|\x99\b\x17TK\xf4v\xa3\xb4\x88]X\xa0\x9e\xaf\x89&U\x85\xeb\nK\x91a\u0314\x84\x1b\xaa'LD}\x89\xc6\xe8\xf5\xc3\x10k/\x16\xaa\x9b\xbd\xa2+$\u0395\vV\x1c\xa8dW\x1e\x9d\u03a2REk~\x85{\v\xb9\x02\xc8\"G\x9a\x19 Y\xdb\n\xac*y\x15\f\u007f\xacy^\x88}\xf8N\x82\x17D\xe8\x00\xe3N\x8a\xfe\x05\x14S\xb9\xceY\x8el\xa4\xf7\x11;c>0f\xda\xea\xbd2\x95\xb2\xb05:\xb1\xfffQ\xeft\x9d\x06\x99\x821\x97\x8c!\u05f3x&\x04\xe3\xf9JH\x1cs\xc7g\x18\xc32!X\x0f\x1a\x90\xe3\xcfu\x94\x00\x92\xa0\xd0A\u0475\xf9\x97\u0699L\xc0`\x89)\x8a(\x9bB\u007f\x91\u05cax\xd3o\xe9Q\x93\xe5x\xe8\xa4;\xde\x0fOhTag\xa4\xba\x94EH\xf5\xdfO\x12\x17Q\x03\xec\t\x11\x0f\xd5{\xac\x00\xc2\xc8<&&Ruh\xf4\xe4X\x82\xf9\x1e\x8a\x9fqf\xfa-\xd2\x16\x8cF\xbd\xfe\x1a\xfb\x9f\xeb\u06ad\x01J\\}\x9b\x9d\xdcR\x84_\xcb\u0482\x9eg\x12\x18\x9a\xaf\x16\xc5\xcbH\xbc\x17\x9d4>\x0f\xf3\xad\xb6%\x9a\x80\xe3\xee\x16\x86>m\x02\x05\x00ae\x930\x06\x800\u0684\xa5I4\u007f\xfd\xddi\xdci\xd6UW\xb4;\x17\xc8;\\A\xda\xf1i\u02cfDNkD\u03d3O\xe8\u07c7M'&#]\xb9\"\x86\xb6\r\xe2l%\xbc\x10\x83^\t\xcc\xe9_5\xb8\xee8\xab\xb0\xb0\xf4!\x95\"\xb44,ufn;\x8a\xaf\xc52\u0329\xb6\x83\u06c2\xec?'\xc6\xf7|oA\xffj\x02>\u068ey6)\x87\x13\x1aEG\x8d\xc2\xff\v\xaf\xc0\xc6\x06\xed\xbd[\xee\xf0!\xd1\xf8p\xcc\xd2*\x8f\xdf\xd5`\x83b\xeb\xf0\x94\xf1\t\xd5B\xe9\x97\xf9\n\x94\x17`sy\x82\x97\xc8\xe9\x8b\x04\u050bA\x8at\x86\xd6*Zc\x9a\x81\xb6=3\u0228\xd6F\xac\x04'#\u01c3\u0539r\xe6\xf9\x9f\xf3\x86\n\x8b\xe8@l\x12\xe5e\x06\x98\x81\x9f\xd9\xc6\vNL\x06\xff\xa4\x03Rr\x00\x1c\xea\xff0\xc7\x04b8\x83\x116,\x9f\x83\x8c\xa8-\v\x13\x98\xd1~\xdd\x15\u0363\x9ct\xc7RP\xfd\x1d\xae#g<\xc5\xd0\xf9\x82\xf5\x80\xcd\u0733#\x06\\k2\xf7>\x19\x86\xbb'^\xd8s\xf1\x05\xaf/J\u0632g\xa1\xf8P\x19\xf4YD@\xf4Ku\x89]\x84SnB\xc9e\t\u063d\xb8\x85\xe7Dd\xcf\xe8y,\xd4y\u00f5\xc6\"\b/\x1c@E\xe0\u0526\xc1\x831\x02\x02\xc1ul~\xd81\xf7\xd1\xd6'\xf5p\xcf\xe2\x17>\xe2\xe1\x83\xe5{\xa8\xcd\xf3U\x1a\xef*\xe7\u0270\x19\x06\x17\xd5\u03a3\xaf\x99\xcb1b2\xea\u0309\xee\x0e\u062a*sf\u0589\xb0\a[\xcc,\xc6\x16\xcfI\x1a\xe7\xd1\x19\xf8\xe5]\xb5&i\xd2\x1bqVT\x93\x89\xaf\xca8\xd7jY\x8d\x8d\"\\\x14\xd04b\x8c\"'\xff\xa0\x8f\xa6\x94\xfa\xfee\xf4S90\xbej\x1e\x8c\x15\x8e\x1d\u01d6\x9006\x19\xca8\x81\xeb\xf5L\xbe\x87\xf3A\x83\x9dB4\xd7x\xe9\xc1\x85\xf0\x89\x9e\x80\xc7a.a\xab\x8a\xc5\xca\xc7 \xfd\x9fw\xe5e\xdd@\xd5\x1b\x00\x03\x15xY\x16j\u02aa\x95j6\u95b4\x8c\x93T\x87\x1a\x10\x16lV\x83b\x12\u0726@7\x19\x14\rv\xcbj\x99\xccY\r\xbb/\xfcT\xa8\xeei*\x14\x82\xc6\xe9\xe67 Ilte\xb5z\xe4\b&\x05\xcc%\b]?a\xbbe!P\ay\u1959F\x00F\x96\xa7eYQcH\x99~\x8aC\x83\xd5w\x99\xe92\x03|\xd5\n{\u03b4\x90\xbf\xfc\xfc\x9e\x1c\x89\xf8\x9c0S\xed\x18\xb2t\xe6\u04d2\xc4\xf0~_\f\xda\x1b\x8c\xc4\x1a\x00\x0e\xc8I\xba\x81\xca\x1e\xf1\x01\xc1\xc7\x13;bC\xb2br\xb6:\u032d\xfc$7))\xb5\xe5+\xebG`\x13\noo\x13@b\U000c1e0b\xd5\xf3\x1b\xb1'\x1f\x82(\x89\xaa\x04L\xc4_\u07c8\x1f\xc2\u01b5I\xd5{Ra\x82\xbbT\x9b\xb4\xa7\x95\x00'R\xc1\x156n\x8f\x0e4d\x9b\xbd\x9a\xb4\xe8\xea/'\xfd\u0087\xd4\x17\xe0\xac\xe3\x15F]@\x89\x975\xf1B\x84\x92\x17#\x03\xda5\x1f\xe2\ub91d\xb4&\xee\xc5\u01d8\xe5\aM\x0e\xf0>\x98,GK\x9c\xad\x84\x82Pdtv\xb6\xdbR\xe5I\xd1f$z\xa5\xe8<\xfe9\x84\xe4\xf7\x91\xe3\xc0\xf8\xd5kH\x04F\x80X\x18\x00<\u03f3\x1e\xda\x0fw@\xdb4Pz\x19\x8fG\xe1T\x86'9\xc0\x86\xb3\x82\xd6Rj\x9dW\xb1\xcf\x13: \xee1\xc7^{\x9f'&\x9e\u03e1u\xf2`$\xbb:t\xc4\x06\x949P\xe5A\x8f\xad\x9c?qm\x16@\x89\n3\x93I_\xb91\xe8\xc4`=_\x04\x98\xe4\xc0U\xa6Jl\b\x8fN:\xf8\x01C\xedk\xac\x9f\xe6\xab\xdcI\x04g\xd8'6\xee:\x00A\x1a\xc1;2\x87\x12\xee\xaeRP\xc3X\x9dg\xa2\xd2\x10v\x82R\xfa\xec\u0370\x9a\xa8\x01W\"\xf6\xfe\xc14\xd4\xdd$\xeb\xe5]C:'\f\x844\xbf\u032b1f!4Rm\x93<\x85u{\x10X\x8b\"\xbd\x1e\u00aba\x8e\x11_$\x9aI\xc1\x01\x1aO\x9f2\xc0\xd2E\x1a@\x1bF\xb8\xd0;x\x9b\x1c\x8e\xf9\xffu\xd9]\xcc@\a\xbd\xe4\xb6B\xad3\x0e\xb3\x92/3A\xb1\xfd\x14\x1c'C\xf4/\xb0\x9e\x17G\x12\xe2\x13\u0231\x05\x98`\x8d\f\x0f\x1ffv\x04L\x06\xee\x1cNa0U\xdc\u01e5\xbb\x83\u05cb\u00ac9^\x15V\xda\x16#\xab\x18Ibg\x16\xc0(L\xd1M\xd7\xe6t\xea\"T\x90\xac\xb6\xcap\u0410\x19\xdb\a+\x87\u07d7~\xe5yT\x01z\xacF\x1e\xdbr\xc6\x028\x16I\x115h6\x0f7\xffL\xe3\xf6,\xbey\xb3\xab&x=\x96!%\x99\x83\t\xee\xef-b\x89b\x94z\x82j\u007f\xed?f\x828\vl\x04\x01\xc6L~\xb8\x16\xde\xcd7\u066cbJ\xaat\a\\\xe9\xf4>\x82\xba\xb6u\x15\x98\x19\xd4\xc6vA\xde\xde9U\xb1\xfef\xd5\xd4\\\xabkgQd\xf3\aITX[\f\n \"\xb8\x17\xc6k\x9d\\\n\x85]}\xce\xc0\u04c5\xb9\xb8{y\x9f`\xa3\xd4\x0e\xa94C\xccL\x17\x90\u03b2OZP\x13\x01\xee\x03\x988\u0766s\xcd\xe9\xe2\u034e\xe1\xb1KL-\x97d\xb5~e\x035\xb1\x8a\x92\x87\x91\xa2\tz\x8d\x18{\x98`\x17\\\u02b0/\x90\u0396\xf1\x19\xd7\xeeT\u007f\xeb\xe3\xeeP\u0612Kd\xad\x99\xa5GtLy\xe9\x13\x14\x81\xe5\xe2\xca\x14TR\x81\xfeT.\x04\xcb\xc2jH\b\x89n\xeb\x0e\xf9\x8cH\x12E\xfc\u03f0q\x15\xff/J\x05\xf2'\x83Db\u0782\xf2UNEK\x8d>E\x99Jh\xd3\xf2\b\x97*\xec\x1b\xca|\xff\xd3\x122,N\xcf\xf2\t\xf39\x19PQ}\x9a\xd1M|Y`\x00E\xb1R\xe1#-\x95\x00 \xbe\xee\xf2#\x83vN\x93\x9fN#P\xb4O\xc2^\x94=i%t\xdd\xefh\x93\xbdn\x81\x80\xb9[\\\x91n/@\xb9\b\u070b\x1a\x95\u064a/\x9c\xcaN\x84\x94\xb2B\xad\xc9p\xa5<\u02969i\xbbw\x11;w\x89\x85\x1c\x9d\x1d\x8d\x15\xf0\x10\x87\xcc\u007f\xb7\x91\x87^\xdb\xfa\xfe%\xf0\u0105\xb4\xde>\xccT\x97\xf1\x1d*\xb7%\xb4\x8a\x8a\u07b3\x92&\xfd\x03\xfa-b\xe2\xa4\x0e\xb0\x87\xac[\x9e\xb5!\bc\x16\xd8xi\x107K7\b\xd4u!\x84.a4\xd8S\xc9\xc0\x82\x197\x90Cu\xe3\x99\xf2\xdcI\x04\xbb\xf3B\b\xb0D]\x14J\xb0\xee\"\xa7\x1c\xd1-|\x01\v\x1c)\xfa)l/\xe4\xff\xc3=n\x803\xfb\xe8Go\xf5\u03f9Yd~ \xd4\xf1(2IB\xb9\a{\x80~o<,\x14\xe63\xb7\t\xa3g\x0f\xa5\nd)\xf1\xf6\xf5\xff\x11\xe1B\x9f/\b\xab\xe7\xa2\x10\x82K\x17\xc8R\x8f\n\x19\xb6\xe8,\xdb1\x05\xa5\x989\xc7\u7f37\xecB\xd5?\xc2\xd7\xd8y\x8e\xa96n\xf3\xa0\u007f~n\x88\"\xad\u0185J0_\x1a\xa2v\xc7 \xe8\xcf\xca*\xbe(\xe54\xe2\xec\xc5Xe|x\u0588\n\tWF\xe0S\bke\xa1c\x06B\x8f\xf7\u49e0\u01e5\x01\x99\x81\xd8\x1bb\x04Y\x8ad\x0e\x02U`o\u058cG\x8b\x12\a\xbe\"\v\x02\x8f\x89)\xc8\xf8\xbe\x89\xb4.]\x01\xaa\x97.v\x8a/\x95\xcf\x11a\x83\x91\xa6NM\x98\xf0 \x97\u0732X\nj\x8e\xdb\"_r\xece\n\xef&.\x05\xf4\x12\xf4\xf3\xf4Q\xd4*\x80&\xfaS(\x17\xb4\x9f\xdeu *\xeaG\x12$H\xb9Y/\xda\\\xbd\x12\xe4*yrH\xaf\x01\xd4\rS\xef\xf6'(\x16\ucaaeE\xb5\xe1\x8dI\xee\xcbVN!\xc9[\vf\xe4s;\xcc\x0f)\x06r(.\xb2#\x86\x89D\xff\x99\xd5~\xb7~\xa4\xa2\x01V\x1eh\x10h\xb2E\xc8\x00\xa4\xd5\xdf\f\xb8%\x8c\x066\xe1\x94_\x97\xece\xb7c;\xcfT)t\x9a\xc8\xf0\xb1\x05\x94\xc8A\xa3\xee\xde]S\xcc3\xbe\xbd]\xeb\xd5\x0e}]@\xd1\xff\x83\xff\xd8\xf2\x85 \x9a.Qm\xc0\xf0\xa0\x04W\x8e\xcf\x03U\xb0 \x87\fF\xe4n\x82]R\x84\xc4\xc2\xf87\x89\x00\xfbJ\xf2Pq\x88\u05a9b\xa4\x9e\u027bAx#\xf6\xd8\xe3::,\xd5\b<\x021\xec\x04\xad\x18\xae\xa2\xa84\xc2~\x94\x9b,2\x92\xaer\xe8\xd6\xc0\x1e\xad\xeb\x19\x0e>\xce3\v\x01\xf3\t\x03S\x89\xc2\x06Z\x11\u02c5v\xb0w\xf4\xcf5u\xec3\xe9g\x13\xb7%\"\xe4\xf3\xdc\xc8\xfd\x0e\x1am\x18\xb8\xe6\xbaT=*\xb9\x12E\xa9r3e\x05l\xcdw+\x1f\"^*\x06e'u\xbd\x8e\x98\xb6\xe5!u\xe5\xc8\bDA2\xa8m\x18|\xd6jO\x8a\vf\xca{\x91\xeb\x9e\x1e6VX*XNX\u0130\x9b\xaf^\twa\\\xa2\xae\rj\xca\x19\xbb:\x99\n\x14\xfe,\xfc\x80p\xc6\x1a\x89z}\x84\xfa`v\xed*\xb7am<\x9b\xd8\xcb2(\xf7\xdb'\xa1$cv\x8d\x13\xf1<\x9b\x94\x15\x19\xd3\xe6\xc7e\xab\x88r\xb1\x9b\xffXM\xc7G4\x94\xea\x06\xb1\v\x12$\x8d\x8baE\x930\xbbjN\xfb\xb9\x92\xd0\nIL\u9432Z\x91!a1ka\x15\xaf\x91n\xb1\x9e\x1d\"\xccfk\x91\xd1\u007f\xf6\xa2\xa0\u0629\x84\xbd#\xbf\xfe\xc4\xceK]\x14\xd2\xeaX\xc7\xf1E\xc8,\x93\x97\xbc\xefG\x8b\xd4oiN\x02\x06t\f\xe0\x14X&\xa0@\x88\x8b|GXh\xda\xc1P\x83\xe15\x02|1\xcaZ\xf9\\\x8a&\x06~\x0e\x12\b\x9f\x04k\nV\x10\xfb\xff\xccX\x84w\x84*\x84\xe9\x04_\x05~\x03\x97\xbdF\x9e\x84\x02\x01\x81\xc5,\x95\xf4:0\xaau\xd8\xd2@\xa4\x03\xbc\n(x?\xfd\x00/\x80Bi'\xba\x90\x18\x01\xa5\xb8t\xa5=\xe3\x06\x8e\xd3h\x02\xe8\x0e\x84s!0\x02\x90q\u3b23\x8a\xf9\xfec\xf3\xa1_\x91O\xfcU\x9f\xb1\xd8UF\x01\xfc\x81C\xfa\xd8H\bc3\xfb\u007f\xcb\xfe\x9f\xf1\xbc?\xf2=\xe2<\x1a\x1e\x0e\xbe\x18z\xf5\xeeX8\xf69^V^\xd6\xfa\x15\xf6\x11\u0607h\xba\xbe\xec+\xa7\xbe\x93\x81\x8b\xa8y\xed\xcc\x14|\x806!\xb2\vP\x82\x94\xa4x\u0202\x19\xe0\x11H\b\t\x9d\xe2\x95\x04=\x9d\xc0\xa0hT\x15\xdbDQhA\xf9M\x8e\xa1G\x12\xd5?)Y+;\x88\x81\x0e,?\xb4+\xc7$\x93\xa1\x95\xb1\xa7\x0f4B'F\xb3\xd0\xc1\xd0vt\n\x81\x90\xd7b\xbcC\x04>\xf1\x0fD\xfd\xc9Z\xb3a\t\xbb\x81\xa0\x97ndk&b+\x1b\xfbq\x99\x93\xb8u\x0e\ucd48\\\xe8\xe9T\x8bH\x9f\xdf\xfe\xed\xfff2\xf19\x8c\xba\x9f\x85\u040930\x88N0r\xd9j\xf0U\xa9\xaf\xf5\x941\x1c\xf0G\x1c\xb0\x1d\xf9%_X\x19\xf5\xb2\xb9\xf3\xe6d\xdex|\x8d=9a\x8b\x83l]x\x9a\x80n\xe4\xed\x8d\xfa\xf2\x82P\xbc6\x92\xc8\x0f^|sE\x91\xb05\x85q\u25fe\xe0\xc0\xcdm}\xb3\x93*\xe2\xf9\x98\xa2\xf9\xed\xcby\xa6\x9f\xd4&\xd7\x15\x0fo\xc5w\x18[H\x95\xa1\x85\xe0\x8fr\x85+\u0540\x8b\xb7Q~\xa0q\xce\nL9>\xbbh\n\xf4\x9d\x13;\xc7\aJ\u0710\xbc\xf5\xb5P]\x19\x13r\xc0\xde\u00e9\xb9\x15h[\xa2\xad\x05\xf8\"#^D(jJ\xe0\x9dX\x9c\u04ec\xb8*\x1e\u028dT\r\x8d\x95\u069c\xfe\x962Z\xa9I\xd1i\x9b\xdd\x1d\xbaSs\xa6\u05a3(\u0253\xf1\x9d\xae;q\x14c\xdc@\x94\"Z\x01\x96df\x8c\x1dM\x04\xea\f3\x03n\u008dI\xb7N\x87\xfa\u009a$\u0561~`\xc8\f\x83~\x9e\x1f\x9a\xbf\x85\x17\xf4\x87*\u014d\xb6\xe0\xa9j]Z\xd7\xd69\xc1\x1b3\x06\xf1~9I\xcd\xd0PF\x88>\xf8Qx9x\xfc\xf1\x04\xe9\xd9\f,\xd5\u0412\xe0npV\xa2%\x05\xab\xf9\x8b\rA\xcaP#\x96`*\xe3\x8ax\x89gE\xdcnz\xf2aO\x85\x89d\x8a><:\u06d4\x04\xd2 e\xfe\xddN:\x85\x05cL\x862\x00`D\xd3\u01d0N\xfe\x06\x99u\x8duE\xae(\b\f!>\x82 >\x96A\xeeQ\xa2\x11r4:1\xd0-\xc4X\xedA\xe07\xbe\x9bF&L\x8a\x88a\xa3\xc1\xa4{\x03\xb2\u0216P;J\xfe\xea\x84\xd7N\xae\x9e\x82\x8e\x95\xc4\xed\u008e\xd5l=\x0f\x87\x01\x99=\x98\xb7s\x905)\x84\x8d\x9c\xd1\u0695\aeB^\xb1\x0e\xbc\xd6\xef\x01,D\x91\xf98\xa1J#\x9bV\bT]\xc6vB\xe32d\xb6\xce$\x12DH\x84\x18tmj\x8cS5\x01\xc0\x14\xa0\xd2*\x89\u0465\x14\xc6\\\x8f8\x01\x80\x00\x0e6\v\x04\xa6\xb2\xd9}\xcc\xf4\u02b1=\xdeX\xb0\xa9\x97\x8ayMI\x18\xe1\xad(t\x80U7s\xc6)\xadGc\x86\x98\xe1;\xecL\vP\x9cM\x9aqT\xe4V\xaa\u01dc\xa1\xad\x06\u052e*E\x02\xb2\"Ua\xccc\x15S\x80\xb8\xe6df\xb5\xcaAb\u007f#\xe2]\xc6y\u2c9a\xe8L\x87rQ\xdda\xb3@\xd4J\xd3\x1a\x9e\rH\xa2p\xf2\x83\b\x85\x14\xe0\xde\xe2\x89n:\\\xc1\xc6\x11\xa2\xb0\xc1\xb6\x04s\xb7\xc8p\xd7#\x86\x06\x97\x9e\x13\xa5_\xee0\xed\x82\xc0&4 \xc1\xa0\x1c\xa6\xb6\x89\x1b\xf0\xdaD5\u061dN\xad\fx\xb5\xe1\xf0\xbb\xb0\xc5\x1a\xaa\xee'\xe5\xa9\x1dS\xd10\x98\\%\x19\x90G\xab!\n\xad\x89\xe1\x1by\xe5HJ\x97\x00\x9c\x8c\xba\xd7\xde\u06d0\x93N\xbf3iC\xd3\xd96)q\xc0\x1d\xc2I\xc8\xd2o\xfa\x0e\x80\xee\xd5*\xb1X\x02\x00\x04\xc0\xc1\xb8\xe4\x02CY\x91q\xd9S\x96\x19\xb4b\xf4\xde\u67c3V(d\x04Y\xcd\v\xdb*4\x8a1\xe0\b\xe1\xc1\x03E\x16\xd22-\xc0\x1f<\xa3\f^\x9c\x94\xc7\xed\u0155Q\xf07@\xa6\xb6\b+\xd2p;\xe6T\x80\x9c\xd0\u1c9cz\xa7\x9e\xaf\x86\x9eYu\x1a\xaa\xa7U\u015a\x82+C\u0086\x00\x02T\xa2\x05\r\x99S\x1d\x9f}%\x94\xa1\x12\x19\xf0\xbc\xf3\x18\xe2\x00H\x985\xfe`\xe1H'\xd1\xee\xf6c\x99\r\xd1`\x15a\xa8\x8b\x84Rg\x13\xcb\xde\x1f/p\f\u02dc$\xe2l\u061ft\xd2!\xc7F\\\x9d\x1c`|\xb9\xb3\x06\xfcD77\x16\xc7i6k\xf3\x84%1\u7323\x04T\xd0\xfd\xb8\xc8\xe8\x1f\xf1F\u06d0\xb9%~\xbd\x13\xdb{\x98\x91\xac\xa3\x02=\xe0\xa8\u00ba&\x91\xa3L\xe4N\xa7;\x05V(\x9c\x9c\xbei~\x87\f\xac\xaa]\r\x90C\xd5\x1c*U\x8f\x9ad\x99\xd7\u00c2U\xa3[\xc0\xe2\xa8Q\x89\u6514U/\x05\xdbd\x0e\x11\u0626\f?\u07e1\x05$\xa3\f\x14\x0f\x97\xe0p\xb2\t\xb7\x1a\xa0\x9e\xfaq\xa0ucFw\x04\xb8\xa1gf\xb2VO\x13\xf6ofc\x01\xdeA\x90\u02d0\xcbc\xf259%\xcdT\u06ae\x1a\xaa\xe6\x81v\xcf\xf5\x05F\x003\x92\xc6\x13\x1dn\f\xd9.\xe2\x83w\xfc\xda2;\xe0>\x93\b\xf3y\x94+\xaf\xc4\xd86X\xa8S3\xbd\x0e\xc4|\xef\xdd\xfa\x1d\xa9\xed\x90d\xa3\xba\x83\x80\xa3_\u0211N>\xc40\x89/\xaap\xd28\xc8\x1f\xee\f?\xee$\x05\x02\r\xaa\xc8\x02W7\xbee\xa8\ue942=xX3\xdd\u01f84\xc5\x0f\xbdn\x87\xe2\xe2n\f\x04\xe8\\\xad\xa2U\x86\u00e8\x94\xcb[\xe1:+\xc7\"R\x03\x13\xbfD\x9d)\xec\"M\xb1U[y\xa9\xa7\xce\x12e\x9e\x83\xdbu<\x8f\x1b\\\xc2p\x80\x9b\x90e\x97CV=\xa5\u007fN\xf2\xfc\xad\x1a\x0e\x9b\x90\xfeB\x1d\xd8!\x1dY\x11~\xc0\xfd;[68\x97\xda%c\x80a\t+\x1cT\xcaQ\xf3h\u0512\xeeE\x9a?M\xe35\x1c\xf1\x97\xeb\x16D\x91\xdc\x1b\x81\x92\xf1\u007f\x11\x1e2\xaa\x9b\x1f\x8d\x14\x1bP(\xecdp\xf81\x94{YR\xd1\x02\x83>\f\x12g\xfd\xb2\xd40Z\xe8\xff\xa7\x1e\x8f\x037B\x13\x06\tB\xbc\u01a8\x00\uc8e0\n\xb58\x00i\xa9\xbe\x1a\xfc\x8a\xd7\u04b1m\xe5x\xad\x1b$~\x81L \x10=pY\xcf\xd3^lp\xcct\xf0\x1e\v\xa8\x8d}^\xec\\X;\xa0\xa3zD\xde\xe5\xe7\xeb\xac\xcd\xf1c\x86'>$V\x91Y\xe3f\xbb\x9e\x81\xe0\xb4\xfaM\x17\xa9\x9c\xff\xd9S\x1fH#\xbf\xd6#7\x96Q\x85\xe5\x82\x0f\xff\x82D\xc3\xe0\xc8D\x0fQ\x06\xbe)\x06\xc3\u00f8\x1f'^\xa2S\x84\xbblS>X\xf7\xee\x83\x18\xb2\x81\xe71HG\uf260\xd5\xd0opm\xe9O\x05G\xf8R\xe4\x116\x97sf\x92?\xf9v\xe1\xcf\ft\x114:\xf2\aP\x120!Re\x88\xc6M\xe4\xd7\xd8\"\b\xb5I\x86\x90\x88\xf0\xa3\x17\xcf#;@0\xe9\x946\xd86\u0521\x02\x861#O\x103*\"k\x19\xa4{\xb0\x91\x1a\x92`\xa0O^\xfcg\xe7\xe3\u0209\xed,\x04$\x87\x1c\x8dE\xa2A\a\xd7u\xeec\xa4\xe7\xe3\x9eA\xf2[t&v\x94F\xc1\xaaA1]\a\xe7\xd0A\x1cx \x1b\xadz\xc0^\u0555\x82\x0623ym\x16f\xac=\x1ce(5\x91A\x92\x87fBFv^^\x8a\r\xd5\xe8#\x95(+&\xae?\xb4\x1b\r*\xe1\xa8I\xc2Bx*\x16\x84\x11\xe0l\x80Ld\n\xbc\x19\xea\x1ebj\xa2\xddP\x0e\xa7|\xbb\x95![\x96\x85\xf4\xae\u0371\xaa\xd2E\xb2\xc2\xda)xeAF+\xbc\x06\x84\x16\xb9\x1aP\xc3TQ\x13lk1\x86\xe3\x8a\xcc\xd7\xd3\bb:\v<\xda\xd0O\xf0:\xfc\x87\xb4'\xf0\xf4\x04\xdc\x18T\xe4\xf9\x00\xb8\xb9\xe1\xf3|\x18#\xf7\x9d\x00n\v3\x95\xb7\xa5\x9a\xfbP\xc0Jw\x9b\xd5\u02fd\x85\xaa\xcb4/\xfc\x85;JI\xa3\xa2\xe6\xf2f\x8e\x87\a|6`\xab\b\xb3u\xb2\xc41\xdda\xc6\x130\x1e\r\xb9\xf3.y\xa7=\xe9\xaa[6\xc3\x1d\x15!\u05fcS,\x02\xf8\xe29\xea\xe0/\xb7\xe8\xec~\x907\x13<\x86\x80\xb7D\xc8\u02c7\xfe\xaa\xbf*\xab\u0671U\xeb\xb0\xea\u0522N\x03\x85`\xbc\a\xbd\xacg-5o\x14\xa1\xdc/\xce\xd2A\xbeRn\x0eE\xff\xad,\xc9\x00%\xfcb\xe7=t\xe7\x9ak\t\x16\x1a\xf0\x0f\xceG\u5342:\xe2\x1a|7\x04\"0\x84\x0e\xb6@\xaa\x83\u007f\x19\xc2+> \u06d8\x92B\xd8\\T\xfeoB\x85\xc8g\xdcqK,\xef\xb4H\f\xeaK\x06\x01\xb5\x03\x1d&<\u0305\"\x9ah7\x85u\x8c\xa6\x02Q\xe9'\xe1\xe8/\x16\x13\xae\x1b\xd64\xd7\xd2=Bg\xcf5\x89g7\u054b\xb0Am\x1d*o\xcf\u0677\xd6W\xaf\xec\x96C\x8e\x91\xa8\x18\xc8)\xb4\xf1\x11\x92l\x1e\x84\xfe\x03\x8a4\x1c\xa2\x12~\x95\x88\x8b:\xd8$\x80\xb5z\xe6\xa9J\xdcq\x13\x82\n\xbd7\x85\x110\n\xad\x0f\xb8\xba\xa6\x9e\x06\xa1\xc1\x81\xb1l\x1b\xb6V\xa4\xa2-\x03\xb80v\xdc9\x00\v\xa4\x19\x8c\x97\xaa\xd4\x15*\xc0\xac\a\x1d\x8f\x1a\x9a\x1e:\x86\x9a;A\n\xce?\xb2\xa1\x80\xcf\xd1C\xa8\xb4Nj\xd0 4\xa5\xf3\xf2\xca\x1ak-r\xd6\xfc\\\xbe\xf2C\xe4,Et}\x17\xb8\xd5\x12\xd5e\a9\xb2\x90\xd6l\":6\x86e\x16\x01bb\xca\xff:'Ee\v\x9ch\x95\xa6\x14\x13\xe6\xb0\xc2\x14\xd4Z\f\xac\x92\bc\x9f\xa0\x89\u041f\xefiR\xd3Q\xc98[\x0e\xc7E\xf7\x12\xc1\x83\u060e\xf0\x95\x89\x14\xc1\xd0:\x01\xdcz\x83C\xb4c\\\u0756\xeeI5\xd0\xe8\x88Y\xcaZi1\xb2@z\xf8mS\xfb\xf4\xc7R\x12\u03dd\xaa\xff\xa6\xaeD\x8c\xe2\xfbJe/p\x11D\xf3l\xa7\xa8\xca\xfa)<\x03GA)Q:\u06b2\xb2\xc6\x1e\xd2]t\r\xe0osC!\x9c\x92\xf2\x87\xf4\xc5\xea!\x05P\u03b6\xd8\x10E\x88\xf2\xa5a\xa4\x00\xd2>7\x12\x80\x15\xf9\x8c\xa3W \xe2N\x04\xe2\xb4;aZ\xb0qK,\x80\\\xa2\x88\x88Ii\xa5\xc2\x1f\x97(\xd18\xaa\u04d1\xdf\xc0\xf2\x18\xb8\x1exd \x8c\x10\x0f\xb8p\xf0\x99\xfa\u056e\x94\x8c\xe4\xb5+\x19\xfdt\xb9\xe5\x01\xd1cX\x1eO\x99\x16V\x8aM{\x182\x8ab\b\x82\xd72\xaa\x86\xd4\xeb\xf0\x81r\x8b4\xb4\x87\x95P\x0fh\x03 l\xb4o`\"\xa1q.{f\xacm.\xd7RP\f\xa5\xccZ\x1d\x87m<\x00\xaf\xd8Z\x974'\x19\xe7\x9d\xf2z0$\x06A.\x82\xef\xeb\x9dr\xa2\xcb\u00c2Tp\x16\u06f5\x9f\xef\x99H\xdc'\xe8Z\x19\xab\x1e\u0678[xd\x84\xc4\xfd\xaa)zY\u0324C\u007f.\xd9\xf4\xc4\xe0!_\xf2\x05\x06\x88\u8a57qe-\u007f\u0143\xe5L\x0f\xe9\xf9\xe2y\x82\xa6\x80\xa7\x99\xfe\x01?Y\x18\x166\x800XW\xaf7\u0310v\x8b#2\x90j\x87ZK\xb6&\xb0\xbe\xffl\x9b\x87\xd0EO\x85k\x11\xc4\xfc\x06\x96\\\x01;{l\a\x1b\xf2\x91\u2b91\xfb\xa4\xcc\x18\xd6&:\x91\xb9?\f\xa2\xad\f|\xd5\x13\xed|\xd0I\u05c3\xd3\xf2 {mJ\xe0\x1eS\x8d\xe1\xc2\a\xc0\u05a8Vv#zo}\xecNO\xbb\x19\x98\xe3\xdb9\x9c\xd1<\r2V,y\xe8\x18\xfe\x98\xfd\xb3\u06b5\nO\xa4\xbbBV\xf57\xec\xae\x19;\x82''\x89.\xaf\xa1j\xadU\xef\x8bX\r\x8c\xdbo:T\u0784S\x8bhg\x06\xc8\x03\x92\xec\xd5\x04\xe3\xb2\u071eN\f\xab,\x94g\xfcyzl\xda\"V\xe8=\u02fb\b\xb6+0\x05\x85\x9bB\x04\n\x9b\xebF\xf1\x92\xf69pI\\r\xa0A\a\xf8\x9d\xe85\x98n\xc0\xe1Z\b^n\x97\xe4\x11zGzd\x1bj\x9d\xdbU!;i4 \xd6\xf1\xd5\xc3\x03\x9a\xe6S\x03\xac1\x80\xd8\xf8\u007f\xa8\t\"P)+\xa9\xb2Zb\xb0\xe2\xc5~%t\x99\xd0\t\xd9\x017\x00\x88\x12\xad'\x85r\xaco<\u0147\x00\xffL\xbf\xc9y\xe7\u0136\xc1\xb8\x04\x97 \th\xaaJ\u0417\v\x16H&\x83\xb6\x12'\xb0\xe0L\xaa\v\xc0\xe7O\xc3/\x81\x06\xbbS\u04acH@\x82\a\x1f\xc3U\xb9^\xf0#\xa1\u0290\xc7T\xf3g\x84UM\xe5\xe1/\u007f>\x12\x1a\x84x\xcbs\xd3\xf0\x8f\xf04\x9c}\x88\x06\u007fI\xb1\x1b\xfeB8p\xaf\xa9x3b\xee8\xb0;/\x10\xb4A\xfex\x18\x10\x90O>i\xf0\xb7\xa2\xc1X\xceT\x9a\x01-\x16k\xbd\xef\xb16D\xef\xc2i~M\x88\x9a8HV\x1a+\fYn\x88\x01\x98x\x9e\xf7\u063d#\fI\x17V,\xb1\b\x06\x03\x1f\xcd\f\x01\xe0!\n\u03fe\x1bD{\x14\xfa\x10\xc8\xc0\x81.\x13G\xdc\xd9%k\xcbY#\xaet,1xdnA\xe2.f$\xa1\x06\u05918\x1e*Jv\xffT\x80Fgd\x1d\xa9M\xd6?\x19\b\x9d\xee\x19\x03\x9c\x8d>\xf1\xb4v8\xf1+Z3\tB.\xe4\xb2sz\xda\xfc\x01\xde!\xc4$Du\x00\x02\xf8\vo\xe1cQ\xbc\xef'(-+\xe0\x94-a0\x92V\xff\x1d\x95\u0638;\xfd\x90\x9agW\xf8B\xe3=\xd4c)\n\xa89\xad\xda\x1d%O\tx\xa2\x97\xd1\x1f\x05\x19Em9<\xeeK\xa4'\xde?Tk%\x11u\x85\\\x18\x82C\x9c\u05cbO\x13\n\xec1\xee\xccL\x13\x04\u11adF\xca\xf4\x05\b\x16\xa2\xc9\xe2N\x90L\x90-\xd6\xd1\u488f\u038d\xb6h\x15%.4\u2d8d\x18\xa7\xd2[\xe3+M\x13\x9f\xfb|I\xb1\x98w\x1b\u065fU\x06\x81\xd1\u010a;\u019d\x04$*\x96k\xc0\x1a\a\xb1r\xa6Ml\xa9J\xeb\xd2;;,P\x17\x00F\xa4\u04a6T\xc1s\x83\xbf\xc2\xfa\x81\xff\xe8\x95\xed!\r\"\x84\u04dc$1\xe1s(.\u0257\xf6\xd4E\\5\vX5}H_\x12\xa0\xaf(\x1eC\xf7d\xd8\b&\x93&\x12\x92%\xd0.\xcd\u0619B\x99{\x05\\\x06\xe7\u0401n\x01\x18(\x11\x9f\xfb\xaas#\x83d\xe2x\xf6U\xb8JG\x8c\x1d\xc9:\xc9z'3\xbc\x1e\xa1@\xf0\x17\xe5\xeb\x91\x06\xfc\x00\xf9\xa7\x9c1\x80\xdf\n\xda\x12Br5N\t\xb8\x8d\x01\xa0\u007fO\n\xa1fN\xc6\xdb9\x1e\u0769\x80v\x8b\xa0\xa60}\xa8\xb8\u01179\x18\x06\x94\u007f\xe7\"\x1bU2;\xb3)\xda\x05\xd4\x00\xf6\xd9\xf4W\x89~\xca4\x0e\xe1\xe4\x1a\x1c\xe9\xf3\xd0i\x14\xb9A\x99@\xeeP3\b\xdc7a\n\x01\x8f=\x88DW\x04\vx\xda\xcd\xc4\xce\xd5|\fK\x00p\x151\x93\x00\u0135\xe7\u05b0\xc2N\xc3g\xf8\x99@\xb3\x0f]E\x81}G \xa7\u0593\xb95\t\xc3\xec\x14tM\u043c&;\x067q\x11-jv\x84\x8czT3\xbaT\a\xb0\x8e\xd5\xd2k\xaf?\x9e\xe3\xb9n+\x88\xe1\xd1bY%\x93\aH\"&\x80\x9d\x90)\x10\xf3\x1c\xf9J\u054bq\xa4\xaa`\x0e\v\x9a`#/\x90\x00\xe5\x9eb\xc6\xd8\xd3\xf9\b\x95\x019\xe1\xefSA\xb4\xd7JwE6O(\x1d\x118NOL\xd3d\xb6#\x1f\x10a\xb8M\x93\xed\xa9\xfd\xefs\xd5@\xb5|:\xd4D\x83\xa36Zt\xdbYf\nzip\xddZ\xc7\xd0\u0620\x02\x01X\xbc\x022\x0f\ua8827\xda\xc4\x05!\xac\xc7\xe45\x00@\xf6D\r\xc6\xea\xde0\xdeD|\xa1\xb6b\xc0W\xf1\x1d\x02\\\v\xed\x19C\xdc8 vPUP\x18d\xbb\xaf\x9eL\xdf%O<\xd0\xf9\f\xeb|\x94\xd1_\u0240)\x83\xfe\x81\xf9\xb9\xe4,$,\rB\x82_OE \xfa\x814\x9d\xbe\xa4oa\n\x10y\xe1\xe0\u040e\x89\x80j\x8a\xf2\x16\xcceX\x06SN\x9d\x85C\xfb\xeb\x06\xcdr\x83\x06O+\xa6\x8f\xbb\x16\xeb`H\x9e\x1a\x84`\u070b\xbc\x06bIg\x96\xc9P\xf1:n\xec\x83)\x8b\xd8$\xaf\f\xd2\xed\xecfYr\xee\x17\r\u0d68`\xf8M\u05c2\x15\x0f\u0262\xc1R\r&\x14\xe2_I\x0eZ\xd0\xdb-\xd2@$\xe6-\xf3>\x18\x83W.\xde\x1c\x14\xb9@\xbc\"m\xa0{\x987r\xe5\xf8&\xfc\xa0\xc4\xe2^\x10\xad\xac\x8a.\a\x1a\xf3h\b|\x8a\xb5,s\x1b\xf7\xb6\x89<\xa3\xa96\x14Q\xa8\xa1\"\x8b\x99M\t\xc8\"LX\x0e\xf0\x15\rc\xf7\x90bD\xf4n\xa7\xad& 4\x91ec\xc4 \x92qA\xebJ\x98SE\x87\x10\x9a\"\x80\x10\xec\x02\x14\x05\x15n\"@S\x85\xdf\x05\xa8\xa8\r\xe6i\xeem\xf9\xae\x142\xfdy\xbd6\x15\xe7\xe8\xcde4\x91d\x1d\xc28J\x1a\x93\xbc\xe8\x16I\xb1\xb8\xe5\u05ad\u0243\x8f\xc3\xf1\x1a\v\xf6\r\x83\xe7\xcaZ\u07c3\xbe\xf5\b3\x15A\xf8\u0739\xa6\xd0\x10,\x15g\xc0\xf8,x\xfb\xc9B\u0705\xfe\x9bC\xbcX\x82\u0165\x80u\x0f\xd3d\xaa\xef\x04\xc1<\x83-\xb4\x05\x15\x1a\xf2\x925\xb5\x93\xd7m\xd7\x03\x85g\xad\x06s\xc6D\xf7u\xb1\xec\xc0\xa2\x10ll\xe8],eZ\xd1e\x84O\xe4\x85N2\n{\xe4\xc2#b\x8aL\x0ezH/\xa0B\xf0\x12,s\xc3\xef\x15\a\x9b\xfe\x932cf\x9ec\x84\x94\x17\xbdLL\xb3H\xf4\xea^h\xb1v\xd70\u011b\x98\x00\x9bK>\xac\x03f\x17;6U\x82PpM\x81\xa3u\x1d\xbe\x10\x10\xd1\x1b1\xc2!\x8e?\xc1\xaaQ\xadF\xd2r\x11\xe5\u048c\x87z\xe0^\xd0>$\xe1\xa0b\xf8\xbb\xf4IF\u075a\xe0c~\xd4}pT\xa8\xa3\x01\xba\xf4\x1c\x06EQ\x8f\x97\f\xd1\xfe4D\xacY\xf9[f^\xac\xb6\x03\tZ\xd0\x0e6&\xfe\x8ap\x06DD\x8e!\x041p}g\u0160\x1a\x91\xb7c\xb8\u02b7\xa2\v\x02\xc5R'\f\xa9h~\v\x88\xa5(B1\x18\xd4\xda\u0474\x89\u007f\f\x88B\xc7a\xc2\xf9\x96n\u0607\xb1\xd1\x1aV\x04F\xbd\xe9\x1cF.N\xfb\xa1\x91N\x8a4\xf5\u06c5nZ\xc97\x14\x02O\u0354\x1d\xdf\xdf\xd8w\x18/b\u00e8m\xdf\xf8\x00\x91@l\x81\u02d4\xc6\xdbB/\xea\xcc)\xed\x80\xfd\x90\xc9!s\x1a\xa8`0\t\xbb]\xc2\xff\xbd\xa5Rr[e\xf8\n\bs$\x88\xf0^\x00q\xb4\u007f\x83]\xa1 }H\xc1\t\xeb\x1a\x99/\x8e1l\x97\x01)\xf8\xaf$\x1e\xac@\xae\xe9\x80*R\xf4\xf0\u0647\xf0\x93u\xb9\xfc9,\x1d\x03!\xb8\xa0G\x94\xbe<7O\xa4\xf9\x86\xb7\xc9\xe2V\xea0\xe0\xc0TZ|\xb1\x0e\xe5\x01?9\xe5]\x04z\xb3\x02wK\x8d\x84\xf6\x11g\xf2\xcb\x89\xc6;\x88pD5\x83/.L\x18\x8a-gX\x03\x0e\xe0\xa0Y\x98D^\x0e\x94\xe8\x85\f\x87_\"\x1c$>\x01\xd0\xc15\xe6\xc2\xcc\xe3l\x1fz!\x81\x041>\x1a\x03/\x15\x90\x89!%\x99\xcd\bj\xe3\xb2=\x1a \xe1k\x17\xca\xd3\x05qq\x1fD%\x8bif\x96\x00\x94\x8f\xd4$\f\xc4\xf5`\x1d\x04 A\xb2P\n\xf3\x12\xe6\xa2)*Oj\n3\xc0NL\x8aR\x8e*\xcab`\x8c\x94@C\x05\x12]\xc1o\x8d!\xc9h\xa2\u00d5a\x00\x844vx\u06e0\xb6#\xc0s$\xe2\x10\xdb\x02<~\xe8\x02s^6U^Ld\x91\x8a\u00ae \xe1\xfe%\x14\xbf\x0409.\x98w\b\xea\xb9\x1d\xb6m\x14\xe1\x16f1\x84\xda~\xa4s\r\xa4\t\xe8\n*\x86\u007fI\x13\xb6\x1aV\u028aZJ_\xc6Z\u00aa\"tf\x90~\x15m\xd8`G\xca?\xa4M\xc1\xa8\x8b\xb2v\x05\x92 \xa3I\xa4\x98\x93\x8d\xb7\xb4\x989t\x8dV@\x15\x98\x1c\a\xcb<=\x87\x19\xa4\xf4\xda=\x9cj\xeeHy\x8cNau\x89vI\x8d\x90\x1c\xe3;\x96\x17\x87G[$\x98\x97k*\xcd\xdd\x1d\x97D\xbeIH\xdd3\x9bbb\x14\x19\x199!\xa7l\x8a\xd1\xf1\x0f\xabo\xa7w\x9b\x9d\xab\b\r\xd3\xfd\xa9\f@\u05e0(\xa9J\x97OS\x8f9\x04\xb5\xa4\xd8\xff(\xf3C\xdc\xc4\u0305\xb4\xc4|\aP\nC\x91\x9e\u007fwUk\x1e*\xd4\xc6\x14`\xf4\xf0\x16\xfbo\x11\xfa-`n\xaeASZ\xeab\xa4\xe1b\x9dmX\xa3\x14\u05d6\xd5\xcew\xae\n_\xbe\xc9\xe9~\x15\xf9e\xa6\xf4\xc1}\x80\x9d\xf0\xe0\x1e\x99{\xdf\x15Q\xc7h\x80\x1f\u0090\x00\x15\xbf\xa2\xaa\xb6\xee\u0126\x04\u0336a*\x19\b2\x00\x93\xe3\xc6\t\x98\x01_\fu\xc2x\xaaFw\x12\x89\u0523@n \xe9\xf3\xaa\n\xb3\x0f`\xb1\xa01\xb4\u01c34\x8d\u074a\"\x85q\xa8\x1b\xee\x1f\x85\xd88\xff\u0091\xdd\x1c-{\u0205\xb1\xd6_\x02\x91\x9b'\x1fX\xe3d\xb9\u007f1\x9fA\xfes\x8b!;%0\x89q\x80\x1f\xc8\x12\r\x8a^&\x91t4w\xacX$\x02\x96\xbf \xba\n\x06\x83\xb9z\"\xc0\x85-\x8c\x885\x10\xadu\xd3\xd0\xcf&\xda\xef^\xf4\xf9s0\x10j7o\xc2;;^\xb7\xd2\x13r\xb3\x91g\v\x81\x90\xc0B\u025b\xe7\xdd\"\xb0\xf7f\xf3\x0f\x10\xa5B.QH\x8e\xe7=\xe0HO\xb1\x96\x06\x8c\xfc\"5`\x81\r\xf7`\x16\x88J\x8d\xa7\x0e\x814D\xf6\x1c\xe10\xda\x1a9K\xdcJ\f)\x00\xaa\u0460md\xe3I\xa8\u057a\a6Z\rJ;\xa7\x013QF\x023\xcfk\x1f\x88\x16r\x8a 1\u02a0\xd4\u05ac\xa6\xddZ8\x80r\xc45C\n\xfb\xc9\xf6\xef\xcc\xd6\n\tQq\x93\x99ZNQ\x83\x80\xa6@z\x81\xa7\xe2\x85\xc0\xaa[\xf3\u04660u\xe0\xe6\xccp\xac\x9c\xd8j+^])\x86\xa8\xa5\x86\xaea\xe8F\x8a\xb57\xc8aW\xac\xe8\x12\u01b2\x19AM]s0\"\xc0\x15)\x16\xa4\xbc\xc7`[\xf2\x8c3\xf0,\xaf\x17\x8d\x95\x98\x0e\x1a\x82\u007f)l\\A'@.\xf4\xd1,f\x01\xc5,I\x8f\xa9l\xe3\xe1/5\xeen\n\u0132\u0290\x97\xc7r\xb4f6|\x873\xb9\xb7\u0703k\x17\xec\xd6\x05]\x0f\xd2H\xbd]\xa3\xf5!1|\"J\x94\x0e\xb4E\xfd\x8b\x8a^W\x00\x1b4&\xb1\x1e\x8fN\x12\x0ej\xf2zt\u0261}\u05f6\x00\xdepp\xe1\xa5w\xb0Z\xc3HAI\\\x06\xea\x1e\x12,f8\xc6K\x9f\xb6\x11\x81l\u03b3\xf0\xc9eM>F/\xee\xec`\xa2\xe0\x03L\xeb\xdb(\xa4;\b\xc0\xa5\x1c\xe0\x15\xcd\x0f;\x139\x06\xd0@U=\x85o\xfe\xc7\x01]\x98\vX\xd7s=X\x82\xeea\x8d\x03`F8\x10\xab8\xb0\x1f8\x89\xe2\xc9\xc5rh}u\x12\xb2G6\x87\x1f:\x8e\x16\x99\xb1\x14X\xaa\x80\xf1Q\v\x9c\x1aV`\x86\f\x94%\x10\xef\xf00\xfcAFUL\xc0\x99\xda,\xae\x04\xb8\xfep<[\xb6 ;\xbe\xa7\xcfa\x84:\x037P\x92\n\x12u\x80\x85)3\x8f\x84\xc1\x83\x18\x84~\x84\x04\x96\x9f\xfd:(\x927\u0352\xd9K\b\x00\xd5N:\x18=(\xa7\u06e6\x14\xd0\b\x1a\x9d\u042b\xa1\xd3\u0468\xc8T\xa9\bP\xc0*\x01{/\f\xb3\x9e\u053f\"\xcbK\x15\xb6\xdb\x0e\x96\x8e[l\x93\xb0\x1a\x11\xee0\u02a7U\x01y\x92K\xf1\x1a\xf2Z2\xbcC\xf8&V0\xb6\xd8\x15\x96\xbe\"1B\xe6.!\x96lWsa%ra\x10\xea\x8e\x0e\u0206\xd0e\xb8\x86(T\xb1FV\xda\xd7Mzfr\x14\x85\x9d\xc1X\xbe\f\xb08\xf4\xa8\xe1\x01\x90\f\u0256\b\xf24R9V\xcc396P(\xbd\xd4\x1f\x00\a\xf2\x9a\xaeY\f\x91\x87a\xec\x17\xc1\xd5\u0464th0\u02f7\xb6jUk\xf2\x88s\xdc?D\xfcR\xa8H\xddd\v\r\xb8\xb9s\xc0\xb0\x89\xc6\xea\xb5Ld\xeb\x1f\xce]\x8c\x19B\xe0Up8U\x1e\x1c\xf1\xc9\xc09\x17T\xcd\x0eY\xf4\x10\x8eD\xb2'&\xa0\x87\x14\u013c\x9f;\xe8\xabZ\x94\x8f\rv\xee\xc1\x83[\u0109RiWH\xf4@\x97\xe5\xca:\xc3*\x1e]\xb2\u05b1\a\x05\xba\x951\x11\xac\xc2h\xceOn\x8d\xe1\xa2\x1a\x8a\xfb\u0682\\\xf2}`d\xd7\x16.)\x81E\xb5\u039bKVM\u00d4l7P\xa7\x1a\xef\xdaW\x04\x9d\x80\x82\xc4\xe6\u0775a\x1e\U000107c7\xb4$\xa4\xc1$\xdb\x1d\xees\xb3K\x9f\x1a0L\xd7\x17\x91\n\xad|<\\\xa2\xe0$/7\x1e\x0e\xe6h\x91n\x0fL\x8av[\xa6\x1ab\x96\xabL'\v\xae\\1aER->\u00f0\x8dc\x9c\xc7h\xf5\xb1\nP\x00\xd7Y(\xffe\x80Y\xb7\u0563\x84in\u01de\x89\x0e\x99O\xe3e\x8d4I\xd0") + +func third_partySwaggerUiFontsDroidSansV6LatinRegularEotBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6LatinRegularEot, nil +} + +func third_partySwaggerUiFontsDroidSansV6LatinRegularEot() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6LatinRegularEotBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.eot", size: 22008, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6LatinRegularSvg = []byte(` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`) + +func third_partySwaggerUiFontsDroidSansV6LatinRegularSvgBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6LatinRegularSvg, nil +} + +func third_partySwaggerUiFontsDroidSansV6LatinRegularSvg() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6LatinRegularSvgBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.svg", size: 72148, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6LatinRegularTtf = []byte("\x00\x01\x00\x00\x00\x11\x01\x00\x00\x04\x00\x10GDEF\x00\x10\x00\xd2\x00\x00\x85\xbc\x00\x00\x00\x16GPOS\xf2ZM^\x00\x00\x85\xd4\x00\x00\x12\xc0GSUB\x00\x15\x00\n\x00\x00\x98\x94\x00\x00\x00\fOS/2\xa0\u04f5e\x00\x00u\xb4\x00\x00\x00`cmapmag\xda\x00\x00v\x14\x00\x00\x00\x8ccvt 9~>L\x00\x00\x80\x94\x00\x00\x01\xfcfpgms\xd3#\xb0\x00\x00v\xa0\x00\x00\a\x05gasp\x00\x04\x00\a\x00\x00\x85\xb0\x00\x00\x00\fglyfI;\f|\x00\x00\x01\x1c\x00\x00o(head\xf5\xf5 \xd3\x00\x00r\f\x00\x00\x006hhea\r\xc4\x05\x8a\x00\x00u\x90\x00\x00\x00$hmtxmsT\xd3\x00\x00rD\x00\x00\x03Lloca\xbe\x8a\u06c8\x00\x00pd\x00\x00\x01\xa8maxp\x03i\x01\xd3\x00\x00pD\x00\x00\x00 name\x14\x910\xde\x00\x00\x82\x90\x00\x00\x018post\xa2\xc2\x0f;\x00\x00\x83\xc8\x00\x00\x01\xe7prep\x82\xdc!\x13\x00\x00}\xa8\x00\x00\x02\xec\x00\x02\x00\x93\xff\xe3\x01\x91\x05\xb6\x00\x03\x00\x17\x00:\xb9\x00\x01\xff\xf0@\x13\n\x14H\x10\x19\x80\x19\x90\x19\xa0\x19\x04\x03\x0e\x9a\x04\x02\x02\x04\xb8\xff\xc0@\n\a\nH\x04\x01\t\x9b\x13\x02\x03\x00?/\xf5\xce\x01/+3/\x10\xe12]10+\x01#\x033\x034>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01Py3\xdf\xf0\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14\x01\x9e\x04\x18\xfa\xb9&5!\x0f\x0f!5&%5\"\x10\x10\"5\x00\x00\x00\x00\x02\x00\x85\x03\xa6\x02\xb2\x05\xb6\x00\x03\x00\a\x007@#\x04\x98\a\a\t\xd0\t\xe0\t\x02/\to\t\u007f\t\x03\x00\x98\x00\x03\x10\x03\xe0\x03\xf0\x03\x04\x03\x06\x02\x02\a\x03\x03\x00?33/3\x01/]\xe1]]\x129/\xe110\x01\x03#\x03!\x03#\x03\x01J)s)\x02-)r)\x05\xb6\xfd\xf0\x02\x10\xfd\xf0\x02\x10\x00\x00\x02\x003\x00\x00\x04\xf8\x05\xb6\x00\x1b\x00\x1f\x00\x99@X\x03\x03\x1a\x1a\x18\x16\x1e\x1d\a\x04\x06\x17\x17\x06\x19\x00\x01\x04\x04\x05\xb1\x18\x18!\x15\x1f\x1c\b\x04\t\x14\x14\x12\x0f\x0e\v\x04\x13\xb1\nP\x10\x01\x10\x10\f\f\tP\n\x01\n\x1c\x01H\r\x01\r\xae\f\b\x04\f\x1f\x00\x10\xae\x11\x19\x15\x11?\x11O\x11\xdf\x11\x03\f\x11\f\x11\x05\x17\x13\x06\n\x05\x00/3?3\x1299//]\x1133\x10\xe122\x1133\x10\xe1]22\x01/]33/3/]\x10\xe4\x1792\x11\x12\x179\x113/\xe4\x17923\x11\x12\x179\x113/3/10\x01\x03!\x15!\x03#\x13!\x03#\x13!5!\x13!5!\x133\x03!\x133\x03!\x15\x01!\x13!\x03\xd7?\x01\x18\xfe\xcdR\x93T\xfe\xddR\x90N\xfe\xfe\x01\x1dA\xfe\xee\x01+R\x93R\x01%T\x90T\x01\x06\xfc\xeb\x01#@\xfe\xdd\x03}\xfe\xb8\x89\xfeT\x01\xac\xfeT\x01\xac\x89\x01H\x89\x01\xb0\xfeP\x01\xb0\xfeP\x89\xfe\xb8\x01H\x00\x03\x00{\xff\x89\x03\xd9\x06\x12\x00-\x006\x00?\x00\xb4@34/)\x01)/!\x01!\x06p/<\x01\x02753\x15\x1e\x01\x17\a.\x01'\x11\x1e\x03\a4.\x02'\x11>\x01\x01\x14\x1e\x02\x17\x11\x0e\x01\x03\xd92]\x85T\x8a2f`T !W`e/Y\x83V*1[\x81O\x8ad\xa9CB8\x8cJX\x87[.\xb0\x14+F3][\xfe\x12\x11(B1YS\x01\xbeFrT7\f\xe6\xdd\t\x12\x1a\x11\xac\x10!\x1a\x11\x01\xb2\x1eBUnJCoS5\t\xb4\xb0\x05*\x1f\x91\x19)\x06\xfeZ\x1fBSkH!7-&\x12\xfe\x8b\x0eb\x02\xa3$9/&\x11\x01q\x10Y\x00\x00\x00\x00\x05\x00f\xff\xec\x063\x05\xcb\x00\t\x00\x1d\x00'\x00;\x00?\x00]\xb2<\x10>\xb8\xff\xf0@3<><>(\x14\x1e\xb42\xb5#\xb4(A\x0fA\x01\x05\xb4\n\xb5\x00\xb4\x10\x14 \x140\x14\x03\x14?\x06>\x18%\xb67\xb7!\xb6-\x19\x03\xb6\x0f\xb7\a\xb6\x19\a\x00?\xe1\xf4\xe1?\xe1\xf4\xe1??\x01/]\xe1\xf4\xe1]\x10\xde\xe1\xf4\xe1\x11\x1299//8810\x13\x14\x1632\x11\x10#\"\x06\x05\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x01\x14\x1632\x11\x10#\"\x06\x05\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\t\x01#\x01\xfaGP\x9c\x9cPG\x01\xc7$JsOIpL&#IqNKqM'\x01\xacGP\x9c\x9cPG\x01\xc6#JsOJpK&#IqNKqL'\xff\x00\xfc\u055e\x03,\x04\x02\xa5\xa5\x01J\x01H\xa3\xa5l\xacv??v\xacll\xaau>>u\xaa\xfdJ\xa5\xa4\x01I\x01H\xa3\xa5l\xabv??v\xabll\xaau>>u\xaa\x03\x92\xfaJ\x05\xb6\x00\x00\x00\x00\x03\x00m\xff\xec\x05}\x05\xcd\x00\x11\x00!\x00S\x00\x80@M'\x18\x17J\x04I,IH\nG6AGB B\x016B6B\x1d\x05;\x0354.\x02#\"\x06\x132>\x027\x01\x0e\x03\x15\x14\x1e\x02%4>\x027.\x0354>\x0232\x1e\x02\x15\x14\x0e\x02\a\x01>\x0373\x0e\x03\a\x01#'\x0e\x03#\".\x02\x01\xa6\x10!4$;V8\x1c\x19/B*Vd\x87:bTH \xfe}4P7\x1c#B`\xfe}(MoG\x1f<-\x1c2^\x8aXS\x83[02Tm<\x01`\x1b+\"\x1b\n\xb8\x0f)5A'\x01\x15\xe1\xa81`l|Ni\xa7s=\x04\x8d\"AAC%#>@F)$=,\x19Y\xfb\xaf\x17(6\x1f\x01\x97!?HU86[A$\xf0NzdV*$MWc9KwS++SwK@m]O$\xfe\x8c\x1d\x0273\x06\x02\x15\x14\x1e\x02\x17#.\x03R$JqN\xac\x8c\x91%GjE\xaaNqJ$\x021}\xf3\xe5\xd3]\xc1\xfe2\xf4w\xec\xe2\xd4^Z\xce\xe1\xf0\x00\x00\x00\x00\x01\x00=\xfe\xbc\x02\x17\x05\xb6\x00\x13\x00\x1c@\x0e\x06\x0e\xf2\v\xf0\xb0\x00\x01\x00\x15\x0e\xf8\x05\xf9\x00??\x01\x10\xde]\xe1\xe4210\x01\x14\x0e\x02\a#>\x0354\x02'3\x1e\x03\x02\x17$KqN\xaaEjH$\x90\x8d\xacNqK$\x021|\xf0\xe1\xceZ^\xd4\xe2\xecw\xf4\x01\xce\xc1]\xd3\xe5\xf3\x00\x00\x01\x00R\x02w\x04\x14\x06\x14\x00\x0e\x00$@\x15\x1f\x10\x01\x00\x98\x00\x0e\x80\x0e\x90\x0e\x03\b\x0e\x1f\x06\x01\x06\x06\x00\x00\x00?2/]\x01/^]\xe5]10\x01\x03%\x17\x05\x13\a\v\x01'\x13%7\x05\x03\x02\x98+\x01\x8d\x1a\xfe\x86\xf5\xb2\xb0\x9e\xb8\xf2\xfe\x89\x1d\x01\x87+\x06\x14\xfewo\xc1\x1c\xfe\xba`\x01f\xfe\x9a`\x01F\x1c\xc1o\x01\x89\x00\x00\x01\x00f\x01\x06\x04\x02\x04\xa2\x00\v\x00)@\x18\x10\r\x01\x06\t\xaa\x03\xef\x00\x01 \x00`\x00\xa0\x00\x03\x00\t\x00\xad\x06\x03\xb3\x00?3\xe12\x01/]]2\xe12]10\x01!5!\x113\x11!\x15!\x11#\x01\xe9\xfe}\x01\x83\x96\x01\x83\xfe}\x96\x02\x87\x96\x01\x85\xfe{\x96\xfe\u007f\x00\x00\x00\x00\x01\x00?\xfe\xf8\x01y\x00\xee\x00\f\x008@\x14\xcf\x0e\x01\x10\x0e\x90\x0e\xa0\x0e\x03\x1b\f+\f\x02\f\x01\x97\x06\a\xb8\xff\xc0@\r\x10\x14H_\a\x01\x10\a\x01\a\x06\x9c\f\x00/\xed\x01/]]+3\xed2]]]10%\x17\x0e\x03\a#>\x037\x01j\x0f\x0e'/3\x19\x8a\x0f\x1d\x1b\x16\b\xee\x176z|{8=\x84\x83}5\x00\x00\x00\x00\x01\x00R\x01\xd1\x02B\x02y\x00\x03\x00\x15@\t\x02\x05@\x00\x01\x00\x00\xb9\x01\x00/\xe1\x01/]\x10\xce10\x135!\x15R\x01\xf0\x01\u0468\xa8\x00\x00\x00\x01\x00\x93\xff\xe3\x01\x91\x00\xfa\x00\x13\x005@\x1b\x80\x15\x90\x15\xa0\x15\x03\x11\x15\x01\n\x96\xc0\x00\xd0\x00\x024\x00D\x00d\x00t\x00\x04\x00\xb8\xff\xc0\xb6\a\nH\x00\x05\x9b\x0f\x00/\xed\x01/+]]\xed]]1074>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x93\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14o&5!\x0f\x0f!5&%5\"\x10\x10\"5\x00\x01\x00\x14\x00\x00\x02\xe7\x05\xb6\x00\x03\x00\x1e\xb1\x01\x02\xb8\xff\xf0@\t\x02\x03\x00\x10\x00\x05\x01\x00\x03\x00?/\x11\x01382/8310\t\x01#\x01\x02\xe7\xfd\xe0\xb3\x02!\x05\xb6\xfaJ\x05\xb6\x00\x00\x00\x00\x02\x00b\xff\xec\x04\b\x05\xcd\x00\x13\x00'\x00&@\x15\x1eo\x00)\x10)\x01\x14o \n\x01\n#s\x0f\a\x19s\x05\x19\x00?\xe1?\xe1\x01/]\xe1]\x10\xde\xe110\x01\x14\x02\x0e\x01#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x04\b3q\xb2\u007fv\xafs93o\xb1~w\xb0t:\xfd\x13\x1eBkMMlE\x1f\x1fElMMkB\x1e\x02\u0771\xfe\xe8\xc2ff\xc2\x01\x18\xb1\xb1\x01\x18\xc1fe\xc1\xfe\u8c96\xe0\x95KJ\x94\u15d6\xe0\x94JJ\x94\xe0\x00\x00\x01\x00\xb2\x00\x00\x02\xc7\x05\xb6\x00\x10\x005@!@\x12\x01\x0f\x01\x0e\x0e\x00n\xbf\x01\xff\x01\x02~\x01\x01\x00\x01\x10\x01 \x01@\x01\x04\x06\x01\r\x0f\x06\x00\x18\x00??\xcd\x01/^]]]\xe13/\x113]10!#\x114>\x027\x0e\x03\x0f\x01'\x013\x02\u01f0\x01\x03\x03\x01\x11\x1a\x1b\x1e\x15\x94`\x01\u007f\x96\x03\x91+baY\"\x12\x1a\x18\x1b\x12y{\x01+\x00\x00\x00\x01\x00`\x00\x00\x03\xf0\x05\xcb\x00#\x00<@ #\bo\x1b\x1b%\x10%\x01\"o\x01!\x01\x11\x11 \x01\x01\x01\b\"\x10\rs\x16\a\x02\"t\x01\x18\x00?\xe12?\xe13\x129\x01/]3/\x113\x10\xed]\x113/\xe1310)\x015\x01>\x0354.\x02#\"\x06\a'>\x0332\x1e\x02\x15\x14\x0e\x02\a\x01\x15!\x03\xf0\xfcp\x01^KvS,\"?V5_\x99Ef(\\jvA`\x9bl;5]\x81K\xfe\xe7\x02\xb1\x9c\x01}Q\x86\x80\x81L;Z? M\x0254.\x02+\x01532>\x0254.\x02#\"\x06\a'>\x0332\x1e\x02\x03\xc1.StG\xb1\xb8A\x84\u028am\xc1UW\xcb]\\\x86W)5b\x8dY\x85\x85Q~U,$B\\8k\xa3J\\&]n}Fl\xa3n8\x04`IxX9\f\x06\x16\xb5\x91`\xa0t@\"-\xaa.2(JlCDa?\x1e\x97(Jf=4R9\x1eC6}\x1f6)\x186a\x85\x00\x02\x00\x17\x00\x00\x04?\x05\xbe\x00\n\x00\x18\x00N@,\tV\x00\x01\x00\x00\x02n\x11\f\v\a \x03\x01\x03\x03\x1a\x10\x1a\x01w\x18\x87\x18\x02\x18_\x05\x01\x05\t\x06\x18t\x01\x05\x05\x02\x11\a\x06\x02\x18\x00??3\x129/3\xe122\x01/]3]]\x129/]3333\xe12/]210\x01#\x11#\x11!5\x013\x113!\x114>\x027#\x0e\x03\a\x01\x04?\u0570\xfd]\x02\x97\xbc\xd5\xfe{\x03\x04\x05\x01\t\a\x15\x19\x1a\v\xfee\x01H\xfe\xb8\x01H\x9f\x03\xd7\xfc0\x01d8{uf\"\x1411.\x10\xfd\xa0\x00\x00\x00\x00\x01\x00\x83\xff\xec\x03\xf6\x05\xb6\x00*\x00N@\x18&\x1ao\x05,\x10,\x01'$$(h#\x01Y#\x01##\xf0\x0f\x01\x0f\xb8\xff\xc0@\x12\b\vH\x0f\x1ds\x00\x00\x15't$\x06\x15s\x10\n\x19\x00?3\xe1?\xe1\x129/\xe1\x01/+]3/]]33\x113]\x10\xde\xe1310\x012\x1e\x02\x15\x14\x0e\x02#\".\x02'5\x1e\x0332>\x0254&#\"\x0e\x02\a'\x13!\x15!\x03>\x01\x02!c\xab\u007fHD\x86\u01403c[R!!Ybc*O|V.\xb0\xa8\x1b??9\x15Z7\x02\xb2\xfd\xec' i\x03\x817l\xa0ir\xb6~C\n\x13\x1e\x14\xac\x17$\x18\r%NvQ\x8f\x97\x05\b\t\x049\x02\xb0\xa6\xfe]\x06\x0e\x00\x00\x00\x00\x02\x00q\xff\xec\x04\n\x05\xcb\x00+\x00?\x007@ 1n\f\"A\x10A\x01\x17;o\x00\x00\x10\x00 \x00\x03\x006u\x1d\x1d\a,s'\x19\x10s\a\a\x00?\xe1?\xe1\x119/\xe1\x01/]\xe12]\x10\xde2\xe110\x134>\x0432\x1e\x02\x17\x15.\x01#\"\x0e\x04\a3>\x0332\x1e\x02\x15\x14\x0e\x02#\".\x02\x012>\x0254.\x02#\"\x0e\x02\x15\x14\x1e\x02q\x155\\\x8e\u0185\x13./+\x11#X+Z\x89dC*\x14\x03\f\x149L_;_\x9al;>t\xa4fd\xaf\x80J\x01\xdbn\xd5#\x01\xcc#\x01\xba#\x01##\x10\x19 \x19\x02\x19\n\x1eh8\x988\x02Y8\x01(888H8\x038\x93C\x01&CVC\x02CC\x00-s\x14\x19;s\x00\a\x00?\xe1?\xe1\x119/]]\xc1]]]99\x01/]3/]]]\xe1\x10\xe1]\x10\xce2/]]\xe1\x129\x10\xe1\x11910\x012\x1e\x02\x15\x14\x0e\x02\a\x1e\x03\x15\x14\x0e\x02#\".\x0254>\x027.\x0354>\x02\x03\x14\x1e\x0232>\x0254.\x02/\x01\x0e\x01\x01\"\x06\x15\x14\x1e\x02\x17>\x0354&\x025T\x95qB(F`8:oW5Cy\xa9fn\xabu=-Lh:1V?%Cr\x95\xc7 DhHFkH$'If?\x1e~\x80\x01\x16j}#>W30U?$~\x05\xcd,X\x84XClWE\x1c\x1fL_vI\\\x95h86e\x92\\Kx`J\x1c\x1fIZmBW\x83X,\xfb\xa65Y?##A\\84TH@\x1f\x0e<\x9b\x03Tje9R@3\x18\x164BT6ej\x00\x00\x02\x00j\xff\xec\x04\x04\x05\xcb\x00)\x00=\x005@\x1e9\x15o\x00?\x10?\x01/n\f\x10 \x02 4u\x1b\x1b\a*s%\a\x10u\a\x1a\x00?\xe1?\xe1\x119/\xe1\x01/]3\xe1]\x10\xde\xe1210\x01\x14\x0e\x04#\".\x02'5\x1e\x0132>\x027#\x0e\x03#\".\x0254>\x0232\x1e\x02\x01\"\x0e\x02\x15\x14\x1e\x0232>\x0254.\x02\x04\x04\x155\\\x8e\u0185\x13..,\x11#X+\x87\xaef+\x05\r\x148L`;_\x9al;?s\xa5fe\xae\x80J\xfe%.\x1a;r\xa5jr\xb7\u007fDN\xa0\xf3\x01G(T\u007fWFoN*/K`0C\x85kB\x00\x00\x00\x00\x02\x00\x93\xff\xe3\x01\x91\x04f\x00\x13\x00'\x00>@\x1c\x10)\x80)\x90)\xa0)\x04\x1e\n\x96\x14\xc0\x00\xd0\x00\x024\x00D\x00d\x00t\x00\x04\x00\xb8\xff\xc0@\v\a\nH\x00#\x9b\x19\x10\x05\x9b\x0f\x00/\xed?\xed\x01/+]]3\xe52]1074>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x114>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x93\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14o&5!\x0f\x0f!5&%5\"\x10\x10\"5\x03\x91'5!\x0e\x0e!5'%4\"\x10\x10\"4\x00\x02\x00?\xfe\xf8\x01\x91\x04f\x00\f\x00 \x00a@/\x10\"\x80\"\x90\"\xa0\"\x04\x17\x96\xc0\r\xd0\r\x02d\rt\r\x02P\r\x01D\r\x01;\r\x01\x1f\r/\r\x02\r\r\x1b\f+\f\x02\f\x01\x97\x06\a\xb8\xff\xc0@\x11\x10\x14H_\a\x01\x10\a\x01\a\x1c\x9b\x12\x10\x06\x9c\f\x00/\xed?\xed\x01/]]+3\xed2]3/]]]]]]\xe5]10%\x17\x0e\x03\a#>\x037\x034>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01j\x0f\x0e'/3\x19\x8a\x0f\x1d\x1b\x16\b\x11\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14\xee\x176z|{8=\x84\x83}5\x02\xed'5!\x0e\x0e!5'%4\"\x10\x10\"4\x00\x00\x00\x01\x00f\x00\xee\x04\x02\x04\xdd\x00\x06\x00N@0\x00\b@\b\x01@\x01\x01\x01\x02\x01\x05\x05\x03\x06o\x00\u007f\x00\x020\x00\x01\x00\x00\x04 \x03\x01P\x03p\x03\x80\x03\xd0\x03\xf0\x03\x05?\x03\x01\x00\x03\x01\x06\x03\x00/^]]]q33/]]2\x129=/33\x01\x18/]]\x10\xce10%\x015\x01\x15\t\x01\x04\x02\xfcd\x03\x9c\xfd!\x02\xdf\xee\x01\xa8f\x01\xe1\xa0\xfe\x94\xfe\xbe\x00\x02\x00f\x01\xba\x04\x02\x03\xe9\x00\x03\x00\a\x00\\@=\a\x02\t@\t\x01\x04\xc6\x00\x01\xbb\x00\x01\xa9\x00\x01\x86\x00\x01{\x00\x01h\x00\x01B\x00\x019\x00\x01\x00\x04\xad\x1f\x05/\x05\x02\u007f\x05\x01\x00\x05\x10\x05\x02\x06\x05\x05\x00\xad\xf0\x01\x01\x0f\x01o\x01\x02\x01\x00/]]\xe13/^]]q\xe1\x01/]]]]]]]]3]\x10\xce210\x135!\x15\x015!\x15f\x03\x9c\xfcd\x03\x9c\x03T\x95\x95\xfef\x96\x96\x00\x00\x01\x00f\x00\xee\x04\x02\x04\xdd\x00\x06\x00N@0\x05\b@\b\x01@\x06\x01\x06\x05\x04\x01\x01\x03\x00o\x06\u007f\x06\x020\x06\x01\x06\x06\x02 \x03\x01P\x03p\x03\x80\x03\xd0\x03\xf0\x03\x05?\x03\x01\x00\x03\x01\x06\x03\x00/^]]]q33/]]3\x129=/33\x01\x18/]]\x10\xce10\x13\t\x015\x01\x15\x01f\x02\xe0\xfd \x03\x9c\xfcd\x01\x8f\x01B\x01l\xa0\xfe\x1ff\xfeX\x00\x02\x00%\xff\xe3\x03%\x05\xcb\x00'\x00;\x00>@!2\x9a(('F\x00\x00\x14\vF\x1c=/=\x01\x14\v\x17\x0f\x00\x01\x06\x00\x00-\x9b7\x13\x10Q\x17\x04\x00?\xe13/\xe52/^]\x129\x01/]\x10\xde\xe1\x119/\xe13/\xe110\x0154>\x027>\x0354.\x02#\"\x06\a'>\x0132\x1e\x02\x15\x14\x0e\x02\a\x0e\x03\x1d\x01\x034>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x01\x19\x0f'B20D+\x15\x1e9U8S\x96F?Q\xbca]\x95h8\x1b6P64B&\x0e\xbb\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14\x01\x9e%9\\PM*)CEO50O9\x1f4\"\x91*;3`\x8bWCiZT/-C?B,\x12\xfe\xd1&5!\x0f\x0f!5&%5\"\x10\x10\"5\x00\x00\x00\x02\x00m\xffJ\x06\x81\x05\xb6\x00W\x00h\x00o@?X\x17`'\x1f\x17\x01\u007f'\x01\x17'FF'\x17\x03N1 \x00\x01\x00j@j\x01;@N\x01N,\f[\x12\a\x12d\x1c\x0f\x12\x1f\x12\xbf\x12\x03\x06\x00\x1c\x01\a\x12\x1c\x12\x1c@6S\x03@EI\x00/3\xc1?\xc1\x1299//^]^]\x10\xc1\x113\x10\xc122\x01/]\xc1]\x10\xdeq\xc1\x11\x179///]]\x10\xc1\x10\xc110\x01\x14\x0e\x04#\".\x02'#\x0e\x03#\".\x0254>\x0232\x1e\x02\x17\x03\x0e\x01\x1c\x01\x15\x14\x1e\x0232>\x0254.\x02#\"\x04\x06\x02\x15\x14\x1e\x0232>\x027\x15\x0e\x01#\"$&\x0254\x126$32\x04\x16\x12\x01\x14\x1632>\x02?\x01.\x01#\"\x0e\x02\x06\x81\x13%9La:-I4!\x06\x04\x126GY5MwR+;o\x9eb-ZRE\x17\x17\x01\x01\x15\"+\x17.F/\x18V\x98\xd1{\xa9\xfe\xfe\xafZO\x99\xe3\x93=wod+V\u0602\xb3\xfe\xe7\xc3fv\xdb\x017\xc1\x9c\x01\x06\xbfj\xfc\x15eU7N2\x1a\x04\x0e\x1cM*Je?\x1c\x02\xdb>}qaH)\x1e2A#%B1\x1c8e\x8eVe\xa8zD\b\x0e\x11\b\xfe`\x16\x1b\x10\b\x035D(\x0f=h\x8cN\x8e\u0758Oo\xc7\xfe\uf897\xea\xa0R\x0e\x18\x1f\x11\x8d&,f\xc3\x01\x19\xb3\xbc\x01E\xee\x88e\xbd\xfe\xf1\xfe\u0545w-SsE\xfd\b\r:^x\x00\x00\x02\x00\x00\x00\x00\x04\xdd\x05\xbc\x00\a\x00\x14\x00\x84@$\x06\x05F\x02\x01F\x14\x01\x02\x14\x03I\b\x01I\x01\x01\b\x01\x00\x0e\x0e\x03\x00\x00\x10\a\x01\x80\a\x90\a\xd0\a\x03\a\xb8\xff\xc0@\x18\x06\nH\a\x10\a\a\x16\x0f\x16\x1f\x16/\x16\x8f\x16\x9f\x16\xdf\x16\x06\a\x03\x04\xb8\xff\xf0@\x11\x04\x02_\x0e \n\x0eH\x0e\x05\x14\x14\x05\x03\x04\x00\x12\x00?2?9/\x129+\xe1\x01/83^]\x113/8+]q3\x11\x129=/\x1299]]\x1299]]3310!\x03!\x03#\x013\t\x01\x03.\x03'\x0e\x03\a\x03\x04\x1f\xa0\xfd\u07e2\xbc\x02\x19\xaa\x02\x1a\xfeg\x94\x06\x11\x12\x12\b\a\x12\x12\x11\x06\x91\x01\xc5\xfe;\x05\xbc\xfaD\x02j\x01\xa8\x124\v\x1eZ\x05\x06\x01\xe5\x06\xf5\x06\x02\xd6\x06\x01\x06\x06$*[p\x11\x80\x11\x02\x11g1\u007f1\x8f1\x02\x101\x01\x18$Z\x17d0\v#`y\x18\x01\v\x18\x01\b\x18\x18\x00$`\x17\x12\"`\x00\x03\x00?\xe1?\xe1\x119/^]]\xe19\x01\x10\xf6\xe12]]\x10\xf6]\xe1\x129/]]q\xe1210\x13!2\x1e\x02\x15\x14\x0e\x02\a\x15\x1e\x03\x15\x14\x0e\x02#!\x1332>\x0254&+\x01\x19\x01!2>\x0254.\x02#\xc7\x01\x8f\x80\u00c3B'JmEEyZ4A{\xb0o\xfe\x1b\xba\xf4TrF\x1f\x9a\xa6\xdf\x01\nXwI !K|\\\x05\xb6'W\x8dg>lR7\t\n\f-OxVd\x9dm:\x03J\x1e;Y;xh\xfd\x97\xfd\xf0(He=8^C%\x00\x00\x00\x00\x01\x00}\xff\xec\x04\x98\x05\xcb\x00#\x00L@\x14\xaf\x0e\x01\x0e@\x15\x18H\x0e\x0e\x18\xba \x01` p \x02 \xb8\xff\xc0@\x18\x06\nH %\xaf%\x01\x05[\x18f$!\x00_\x1d\x04\r\n_\x13\x13\x00?\xe13?\xe13\x01\x10\xf6\xe1]\x113/+]]\x129/+]10\x01\"\x0e\x02\x15\x14\x1e\x023267\x15\x0e\x03#\".\x01\x0254\x12>\x0132\x16\x17\a.\x01\x03\x19k\xae{C;v\xb0vY\xa0N'NUa;\xa4\xf0\x9dLW\xa9\xfa\xa2l\xc4ON?\x94\x05'Q\x98\u0689\x8d\u06d6N#\x17\xa2\x0f\x17\x0e\al\xc6\x01\x16\xa9\xa6\x01\x14\xc6n,*\x9c .\x00\x00\x00\x02\x00\xc7\x00\x00\x04\xfc\x05\xb6\x00\f\x00\x17\x00&@\x15\r[\x00g\x19\x10\x19\x01\x14Z\x06d\x18\x13`\a\x03\x14`\x06\x12\x00?\xe1?\xe1\x01\x10\xf6\xe1]\x10\xf6\xe110\x01\x14\x02\x06\x04#!\x11!2\x1e\x01\x12\a4.\x02+\x01\x113 \x00\x04\xfc`\xb6\xfe\xf7\xa8\xfe\x92\x01\x97\x99\xf8\xae_\xc5B~\xb8u\u0262\x01\b\x01\f\x02\xe9\xb9\xfe\xe9\xbb^\x05\xb6\\\xb5\xfe\xf4\xb6\x92\u054aC\xfb\x89\x01$\x00\x00\x00\x00\x01\x00\xc7\x00\x00\x03\xbe\x05\xb6\x00\v\x00B@&\x14\b\x01\b\b\x01\x04\x00g\r\x06\nZ\x01d\f\t_O\x06\x01\x0f\x06\xaf\x06\x02\b\x06\x06\n\x05_\x02\x03\n_\x01\x12\x00?\xe1?\xe1\x129/^]q\xe1\x01\x10\xf6\xe12\x10\xe62\x119/]10)\x01\x11!\x15!\x11!\x15!\x11!\x03\xbe\xfd\t\x02\xf7\xfd\xc3\x02\x17\xfd\xe9\x02=\x05\xb6\xa4\xfe<\xa2\xfd\xf8\x00\x00\x00\x01\x00\xc7\x00\x00\x03\xbe\x05\xb6\x00\t\x00p@\x11\b\b\x01\x0f\x03\x01\xff\x03\x01\x80\x03\x90\x03\xd0\x03\x03\x03\xb8\xff\xc0@8\a\nH\x03\x03\v\x0f\v/\v\x8f\v\xaf\v\x04\a\x06\x00Z\x01d\n\t_\x0f\x06\x01\x0f\x06?\x06o\x06\xff\x06\x04\b\x06@\x1a\x1dH\x06@\x10\x15H\x06\x06\x00\x05_\x02\x03\x00\x12\x00??\xe1\x129/++^]q\xe1\x01\x10\xf6\xe12^]\x113/+]]q\x129/10!#\x11!\x15!\x11!\x15!\x01\x81\xba\x02\xf7\xfd\xc3\x02\x17\xfd\xe9\x05\xb6\xa4\xfd\xfc\xa4\x00\x00\x00\x00\x01\x00}\xff\xec\x04\xf2\x05\xcb\x00+\x007@\x1e++\f)Z\x14\x02g-\x10-\x01\x1f[\ff,+_\x00\x00$\x1a_\x11\x04$_\a\x13\x00?\xe1?\xe1\x129/\xe1\x01\x10\xf6\xe1]\x10\xf62\xe1\x119/10\x01!\x11\x0e\x03#\".\x01\x0254\x126$32\x16\x17\a.\x03#\"\x0e\x02\x15\x14\x1e\x0232>\x027\x11!\x03\x0e\x01\xe47pv\x82K\x9d\xf2\xa6V_\xb6\x01\v\xabo\xccXH$SX].z\xbc\u007fB7x\xbe\x86,I>7\x1a\xfe\xd5\x03\x04\xfd3\x12\x1c\x13\ni\xc3\x01\x17\xae\xac\x01\x16\xc3i,*\xa2\x11\x1e\x17\x0eQ\x98\u0689\x82\u061cV\x05\b\v\x05\x01\xb4\x00\x00\x01\x00\xc7\x00\x00\x04\xd5\x05\xb6\x00\v\x00=@#\t\x01Z\x00e\r\xc0\r\x01\xbf\r\x01 \r\x01\b\x04Z\x05d\f\x03_\x0f\b\x01\b\b\b\n\x06\x03\x05\x00\x12\x00?2?39/^]\xe1\x01\x10\xf6\xe12]]]\x10\xf6\xe1210!#\x11!\x11#\x113\x11!\x113\x04\u057a\xfdf\xba\xba\x02\x9a\xba\x02\xaa\xfdV\x05\xb6\xfd\x98\x02h\x00\x00\x01\x00R\x00\x00\x02d\x05\xb6\x00\v\x00W@&\v\r+\r\x02{\r\x9b\r\xab\r\xfb\r\x04T\r\x01+\r;\rK\r\x03\x1f\r\x01\x02\b\v\nZ\x05\x02\xc9\x03\x01\x03\xb8\xff\xf8@\x10\r\x10H\x00\x03\x01\x06\x03\t\x04\x06\x03\x03\n\x00\x12\x00?\xc12?\xc12\x01/^]+]\xc12\xf1\xc12_]]]]q10)\x0157\x11'5!\x15\a\x11\x17\x02d\xfd\ueb2c\x02\x12\xac\xacf)\x04\x98)ff)\xfbh)\x00\x00\x00\x01\xffH\xfe{\x01s\x05\xb6\x00\x13\x00/@\x1c\xdf\x15\x01`\x15p\x15\x02/\x15\x01\x0fZ\f\x03\x03\x00\f\x10\f\x02\a\f\r\x03\a_\x00\x00/\xe1?\x01/^]3/\x10\xe1]]]10\x03\"&'5\x1e\x0132>\x025\x113\x11\x14\x0e\x02\x1d3L\x1c\"N-%K=&\xbb;i\x93\xfe{\r\v\xa0\t\v\x132XD\x05\xb6\xfa^i\x9ae1\x00\x00\x00\x00\x01\x00\xc7\x00\x00\x04\xa2\x05\xb6\x00\f\x00d@-\x02\ff\f\x01\f\x00\n\v\x10\v\v\x01\x00\x00\x10\x00\x02\a\x00\x10\x00\x00\x0e\xb0\x0e\x01/\x0e\x01\x10\x0e\x01\b\x04Z\x05d\r\x02\x10\v\x10H\b\xb8\xff\xf0@\f\v\x10H\x02\b\x05\n\x06\x03\x00\x05\x12\x00?3?3\x1299++\x01\x10\xf6\xe12]]]\x113/8^]33/83\x119]\x11310!#\x01\a\x11#\x113\x117\x013\x01\x04\xa2\xd3\xfe=\x8b\xba\xbay\x01\xc4\xd1\xfd\xf8\x02\xbar\xfd\xb8\x05\xb6\xfd%\xa8\x023\xfd\x83\x00\x00\x01\x00\xc7\x00\x00\x03\xbe\x05\xb6\x00\x05\x00#@\x13\x04\a\xaf\a\x01\x10\a\x01\x03Z\x00d\x06\x01\x03\x03_\x00\x12\x00?\xe1?\x01\x10\xf6\xe1]]\x113103\x113\x11!\x15\u01fa\x02=\x05\xb6\xfa\xf0\xa6\x00\x01\x00\xc7\x00\x00\x06/\x05\xb6\x00\x19\x00\x8b@\x136\x19\x019\x00\x01\x17\x0e\b\f\x0fH9\x0e\x01\x0e\x11Z\x19\xb8\xff\xf8@\x1c\f\x0fH\x19\x00\b\f\x0fH\x00\r\r\f\t\x10e\x1bO\x1b\x01 \x1b\x01\x0f\x1b\x01\b\v\xb8\xff\xf8@\x1a\f\x0fH&\v\x01\v\x02\bZ\td\x1a\x18\x01\x01\x10\t\x12H\x01\x0e\v\x03\x11\f\xb8\xff\xf0\xb6\t\x12H\f\b\x00\x12\x00?22+2?33+\x113\x01\x10\xf6\xe122]+^]]]\x10\xf6\x1199\x113+3+\xe12]+210]]!\x01#\x16\x17\x1e\x01\x15\x11#\x11!\x013\x01!\x11#\x1146767#\x01\x03#\xfeE\b\x06\x04\x04\x05\xac\x01\x14\x01\x9c\x06\x01\x9e\x01\x14\xba\x04\x03\x04\x03\b\xfeA\x05\x00JI?\x8b9\xfc\x96\x05\xb6\xfbX\x04\xa8\xfaJ\x03w4\x86=GI\xfb\x02\x00\x01\x00\xc7\x00\x00\x05\x0e\x05\xb6\x00\x17\x00Q@)\x0e(\x01\x01\x01\x15Z\x00e\x19\xb0\x19\x01\x8f\x19\x01\x00\x19\x10\x19\x02'\f\x01\f\x03\tZ\nd\x18\x16\x02\x10\x06\x18H\x02\v\x03\r\xb8\xff\xf0\xb6\x06\x18H\r\n\x00\x12\x00?22+?3+3\x01\x10\xf6\xe122]]]]\x10\xf6\xe12]210!#\x01#\x16\x17\x1e\x01\x15\x11#\x113\x013&'.\x035\x113\x05\x0e\xd7\xfd1\b\x06\x04\x04\x05\xac\xd5\x02\xcc\a\x03\x04\x01\x03\x03\x01\xae\x04\xbaMLA\x8e9\xfc\xe7\x05\xb6\xfbLLJ CC>\x1a\x03 \x00\x00\x00\x00\x02\x00}\xff\xec\x05q\x05\xcd\x00\x13\x00'\x004@ \x1e[\x00g)\xc0)\x01\xbf)\x01p)\x01/)_)\x02\x14[\nf(#_\x0f\x04\x19_\x05\x13\x00?\xe1?\xe1\x01\x10\xf6\xe1]]]]\x10\xf6\xe110\x01\x14\x02\x0e\x01#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x05qQ\xa0\ud6e3\xef\x9dLL\x9e\xf0\xa3\x9b\xeb\xa0Q\xfb\xd14k\xa5rr\xa5k22j\xa4rr\xa6l4\x02\u0769\xfe\xea\xc6ll\xc6\x01\x17\xaa\xaa\x01\x15\xc4kk\xc5\xfe\ubac9\u06d9QQ\x99\u06c9\x8a\u0697QQ\x97\xda\x00\x00\x00\x00\x02\x00\xc7\x00\x00\x043\x05\xb6\x00\x0e\x00\x19\x00F@,\x15[(\x008\x00H\x00\x03\x00g\x1b\xcf\x1b\x01@\x1b\x01\x0f\x1b\x01\x06\x0f\aZ\bd\x1a\x0f`0\x06@\x06\x02\x06\x06\a\x19`\t\x03\a\x12\x00??\xe1\x119/]\xe1\x01\x10\xf6\xe12^]]]\x10\xf6]\xe110\x01\x14\x0e\x02+\x01\x11#\x11!2\x1e\x02\x0132>\x0254&+\x01\x0437~\u03d8\x96\xba\x01j\x86\xc2~<\xfdN\x81]\x8b[.\xa4\xae\xa0\x04\n[\xa8\x81M\xfd\xc7\x05\xb69m\xa0\xfeg GqQ\x8e\x89\x00\x00\x00\x02\x00}\xfeb\x05q\x05\xcd\x00\x1d\x001\x008@\"([\x00g3\xc03\x01\xbf3\x01p3\x01/3_3\x02\x1e[\x14f2-_\x19\x04#_\x05\x0f\x13\t\x00/?3\xe1?\xe1\x01\x10\xf6\xe1]]]]\x10\xf6\xe110\x01\x14\x0e\x02\a\x1e\x01\x17\a.\x01'\x0e\x01#\".\x01\x0254\x12>\x0132\x1e\x01\x12\x05\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x05q1_\x8e]+\x89Zyg\xad3\x11)\x12\xa3\xef\x9dLL\x9e\xf0\xa3\x9b\xeb\xa0Q\xfb\xd14k\xa5rr\xa5k22j\xa4rr\xa6l4\x02\u0743\u2d44&^\x8f<\x8eI\xc6\u007f\x02\x02l\xc6\x01\x17\xaa\xaa\x01\x15\xc4kk\xc5\xfe\ubac9\u06d9QQ\x99\u06c9\x8a\u0697QQ\x97\xda\x00\x00\x00\x00\x02\x00\xc7\x00\x00\x04\xa0\x05\xb6\x00\x0f\x00\x1c\x00\x82@V\t\x0f\x19\x0f\x02\xf9\x0f\x01\x0f\b\v\x0fH\x0f\f\t\f\x01\a\f\x01\x16[\b\a\x18\a\x02\a\a\t\x0e\x01\xe9\x0e\xf9\x0e\x02\x0e\b\v\x0fH\x0e\r\x10\r\x1e?\x1e\x8f\x1e\x9f\x1e\xbf\x1e\xdf\x1e\x05 \x1e\x01\x10\x01Z\x02d\x1d\f\x03\x10`\x00\x00\x01\b\x00\x00\x01\x1c`\x03\x03\x0e\x01\x12\x00?3?\xe1\x119/^]\xe1\x129\x01\x10\xf6\xe12]]\x10\xce82+]q2/]\xe1\x129^]\x113+]q10\x01\x11#\x11! \x16\x15\x14\x0e\x02\a\x01#\x01'32>\x0254.\x02+\x01\x01\x81\xba\x01d\x01\n\xfe1Qh7\x01\x8e\xdb\xfe\xa1\xe5\xa4Z~Q%)S\u007fW\xa0\x02\\\xfd\xa4\x05\xb6\xce\xd1W\x82]>\x14\xfdq\x02\\\x9e#EgEHd@\x1d\x00\x00\x00\x01\x00h\xff\xec\x03\xc9\x05\xcb\x003\x00B@'Y#\x01#\x11Z\x00g5\xbf5\xff5\x02`5\x01?5\x01*Z\t\x1bf4\x11*\x05'_$ \x04\x0e`\t\x05\x13\x00?3\xe1?3\xe1\x1299\x01\x10\xf62\xe1]]]\x10\xf6\xe13]10\x01\x14\x0e\x02#\"&'5\x1e\x0332654.\x02'.\x0354>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x03\xc9E\x80\xb8so\xc1A\"W`f2\xa0\x99\x1dIz]Y\x83U)@t\xa1aw\xbeJCA\xa5Xz\x86\x1eFsT[\x89\\/\x01\x87a\x99j7#\"\xb2\x10\x1f\x18\x0fxp6PC?%#Sh\x84TX\x8a_2-#\x9c\x1d+q`9SC;!$L`~\x00\x01\x00\x14\x00\x00\x04\x12\x05\xb6\x00\a\x00^@2\x0f\t\x01\xd0\t\x01O\t\xcf\t\x02\x10\t \t0\t\x03\xaf\x06\xef\x06\x02\x84\x06\x01\x06\x06\aZ\x02@\x03\xe0\x03\x02\x0f\x03\x01\b\x03\x03W\x02g\x02w\x02\x03\x02\xb8\xff\xc0@\v\a\nH\x02\a\x03_\x04\x03\x00\x12\x00??\xe12\x01/+]3/^]]\x10\xe12/]]]]]q10!#\x11!5!\x15!\x02q\xbb\xfe^\x03\xfe\xfe_\x05\x12\xa4\xa4\x00\x00\x00\x00\x01\x00\xb8\xff\xec\x04\xdd\x05\xb8\x00\x17\x00/@\x1c\x16Z\x01e\x19\xb0\x19\x01o\x19\xaf\x19\x02\x10\x19\x01\x0eZ\vd\x18\x11_\x06\x13\f\x00\x03\x00?2?\xe1\x01\x10\xf6\xe1]]]\x10\xf6\xe110\x01\x11\x14\x0e\x02#\".\x025\x113\x11\x14\x1632>\x027\x11\x04\xddB\x85\u0248\x80\u0105D\xbb\xad\xafY\x80R(\x01\x05\xb8\xfcLr\u0110RM\x8e\xc7z\x03\xae\xfcH\xaf\xc06b\x88Q\x03\xb8\x00\x01\x00\x00\x00\x00\x04\x8b\x05\xb6\x00\f\x00l@\x10\x03\x02\t\t\x04\x00`\x01p\x01\xb0\x01\xf0\x01\x04\x01\xb8\xff\xc0@\x16\x06\nH\x01\x10\x01\x01\x0e/\x0e\u007f\x0e\xbf\x0e\x03\x0e@\x06\tH\x05\x04\xb8\xff\xf0\xb4\x04\x05\x04\x03\t\xb8\xff\xe0\xb3\n\x11H\t\xb8\xff\xf0@\n\x06\tH\t\x02\x03\x12\x00\x01\x03\x00?3?33++?3\x01/83+]\x113/8+]3\x129=/3310\x013\x01#\x013\x01\x1e\x01\x17>\x017\x03\xc5\xc6\xfe\x17\xbb\xfe\x19\xc5\x01'\x1d*\x11\x0f.\x1f\x05\xb6\xfaJ\x05\xb6\xfca[\xa9JJ\xa9a\x00\x00\x00\x01\x00\x14\x00\x00\x06\xfe\x05\xb6\x00*\x00\u07f6\x10\b\x15\x18H\x10\x0f\xb8\xff\xf8\xb5\x15\x18H\x0f\a\x01\xb8\xff\xf8@\x12\x15\x18H\x01\x00\b\x15\x18H\x00\x16\x1d\b\x15\x18H\x1d\x1c\xb8\xff\xf8@/\x15\x18H\x1c%\x14\a\x01\x04\aD\a\xb4\a\x03\a\x04%\x14%$%D%T%\x05\a\x16%%\x16\a\x03\x1e\r\x00\x0e\x01p\x0e\x80\x0e\xc0\x0e\x03\x0e\xb8\xff\xc0@\x18\a\nH\x0e\x10\x0e\x0e,o,\u007f,\x02 ,0,\x02\x0f,\x01\b\x1f\x1e\xb8\xff\xf0@\x13\x1e\x16 \n\x11H\x16\x10\x06\tH\x16\r\x00\x1e\x03\a%%\xb8\xff\xe0\xb3\n\x11H%\xb8\xff\xf0\xb6\x06\tH%\x10\x1d\x12\x00?33++\x113?333++\x01/83^]]]\x113/8+]q3\x12\x179=///]^]q\x113+3+\x113+3+\x113+3+10\x013\x13\x1e\x03\x17>\x037\x133\x01#\x03.\x01'&'\x06\a\x0e\x01\a\x03#\x013\x13\x1e\x03\x17>\x037\x03)\xc5\xe5\x0f\x1d\x19\x13\x06\x04\f\x10\x13\v\xc8\xc7\xfe\x91\xbc\xfe\x0e\x1a\v\f\v\v\v\n\x19\x0e\xf2\xbc\xfe~\xc5\xdf\f\x14\x11\x0e\x05\x05\x0f\x14\x17\r\x05\xb6\xfc\xa88pi^&&Zcg1\x03r\xfaJ\x03\xaa3l/7437/p6\xfc\\\x05\xb6\xfc\x87.cb[&%blo1\x00\x01\x00\x00\x00\x00\x04`\x05\xb6\x00\v\x00\x81@\x1d\t\n\x10\n\n\x007\v\x01\v\b8\x05\x01\x05\x02\x02\x01\x00\x00\x01p\x00\x80\x00\xc0\x00\x03\x00\xb8\xff\xc0@\x14\a\nH\x00\x10\x00\x00\r\x0f\r\x1f\r/\r\u007f\r\x04\b\a\x06\xb8\xff\xf0\xb3\x06\x06\x03\x04\xb8\xff\xf0@\x10\x04(\x02\x01'\b\x01\x02\b\x04\t\x06\x03\x04\x00\x12\x00?2?3\x1299]]\x01/822/83^]\x113/8+]q39=/3]33]\x113\x18/8310!#\t\x01#\t\x013\t\x013\x01\x04`\xd3\xfe\x9e\xfe\x91\xbc\x01\xc5\xfeZ\xc6\x01L\x01N\xbe\xfe[\x02{\xfd\x85\x02\xfc\x02\xba\xfd\xd1\x02/\xfdL\x00\x00\x00\x00\x01\x00\x00\x00\x00\x047\x05\xb6\x00\b\x00s@\x19\xef\n\x01\n@\t\fH\b\xab\a\x01\x98\a\x01@\a\x01\x1b\a\x01\x0f\a\x01\a\xb8\xff\xf0@/\a\a\x05\x01\x80\x02\x01O\x02\x01\x1b\x02\x01\x02\x10\x02\x02\x00\x04Zw\x05\x87\x05\x97\x05\x03O\x05\x01\x00\x05\x10\x05\x02\a\x056\x00\x01\x00\x01\x04\x12\a\x01\x03\x00?3?\x129]\x01/^]]]\xe192/8]]]3\x113/8]]]]]3+]10\t\x013\x01\x11#\x11\x013\x02\x1b\x01T\xc8\xfeB\xbb\xfeB\xcb\x02\xd3\x02\xe3\xfc\x83\xfd\xc7\x02/\x03\x87\x00\x00\x00\x00\x01\x00R\x00\x00\x03\xfe\x05\xb6\x00\t\x008@ \t\t\x03\ag\v\x0f\v?\vO\v\x9f\v\x04\b\b\x04\x04\x01f\n\a\x04_\x05\x03\x02\b_\x01\x12\x00?\xe19?\xe19\x01\x10\xe62/2^]\x10\xe622/10)\x015\x01!5!\x15\x01!\x03\xfe\xfcT\x02\xc7\xfdM\x03\x83\xfd:\x02\u06d1\x04\u007f\xa6\x91\xfb\x81\x00\x00\x00\x00\x01\x00\xa4\xfe\xbc\x029\x05\xb6\x00\a\x00&@\x17\x04\x00\xf3\x06\xf1\x00\x01\x10\x01\xb0\x01\xc0\x01\x04\x01\x05\xf5\x02\xf8\x06\xf5\x01\xf9\x00?\xe1?\xe1\x01/]\xe1\xed210\x01!\x11!\x15#\x113\x029\xfek\x01\x95\xdf\xdf\xfe\xbc\x06\xfa\x95\xfa1\x00\x00\x01\x00\x17\x00\x00\x02\xe9\x05\xb6\x00\x03\x00!\xb7\x02\x01\x01\x10\x01\x05\x00\x03\xb8\xff\xf0\xb4\x03\x02\x01\x00\x03\x00?//\x01/83\x1138\x11310\x13\x01#\x01\xc9\x02 \xb2\xfd\xe0\x05\xb6\xfaJ\x05\xb6\x00\x00\x01\x003\xfe\xbc\x01\xc9\x05\xb6\x00\a\x00$@\x14\x03\x00\xf3\x01\xf1`\x06p\x06\x02\x06\t\x00\xf5\a\xf9\x03\xf5\x04\xf8\x00?\xe1?\xe1\x01\x10\xd6]\xe1\xed210\x173\x11#5!\x11!3\xdf\xdf\x01\x96\xfej\xae\x05\u03d5\xf9\x06\x00\x00\x01\x00)\x02%\x04\x19\x05\xc1\x00\x06\x00\x12\xb6\x03\x03\b\x00\x00\x01\x06\x00?\xcd\x01/\x113/10\x13\x013\x01#\t\x01)\x01\xcbf\x01\xbf\xa1\xfe\xaf\xfe\xa3\x02%\x03\x9c\xfcd\x02\xdf\xfd!\x00\x01\xff\xfc\xfe\xbc\x03N\xffH\x00\x03\x00\x12\xb6\x00\x00\x05\x01\x01\xba\x02\x00/\xe1\x01/\x113/10\x01!5!\x03N\xfc\xae\x03R\xfe\xbc\x8c\x00\x00\x00\x00\x01\x01\x89\x04\xd9\x03\x12\x06!\x00\r\x00\x16@\n\x00\x06\b\x80\x0f\x00_\x00\x02\x00\x00/]\x1a\xcc\x01/\xcd10\x01#.\x03'53\x1e\x03\x17\x03\x12x#RM?\x10\xdb\x10+.0\x15\x04\xd9\x1cSXQ\x1b\x15\"QQL\x1d\x00\x00\x00\x00\x02\x00^\xff\xec\x03\x9c\x04^\x00#\x002\x00T@\x11\x10\x01)G#U4\x0f4o4\x02\x060H\f\x1a\xb8\xff\xd0@\x1e\r\x11H\x1a\x10\t\fH\x1a\x1a\fV3\x19\x16P\x1d*R\x10\x10\x1d\x10$P\x02\a\x16\x00\x15\x00??3\xe1?9/\xe1\x10\xe12\x01\x10\xe62/++\x10\xe1^]\x10\xf6\xe12210!'#\x0e\x03#\".\x02546?\x0154.\x02#\"\x06\a'>\x0132\x1e\x02\x15\x11%2>\x02=\x01\a\x0e\x03\x15\x14\x16\x03\x19%\b!BN`?EtU0\xe7\xec\xb8\x1d7Q4S\x8fB@J\xb6df\x95a0\xfe/=hL+\x8fZzI a\x98-A*\x14'Q{T\xa4\xb0\b\aECZ7\x180\"\x89(8)Y\x8ab\xfd\x10\u007f&MuOc\a\x04 9Q3\\V\x00\x00\x00\x00\x02\x00\xae\xff\xec\x04?\x06\x14\x00\x1f\x00/\x008\xb5-H\x05W11\xb8\xff\xb8@\x17\nI\x15\x10%G\x12T0\x13\x00\x12\x15*P\x0f\n\x16 P\x1b\x00\x10\x00?2\xe1?3\xe1??\x01\x10\xf6\xe122+\x10\xf6\xe110\x012\x1e\x02\x15\x14\x0e\x02#\".\x02'#\a#\x113\x11\x14\x06\a\x06\a3>\x03\x17\"\x0e\x02\x15\x14\x1e\x0232654&\x02\x9e^\x9am<\x0232\x16\x17\a.\x03#\"\x06\x15\x14\x163267\x15\x0e\x01\x02Re\xb0\x82JL\x85\xb2fN\x9526\x178<:\x1a\x9d\x90\x91\x94Q\x8366{\x14?\x89\u0556\x9d\u06c9>\"\x19\x9a\n\x13\x0f\t\xc9\xd4\xd3\xc3%\x19\xa2\x1d\x1e\x00\x00\x00\x00\x02\x00q\xff\xec\x04\x02\x06\x14\x00\x1f\x000\x004@\x1d&\x00\x1bG\x1eU2\x102\x01.H\vV1\x1f\x15\x1c\x00+P\x16\x10\x10 P\x01\x06\x16\x00?3\xe1?3\xe1??\x01\x10\xf6\xe1]\x10\xf6\xe12210%#\x0e\x03#\".\x0254>\x0232\x1e\x02\x173&'.\x015\x113\x11#%2>\x02754.\x02#\"\x06\x15\x14\x16\x03T\b\x16;M`<]\x9an<\x0232\x1e\x02\x1d\x01!\x1e\x0132>\x027\x15\x0e\x03\x03\"\x06\a!4.\x02\x02`n\xb6\x83HBx\xa7ec\x9en;\xfdL\x05\x99\x973WQL'(MQW`r\x85\v\x01\xec\x1b9X\x14J\x8e\u0487\x88\u0595NG\x81\xb5nq\xc1\xb6\n\x13\x1d\x12\xa2\x13\x1c\x12\b\x03\u06dc\x95DqP,\x00\x00\x00\x01\x00\x1d\x00\x00\x02\xf0\x06\x1f\x00\x1b\x00p@N\xcf\x1d\xdf\x1d\x02`\x1d\x80\x1d\x90\x1d\xa0\x1d\x04\x1f\x1d?\x1dO\x1d\x03\x1b\x1b\u007f\x10\xbf\x10\x02\x10\x10\x1a\x02G\x03\a\x03\x0f\x05\x1f\x05/\x05\xaf\x05\x04\x05\x05\x00\x03\x10\x03 \x03\x80\x03\x90\x03\xa0\x03\x06\x06\x03\x01\x05O\a\x00\x1a\x01\a\x1a\x0f\x14P\r\x01\x02\x15\x00??\xe1?^]3\xe12\x01/^]3/]\x113\x10\xe122/]9/]]]10\x01#\x11#\x11#5754>\x0232\x16\x17\a.\x01#\"\x0e\x02\x1d\x013\x02\x8b\xf5\xb7\xc2\xc2-U|N;c'/\x1fI((:&\x13\xf5\x03\xc1\xfc?\x03\xc1KD`k\x8dT#\x17\x0e\x8d\v\x11\x130SAh\x00\x00\x00\x00\x03\x00%\xfe\x14\x03\xfc\x04^\x00?\x00R\x00^\x00\xa7@\x19\r2\x05SG7\x12/`7p7\x807\x037/7/'H\x1dYG\x05\xb8\xff\xc0@M\a\nH\x05\x05\x01\n\x1d\x01\xfd\x1d\x01\xb0\x1d\x01\x88\x1d\x01 \x1d0\x1d@\x1d\x03\x1d\x1d`\x1f`\x01\xbf`\xdf`\x02\xa0`\x01@'@\f\x0fH'\x02\x052\r\x04\x027.\x015467.\x0354>\x0232\x16\x17\x01\x14\x1e\x0232654.\x02+\x01\"\x0e\x02\x13\x14\x1632654&#\"\x06\x03\xfc\xc5\x1c&/_\x8c]\x16,\x0e\x11!\x1b\x11\x18)8\x1f\xb0]\x80Q$A\x86\u034bk\xa0j5'BW/*6@E+G1\x1b2b\x92a%O\x1b\xfe@\x1a;aH\xba\xb9\x187ZA\xb0#L?)\\lcdgidcj\x04Jq\x1b#mEL\x81^5\x01\x03\n\x19 (\x18\x1b!\x12\x06/Pm=X\x8ca4*PqG<[B*\v\x13R5=Y*\x12?Q`3Y\x8cb4\v\t\xfb\x02%@.\x1bsl.:!\f\x10,M\x03`spow{tx\x00\x01\x00\xae\x00\x00\x04\x12\x06\x14\x00\x19\x002@\x1d\x00G\x19U\x1b\x10\x1b`\x1b\x80\x1b\x03\x0f\x0e\nG\vT\x1a\x10\x04P\x15\x10\f\x00\v\x00\x15\x00?2??\xe13\x01\x10\xf6\xe122]\x10\xf6\xe110!\x114&#\"\x0e\x02\x15\x11#\x113\x11\a3>\x0332\x16\x15\x11\x03\\ipQnC\x1d\xb6\xb6\b\n\x19ER\\0\xb7\xb9\x02\u00c2\x824f\x94`\xfd\xc7\x06\x14\xfe2\x90+?*\x14\xbf\xd2\xfd3\x00\x00\x00\x00\x02\x00\xa0\x00\x00\x01u\x05\xe5\x00\x03\x00\x11\x00%@\x14\x10\x13 \x13\x02\f\x00G\x04\x01T\x12\aS\x0f\x0f\x02\x0f\x00\x15\x00??3/\xe5\x01\x10\xf62\xe12]10!#\x113\x034632\x1e\x02\x15\x14\x06#\"&\x01d\xb6\xb6\xc4=-\x16'\x1d\x11?,-=\x04J\x01)<6\r\x1c+\x1e:98\x00\x00\x00\x02\xff\xbc\xfe\x14\x01u\x05\xe5\x00\x13\x00!\x00.@\x19\x10# #\x02\x1c\x0fG\f\x14\x03\x03\fT\"\x17S\x1f\x1f\r\x0f\aP\x00\x1b\x00?\xe1?3/\xe5\x01\x10\xe62/2\x10\xe12]10\x13\"&'5\x1e\x0132>\x025\x113\x11\x14\x0e\x02\x134632\x1e\x02\x15\x14\x06#\"&B0?\x17\x1a6#\x1b.#\x13\xb6\"Hm\x13=-\x16'\x1d\x11?,-=\xfe\x14\x0e\v\x94\n\v\x0f'A3\x04\xf4\xfb\x18M{W/\a_<6\r\x1c+\x1e:98\x00\x00\x00\x00\x01\x00\xae\x00\x00\x03\xf0\x06\x14\x00\x0e\x00^@\v\a\x04\x04\x02\x03\x03\x06D\x05\x01\x05\xb8\xff\xc0@\x17\a\nH\x05\x10\x05\x05\x10\x0f\x10/\x10\x02\a\r\tG\nT\x0f\v\x00\x00\xb8\xff\xf8@\x10\f\x0fH\a\b\f\x0fH\x00\a\x03\x06\n\x15\x03\x0f\x00??3\x1299++?\x01\x10\xf6\xe12^]\x113/8+]33\x1139\x11310\x017\x013\t\x01#\x01\a\x11#\x113\x11\x03\x01V\x87\x01%\xd3\xfeo\x01\xac\xd1\xfe\xb0m\xb4\xb4\x10\x027\xaa\x01i\xfe%\xfd\x91\x01\xf8R\xfeZ\x06\x14\xfd6\xfe\xed\x00\x01\x00\xae\x00\x00\x01d\x06\x14\x00\x03\x00\x1a@\x0e\x10\x05 \x05\x02\x00G\x01T\x04\x02\x00\x00\x15\x00??\x01\x10\xf6\xe1]10!#\x113\x01d\xb6\xb6\x06\x14\x00\x00\x00\x01\x00\xae\x00\x00\x06\x87\x04^\x00,\x00e@?#\nG\xb9\v\x01\x96\v\xa6\v\x02\x89\v\x01g\vw\v\x02\v\v\x16\x00G,U.\xf0.\x01\xcf.\x01 .P.\x02\x0f.\x01\b\x19\x15G\x16T-#\x1a\x1a\x04\x0fP(\x1f\x10\x17\x0f\x16\v\x00\x15\x00?22??3\xe122\x113\x01\x10\xf6\xe12^]]]]\x10\xf6\xe1\x119/]]]]\xe1210!\x114&#\"\x0e\x02\x15\x11#\x114&#\"\x0e\x02\x15\x11#\x113\x173>\x0332\x16\x173>\x0332\x16\x15\x11\x05\xd1diIfA\x1e\xb7ciMh?\x1b\xb6\x94\x1a\n\x18BOY.x\x9f&\b\x1aIW`2\xaf\xb1\x02\u00c2\x82/[\x87X\xfd\xa2\x02\u00c2\x824f\x94`\xfd\xc7\x04J\x94+?*\x14X^/D-\x16\xbf\xd2\xfd3\x00\x00\x00\x01\x00\xae\x00\x00\x04\x12\x04^\x00\x18\x000@\x1c\x00G\x18U\x1a\x10\x1a`\x1a\x80\x1a\x03\x0e\nG\vT\x19\x0f\x04P\x14\x10\f\x0f\v\x00\x15\x00?2??\xe13\x01\x10\xf6\xe12]\x10\xf6\xe110!\x114&#\"\x0e\x02\x15\x11#\x113\x173>\x0332\x16\x15\x11\x03\\ipQnC\x1d\xb6\x94\x1a\n\x19ER\\0\xb7\xb9\x02\u00c2\x824f\x94`\xfd\xc7\x04J\x94+?*\x14\xbf\xd2\xfd3\x00\x02\x00q\xff\xec\x04-\x04^\x00\x13\x00\x1f\x000@\x1d\x1aH\x00W!@!\xd0!\xe0!\x03\x0f!\x01\x06\x14H\nV \x1dP\x0f\x10\x17P\x05\x16\x00?\xe1?\xe1\x01\x10\xf6\xe1^]]\x10\xf6\xe110\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x05\x14\x1632654&#\"\x06\x04-C}\xb2og\xae\u007fGC|\xb3og\xae\u007fG\xfd\x00\x89\x9a\x9a\x87\x89\x9a\x9a\x87\x02'\x89\u0551LL\x91\u0549\x88\u04d1KK\x91\u04c8\xd1\xd3\xd3\xd1\xd1\xcf\xcf\x00\x00\x00\x00\x02\x00\xae\xfe\x14\x04?\x04^\x00\x1f\x000\x006@\x1e.H\x1bW2\x102\x01&\x10\x06\fG\rT1 P\x11\x16\x10\x0e\x0f\f\x1b+P\x05\x00\x16\x00?2\xe1???3\xe1\x01\x10\xf6\xe1222]\x10\xf6\xe110\x05\".\x02'#\x16\x17\x1e\x01\x15\x11#\x113\x173>\x0332\x1e\x02\x15\x14\x0e\x02\x03\"\x0e\x02\a\x15\x14\x1e\x0232654&\x02\x9e;`M;\x17\f\x03\x03\x02\x04\xb6\x94\x1a\b\x17:M`<^\x9am<\x02754.\x02#\"\x06\x15\x14\x16\x17\".\x0254>\x0232\x1e\x02\x17373\x11#\x1146767#\x0e\x03\x025LiA\x1f\x02\x1bAlQ\x87\u007f\u007ff]\x9an<\x03\x02\x89\x1dH\x1a\x18\x1c;\x1a?hK)\xb6\x94\x16\b\x199GX\x04^\x05\x05\xa8\x05\a3_\x85Q\xfd\xb0\x04J\xc9+P=%\x00\x01\x00Z\xff\xec\x03?\x04^\x005\x00H@-%\x13G\x90\x00\xa0\x00\x02\x00W7?7_7\x9f7\x03\x107\x01,G\t\x9f\x1d\xaf\x1d\x02\x1dV6&)P\x13,\x05\"\x10\t\x0eP\x05\x16\x00?\xe12?\x1299\xe12\x01\x10\xf6]2\xe1]]\x10\xf6]\xe1310\x01\x14\x0e\x02#\"&'5\x1e\x0332>\x0254.\x02'.\x0354>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x03?:m\x9a`m\x9c;\x1fLTY,A[9\x1a\x145\\HHsP+7d\x8cVa\xa1H?A\x89Gfb\x178^FHqP*\x01-PxQ(#\"\xa6\x10\x1f\x18\x0f\x16);$\x1f212\x1f\x1f#4./\x1d\x1e\x027\x15\x0e\x03#\".\x025\x11#5?\x013\x15!\x15!\x11\x14\x16\x01\xfa\x12-*#\t\r(04\x19>jM,\x9b\x9bNi\x01\x14\xfe\xec?\x81\x04\x06\b\x03\x8a\x06\f\t\x05 N\x85e\x02}QN\xe6\xfc\x89\xfd\x83ab\x00\x00\x00\x01\x00\xa4\xff\xec\x04\b\x04J\x00\x1a\x000@\x1c\x01\x17G\x1aU\x1c\x10\x1c`\x1c\x80\x1c\x03\x0fG\fT\x1b\x18\r\x0f\x12P\x02\a\x16\x00\x15\x00??3\xe1?3\x01\x10\xf6\xe1]\x10\xf6\xe1210!'#\x0e\x03#\".\x025\x113\x11\x14\x1632>\x025\x113\x11\x03u\x1b\n\x19ER\\0[\x8a\\/\xb6joQnC\x1d\xb6\x93+?)\x14.b\x98i\x02\xcd\xfd=\x82\x824e\x94`\x02:\xfb\xb6\x00\x00\x00\x00\x01\x00\x00\x00\x00\x03\xd5\x04J\x00\x11\x00m\xb9\x00\x11\xff\xf8@\x0f\n\x0eH\x11\x00\b\n\x0eH\x00\t\t\x01\x0f\x10\xb8\xff\xc0\xb3\x12\x15H\x10\xb8\xff\xc0@\x1c\a\vH\x10\x10\x10\x10\x13\xbf\x13\xcf\x13\xef\x13\x03P\x13\x01\x0f\x13/\x13O\x13\x03\a\x02\x01\xb8\xff\xf0@\n\x01G\t\x01\t\x0f\x01\x0f\x00\x15\x00??39]\x01/8\xc1^]]]\x113/8++\xc1\x129=/3+3+10!\x013\x13\x1e\x03\x173>\x037\x133\x01\x01w\xfe\x89\xbc\xc7\v\x1e\x1e\x19\x04\a\x05\x18\x1e\x1e\v\u01fc\xfe\x89\x04J\xfd\x9d!hl`\x19\x19`lh!\x02c\xfb\xb6\x00\x01\x00\x14\x00\x00\x05\xe3\x04J\x00/\x00\u00f9\x00/\xff\xf8@\f\n\x0eH/\x00\b\t\x0eH\x00' \xb8\xff\xf8@\x12\t\x0eH \x1f\b\t\x0eH\x1f\t\x10\b\n\x0eH\x10\x0f\xb8\xff\xf8@\t\t\x0eH\x0f\x18T'\x01'\xb8\xff\xe0@\x15\a\nH[\x18\x01\x18 \a\nH'\t\x18\x18\t'\x03\x11-.\xb8\xff\xc0\xb3\x12\x15H.\xb8\xff\xc0@\x13\a\vH.\x10..1 101\x02\x0f1\x01\a\x12\x11\xb8\xff\xf0@\x16\x11-\x1f\t\t\x01\t\x11\x0f'\x19\x06\x19f\x19v\x19\x03\x19\x00\x10\x15\x00?33]\x113?3]33\x01/83^]]\x113/8++3\x12\x179=///+]+]\x113+3+\x113+3+\x113+3+10!\x03.\x03'&'#\x06\a\x0e\x01\a\x03#\x013\x13\x1e\x03\x173>\x037\x133\x13\x1e\x03\x173>\x037\x133\x01\x03\xf0\xa8\x04\f\f\r\x06\x0e\x0f\x06\x0e\r\v\x19\v\xac\xd3\xfe\u7fc3\n\x14\x12\x0e\x04\x06\x05\x11\x15\x16\n\xb3\u012c\t\x17\x16\x12\x04\x06\x03\r\x12\x15\v\x89\xba\xfe\xe4\x02h\x12-24\x19:>?:2j%\xfd\x9c\x04J\xfd\xb8-ig[\x1d\x1aWa_!\x02k\xfd\x95\"\\_X\x1d\x1aWhm/\x02H\xfb\xb6\x00\x00\x00\x01\x00#\x00\x00\x03\xdb\x04J\x00\v\x00\xe5@\xa1\x89\t\x01\x86\x03\x01\x06\x04\x01\xf7\x04\x01\xe5\x04\x016\x04\x01\x04\x05\xe8\x06\x01\x06\x03\xe7\x00\x01\x00\t\t\x02\x01\xf8\x02\x01\xea\x02\x019\x02\x01\x02\x01k\x05{\x05\x02W\x05\x01:\x05J\x05\x02d\x01t\x01\x02X\x01\x015\x01E\x01\x02\x05\x01\t\x01\t\x05\x03\v\x06\b\x01\xf7\b\x01\xe5\b\x016\b\x01\b\a@\x16\x19H\a@\x0e\x11Hk\a{\a\x02W\a\x01:\aJ\a\x02\a\r\x10\r0\r\x02\x90\r\xb0\r\x02\x0f\r\x01\x06\xd9\n\x01\xc8\n\x01\xba\n\x01\t\n\x01\n;\vK\v\x02(\v\x01\x05\v\x15\v\x02\v\a\x15\x01\x0f\x00??\x01/]]]\xc1]]]]^]]q\x10\xde]]]++\xc1]]]q\x12\x179=/\x18//]]]]]]\x10\xc1]]]q\x113]33]\x10\xc1]]]q10\x00]]\t\x013\x1b\x013\t\x01#\t\x01#\x01\x98\xfe\x9f\xcf\xfa\xfa\xcf\xfe\x9d\x01u\xcf\xfe\xf4\xfe\xf2\xcf\x023\x02\x17\xfef\x01\x9a\xfd\xe9\xfd\xcd\x01\xb4\xfeL\x00\x00\x00\x00\x01\x00\n\xfe\x14\x03\xdf\x04J\x00\"\x00d\xb6\"\x10\b\b\x00\x0e\x0f\xb8\xff\xc0\xb3\x12\x15H\x0f\xb8\xff\xc0@\x1d\a\vH\x0f\x10\x0f\x0f$\xbf$\xcf$\xef$\x03P$\x01\x0f$/$O$\x03\a\x18\x01\x00\xb8\xff\xf0@\f\x00\"\x10\b#\x1cP\x15\x1b\x0e\x00\x0f\x00?2?\xe1\x11333\x01/8\xc13^]]]\x113/8++\xc1\x129=/3310\x133\x13\x1e\x03\x173>\x037\x133\x01\x0e\x03#\"&'5\x1e\x0132>\x02?\x01\n\xbd\xd7\x0e\x1d\x19\x12\x04\x06\x05\x16\x1b\x1d\v\u01fc\xfeN\x1cAVtP4L\x1b\x15@#0F4%\x0f9\x04J\xfd\x9b(XXR#\x19Va^!\x02c\xfb'Q\x81Z1\v\x06\x91\x05\a\x17,@)\xa0\x00\x00\x00\x00\x01\x00R\x00\x00\x035\x04J\x00\t\x00l@\v\t\x97\x03\x01\x03\b\t\rH\x03\a\xb8\xff\xc0@\x11\a\nH\a\a\v?\v_\v\u007f\v\x03\x98\b\x01\b\xb8\xff\xf8\xb5\t\rH\b\x04\x02\xb8\xff\xc0\xb7\x12\x15H?\x02\x01\x02\a\xb8\xff\xf0@\x12\a\fH\a\x04O\x05\x0f\x02\x10\a\fH\x02\bO\x01\x15\x00?\xe12+?\xe12+\x01/]+33+]]\x113/+3+]310)\x015\x01!5!\x15\x01!\x035\xfd\x1d\x02\x18\xfe\t\x02\xb0\xfd\xf4\x02\x1e}\x03D\x89\x92\xfc\xd1\x00\x00\x00\x00\x01\x00=\xfe\xbc\x02\xa2\x05\xb6\x00'\x00@@%\x1a\x05\x05\xf7 '\xf1#\x13\x0f\xf6\x10\f\x01\f#\x0f\xf5\xd9\x10\x01\x0f\x10_\x10\x02\x10\x10)\x1a\xf5\x19\xf8\x05\xf5\x06\xf9\x00?\xe1?\xe1\x129/]]\xe19\x01/]\xe633\xf12\xe2/210\x05\x14\x1e\x02\x17\x15.\x035\x114ᒑ\x114>\x027\x15\x0e\x03\x15\x11\x14\x06\a\x15\x1e\x01\x15\x01\xf4\x18-A(M\x83_6\x83}}\x836_\x83M(A-\x18wssw\x100=#\r\x01\x96\x01!GnN\x01NgV\x9bVg\x01MNnG!\x01\x95\x01\r#=0\xfe\xb4i{\x14\f\x14zj\x00\x00\x01\x01\xe9\xfe\x14\x02\u007f\x06\x14\x00\x03\x00-@\x1f\x00\x05\x010\x05@\x05p\x05\x80\x05\x04\x02\xaa\x00\x03\x10\x03@\x03\x80\x03\xc0\x03\x05\a\x03\x02\x1b\x00\x00\x00??\x01/^]\xe1]q10\x013\x11#\x01\u9596\x06\x14\xf8\x00\x00\x00\x01\x003\xfe\xbc\x02\x98\x05\xb6\x00)\x00@@%\r$$\xf7\a\x00\xf1\x1a\xf6\x14\x03\x90\x1d\x01\x1d\x04\x1a\xf5\xef\x19\xff\x19\x02\xd9\x19\x01\x19\x19\x0e$\xf5#\xf9\r\xf5\x0e\xf8\x00?\xe1?\xe1\x119/]]\xe19\x01/]33\xe6\xf12\xe2/210\x134675.\x015\x114.\x02'5\x1e\x03\x15\x11\x14\x1e\x023\x15\"\x06\x15\x11\x14\x0e\x02\a5>\x035\xe1wssw\x18-A(M\x83_6!A`>}\x836_\x83M(A-\x18\x01;jz\x14\f\x14{i\x01L0=#\r\x01\x95\x01!GnN\xfe\xb34H-\x14\x9bVg\xfe\xb2NnG!\x01\x96\x01\r#=0\x00\x01\x00f\x02J\x04\x02\x03Z\x00#\x00<@\r\x1d%\x10%\x01\x10\n\x01\n\x17\xad\n\x1f\xb8\xff\xc0@\x16\x10\x13H\x1f\x1f\x05\xad\x1c\x0f\r\x1f\r?\rO\ro\r\x8f\r\x06\r\x00/]3\xf1\xc8/+2\xe1\x01/]]\x10\xce10\x01.\x03#\"\x0e\x02\a5632\x1e\x02\x17\x1e\x0332>\x027\x15\x06#\".\x02\x02\x12%7-)\x16\x1c<;8\x19d\x94\x1d27C/%7/(\x16\x1c<;8\x18c\x95\x1d27C\x02\x8b\x10\x16\r\x05\x13!,\x19\xa2l\x05\r\x19\x14\x10\x16\r\x05\x13!,\x19\xa2l\x05\r\x19\x00\x00\x00\x02\x00\x93\xfe\x8b\x01\x91\x04^\x00\x03\x00\x17\x00A\xb9\x00\x00\xff\xf0@\x13\n\x14H0\x19\xa0\x19\xb0\x19\xc0\x19\x04\x02\x04\x9a\x0e\x03\x03\x0e\xb8\xff\xc0@\x0f\a\nH\x0e\x00\t\x9b\x13\x00\x02\x10\x02\x02\a\x02\x00/^]/\xf5\xce\x01/+3/\x10\xe12]10+\x133\x13#\x13\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\xd5y3\xdf\xef\x13#.\x1b\x1a.#\x14\x14#.\x1a\x1b.#\x13\x02\xa4\xfb\xe7\x05H&5!\x0f\x0f!5&%4\"\x10\x10\"4\x00\x00\x01\x00\xbc\xff\xec\x03\xba\x05\xcb\x00%\x00Z@%\x12\x03F\x0f\x04\x04\n%\x15'@'\x01\x1eH\x00\n0\n@\n\xd0\n\x04\x06\n\x1bs\x0f\x12\x0f!s\x05\x02\x05\x0f\xb8\xff\xc0@\f\x0f\x12H\x0f\x05\x0f\x05\x03\x10\a\x03\x19\x00??\x1299//+\x113\x10\xe1\x113\x10\xe1\x01/^]\xe1]\x10\xc62\x119/3\xe1210$\x06\a\x15#5.\x0354>\x02753\x15\x1e\x01\x17\a.\x03#\"\x06\x15\x14\x163267\x15\x03vnL\x89W\x8ab45a\x8bV\x89H\x88.5\x178<;\x19\x9d\x90\x91\x94Q\x836\xd4\x1e\x02\xc8\xce\rK\x85\u01c9\x8d\u02c8K\r\xac\xa4\x03!\x17\x9a\n\x13\x0f\t\xca\xd4\xd2\xc3%\x18\xa1\x00\x00\x01\x00D\x00\x00\x04#\x05\xc9\x00(\x00u@\x11\r\x11o#\x0f\x0f\x1f\x0f\x02\a\x1f\x0f\x1f\x0f\x19\x03\x17\xb8\xff\xc0\xb3\n\x0eH\x17\xb8\xff\xc8@0\x06\tH\x17\x17*\x10*\x01!\x19@\v\x0eH\x19\x19)\x10!u\r/\"\u007f\"\x8f\"\xaf\"\xbf\"\xdf\"\xff\"\a\"\"\x00\x16t\x19\x18\as\x00\a\x00?\xe1?\xe1\x119/]3\xe12\x11\x013/+3]\x113/++3\x1299//^]3\xe1210\x012\x16\x17\a.\x01#\"\x0e\x02\x15\x11!\x15!\x15\x14\x0e\x02\a!\x15!5>\x03=\x01#53\x114>\x02\x02\x9aj\xaeBB8\x8dK0RY@+\x10\xa6\x9a\v)DaC\u0549\x01DW\x89_2\x00\x02\x00{\x01\x1d\x03\xec\x04\x8b\x00#\x007\x00\x86@#\x0e\x8f\x16\x01\x16\x16.\xab\x15\x0f\f\x18\x06\x1e!\x03\b\x00p\x12\x01\x12\x129\x109\x01\x04 $\xaa\x80\x00\x01\x00\xb8\xff\xc0@1\x06\nH\x00\x008\x17\x80\x1f\x01\x1f\f\x06\x18\x1e\x0f\x06\x04\t)\xae\x00\x1b\x01\x1b\r\x053\xae\xcf\t\xef\t\x02\x90\t\xa0\t\xb0\t\x03\x1f\t?\to\t\x03\t\x00/]]]\xe1\xc62/]\xe1\x12\x179\x113\xc6]2\x11\x013/+]\xe1\xc62]\x113/]\x12\x179\xf1\xc0/]210\x13467'7\x17>\x0132\x16\x177\x17\a\x1e\x01\x15\x14\x06\a\x17\a'\x0e\x01#\"&'\a'7.\x017\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\xba#\x1f\x81b\u007f/l<\x027.\x0154>\x0232\x16\x17\a.\x01#\"\x06\x15\x14\x1e\x02\x17\x1e\x03\x15\x14\x0e\x02\a\x1e\x01\x15\x14\x0e\x02#\"&'5\x1e\x0332>\x0254.\x02'.\x037\x14\x1e\x02\x1f\x01>\x0354.\x02'\x0e\x03\x89\x1a-:\x1fKU7d\x8cVa\x9dH8A\x8cGcf\x189_FHqN*\x18)4\x1cEL;l\x9b`l\x9c;\x1fLTY+E]7\x17\x113^LIsP)\x9a\x1c?eH#\x14)!\x15\x1aAlR\x19/&\x17\x03)3S@-\x0f&rT=bD%( \x8b\x1c';9\x1b.,/\x1d\x1cANa>4UD1\x10&mNGoM(! \x9e\x0f\x1e\x17\x0e\x18'3\x1b\x1d--1\x1f\x1f>NdY%?:7\x1e\x0f\r$.8\"&@;9\x1e\b\x1f-:\x00\x00\x00\x00\x02\x013\x05\f\x03j\x05\xd9\x00\v\x00\x19\x005@!\f\x86\xaf\x14\x01\x14\xc0\x06\x86\x00\x00\x10\x00@\x00P\x00\x04\x06\x00\x0f\x03\x91\x17\x9f\t\xcf\t\x020\t\x01\t\x00/]]3\xe52\x01/^]\xe1\x1a\xdc]\xe110\x014632\x16\x15\x14\x06#\"&%4632\x1e\x02\x15\x14\x06#\"&\x0138('::'(8\x01w8(\x13#\x1a\x10:&(8\x05s6015522560\f\x19&\x1b522\x00\x00\x03\x00d\xff\xec\x06D\x05\xcb\x00%\x00A\x00U\x00j@C\x05\xc5\x1a\x0f\x0f\"\x1a\"\x1a\"&L\xc3\x004\x01\xc04\x014WB\xc3&\n\xc9\x15\x00\xc9\x1f\x0f\x15\x1f\x15/\x15\u007f\x15\x8f\x15\x9f\x15\x06\b\x00\x1f\x10\x1f`\x1fp\x1f\x80\x1f\x05\x15\x1f\x15\x1f-G\xc8;Q\xc8-\x04\x00?\xe1/\xe1\x1199//]^]\x10\xe1\x10\xe1\x01/\xe1\x10\xde]q\xe1\x1199//\x113/\x10\xe110\x01\"\x0e\x02\x15\x14\x1e\x0232>\x027\x15\x0e\x03#\".\x0254>\x0232\x16\x17\a.\x01\x014>\x0432\x1e\x04\x15\x14\x0e\x04#\".\x047\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x03{=^@!\x1d=_C\x17698\x19\x1815<#f\x98e36i\x99d?\x84;>4a\xfc\xbe6a\x8a\xa7\xc0hh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x8aa6me\xaf\ua145\xea\xafee\xaf\ua145\xea\xafe\x04\x1d,SxKNxR+\a\f\x11\t\x83\v\x12\x0e\aBz\xaage\xa7xC!\x1d\u007f\x1a\x1c\xfe\xbeh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x89b55b\x89\xa7\xc0h\x85\xea\xafee\xaf\ua145\xea\xafee\xaf\xea\x00\x00\x00\x00\x02\x00D\x03\x10\x02B\x05\xc7\x00\x1e\x00-\x00N@/-\x01\x0f\xe0\x00\x1d\x10\x1d\x02\x1d/\x0f/\x1f/O/\u007f/\xaf/\x05$\xe0\v\x17\x17`\v\x01\v.-\xe4\x0f\x0f\x1a\x01'\xe4\x00\x06\xc0\x13\xe4\x1a\xde\x00?\xe1\x1a\xdc\xc4\xe19\x119/\xe1\x01\x10\xc6]2/\x10\xe1]\x10\xd6]\xe12210\x01'\x0e\x03#\".\x02546?\x0154&#\"\x06\a'>\x0132\x16\x15\x11\x03\x0e\x03\x15\x14\x1632>\x02=\x01\x01\xe7\x1c\x12'/8#+H4\x1d\x8d\x8fc=80Z*03u<}w\xc93D)\x122*\":+\x19\x03\x1dR\x16#\x19\r\x1a3M3fl\x05\x04\x1fH9\x1d\x16d\x1a$jz\xfe:\x019\x03\x12\x1e+\x1d3-\x15,A,1\x00\x02\x00R\x00s\x03\x93\x03\xc7\x00\x06\x00\r\x00`@\x11\x02\x04\r\xeb\nP\x04`\x04\x02\x04\n\x04\n\x06\v\t\xb8\xff\xc0@!\t\fH\t\x0f\x0f\x0f\x9f\x0f\xaf\x0f\x03\x06\xeb\x9f\x03\x01\x03\x06\x00\x03\r\a\n\n\x05\x03\x03\x01\f\x05\b\x01\x00/3/3\x129=/\x129\x1133\x1133\x01\x18/]\xe1]\x10\xc6+2\x1199//]\x10\xe1\x11310\x13\x01\x17\x03\x13\a\x01%\x01\x17\x03\x13\a\x01R\x015u\xee\xeeu\xfe\xcb\x01\x97\x016t\xed\xedt\xfe\xca\x02)\x01\x9eN\xfe\xa4\xfe\xa4N\x01\x9b\x1b\x01\x9eN\xfe\xa4\xfe\xa4N\x01\x9b\x00\x01\x00f\x01\x06\x04\x02\x03\x1d\x00\x05\x009@$\x02\xaa\x01\a\x10\a\x01\x96\x04\x01\x8b\x04\x01y\x04\x01V\x04\x01K\x04\x018\x04\x01\x12\x04\x01\t\x04\x01\x04\x04\xad\x05\xb3\x00?\xe1\x01/]]]]]]]]]\x10\xde\xe110\x01\x11#\x11!5\x04\x02\x95\xfc\xf9\x03\x1d\xfd\xe9\x01\x81\x96\x00\x00\x00\xff\xff\x00R\x01\xd1\x02B\x02y\x12\x06\x00\x10\x00\x00\x00\x04\x00d\xff\xec\x06D\x05\xcb\x00\b\x00\x1e\x00:\x00N\x00\xc2@}\xa4\x16\xb4\x16\xc4\x16\x03\xb4\x17\xc4\x17\x02\x17\x16\x01R\x15\x0e\x17\x0e\x16\xc5\x15\x0e\x14\x15\x15\x0e\x0e\t\x00\x19\xc5\x1a\t\xc5\x04\x15\x04\x00\x1a\x01\x00\x1a\xc0\x1a\xd0\x1a\x03\a\x8f\x04\x01\x1a\x04\x1a\x04\x1fE\xc3\x00-\x01\xc0-\x01-P;\xc3\x1f\x0e\x18\xc9\x00\x00\x16\x1b\x16\x15\x1a\b\xc9\x1b\x00\x1a\x01\x0f\x1a\x1f\x1a/\x1a\u007f\x1a\x8f\x1a\x9f\x1a\x06\b\x00\x1b\x10\x1b`\x1bp\x1b\x80\x1b\x05\x1a\x1b\x1a\x1b&@\xc84\x13J\xc8&\x04\x00?\xe1?\xe1\x1199//]^]q\x10\xe1\x1133\x11\x129\x10\xe12\x01/\xe1\x10\xde]q\xe1\x1199//]^]q\x119\x10\xe1\x10\xe12\x119\x87\x10+\x10\x00\xc1\x87\x05+\x10\xc4\x01]10]\x0132654&+\x01\x05\x14\x0e\x02\a\x16\x17\x1e\x02\x1f\x01#\x03#\x11#\x1132\x16\x014>\x0432\x1e\x04\x15\x14\x0e\x04#\".\x047\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02\x02\xe7H[OSYF\x01\x92\x1b-9\x1fC5\x17*!\n\n\xb3\xce_\x9d\u9a1e\xfb\xeb6a\x8a\xa7\xc0hh\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x8aa6me\xaf\ua145\xea\xafee\xaf\ua145\xea\xafe\x03\x00HEJ;\x810K9(\rnW%G8\x11\x11\x01`\xfe\xa0\x03}\x82\xfe\xc3h\xc0\xa7\x8aa66a\x8a\xa7\xc0hh\xc0\xa7\x89b55b\x89\xa7\xc0h\x85\xea\xafee\xaf\ua145\xea\xafee\xaf\xea\x00\x00\x00\x00\x01\xff\xfa\x06\x14\x04\x06\x06\xa0\x00\x03\x00\x12\xb6\x00\x00\x05\x01\x01\xba\x02\x00/\xe1\x01/\x113/10\x01!5!\x04\x06\xfb\xf4\x04\f\x06\x14\x8c\x00\x00\x00\x00\x02\x00{\x03V\x02\xf2\x05\xcb\x00\x13\x00'\x00C@,\x1e\xab\n)\x9f)\x01\x14\xaa0\x00@\x00\x02\x00\x19\xae\x10\x0f \x0f\x02\xe0\x0f\xf0\x0f\x02o\x0f\x01\x00\x0f\x10\x0f \x0f\x03\x06\x0f\x0f#\xae\x05\x04\x00?\xe13/^]]]q\xe1\x01/]\xe1]\x10\xd6\xe110\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x027\x14\x1e\x0232>\x0254.\x02#\"\x0e\x02{2UsAAsV22VsAAsU2{\x1e4F((F5\x1e\x1e5F((F4\x1e\x04\x8fAsV22VsAArU11UrA'E4\x1e\x1e4E'(G5\x1f\x1f5G\x00\x00\x00\x02\x00f\x00\x00\x04\x02\x04\xa2\x00\v\x00\x0f\x00:@!\x10\x11\x01\x0f\b\b\x06\t\xaa\f\x01\x01\x03\xef\x00\x01 \x00`\x00\xa0\x00\x03\x00\r\xad\f\t\x00\xad\x06\x03\xb3\x00?3\xe12/\xe1\x01/]]33\x113\xe122\x113]10\x01!5!\x113\x11!\x15!\x11#\x015!\x15\x01\xe9\xfe}\x01\x83\x96\x01\x83\xfe}\x96\xfe}\x03\x9c\x02\x87\x96\x01\x85\xfe{\x96\xfe\u007f\xfe\xfa\x96\x96\x00\x01\x001\x02J\x02m\x05\xc9\x00\x1e\x00@@\x15\b\xe1\x00\x17 O \u007f \x02 @\x06\nH\x1d\xe1\x01\x0f\x0f\x01\xb8\xff\xc0@\x0e\x15\x18H\x01\b\x1d\v\xe5\x12\xde\x1d\xe5\x01\xdd\x00?\xe1?\xe1\x129\x01/+3/\x10\xe1+]\x10\xde2\xe110\x01!57>\x0354&#\"\x06\a'>\x0132\x1e\x02\x15\x14\x0e\x02\x0f\x01!\x02m\xfd\xc4\xd19H(\x0fB63]-N6\x85RUC;\"A@2&^0A!?[92VU[7\x9d\x00\x01\x00\x1f\x029\x02h\x05\xc9\x000\x00a@<\x03\x00\x19\x19\x0e\x06\x1e\xe1\x00\x00\x15\xe1\x062_2\x8f2\x022@\x06\nH''\x0e@\x19 H\x0e\x03\x19\xe4\x0f\x1a\x1f\x1a/\x1a_\x1a\xdf\x1a\x05\b\x1a\x1a\x12&#\xe5,\xde\x12\xe5\x0f\v\xdf\x00?3\xe1?\xe13\x129/^]\xe19\x01/+3/+]\x10\xde\xe13/\xe1\x11\x129/\x12910\x01\x14\x06\a\x1e\x01\x15\x14\x0e\x02#\"&'5\x1e\x0132654&+\x01532654.\x02#\"\x06\a'>\x0332\x1e\x02\x02NQEXX(S~VF{9?\x845bXk`bb\\T\x14#/\x1b;a3E\x1d=DL,EiF#\x04\xe7Nj\x18\x17jN\x0373\x15\x0e\x03\a#\x01\x89\x16//*\x10\xdb\x10?MQ#y\x04\xf4\x1dLQQ\"\x15\x1bQXS\x1c\x00\x00\x00\x00\x01\x00\xae\xfe\x14\x04\x12\x04J\x00\x1d\x007@\"\r\tG\nU\x1f\x10\x1f \x1f`\x1fp\x1f\x80\x1f\x05\x14\x1dG\x1cT\x1e\x1a\x1b\x03P\x11\x16\v\x15\x1c\t\x0f\x00?3??\xe1?\x01\x10\xf6\xe12]\x10\xf6\xe1210\x01\x14\x1632>\x025\x113\x11#'#\x0e\x01#\"&'\x16\x17\x1e\x01\x15\x11#\x113\x01djoRnC\x1c\xb6\x93\x1b\n0\x90gHj#\x01\x02\x02\x01\xb6\xb6\x01\x87\x82\x824e\x94`\x02:\xfb\xb6\x93ST.*&(#U*\xfe\xc0\x066\x00\x01\x00q\xfe\xfc\x04f\x06\x14\x00\x13\x007@!\x04\x99\x00\x050\x05@\x05P\x05\x04\x06\x05\x05\r\x01\x99\x00\x15\x10\x15\x01\x00\r\x10\r\x02\r\x03\x12\x00\x05\x00\x00/2?\xc1\x01/]]\x10\xd6\xe1\x129/^]\xe110\x01#\x11#\x11#\x11\x06#\".\x0254>\x023!\x04fx\xcfy=U_\x9bm\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x93\x14\".\x1b\x1a/\"\x14\x14\"/\x1a\x1b.\"\x14\x02\xd3&5!\x0f\x0f!5&%4\"\x10\x10\"4\x00\x00\x01\x00#\xfe\x14\x01\x98\x00\x00\x00\x19\x009@\x1f\x14\x13\x13\x15\u007f\x12\x8f\x12\x02\x12\x12\x06\r\x84\x00\x1b\x06\x1a\x12\x8c\x15@\t\x0eH\x15\x15\x13\n\x8d\x03\x00/\xe1/9/+\xe1\x01\x10\xc6\x10\xd6\xe1\x119/]33\x11310\x01\x14\x06#\"&'5\x1e\x0132654.\x02'73\a\x1e\x03\x01\x98\x8d\x96\x16-\x0f\x0f1\x10GP\x1a.?%Zy9\":+\x19\xfe\xe1al\x06\x03l\x03\x03+1\x18#\x1a\x13\t\xb0s\b\x1a):\x00\x00\x01\x00?\x02J\x01\xba\x05\xb6\x00\x0e\x004@!O\x10\u007f\x10\x02\x10@\x06\nH\x0e\x0e\x02\xe1\x00\u007f\x03\x8f\x03\x02 \x030\x03\x02\x03\x02\xdd\r\t\xe5\x00\xdc\x00?\xe1\xcd?\x01/]]3\xe13/+]10\x013\x11#\x114>\x027\x0e\x01\x0f\x01'\x013\x87\x91\x01\x03\x03\x01\x0e&\x16^J\x05\xb6\xfc\x94\x02\x04\x19<<8\x16\x11(\x11I`\x00\x00\x00\x00\x02\x00B\x03\x10\x02\x8b\x05\xc7\x00\x13\x00\x1f\x00.\xb2\x1a\xe0\x00\xb8\xff\xc0@\x14\t\x0fH\x00!\x0f!\x01\x14\xe0\n \x17\xe4\x05\xc0\x1d\xe4\x0f\xde\x00?\xe1\x1a\xdc\xe1\x01\x10\xd6\xe1]\x10\xd6+\xe110\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x05\x14\x1632654&#\"\x06\x02\x8b)MmD?jN+)LmD>kN,\xfe:KVUKKUVK\x04mS\x82Y//Y\x82SS\x81X..X\x81Swyywxss\x00\x00\x02\x00T\x00s\x03\x96\x03\xc7\x00\x06\x00\r\x00V@/\x0f\x0f\x9f\x0f\xaf\x0f\x03\a\xeb\x04\x02\n\x02\n\x02\x03\v\t\x0e\x00\xeb\x9f\x03\x01\x10\x03 \x03@\x03\x03\x03\r\a\n\x06\x00\x03\n\x03\n\x03\x01\f\x05\b\x01\x00/3/3\x1299=//\x1133\x1133\x01\x18/]]\xe1\x10\xc62\x1199//\x113\xe1]10\t\x01'\x13\x037\x01\x05\x01'\x13\x037\x01\x03\x96\xfe\xcat\xed\xedt\x016\xfeh\xfe\xcbu\xee\xeeu\x015\x02\x0e\xfeeN\x01\\\x01\\N\xfeb\x1b\xfeeN\x01\\\x01\\N\xfeb\x00\xff\xff\x00?\x00\x00\x05\x8b\x05\xb6\x10&\x00{\x00\x00\x10'\x00\xd1\x02J\x00\x00\x11\a\x00\xd2\x02\xfc\xfd\xb7\x000@\x1d\x03\x02\x16\x18\x03\x02\xbf\x16\x01\x8f\x16\x01?\x16\x01\x16\x01@\x11\x01\x00\x11\x01\x11\x00@\x00\x01\x00\x11]5\x11]]5\x11]]]55\x00?55\x00\x00\xff\xff\x00,\x00\x00\x05\xa0\x05\xb6\x10&\x00{\xed\x00\x10'\x00\xd1\x025\x00\x00\x11\a\x00t\x033\xfd\xb7\x00(@\x18\x02\x14\x18\x02\x00\x14\x01\x14\x01\xb0\x11\x01@\x11\x01\x11\x00p\x00\x01@\x00\x01\x00\x11]]5\x11]]5\x11]5\x00?5\x00\x00\xff\xff\x00\x1f\x00\x00\x05\xce\x05\xc9\x10&\x00u\x00\x00\x10'\x00\xd1\x02\xa8\x00\x00\x11\a\x00\xd2\x03?\xfd\xb7\x00<@'\x03\x028\x18\x03\x02p8\x01P8\x018\x01\xb43\x01\xa43\x01\x843\x01d3\x01P3\x0103\x01 3\x013\x0fL\x01]\x11]]]]]]]5\x11]]55\x00?55\x00\x00\x00\x02\x00D\xfew\x03D\x04^\x00'\x00;\x00D@\x122\x9a(('F\x00\x00\v\x14=\x0f=\x01\b\vF\x1c\xb8\xff\xc0@\x10\x0f\x1bH\x1c\v\x17''-\x9b7\x10\x13\x10Q\x17\x00/\xe13?\xe52/\x129\x01/+\xe1^]\x10\xce\x119/\xe13/\xe110\x01\x15\x14\x0e\x02\a\x0e\x03\x15\x14\x1e\x023267\x17\x0e\x01#\".\x0254>\x027>\x03=\x01\x13\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\x02P\x10'A20D+\x15\x1e9U7T\x96E@R\xbca]\x95g8\x1b5Q64B&\x0e\xba\x13#.\x1b\x1a.#\x14\x14#.\x1a\x1b.#\x13\x02\xa4%:[QL*)CEO50O9\x1f3#\x92*:3`\x8aXDhZT/-C>C+\x13\x01/&5!\x0f\x0f!5&%4\"\x10\x10\"4\xff\xff\x00\x00\x00\x00\x04\xdd\as\x12&\x00$\x00\x00\x11\a\x00C\xff\xbd\x01R\x00\x15\xb4\x02\x15\x05&\x02\xb8\xff\x9c\xb4\x1b\x15\x04\a%\x01+5\x00+5\x00\xff\xff\x00\x00\x00\x00\x04\xdd\as\x12&\x00$\x00\x00\x11\a\x00v\x00\x8d\x01R\x00\x13@\v\x02!\x05&\x02l\x15\x1b\x04\a%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x00\x00\x00\x04\xdd\as\x12&\x00$\x00\x00\x11\a\x00\xc3\x00\x1f\x01R\x00\x15\xb4\x02\x15\x05&\x02\xb8\xff\xff\xb4\x1d\x15\x04\a%\x01+5\x00+5\x00\xff\xff\x00\x00\x00\x00\x04\xdd\a5\x12&\x00$\x00\x00\x11\a\x00\xc5\x00\x06\x01R\x00\x13@\v\x02\x1d\x05&\x02\x01\x1e,\x04\a%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x00\x00\x00\x04\xdd\a+\x12&\x00$\x00\x00\x11\a\x00j\x00!\x01R\x00\x17@\r\x03\x02\x1e\x05&\x03\x02\x01\x15)\x04\a%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\x00\x00\x00\x04\xdd\a\x04\x12&\x00$\x00\x00\x11\x06\x00\xc4\x1f}\x001@ \x03\x02\xef\x1a\x01\xdf\x1a\x01P\x1a\x01@\x1a\x01 \x1a\x01\x10\x1a\x01\x00\x1a\x01\x1a\x03\x02\x00\x1f\x15\x04\a%\x01+55\x00\x11]]]]]]]55\x00\x00\x00\x00\x02\xff\xfe\x00\x00\x06V\x05\xb6\x00\x0f\x00\x13\x00\x84@*\x06\x13\n\x0eZ\x01\x11\x01\x10\x03\x04\x13\xa9\x13\x01$\x134\x13T\x13\x03\x10\x01\x01\x14\f\x01\x13\x01\f\f\x01\x13\x03\x05\b\x00g\x15\x04\x05\xb8\xff\xf0@ \x05\t\x13_\x06\x03_\x10\r_\nO\n\x01\x0f\n\xaf\n\x02\b\x10\n\x10\n\x06\x03\x04\x0e_\x05\x01\x12\x00?3\xe1/?99//^]q\x10\xe1\x10\xe1\x10\xe12\x01/83\x10\xe62\x11\x179///]]]]}\x87\xc4\xc4\x11\x013\x10\xe12\x11310)\x01\x11!\x03#\x01!\x15!\x11!\x15!\x11!\x01!\x11#\x06V\xfd\b\xfe%\u02fa\x02\x8f\x03\xc9\xfd\xc3\x02\x16\xfd\xea\x02=\xfbu\x01\x93l\x01\xc5\xfe;\x05\xb6\xa4\xfe<\xa2\xfd\xf8\x01\xc6\x02\xa8\x00\x00\x00\xff\xff\x00}\xfe\x14\x04\x98\x05\xcb\x12&\x00&\x00\x00\x11\a\x00z\x01\xfc\x00\x00\x00\v\xb6\x01O*$\x18 %\x01+5\x00\x00\x00\xff\xff\x00\xc7\x00\x00\x03\xbe\as\x12&\x00(\x00\x00\x11\a\x00C\xff\xb7\x01R\x00\x15\xb4\x01\f\x05&\x01\xb8\xff\u00b4\x12\f\x01\x00%\x01+5\x00+5\x00\xff\xff\x00\xc7\x00\x00\x03\xbe\as\x12&\x00(\x00\x00\x11\a\x00v\x00?\x01R\x00\x13@\v\x01\x18\x05&\x01J\f\x12\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xc7\x00\x00\x03\xbe\as\x12&\x00(\x00\x00\x11\a\x00\xc3\xff\xf1\x01R\x00\x15\xb4\x01\f\x05&\x01\xb8\xff\xfd\xb4\x14\f\x01\x00%\x01+5\x00+5\x00\xff\xff\x00\xc7\x00\x00\x03\xbe\a+\x12&\x00(\x00\x00\x11\a\x00j\xff\xf5\x01R\x00\x17@\r\x02\x01\x15\x05&\x02\x01\x01\f \x01\x00%\x01+55\x00+55\x00\x00\x00\xff\xff\x00>\x00\x00\x02d\as\x12&\x00,\x00\x00\x11\a\x00C\xfe\xb5\x01R\x00\x15\xb4\x01\f\x05&\x01\xb8\xff\xa8\xb4\x12\f\x01\x00%\x01+5\x00+5\x00\xff\xff\x00R\x00\x00\x02\x8a\as\x12&\x00,\x00\x00\x11\a\x00v\xffx\x01R\x00\x13@\v\x01\x18\x05&\x01j\f\x12\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\x11\x00\x00\x02\xa9\as\x12&\x00,\x00\x00\x11\a\x00\xc3\xff\x0f\x01R\x00\x13@\v\x01\f\x05&\x01\x02\x14\f\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00@\x00\x00\x02w\a+\x12&\x00,\x00\x00\x11\a\x00j\xff\r\x01R\x00\x17@\r\x02\x01\x15\x05&\x02\x01\x00\f \x01\x00%\x01+55\x00+55\x00\x00\x00\x00\x02\x00/\x00\x00\x04\xfc\x05\xb6\x00\x10\x00\x1f\x00]@:\x1a\x1a\x0e\x11[\bg! !\x01\x18\x1cZ\x0e\x10\x10\x01\x0ed \x1b\x10_\x18\x0f\x00\x01\x0f\x00?\x00o\x00\xaf\x00\xdf\x00\xff\x00\x06\b\x00@\x1a\x1dH\x00\x00\x02\x1c`\x0e\x12\x17`\x02\x03\x00?\xe1?\xe1\x119/+^]q3\xe12\x01\x10\xe622/\x10\xe12]\x10\xf6\xe1\x119/10\x133\x11!2\x1e\x01\x12\x15\x14\x02\x06\x04#!\x11#%4.\x02+\x01\x11!\x15!\x113 \x00/\x98\x01\x97\x99\xf8\xae_`\xb6\xfe\xf7\xa8\xfe\x92\x98\x04\bB~\xb8u\xc9\x01P\xfe\xb0\xa2\x01\b\x01\f\x03%\x02\x91\\\xb5\xfe\xf4\xb0\xb9\xfe\xe9\xbb^\x02\x83`\x92\u054aC\xfe\x0e\xa2\xfe\x1d\x01$\xff\xff\x00\xc7\x00\x00\x05\x0e\a5\x12&\x001\x00\x00\x11\a\x00\xc5\x00\x8b\x01R\x00\x13@\v\x01 \x05&\x01\n!/\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00}\xff\xec\x05q\as\x12&\x002\x00\x00\x11\a\x00C\x00T\x01R\x00\x15\xb4\x02(\x05&\x02\xb8\xff\xab\xb4.(\n\x00%\x01+5\x00+5\x00\xff\xff\x00}\xff\xec\x05q\as\x12&\x002\x00\x00\x11\a\x00v\x01\x02\x01R\x00\x13@\v\x024\x05&\x02X(.\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00}\xff\xec\x05q\as\x12&\x002\x00\x00\x11\a\x00\xc3\x00\xae\x01R\x00\x13@\v\x02(\x05&\x02\x050(\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00}\xff\xec\x05q\a5\x12&\x002\x00\x00\x11\a\x00\xc5\x00}\x01R\x00\x15\xb4\x020\x05&\x02\xb8\xff\xf0\xb41?\n\x00%\x01+5\x00+5\x00\xff\xff\x00}\xff\xec\x05q\a+\x12&\x002\x00\x00\x11\a\x00j\x00\xaa\x01R\x00\x17@\r\x03\x021\x05&\x03\x02\x01(<\n\x00%\x01+55\x00+55\x00\x00\x00\x00\x01\x00\x8d\x01-\x03\xdd\x04{\x00\v\x00\x87\xb9\x00\x06\xff\xf0\xb3\x14\x17H\x06\xb8\xff\xe0@\x18\x0f\x12H\x00\x10\x14\x17H\x00 \x0f\x12H\t\x10\x14\x17H\t \x0f\x12H\x03\xb8\xff\xf0\xb3\x14\x17H\x03\xb8\xff\xe0@0\x0f\x12H@\r\x01\a\x05\x05\x03\v\x01\x01P\x03\x01\x03\b\n\n\x04\x02\x02 \x00\x01\x00\x00 \x00P\x00p\x00\x80\x00\xa0\x00\xc0\x00\xd0\x00\xf0\x00\t\x06\x00\xb3\x00\x19?^]q2\x1132\x113\x01/]3\x113\x113\x113]10\x00++++\x01++++\t\x017\t\x01\x17\t\x01\a\t\x01'\x01\xcb\xfe\xc2i\x01=\x01Bh\xfe\xbf\x01?f\xfe\xbe\xfe\xc3g\x02\xd3\x01?i\xfe\xc2\x01>g\xfe\xbf\xfe\xc0f\x01=\xfe\xc5g\x00\x00\x00\x00\x03\x00}\xff\xb4\x05q\x05\xfc\x00\x1a\x00&\x001\x00\\@:)\x1f*\x1e\x04\x1b'[\x01\x19\v\x0e\x04\x11\x04g3\xc03\x01\xbf3\x01p3\x01/3_3\x02\x1b[\x11f2\x1f)\x1e*\x04-\"_\x19\x01\x0e\v\x04\t\x1a\x16\x04-_\f\t\x13\x00?3\xe1?3\x12\x179\xe1\x11\x179\x01\x10\xf6\xe1]]]]\x10\xf6\x11\x179\xe1\x11\x17910\x01\a\x16\x12\x15\x14\x02\x0e\x01#\"'\a'7&\x0254\x12>\x0132\x16\x177\x01\x14\x16\x17\x01.\x01#\"\x0e\x02\x05\x10'\x01\x1e\x0132>\x02\x05\x14\\[^Q\xa0\ud6fd\x85N\x89Za[L\x9e\xf0\xa3^\xa1BP\xfc\xb7.0\x02C0rGr\xa6l4\x03jX\xfd\xbe/rEr\xa5k2\x05\xae\x95c\xfe\u07b7\xa9\xfe\xea\xc6lG\u007fN\x91d\x01*\xbe\xaa\x01\x15\xc4k*&\u007f\xfc\xe1\x83\xd1N\x03\xb1\x1d Q\x97\u068a\x01\x01\x97\xfcT\x1c\x1eQ\x99\xdb\x00\x00\xff\xff\x00\xb8\xff\xec\x04\xdd\as\x12&\x008\x00\x00\x11\a\x00C\x00=\x01R\x00\x15\xb4\x01\x18\x05&\x01\xb8\xff\xc0\xb4\x1e\x18\v\x00%\x01+5\x00+5\x00\xff\xff\x00\xb8\xff\xec\x04\xdd\as\x12&\x008\x00\x00\x11\a\x00v\x00\xc5\x01R\x00\x13@\v\x01$\x05&\x01H\x18\x1e\v\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xb8\xff\xec\x04\xdd\as\x12&\x008\x00\x00\x11\a\x00\xc3\x00y\x01R\x00\x15\xb4\x01\x18\x05&\x01\xb8\xff\xfd\xb4 \x18\v\x00%\x01+5\x00+5\x00\xff\xff\x00\xb8\xff\xec\x04\xdd\a+\x12&\x008\x00\x00\x11\a\x00j\x00}\x01R\x00\x17@\r\x02\x01!\x05&\x02\x01\x01\x18,\v\x00%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\x00\x00\x00\x047\as\x12&\x00<\x00\x00\x11\a\x00v\x001\x01R\x00\x13@\v\x01\x15\x05&\x01c\t\x0f\a\x02%\x01+5\x00+5\x00\x00\x00\x00\x02\x00\xc7\x00\x00\x043\x05\xb6\x00\x10\x00\x1b\x00<@!\x17[\x00g\x1d\x9f\x1d\x01\x10\x1d\x01\x11\v\aZ\bd\x1c\x11`\x06\x1b`\v\x06\v\x06\v\a\t\x03\a\x12\x00??\x1299//\x10\xe1\x10\xe1\x01\x10\xf6\xe122]]\x10\xf6\xe110\x01\x14\x0e\x02+\x01\x11#\x113\x1532\x1e\x02\x0132>\x0254&+\x01\x0437~\u03d8\x96\xba\xba\xb0\x86\xc2~<\xfdN\x81]\x8b[.\xa4\xae\xa0\x03\x0e[\xa8\x81M\xfe\xc3\x05\xb6\xfc9m\xa0\xfeg GqQ\x8f\x88\x00\x00\x01\x00\xae\xff\xec\x04u\x06\x1f\x00K\x00m@H\aF.5G\x00\x0f\x19\x1f\x19/\x19\x03\x19@\r\x13H_.o.\x02\x0f\x00\x1f\x00/\x00\x03\b\x19.\x00\x00.\x19\x03A$G\x11WM\x10M M\xc0M\x03@GATL$\a5\x03\x16:PG\x01A\x15\x1fP\x1a\x16\x16\x00?3\xe1??\xe1\x12\x179\x01\x10\xf6\xe1]\x10\xf6\xe1\x12\x179///^]]+]\x10\xe1\x10\xe110\x01\x14\x0e\x04\x15\x14\x1e\x02\x17\x1e\x03\x15\x14\x0e\x02#\"&'5\x1e\x0332>\x0254.\x02'.\x0354>\x0454.\x02#\"\x0e\x02\x15\x11#\x114>\x0232\x1e\x02\x03\xf2+?K?+\x0e'F98X=!8e\x8dUa\x8b5\x1aAHL%8Q4\x18\x11+H8?U5\x16)>H>)!W~Q'#\"\xa6\x10\x1f\x18\x0f\x19-@($;8:#(DCF*6O?6:C,*>)\x13\x130SA\xfbN\x04\xb0h\x8dU%&Lt\x00\x00\xff\xff\x00^\xff\xec\x03\x9c\x06!\x12&\x00D\x00\x00\x11\x06\x00C\x94\x00\x00\x15\xb4\x023\x11&\x02\xb8\xff\xe5\xb493\f\"%\x01+5\x00+5\x00\x00\x00\xff\xff\x00^\xff\xec\x03\x9c\x06!\x12&\x00D\x00\x00\x11\x06\x00v5\x00\x00\x13@\v\x02?\x11&\x02\x8539\f\"%\x01+5\x00+5\x00\xff\xff\x00^\xff\xec\x03\x9c\x06!\x12&\x00D\x00\x00\x11\x06\x00\xc3\xe2\x00\x00\x13@\v\x023\x11&\x023;3\f\"%\x01+5\x00+5\x00\xff\xff\x00^\xff\xec\x03\x9c\x05\xe3\x12&\x00D\x00\x00\x11\x06\x00\u017d\x00\x00\x13@\v\x02;\x11&\x02)\x0132\x16\x17>\x0132\x1e\x02\x1d\x01!\x1e\x0132>\x027\x15\x0e\x03#\"&'\x0e\x03#\".\x027\x14\x1632>\x02=\x01\a\x0e\x03\x01\"\x06\a!4.\x02^\xe7\xec\xb8\x1d7Q4S\x8fB@J\xb6d\x83\xa6+3\xa6ga\x9al9\xfd`\x05\x93\x931UNJ%'KOU1\x8a\xca>\"L_tJG{Z4\xbdaO=hL+\x8fZzI \x03\x85n\u007f\v\x01\xd7\x1a7T\x013\xa4\xb0\b\aECZ7\x180\"\x89(8U]U]G\x81\xb5nq\xc1\xb6\n\x13\x1d\x12\xa2\x13\x1c\x12\brs6U;\x1f'Q{R\\V&MuOc\a\x04 9Q\x02c\x9c\x95DqP,\x00\xff\xff\x00q\xfe\x14\x03o\x04^\x12&\x00F\x00\x00\x11\a\x00z\x01B\x00\x00\x00\v\xb6\x01/& \x05\r%\x01+5\x00\x00\x00\xff\xff\x00q\xff\xec\x03\xe1\x06!\x12&\x00H\x00\x00\x11\x06\x00C\x94\x00\x00\x15\xb4\x02(\x11&\x02\xb8\xff\xb9\xb4.(\x05\x0f%\x01+5\x00+5\x00\x00\x00\xff\xff\x00q\xff\xec\x03\xe1\x06!\x12&\x00H\x00\x00\x11\x06\x00vR\x00\x00\x13@\v\x024\x11&\x02v(.\x05\x0f%\x01+5\x00+5\x00\xff\xff\x00q\xff\xec\x03\xe1\x06!\x12&\x00H\x00\x00\x11\x06\x00\xc3\xde\x00\x00\x13@\v\x02(\x11&\x02\x030(\x05\x0f%\x01+5\x00+5\x00\xff\xff\x00q\xff\xec\x03\xe1\x05\xd9\x12&\x00H\x00\x00\x11\x06\x00j\xda\x00\x00\x17@\r\x03\x021\x11&\x03\x02\x00(<\x05\x0f%\x01+55\x00+55\x00\xff\xff\xff\xde\x00\x00\x01g\x06!\x12&\x00\xc2\x00\x00\x11\a\x00C\xfeU\x00\x00\x00\x15\xb4\x01\x04\x11&\x01\xb8\xff\x9a\xb4\n\x04\x01\x00%\x01+5\x00+5\x00\xff\xff\x00\xae\x00\x00\x02B\x06!\x12&\x00\xc2\x00\x00\x11\a\x00v\xff0\x00\x00\x00\x13@\v\x01\x10\x11&\x01t\x04\n\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\xff\xbd\x00\x00\x02U\x06!\x12&\x00\xc2\x00\x00\x11\a\x00\xc3\xfe\xbb\x00\x00\x00\x13@\v\x01\x04\x11&\x01\x00\f\x04\x01\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\xff\xee\x00\x00\x02%\x05\xd9\x12&\x00\xc2\x00\x00\x11\a\x00j\xfe\xbb\x00\x00\x00\x17@\r\x02\x01\r\x11&\x02\x01\x00\x04\x18\x01\x00%\x01+55\x00+55\x00\x00\x00\x00\x02\x00o\xff\xec\x04-\x06#\x00'\x009\x00t@F\x12(H\x00# \x16\x19\x04\x1c\"\x18\x1c\"\"\x1c\x18\x03\n\x00W;@;\xd0;\xe0;\x03\x0f;\x01\x062H\nV: \x19#\x16\x04\x17!!\x1d-P\x0f\x12\x0f\xaf\x0f\xbf\x0f\x020\x0f\x01\x17\x0f\x17\x0f\x1d\x017P\x05\x16\x00?\xe1?99//]]\x113\x10\xe1\x113\x11\x12\x179\x01\x10\xf6\xe1^]]\x10\xe6\x11\x179///\x11\x12\x179\x10\xe1210\x01\x14\x0e\x02#\".\x0254>\x0232\x16\x177.\x01'\x05'7.\x01'7\x1e\x01\x177\x17\a\x1e\x03\a4.\x02#\"\x0e\x02\x15\x14\x1e\x02326\x04-C}\xb2oh\xaf\u007fG?v\xa8if\x9a+\b\x1fxZ\xff\x00J\xd9(U/FAz;\xe3J\xc3CoO,\xbc\"FnKMmF!!GmL\x9a\x87\x02=\x8e\u0718OB\u007f\xb9ww\xb8~A;<\x04v\xc0Q\x99r\x83\x1c7\x1a{ H,\x8aquA\x9c\xbb\u07708kR2.X\x83UL}Z1\xc7\x00\xff\xff\x00\xae\x00\x00\x04\x12\x05\xe3\x12&\x00Q\x00\x00\x11\x06\x00\xc5\xf9\x00\x00\x13@\v\x01!\x11&\x01\x02\"0\v\x17%\x01+5\x00+5\x00\xff\xff\x00q\xff\xec\x04-\x06!\x12&\x00R\x00\x00\x11\x06\x00C\xd8\x00\x00\x15\xb4\x02 \x11&\x02\xb8\xff\u05f4& \n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00q\xff\xec\x04-\x06!\x12&\x00R\x00\x00\x11\x06\x00vP\x00\x00\x13@\v\x02,\x11&\x02N &\n\x00%\x01+5\x00+5\x00\xff\xff\x00q\xff\xec\x04-\x06!\x12&\x00R\x00\x00\x11\x06\x00\xc3\xfb\x00\x00\x15\xb4\x02 \x11&\x02\xb8\xff\xfa\xb4( \n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00q\xff\xec\x04-\x05\xe3\x12&\x00R\x00\x00\x11\x06\x00\xc5\xe2\x00\x00\x15\xb4\x02(\x11&\x02\xb8\xff\xfd\xb4)7\n\x00%\x01+5\x00+5\x00\x00\x00\xff\xff\x00q\xff\xec\x04-\x05\xd9\x12&\x00R\x00\x00\x11\x06\x00j\xf9\x00\x00\x19\xb6\x03\x02)\x11&\x03\x02\xb8\xff\xf9\xb4 4\n\x00%\x01+55\x00+55\x00\x00\x00\x00\x03\x00f\x00\xf8\x04\x02\x04\xac\x00\x03\x00\x17\x00+\x00`@\x150-\x01\"\xaa\x18\x18\x0e\xaaV\x03f\x03\x02(\x038\x03\x02\x03\x00\xb8\xff\xf0@(\t\rH\x00\x04'\xad\x10\x1d\x01\x0f\x1d\x01\x1d\x1d\x01\t\xad\x00\x13\x10\x13 \x13`\x13\xb0\x13\xc0\x13\xd0\x13\a\a\x13\x13\x00\xad\x01\xb3\x00?\xe13/^]\xe1\x113/]q\xe1\x01/3+3]]\xe13/\xe1]10\x135!\x15\x014>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x114>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02f\x03\x9c\xfd\xbf\x12\x1f)\x18\x17* \x12\x12 *\x17\x18)\x1f\x12\x12\x1f)\x18\x17* \x12\x12 *\x17\x18)\x1f\x12\x02\x87\x96\x96\xfe\xee#/\x1e\r\r\x1e/#!/\x1f\x0e\x0e\x1f/\x02\xdb#/\x1e\r\r\x1e/#!/\x1f\x0e\x0e\x1f/\x00\x00\x00\x00\x03\x00s\xff\xb4\x04/\x04\x91\x00\x1a\x00$\x00-\x00\\@;'\x1f(\x1e\x04\x1b%H\x17\x18\x16\x15\a\b\n\t\b\r\x00W/@/\xd0/\xe0/\x03\x0f/\x01\x06\x1bH\rV.(\x1e'\x1f\x04+\"P\a\n\x18\x15\x04\x05\x16\x12\x10+P\b\x05\x16\x00?\xc6\xe1?\xc6\x12\x179\xe1\x11\x179\x01\x10\xf6\xe1^]]\x10\xf6\x11\x179\xe1\x11\x17910\x01\x14\x0e\x02#\"'\a'7.\x0154>\x0232\x16\x177\x17\a\x1e\x01\x05\x14\x16\x17\x01.\x01#\"\x06\x054'\x01\x1e\x01326\x04/C}\xb2o}bD\x83P?FC|\xb3o?q1D\x83P>E\xfd\x00\x13\x16\x01\x8d\x1dK-\x9a\x87\x02D'\xfer\x1fH-\x9a\x87\x02'\x89\u0551L5mJ\x83H\u0549\x88\u04d1K\x1d\x1clI\x81I\u0446T\x833\x02\x87\x11\x12\xcf\u045fc\xfd{\x11\x10\xd3\x00\x00\x00\xff\xff\x00\xa4\xff\xec\x04\b\x06!\x12&\x00X\x00\x00\x11\x06\x00C\xa3\x00\x00\x15\xb4\x01\x1b\x11&\x01\xb8\xff\x9b\xb4!\x1b\f\x19%\x01+5\x00+5\x00\x00\x00\xff\xff\x00\xa4\xff\xec\x04\b\x06!\x12&\x00X\x00\x00\x11\x06\x00v`\x00\x00\x13@\v\x01'\x11&\x01W\x1b!\f\x19%\x01+5\x00+5\x00\xff\xff\x00\xa4\xff\xec\x04\b\x06!\x12&\x00X\x00\x00\x11\x06\x00\xc3\b\x00\x00\x13@\v\x01\x1b\x11&\x01\x00#\x1b\f\x19%\x01+5\x00+5\x00\xff\xff\x00\xa4\xff\xec\x04\b\x05\xd9\x12&\x00X\x00\x00\x11\x06\x00j\x02\x00\x00\x19\xb6\x02\x01$\x11&\x02\x01\xb8\xff\xfb\xb4\x1b/\f\x19%\x01+55\x00+55\x00\x00\x00\xff\xff\x00\n\xfe\x14\x03\xdf\x06!\x12&\x00\\\x00\x00\x11\x06\x00v\x0e\x00\x00\x13@\v\x01/\x11&\x01g#)\x00\x0f%\x01+5\x00+5\x00\x00\x02\x00\xae\xfe\x14\x04?\x06\x14\x00 \x001\x008@\x1f/H\nW3\x103\x01' \x1f\x15\x1bG\x1cT2\x1d\x00\x1b\x1b,P\x15\x0f\x16!P\x00\x05\x10\x00?3\xe1?3\xe1??\x01\x10\xf6\xe12222]\x10\xf6\xe110\x01>\x0332\x1e\x02\x15\x14\x0e\x02#\".\x02'#\x16\x17\x1e\x01\x15\x11#\x113\x11\a%\"\x0e\x02\a\x15\x14\x1e\x0232654&\x01d\x17:M`<^\x9am<\x0373\x1e\x03\x17\x03\x9ay3l46j3y\x1aDC;\x10\xc0\x10;CE\x19\x04\xd9\"a77a\"\x1b\x1dLQQ\"\"QQL\x1d\x00\x02\x01m\x04\xd9\x031\x06\x87\x00\x13\x00\x1f\x00@@-\x14\x83\x0f\x00?\x00O\x00_\x00\x04\x00\x1a\x830\n\x01\n\x17\x8c\x0f\x0f\x1f\x0f?\x0fO\x0f_\x0f\xaf\x0f\xff\x0f\a\x06\x0f\x1d\x8c\x0f\x05_\x05\x02\x05\x00/]\xe1\xd4^]\xe1\x01/]\xe1\xd4]\xe110\x01\x14\x0e\x02#\".\x0254>\x0232\x1e\x02\a4&#\"\x06\x15\x14\x16326\x031#=T12R; ;R20T>#u?12?981?\x05\xb23Q8\x1d\x1d8O33O8\x1d\x1d7O45<<55<<\x00\x01\x01\x02\x04\xd9\x03\xd1\x05\xe3\x00\x1b\x008@#\x0f\x17/\x17\x02\x17\x00\t \t\x02\a\t\x16\x05\x8f\x0e@\x10\x13H\x0e@\a\vH\x0e\x0e\x13\x8f\t\x0f\x00\x01\x00\x00/]2\xe13/++\xe13\x01/^]\xcc]10\x01\".\x02#\"\x06\a#>\x0332\x1e\x0232673\x0e\x03\x02\xfe(OLF -0\x0eh\x05!5J.*QLE\x1d-.\x0fi\x05!5J\x04\xdb#+#5>\x0373\x0e\x03\a%\x0e\x0e'.4\x19\x89\x0f\x1d\x1a\x16\b\x03\xc1\x166z|{8=\x84\x83|5\x00\x00\x00\x01\x00\x17\x03\xc1\x01P\x05\xb6\x00\f\x00%@\x17_\x0e\x01\x06\a\f\x98\x0f\x01_\x01o\x01\xbf\x01\xcf\x01\x05\x01\x06\x9c\x00\x03\x00?\xe5\x01/]\xe1/3]10\x01\x17\x0e\x03\a#>\x037\x01B\x0e\x0e'/3\x19\x89\x0e\x1d\x1b\x16\b\x05\xb6\x167y}z8<\x84\x84|5\x00\x00\x01\x00?\xfe\xf8\x01y\x00\xee\x00\f\x005\xb9\x00\x0e\xff\xc0@\x14\n\x18H\f\x98\x0f\x01_\x01o\x01\u007f\x01\xcf\x01\x05\x01\x01\x06\a\xb8\xff\xc0\xb7\x10\x15H\a\x06\x9c\x00\xa8\x00?\xe5\x01/+33/]\xe1+10%\x17\x0e\x03\a#>\x037\x01j\x0f\x0e'/3\x19\x8a\x0f\x1d\x1b\x16\b\xee\x176z|{8=\x84\x83}5\x00\x00\x00\x02\x00\x17\x03\xc1\x02\xd1\x05\xb6\x00\f\x00\x19\x00b@H\xbf\x1b\x01\x90\x1b\x01\x0f\x1b_\x1bo\x1b\x03\x13\x0f\x14_\x14o\x14\u007f\x14\xbf\x14\xcf\x14\xdf\x14\a\x14\x14\x19\x98\x0e\f\x98\x00\x01P\x01`\x01p\x01\xb0\x01\xc0\x01\xd0\x01\a\x01\x01\x06\x0f\a_\ao\a\xbf\a\xcf\a\x05\a\x19\f\x9c\x13\x06\x03\x00?3\xe52\x01/]33/]\xe1/\xe13/]3]]]10\x01'>\x0373\x0e\x03\a!'>\x0373\x0e\x03\a\x01\xa6\x0e\x0e'.4\x19\x89\x0f\x1d\x1a\x16\b\xfd\xb8\x0e\x0e'.4\x19\x89\x0f\x1d\x1a\x16\b\x03\xc1\x166z|{8=\x84\x83|5\x166z|{8=\x84\x83|5\x00\x02\x00\x17\x03\xc1\x02\xd1\x05\xb6\x00\f\x00\x19\x00b@H\xbf\x1b\x01\x90\x1b\x01\x0f\x1b_\x1bo\x1b\x03\x13\x00\x14P\x14`\x14p\x14\xb0\x14\xc0\x14\xd0\x14\a\x14\x14\x19\x98\x0f\x0e_\x0eo\x0e\xbf\x0e\xcf\x0e\x05\x0e\f\x98\x0f\x01_\x01o\x01\u007f\x01\xbf\x01\xcf\x01\xdf\x01\a\x01\x01\x06\a\x13\x06\x9c\r\x00\x03\x00?2\xe52\x01/33/]\xe1/]\xe13/]3]]]10\x01\x17\x0e\x03\a#>\x037!\x17\x0e\x03\a#>\x037\x01B\x0e\x0e'/3\x19\x89\x0e\x1d\x1b\x16\b\x02H\x0e\x0e'/3\x19\x89\x0e\x1d\x1b\x16\b\x05\xb6\x167y}z8<\x84\x84|5\x167y}z8<\x84\x84|5\x00\x02\x00?\xfe\xf8\x02\xfa\x00\xee\x00\f\x00\x19\x00~@Q\xd0\x1b\xe0\x1b\xf0\x1b\x03\xa4\x1b\xb4\x1b\xc4\x1b\x03\x90\x1b\x01\x02 \x1b0\x1b@\x1b`\x1bp\x1b\x80\x1b\x06\x13\x00\x14P\x14`\x14p\x14\xc0\x14\xd0\x14\x06\x14\x14\x19\x98\x90\x0e\xe0\x0e\xf0\x0e\x03\x0f\x0e_\x0e\x02\x0e\f\x98\x0f\x01_\x01o\x01\u007f\x01\xcf\x01\xdf\x01\x06\x01\x01\x06\a\xb8\xff\xc0@\n\x10\x18H\a\x13\x06\x9c\r\x00\xa8\x00?2\xe52\x01/+33/]\xe1/]]\xe13/]3]_]]]10%\x17\x0e\x03\a#>\x037!\x17\x0e\x03\a#>\x037\x01j\x0f\x0e'/3\x19\x8a\x0f\x1d\x1b\x16\b\x02H\x0e\x0e'/3\x19\x89\x0e\x1d\x1b\x16\b\xee\x176z|{8=\x84\x83}5\x176z|{8=\x84\x83}5\x00\x00\x01\x00\x96\x01\xe5\x02m\x03\xf2\x00\x13\x00F@$/\x15_\x15o\x15\u007f\x15\xcf\x15\xef\x15\xff\x15\a\x10\x15\x01_\no\n\x9f\n\xaf\n\xdf\n\xef\n\x06\n\xd0\x00\x01\x00\xb8\xff\xc0@\f\a\nH\x00\x1f\x0f\x01\x0f\x10\x05\x01\x05\x00/]\xc5]\x01/+]\xc5]]]10\x134>\x0232\x1e\x02\x15\x14\x0e\x02#\".\x02\x96$?V21V@%%@V12V?$\x02\xecGd?\x1c\x1c?dGFd?\x1e\x1e?d\x00\x00\x00\x01\x00R\x00s\x01\xfc\x03\xc7\x00\x06\x00<\xb1\x04\x02\xb8\xff\xc0@\x1f\t\fH\x02\b?\b\x9f\b\xaf\b\xdf\b\xef\b\xff\b\x06\x06\xeb\x9f\x03\x01\x03\x06\x00\x03\x03\x01\x05\x01\x00//\x129=/33\x01\x18/]\xe1]\x10\xc6+210\x13\x01\x17\x03\x13\a\x01R\x015u\xee\xeeu\xfe\xcb\x02)\x01\x9eN\xfe\xa4\xfe\xa4N\x01\x9b\x00\x00\x00\x01\x00R\x00s\x01\xfc\x03\xc7\x00\x06\x00?@(\x00\xeb\xdf\x03\xef\x03\xff\x03\x03\x10\x03 \x03\x02\x03?\b\x9f\b\xaf\b\xdf\b\xef\b\xff\b\x06\x04?\x02\x01\x02\x06\x00\x03\x03\x01\x05\x01\x00//\x129=/33\x01\x18/]3]/]]\xe110\t\x01'\x13\x037\x01\x01\xfc\xfe\xcbu\xed\xedu\x015\x02\x0e\xfeeN\x01\\\x01\\N\xfeb\x00\x00\x00\x01\xfe\xa0\x00\x00\x02h\x05\xb6\x00\x03\x00\x1d\xb1\x01\x02\xb8\xff\xf0@\t\x02\x03\x00\x10\x00\x01\x12\x00\x03\x00??\x01/82/8310\t\x01#\x01\x02h\xfc\u055d\x03+\x05\xb6\xfaJ\x05\xb6\x00\x02\x00\f\x02J\x02\x8f\x05\xbc\x00\n\x00\x15\x00F@*\t\x02\xe1\v\a\x03\x03\x17_\x17\x8f\x17\x02\x17@\x06\nH\x15\xe1\x05\x01\x04\xe5\t\x0f\v\x1f\v/\v\x03\b\v\v\x02\x0f\xe5\a\xdc\x02\xdd\x00??\xe1\x129/^]3\xe12\x01/\xe1+]\x129/33\xe1210\x01#\x15#5!5\x013\x113!5467\x0e\x03\x0f\x01\x02\x8f}\x8f\xfe\x89\x01y\x8d}\xfe\xf4\x03\x03\x05\x14\x16\x18\t\x9b\x03\n\xc0\xc0o\x02C\xfd\xcd\xc3*c1\v%*(\x0f\xf0\x00\x00\x00\x00\x01\x00\x00\x00\xd3\x00i\x00\x05\x00S\x00\x04\x00\x02\x00\x10\x00/\x00Z\x00\x00\x02\x1f\x00\xe5\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x00x\x01\x00\x01\xba\x02J\x03\x02\x03&\x03V\x03\x86\x03\xbc\x03\xea\x04 \x048\x04r\x04\x92\x04\xe4\x05\x1e\x05t\x05\xf2\x06F\x06\xae\a\"\aJ\a\xf4\bf\b\xbe\t\"\t^\t\xa0\t\xdc\nP\v\x1a\v\x86\v\xfe\f\\\f\x9c\f\xd6\r$\r\x82\r\xb8\r\xfc\x0e6\x0e\x84\x0e\xa4\x0f\x18\x0fj\x0f\xc4\x10\x12\x10|\x10\xee\x11X\x11\x9a\x11\xd8\x12,\x12\xe2\x13B\x13\x94\x13\xc8\x13\xee\x14\x0e\x142\x14P\x14h\x14\x8e\x15\x02\x15d\x15\xaa\x16\n\x16h\x16\xcc\x17\xa0\x17\xe2\x18\x14\x18`\x18\xb0\x18\xca\x19<\x19z\x19\xc4\x1a&\x1a\x88\x1a\xce\x1b>\x1b\x94\x1b\xd6\x1c.\x1c\xdc\x1dn\x1d\xd8\x1e&\x1e\x80\x1e\xa4\x1f\x00\x1fT\x1fT\x1f\x9c \x00 v!\x0e!\x82!\xb2\"l\"\xb0#Z#\xc4$\x18$F$N%\x1e%6%\x92%\xce&\x1e&\x94&\xba'\x04'B'|'\xc2'\xfa(B(\x92(\xbc(\xe2)\x12)\x88)\xa0)\xb8)\xd0)\xe8*\x02*(*\x92*\xa6*\xbe*\xd6*\xee+\b+ +8+P+j+\xce+\xe6+\xfe,\x16,.,F,`,\xc6-H-`-x-\x90-\xaa-\xc2.\f.\xa8.\xc0.\xd6.\xec/\x02/\x1a/2/\xe2/\xf60\x0e0$0:0R0j0\x820\x9a0\xb41D1Z1r1\x881\xa01\xb81\xd22D2\xbe2\xd62\xec3\x023\x1c323\x983\xb03\xca4\x004P4\x984\xb44\xd04\xfc5(5\\5\xb86\x146~6\xc26\xf67,7J7\x94\x00\x01\x00\x00\x00\x01\x00\x00d\xbc\x83%_\x0f<\xf5\x00\x1f\b\x00\x00\x00\x00\x00\xc8\x17O\xf6\x00\x00\x00\x00\xc8\\\x86Y\xfe\xa0\xfe\x14\a\xae\as\x00\x00\x00\b\x00\x02\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x02\x14\x00\x00\x02'\x00\x93\x037\x00\x85\x05+\x003\x04h\x00{\x06\x9a\x00f\x05\x9e\x00m\x01\xcf\x00\x85\x02h\x00R\x02h\x00=\x04h\x00R\x04h\x00f\x02\x00\x00?\x02\x93\x00R\x02%\x00\x93\x02\xfc\x00\x14\x04h\x00b\x04h\x00\xb2\x04h\x00`\x04h\x00R\x04h\x00\x17\x04h\x00\x83\x04h\x00q\x04h\x00Z\x04h\x00j\x04h\x00j\x02%\x00\x93\x02%\x00?\x04h\x00f\x04h\x00f\x04h\x00f\x03h\x00%\x06\xee\x00m\x04\xdd\x00\x00\x04\xf8\x00\xc7\x04\xd3\x00}\x05y\x00\xc7\x049\x00\xc7\x03\xee\x00\xc7\x05\x85\x00}\x05\x9c\x00\xc7\x02\xb6\x00R\x02+\xffH\x04\xa2\x00\xc7\x03\xee\x00\xc7\x06\xf6\x00\xc7\x05\xd5\x00\xc7\x05\xf0\x00}\x04\x9c\x00\xc7\x05\xee\x00}\x04\xb8\x00\xc7\x04'\x00h\x04'\x00\x14\x05\x96\x00\xb8\x04\x8b\x00\x00\a\x12\x00\x14\x04`\x00\x00\x047\x00\x00\x04P\x00R\x02m\x00\xa4\x02\xfc\x00\x17\x02m\x003\x04B\x00)\x03J\xff\xfc\x04\x9e\x01\x89\x04?\x00^\x04\xb0\x00\xae\x03\xb4\x00q\x04\xb0\x00q\x04H\x00q\x02\xa2\x00\x1d\x04%\x00%\x04\xb6\x00\xae\x02\x12\x00\xa0\x02\x12\xff\xbc\x03\xf8\x00\xae\x02\x12\x00\xae\a+\x00\xae\x04\xb6\x00\xae\x04\x9e\x00q\x04\xb0\x00\xae\x04\xb0\x00q\x031\x00\xae\x03\x9c\x00Z\x02\xb6\x00!\x04\xb6\x00\xa4\x03\xd5\x00\x00\x05\xf8\x00\x14\x04\x00\x00#\x03\xe9\x00\n\x03\x87\x00R\x02\xd5\x00=\x04h\x01\xe9\x02\xd5\x003\x04h\x00f\x02\x14\x00\x00\x02'\x00\x93\x04h\x00\xbc\x04h\x00D\x04h\x00{\x04h\x00\x1d\x04h\x01\xe9\x03\xe3\x00y\x04\x9e\x013\x06\xa8\x00d\x02\xa6\x00D\x03\xe5\x00R\x04h\x00f\x02\x93\x00R\x06\xa8\x00d\x04\x00\xff\xfa\x03m\x00{\x04h\x00f\x02\xa6\x001\x02\xa6\x00\x1f\x04\x9e\x01\x89\x04\xc1\x00\xae\x05=\x00q\x02%\x00\x93\x01\xa4\x00#\x02\xa6\x00?\x02\xcd\x00B\x03\xe5\x00T\x05\xe5\x00?\x05\xe5\x00,\x05\xe5\x00\x1f\x03h\x00D\x04\xdd\x00\x00\x04\xdd\x00\x00\x04\xdd\x00\x00\x04\xdd\x00\x00\x04\xdd\x00\x00\x04\xdd\x00\x00\x06\xd1\xff\xfe\x04\xd3\x00}\x049\x00\xc7\x049\x00\xc7\x049\x00\xc7\x049\x00\xc7\x02\xb6\x00>\x02\xb6\x00R\x02\xb6\x00\x11\x02\xb6\x00@\x05y\x00/\x05\xd5\x00\xc7\x05\xf0\x00}\x05\xf0\x00}\x05\xf0\x00}\x05\xf0\x00}\x05\xf0\x00}\x04h\x00\x8d\x05\xf0\x00}\x05\x96\x00\xb8\x05\x96\x00\xb8\x05\x96\x00\xb8\x05\x96\x00\xb8\x047\x00\x00\x04\x9c\x00\xc7\x04\xd1\x00\xae\x04?\x00^\x04?\x00^\x04?\x00^\x04?\x00^\x04?\x00^\x04?\x00^\x06\xaa\x00^\x03\xb4\x00q\x04H\x00q\x04H\x00q\x04H\x00q\x04H\x00q\x02\x12\xff\xde\x02\x12\x00\xae\x02\x12\xff\xbd\x02\x12\xff\xee\x04\x9e\x00o\x04\xb6\x00\xae\x04\x9e\x00q\x04\x9e\x00q\x04\x9e\x00q\x04\x9e\x00q\x04\x9e\x00q\x04h\x00f\x04\x9e\x00s\x04\xb6\x00\xa4\x04\xb6\x00\xa4\x04\xb6\x00\xa4\x04\xb6\x00\xa4\x03\xe9\x00\n\x04\xb0\x00\xae\x03\xe9\x00\n\x02\x12\x00\xae\x04\x9e\x01\x02\x04\x9e\x01m\x04\x9e\x01\x02\x04\x00\x00R\b\x00\x00R\x01f\x00\x17\x01f\x00\x17\x02\x00\x00?\x02\xe7\x00\x17\x02\xe7\x00\x17\x03\x81\x00?\x03\x02\x00\x96\x02N\x00R\x02N\x00R\x01\n\xfe\xa0\x02\xa6\x00\f\x00\x01\x00\x00\as\xfe\x14\x00\x00\b\x00\xfe\xa0\xfe\xa2\a\xae\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x03\x04&\x01\x90\x00\x05\x00\b\x05\x9a\x053\x00\x00\x01\x1e\x05\x9a\x053\x00\x00\x03\xd0\x00f\x01\xf2\x00\x00\x02\v\x06\x06\x03\b\x04\x02\x02\x04\xe0\x00\x02\xef@\x00 [\x00\x00\x00(\x00\x00\x00\x001ASC\x00@\x00 D\x06\x1f\xfe\x14\x00\x84\as\x01\xec \x00\x01\x9f\x00\x00\x00\x00\x04J\x05\xb6\x00\x00\x00 \x00\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x14\x00\x03\x00\x01\x00\x00\x00\x14\x00\x04\x00x\x00\x00\x00\x1a\x00\x10\x00\x03\x00\n\x00~\x00\xff\x011\x02\xc6\x02\xda\x02\xdc \x14 \x1a \x1e \" : D\xff\xff\x00\x00\x00 \x00\xa0\x011\x02\xc6\x02\xda\x02\xdc \x13 \x18 \x1c \" 9 D\xff\xff\xff\xe3\xff\xc2\xff\x91\xfd\xfd\xfd\xea\xfd\xe9\xe0\xb3\xe0\xb0\xe0\xaf\xe0\xac\xe0\x96\xe0\x8d\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#\"!\x1f\x18\x14\x11\x10\x0f\x0e\r\v\n\t\b\a\x06\x05\x04\x03\x02\x01\x00,E#F` \xb0&`\xb0\x04&#HH-,E#F#a \xb0&a\xb0\x04&#HH-,E#F`\xb0 a \xb0F`\xb0\x04&#HH-,E#F#a\xb0 ` \xb0&a\xb0 a\xb0\x04&#HH-,E#F`\xb0@a \xb0f`\xb0\x04&#HH-,E#F#a\xb0@` \xb0&a\xb0@a\xb0\x04&#HH-,\x01\x10 <\x00<-, E# \xb0\xcdD# \xb8\x01ZQX# \xb0\x8dD#Y \xb0\xedQX# \xb0MD#Y \xb0\x04&QX# \xb0\rD#Y!!-, E\x18hD \xb0\x01` E\xb0Fvh\x8aE`D-,\x01\xb1\v\nC#Ce\n-,\x00\xb1\n\vC#C\v-,\x00\xb0(#p\xb1\x01(>\x01\xb0(#p\xb1\x02(E:\xb1\x02\x00\b\r-, E\xb0\x03%Ead\xb0PQXED\x1b!!Y-,I\xb0\x0e#D-, E\xb0\x00C`D-,\x01\xb0\x06C\xb0\aCe\n-, i\xb0@a\xb0\x00\x8b \xb1,\xc0\x8a\x8c\xb8\x10\x00b`+\fd#da\\X\xb0\x03aY-,\x8a\x03E\x8a\x8a\x87\xb0\x11+\xb0)#D\xb0)z\xe4\x18-,Ee\xb0,#DE\xb0+#D-,KRXED\x1b!!Y-,KQXED\x1b!!Y-,\x01\xb0\x05%\x10# \x8a\xf5\x00\xb0\x01`#\xed\xec-,\x01\xb0\x05%\x10# \x8a\xf5\x00\xb0\x01a#\xed\xec-,\x01\xb0\x06%\x10\xf5\x00\xed\xec-,F#F`\x8a\x8aF# F\x8a`\x8aa\xb8\xff\x80b# \x10#\x8a\xb1\f\f\x8apE` \xb0\x00PX\xb0\x01a\xb8\xff\xba\x8b\x1b\xb0F\x8cY\xb0\x10`h\x01:-, E\xb0\x03%FRK\xb0\x13Q[X\xb0\x02%F ha\xb0\x03%\xb0\x03%?#!8\x1b!\x11Y-, E\xb0\x03%FPX\xb0\x02%F ha\xb0\x03%\xb0\x03%?#!8\x1b!\x11Y-,\x00\xb0\aC\xb0\x06C\v-,!!\fd#d\x8b\xb8@\x00b-,!\xb0\x80QX\fd#d\x8b\xb8 \x00b\x1b\xb2\x00@/+Y\xb0\x02`-,!\xb0\xc0QX\fd#d\x8b\xb8\x15Ub\x1b\xb2\x00\x80/+Y\xb0\x02`-,\fd#d\x8b\xb8@\x00b`#!-,KSX\x8a\xb0\x04%Id#Ei\xb0@\x8ba\xb0\x80b\xb0 aj\xb0\x0e#D#\x10\xb0\x0e\xf6\x1b!#\x8a\x12\x11 9/Y-,KSX \xb0\x03%Idi \xb0\x05&\xb0\x06%Id#a\xb0\x80b\xb0 aj\xb0\x0e#D\xb0\x04&\x10\xb0\x0e\xf6\x8a\x10\xb0\x0e#D\xb0\x0e\xf6\xb0\x0e#D\xb0\x0e\xed\x1b\x8a\xb0\x04&\x11\x12 9# 9//Y-,E#E`#E`#E`#vh\x18\xb0\x80b -,\xb0H+-, E\xb0\x00TX\xb0@D E\xb0@aD\x1b!!Y-,E\xb10/E#Ea`\xb0\x01`iD-,KQX\xb0/#p\xb0\x14#B\x1b!!Y-,KQX \xb0\x03%EiSXD\x1b!!Y\x1b!!Y-,E\xb0\x14C\xb0\x00`c\xb0\x01`iD-,\xb0/ED-,E# E\x8a`D-,E#E`D-,K#QX\xb9\x003\xff\xe0\xb14 \x1b\xb33\x004\x00YDD-,\xb0\x16CX\xb0\x03&E\x8aXdf\xb0\x1f`\x1bd\xb0 `f X\x1b!\xb0@Y\xb0\x01aY#XeY\xb0)#D#\x10\xb0)\xe0\x1b!!!!!Y-,\xb0\x02CTXKS#KQZX8\x1b!!Y\x1b!!!!Y-,\xb0\x16CX\xb0\x04%Ed\xb0 `f X\x1b!\xb0@Y\xb0\x01a#X\x1beY\xb0)#D\xb0\x05%\xb0\b%\b X\x02\x1b\x03Y\xb0\x04%\x10\xb0\x05% F\xb0\x04%#B<\xb0\x04%\xb0\a%\b\xb0\a%\x10\xb0\x06% F\xb0\x04%\xb0\x01`#B< X\x01\x1b\x00Y\xb0\x04%\x10\xb0\x05%\xb0)\xe0\xb0) EeD\xb0\a%\x10\xb0\x06%\xb0)\xe0\xb0\x05%\xb0\b%\b X\x02\x1b\x03Y\xb0\x05%\xb0\x03%CH\xb0\x04%\xb0\a%\b\xb0\x06%\xb0\x03%\xb0\x01`CH\x1b!Y!!!!!!!-,\x02\xb0\x04% F\xb0\x04%#B\xb0\x05%\b\xb0\x03%EH!!!!-,\x02\xb0\x03% \xb0\x04%\b\xb0\x02%CH!!!-,E# E\x18 \xb0\x00P X#e#Y#h \xb0@PX!\xb0@Y#XeY\x8a`D-,KS#KQZX E\x8a`D\x1b!!Y-,KTX E\x8a`D\x1b!!Y-,KS#KQZX8\x1b!!Y-,\xb0\x00!KTX8\x1b!!Y-,\xb0\x02CTX\xb0F+\x1b!!!!Y-,\xb0\x02CTX\xb0G+\x1b!!!Y-,\xb0\x02CTX\xb0H+\x1b!!!!Y-,\xb0\x02CTX\xb0I+\x1b!!!Y-, \x8a\b#KS\x8aKQZX#8\x1b!!Y-,\x00\xb0\x02%I\xb0\x00SX \xb0@8\x11\x1b!Y-,\x01F#F`#Fa# \x10 F\x8aa\xb8\xff\x80b\x8a\xb1@@\x8apE`h:-, \x8a#Id\x8a#SX<\x1b!Y-,KRX}\x1bzY-,\xb0\x12\x00K\x01KTB-,\xb1\x02\x00B\xb1#\x01\x88Q\xb1@\x01\x88SZX\xb9\x10\x00\x00 \x88TX\xb2\x02\x01\x02C`BY\xb1$\x01\x88QX\xb9 \x00\x00@\x88TX\xb2\x02\x02\x02C`B\xb1$\x01\x88TX\xb2\x02 \x02C`B\x00K\x01KRX\xb2\x02\b\x02C`BY\x1b\xb9@\x00\x00\x80\x88TX\xb2\x02\x04\x02C`BY\xb9@\x00\x00\x80c\xb8\x01\x00\x88TX\xb2\x02\b\x02C`BY\xb9@\x00\x01\x00c\xb8\x02\x00\x88TX\xb2\x02\x10\x02C`BY\xb9@\x00\x02\x00c\xb8\x04\x00\x88TX\xb2\x02@\x02C`BYYYYY-,E\x18h#KQX# E d\xb0@PX|Yh\x8a`YD-,\xb0\x00\x16\xb0\x02%\xb0\x02%\x01\xb0\x01#>\x00\xb0\x02#>\xb1\x01\x02\x06\f\xb0\n#eB\xb0\v#B\x01\xb0\x01#?\x00\xb0\x02#?\xb1\x01\x02\x06\f\xb0\x06#eB\xb0\a#B\xb0\x01\x16\x01-,z\x8a\x10E#\xf5\x18-\x00\x00\x00@\x10\t\xf8\x03\xff\x1f\x8f\xf7\x9f\xf7\x02\u007f\xf3\x01`\xf2\x01\xb8\xff\xe8@+\xeb\f\x10F\xdf3\xddU\xde\xff\xdcU0\xdd\x01\xdd\x01\x03U\xdc\x03\xfa\x1f0\xc2\x01o\xc0\xef\xc0\x02\xfc\xb6\x18\x1f0\xb7\x01`\xb7\x80\xb7\x02\xb8\xff\xc0@8\xb7\x0f\x13F\xe7\xb1\x01\x1f\xaf/\xaf?\xaf\x03O\xaf_\xafo\xaf\x03@\xaf\x0f\x13F\xacQ\x18\x1f\x1f\x9c_\x9c\x02\xe0\x9b\x01\x03+\x9a\x01\x1f\x9a\x01\x90\x9a\xa0\x9a\x02s\x9a\x83\x9a\x02\x05\xb8\xff\xea@\x19\x9a\t\vF\xaf\x97\xbf\x97\x02\x03+\x96\x01\x1f\x96\x01\x9f\x96\xaf\x96\x02|\x96\x01\x05\xb8\xff\xea@\x85\x96\t\vF/\x92?\x92O\x92\x03@\x92\f\x0fF/\x91\x01\x9f\x91\x01\x87\x86\x18\x1f@|P|\x02\x03\x10t t0t\x03\x02t\x01\xf2t\x01\no\x01\xffo\x01\xa9o\x01\x97o\x01uo\x85o\x02Ko\x01\nn\x01\xffn\x01\xa9n\x01\x97n\x01Kn\x01\x06\x1a\x01\x18U\x19\x13\xff\x1f\a\x04\xff\x1f\x06\x03\xff\x1f?g\x01\x1fg/g?g\xffg\x04@fPf\xa0f\xb0f\x04?e\x01\x0fe\xafe\x02\x05\xa0d\xe0d\x02\x03\xb8\xff\xc0@Od\x06\nFa_+\x1f`_G\x1f_P\"\x1f\xf7[\x01\xec[\x01T[\x84[\x02I[\x01;[\x01\xf9Z\x01\xefZ\x01kZ\x01KZ\x01;Z\x01\x06\x133\x12U\x05\x01\x03U\x043\x03U\x1f\x03\x01\x0f\x03?\x03\xaf\x03\x03\x0fW\x1fW/W\x03\x03\xb8\xff\xc0\xb3V\x12\x15F\xb8\xff\xe0\xb3V\a\vF\xb8\xff\xc0\xb3T\x12\x15F\xb8\xff\xc0@mT\x06\vFRP+\x1f?POP_P\x03\xfaH\x01\xefH\x01\x87H\x01eH\x01VH\x01:H\x01\xfaG\x01\xefG\x01\x87G\x01;G\x01\x06\x1c\x1b\xff\x1f\x163\x15U\x11\x01\x0fU\x103\x0fU\x02\x01\x00U\x01G\x00U\xfb\xfa+\x1f\xfa\x1b\x12\x1f\x0f\x0f\x01\x1f\x0f\xcf\x0f\x02\x0f\x0f\xff\x0f\x02\x06o\x00\u007f\x00\xaf\x00\xef\x00\x04\x10\x00\x01\x80\x16\x01\x05\x01\xb8\x01\x90\xb1TS++K\xb8\a\xffRK\xb0\x06P[\xb0\x01\x88\xb0%S\xb0\x01\x88\xb0@QZ\xb0\x06\x88\xb0\x00UZ[X\xb1\x01\x01\x8eY\x85\x8d\x8d\x00B\x1dK\xb02SX\xb0`\x1dYK\xb0dSX\xb0@\x1dYK\xb0\x80SX\xb0\x10\x1d\xb1\x16\x00BYss^stu++++++++\x01_ssssssssss\x00s+\x01++++_s\x00st+++\x01_ssssssssss\x00+++\x01+_s^stsst\x00++++\x01_sssstssssst\x00stt\x01_s+\x00st+s\x01+_sstt_s+_sstt\x00_ss\x01+\x00+st\x01s\x00+st+\x01s\x00s++s++\x01+sss\x00+\x18^\x06\x14\x00\v\x00N\x05\xb6\x00\x17\x00u\x05\xb6\x05\xcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04J\x00\x14\x00\x8f\x00\x00\xff\xec\x00\x00\x00\x00\xff\xec\x00\x00\x00\x00\xff\xec\x00\x00\xfe\x14\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\xac\x00\xb6\x00\xbc\x00\x00\x00\xd5\x00\x00\x00\x00\x00\x00\x00U\x00\x83\x00\x97\x00\x9f\x00}\x00\xe5\x00\xae\x00\xae\x00q\x00q\x00\x00\x00\x00\x00\xba\x00\xc5\x00\xba\x00\x00\x00\x00\x00\xa4\x00\x9f\x00\x8c\x00\x00\x00\x00\x00\xc7\x00\xc7\x00}\x00}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x00\xb9\x00\x8a\x00\x00\x00\x00\x00\x9b\x00\xa6\x00\x8f\x00w\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i\x00n\x00\x90\x00\xb4\x00\xc1\x00\xd5\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x00o\x00x\x00\x96\x00\xc0\x00\xd5\x01G\x00\x00\x00\x00\x00\x00\x00\xfe\x01:\x00\xc5\x00x\x00\xfe\x01\x16\x01\xf6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\x00\x00\x00\x96\x00\x88\x00\xae\x00\x96\x00\x89\x01\f\x00\x96\x01\x18\x00\x00\x03\x1d\x00\x94\x02Z\x00\x82\x03\x96\x00\x00\x00\xa8\x00\x8c\x00\x00\x00\x00\x02y\x00\xd9\x00\xb4\x01\n\x00\x00\x01\x83\x00m\x00\u007f\x00\xa0\x00\x00\x00\x00\x00m\x00\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\x00\xa0\x00\x00\x00\x82\x00\x89\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xb6\xfc\x94\x00\x11\xff\xef\x00\x83\x00\x8f\x00\x00\x00\x00\x00m\x00{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x01\xaa\x03T\x00\x00\x00\x00\x00\xbc\x00\xb6\x01\xd7\x01\x95\x00\x00\x00\x96\x01\x00\x00\xae\x05\xb6\xfe\xbc\xfeo\xfe\x83\x00o\x02\xad\x00\x00\x00\a\x00Z\x00\x03\x00\x01\x04\t\x00\x01\x00\x14\x00\x00\x00\x03\x00\x01\x04\t\x00\x02\x00\x0e\x00\x14\x00\x03\x00\x01\x04\t\x00\x03\x00*\x00\"\x00\x03\x00\x01\x04\t\x00\x04\x00\x14\x00\x00\x00\x03\x00\x01\x04\t\x00\x05\x00,\x00L\x00\x03\x00\x01\x04\t\x00\x06\x00\x12\x00x\x00\x03\x00\x01\x04\t\x00\x0e\x00T\x00\x8a\x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00R\x00e\x00g\x00u\x00l\x00a\x00r\x00A\x00s\x00c\x00e\x00n\x00d\x00e\x00r\x00 \x00-\x00 \x00D\x00r\x00o\x00i\x00d\x00 \x00S\x00a\x00n\x00s\x00V\x00e\x00r\x00s\x00i\x00o\x00n\x00 \x001\x00.\x000\x000\x00 \x00b\x00u\x00i\x00l\x00d\x00 \x001\x001\x003\x00D\x00r\x00o\x00i\x00d\x00S\x00a\x00n\x00s\x00h\x00t\x00t\x00p\x00:\x00/\x00/\x00w\x00w\x00w\x00.\x00a\x00p\x00a\x00c\x00h\x00e\x00.\x00o\x00r\x00g\x00/\x00l\x00i\x00c\x00e\x00n\x00s\x00e\x00s\x00/\x00L\x00I\x00C\x00E\x00N\x00S\x00E\x00-\x002\x00.\x000\x00\x02\x00\x00\x00\x00\x00\x00\xfff\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\a\x00\b\x00\t\x00\n\x00\v\x00\f\x00\r\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x1e\x00\x1f\x00 \x00!\x00\"\x00#\x00$\x00%\x00&\x00'\x00(\x00)\x00*\x00+\x00,\x00-\x00.\x00/\x000\x001\x002\x003\x004\x005\x006\x007\x008\x009\x00:\x00;\x00<\x00=\x00>\x00?\x00@\x00A\x00B\x00C\x00D\x00E\x00F\x00G\x00H\x00I\x00J\x00K\x00L\x00M\x00N\x00O\x00P\x00Q\x00R\x00S\x00T\x00U\x00V\x00W\x00X\x00Y\x00Z\x00[\x00\\\x00]\x00^\x00_\x00`\x00a\x00\xac\x00\xa3\x00\x84\x00\x85\x00\xbd\x00\x96\x00\xe8\x00\x86\x00\x8e\x00\x8b\x00\x9d\x00\xa9\x00\xa4\x01\x02\x00\x8a\x01\x03\x00\x83\x00\x93\x00\xf2\x00\xf3\x00\x8d\x00\x97\x00\x88\x00\xc3\x00\xde\x00\xf1\x00\x9e\x00\xaa\x00\xf5\x00\xf4\x00\xf6\x00\xa2\x00\xad\x00\xc9\x00\xc7\x00\xae\x00b\x00c\x00\x90\x00d\x00\xcb\x00e\x00\xc8\x00\xca\x00\xcf\x00\xcc\x00\xcd\x00\xce\x00\xe9\x00f\x00\xd3\x00\xd0\x00\xd1\x00\xaf\x00g\x00\xf0\x00\x91\x00\xd6\x00\xd4\x00\xd5\x00h\x00\xeb\x00\xed\x00\x89\x00j\x00i\x00k\x00m\x00l\x00n\x00\xa0\x00o\x00q\x00p\x00r\x00s\x00u\x00t\x00v\x00w\x00\xea\x00x\x00z\x00y\x00{\x00}\x00|\x00\xb8\x00\xa1\x00\u007f\x00~\x00\x80\x00\x81\x00\xec\x00\xee\x00\xba\x00\xd7\x00\xd8\x00\xdd\x00\xd9\x00\xb2\x00\xb3\x00\xb6\x00\xb7\x00\xc4\x00\xb4\x00\xb5\x00\xc5\x00\x87\x00\xbe\x00\xbf\x00\xbc\x01\x04\auni00AD\toverscore\ffoursuperior\x00\x00\x00\x00\x02\x00\x05\x00\x02\xff\xff\x00\x03\x00\x01\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x00\x00\xd1\x00\x01\x00\x00\x00\x01\x00\x00\x00\n\x00\x1e\x00,\x00\x01latn\x00\b\x00\x04\x00\x00\x00\x00\xff\xff\x00\x01\x00\x00\x00\x01kern\x00\b\x00\x00\x00\x01\x00\x00\x00\x01\x00\x04\x00\x02\x00\b\x00\x01\x00\b\x00\x01\x00\xd6\x00\x04\x00\x00\x00f\x01p\x01p\n\xea\x02\"\x11\xdc\x02\"\x02x\x02\xde\rX\x02\xf8\x03R\x0e.\x03\xac\x03\xea\x0e\xf8\x04P\x04\x92\x04\xec\x04\xf2\x06\x1c\x06F\a@\b:\b\xbc\x0e.\n\xea\x10\xea\x10\xea\x10\xf0\x10\xea\t\xce\t\xf4\n\n\n\x10\x10\xea\x10\xea\x110\n\"\x10\xf0\nT\nj\nj\n\x80\n\xb2\n\xc8\n\xea\v\x86\n\xf0\n\xf0\v\x86\f$\f\xba\rX\r\xe4\r\xa2\r\xe4\r\xe4\x0e.\x0e.\x0e.\x0e.\x0el\x0e\x8a\x0e\x8a\x0e\x8a\x0e\x8a\x0e\x8a\x0e\xf8\x0fR\x0fR\x0fR\x0fR\x0f\xa0\x10\xea\x10\xea\x10\xea\x10\xea\x10\xea\x10\xea\x110\x10\xf0\x11\x02\x11\x02\x11\x02\x11\x02\x11\f\x11\x1a\x11\x1a\x11\x1a\x11\x1a\x11\x1a\x110\x11:\x11:\x11:\x11:\x11D\x11\xbe\x11\xdc\x11\xdc\x11\xe2\x11\xe2\x00\x02\x00\x19\x00\x05\x00\x05\x00\x00\x00\n\x00\v\x00\x01\x00\x0f\x00\x11\x00\x03\x00$\x00'\x00\x06\x00)\x00)\x00\n\x00,\x00,\x00\v\x00.\x00/\x00\f\x002\x005\x00\x0e\x007\x00>\x00\x12\x00D\x00F\x00\x1a\x00H\x00K\x00\x1d\x00N\x00N\x00!\x00P\x00R\x00\"\x00U\x00W\x00%\x00Y\x00^\x00(\x00\x82\x00\x87\x00.\x00\x89\x00\x92\x004\x00\x94\x00\x98\x00>\x00\x9a\x00\x9f\x00C\x00\xa2\x00\xad\x00I\x00\xb3\x00\xb8\x00U\x00\xba\x00\xbf\x00[\x00\xc1\x00\xc1\x00a\x00\xc6\x00\xc8\x00b\x00\xcb\x00\xcb\x00e\x00,\x00$\xff\xae\x00,\x00)\x007\x00R\x009\x00R\x00:\x00f\x00;\x00)\x00<\x00R\x00=\x00)\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xd7\x00R\xff\xc3\x00T\xff\xc3\x00W\x00)\x00Y\x00)\x00Z\x00\x14\x00\\\x00)\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xff\\\x00\x8e\x00)\x00\x8f\x00)\x00\x90\x00)\x00\x91\x00)\x00\x9f\x00R\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\xbf\x00)\x00\xc1\x00)\x00\x15\x00&\xff\xc3\x00*\xff\xc3\x002\xff\xc3\x004\xff\xc3\x007\xff\x9a\x008\xff\xd7\x009\xff\x9a\x00:\xff\xae\x00<\xff\x9a\x00\x89\xff\xc3\x00\x94\xff\xc3\x00\x95\xff\xc3\x00\x96\xff\xc3\x00\x97\xff\xc3\x00\x98\xff\xc3\x00\x9a\xff\xc3\x00\x9b\xff\xd7\x00\x9c\xff\xd7\x00\x9d\xff\xd7\x00\x9e\xff\xd7\x00\x9f\xff\x9a\x00\x19\x00\x05\xff\xae\x00\n\xff\xae\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xc9\xff\xae\x00\xcc\xff\xae\x00\x06\x00,\xff\xec\x007\xff\xec\x009\xff\xec\x00;\xff\xec\x00<\xff\xec\x00\x9f\xff\xec\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xec\x00:\xff\xec\x00;\xff\xec\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xc3\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x16\x00\x05\x00=\x00\n\x00=\x00\f\x00)\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\xd7\x009\x00\x14\x00:\x00\x14\x00<\x00\x14\x00@\x00)\x00`\x00)\x00\x82\xff\xd7\x00\x83\xff\xd7\x00\x84\xff\xd7\x00\x85\xff\xd7\x00\x86\xff\xd7\x00\x87\xff\xd7\x00\x88\xff\xc3\x00\x9f\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\x0f\x00\x05\x00)\x00\n\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x19\x00\x05\xff\x9a\x00\n\xff\x9a\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xae\x00:\xff\xc3\x00<\xff\x9a\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xc9\xff\x9a\x00\xcc\xff\x9a\x00\x10\x00\x0f\xff3\x00\x11\xff3\x00$\xff\xae\x00&\xff\xec\x00;\xff\xec\x00<\xff\xec\x00=\xff\xd7\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xffq\x00\x89\xff\xec\x00\x9f\xff\xec\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xc3\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x01\x007\xff\xec\x00J\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x10\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x85\x00&\xff\xc3\x00*\xff\xc3\x002\xff\xc3\x004\xff\xc3\x006\xff\xec\x007\x00\x14\x00D\xff\x85\x00F\xff\x85\x00G\xff\x85\x00H\xff\x85\x00J\xff\x9a\x00P\xff\xae\x00Q\xff\xae\x00R\xff\x85\x00S\xff\xae\x00T\xff\x85\x00U\xff\xae\x00V\xff\x85\x00X\xff\xae\x00Y\xff\xc3\x00Z\xff\xc3\x00[\xff\xc3\x00\\\xff\xc3\x00]\xff\xc3\x00\x82\xff\x85\x00\x83\xff\x85\x00\x84\xff\x85\x00\x85\xff\x85\x00\x86\xff\x85\x00\x87\xff\x85\x00\x88\xffq\x00\x89\xff\xc3\x00\x94\xff\xc3\x00\x95\xff\xc3\x00\x96\xff\xc3\x00\x97\xff\xc3\x00\x98\xff\xc3\x00\x9a\xff\xc3\x00\xa2\xff\x85\x00\xa3\xff\x85\x00\xa4\xff\x85\x00\xa5\xff\x85\x00\xa6\xff\x85\x00\xa7\xff\x85\x00\xa8\xff\x85\x00\xa9\xff\x85\x00\xaa\xff\x85\x00\xab\xff\x85\x00\xac\xff\x85\x00\xad\xff\x85\x00\xb3\xff\xae\x00\xb4\xff\x85\x00\xb5\xff\x85\x00\xb6\xff\x85\x00\xb7\xff\x85\x00\xb8\xff\x85\x00\xba\xff\x85\x00\xbb\xff\xae\x00\xbc\xff\xae\x00\xbd\xff\xae\x00\xbe\xff\xae\x00\xbf\xff\xc3\x00\xc1\xff\xc3\x00\xc6\xff\xae\x00\xc7\xff\x9a\x00\xc9\x00R\x00\xcc\x00R\x00\n\x00\x0f\xff\xd7\x00\x11\xff\xd7\x00$\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00>\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\xc3\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00D\xff\xc3\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xc3\x00P\xff\xd7\x00Q\xff\xd7\x00R\xff\xc3\x00S\xff\xd7\x00T\xff\xc3\x00U\xff\xd7\x00V\xff\xd7\x00X\xff\xd7\x00\x82\xff\xc3\x00\x83\xff\xc3\x00\x84\xff\xc3\x00\x85\xff\xc3\x00\x86\xff\xc3\x00\x87\xff\xc3\x00\x88\xff\x85\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\xc3\x00\xa3\xff\xc3\x00\xa4\xff\xc3\x00\xa5\xff\xc3\x00\xa6\xff\xc3\x00\xa7\xff\xc3\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb3\xff\xd7\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\xbb\xff\xd7\x00\xbc\xff\xd7\x00\xbd\xff\xd7\x00\xbe\xff\xd7\x00\xc9\x00R\x00\xcc\x00R\x00>\x00\x05\x00f\x00\n\x00f\x00\x0f\xff\xae\x00\x11\xff\xae\x00$\xff\xd7\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x00D\xff\xd7\x00F\xff\xd7\x00G\xff\xd7\x00H\xff\xd7\x00J\xff\xec\x00P\xff\xec\x00Q\xff\xec\x00R\xff\xd7\x00S\xff\xec\x00T\xff\xd7\x00U\xff\xec\x00V\xff\xd7\x00X\xff\xec\x00]\xff\xec\x00\x82\xff\xd7\x00\x83\xff\xd7\x00\x84\xff\xd7\x00\x85\xff\xd7\x00\x86\xff\xd7\x00\x87\xff\xd7\x00\x88\xff\xae\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xa2\xff\xd7\x00\xa3\xff\xd7\x00\xa4\xff\xd7\x00\xa5\xff\xd7\x00\xa6\xff\xd7\x00\xa7\xff\xd7\x00\xa8\xff\xd7\x00\xa9\xff\xd7\x00\xaa\xff\xd7\x00\xab\xff\xd7\x00\xac\xff\xd7\x00\xad\xff\xd7\x00\xb3\xff\xec\x00\xb4\xff\xd7\x00\xb5\xff\xd7\x00\xb6\xff\xd7\x00\xb7\xff\xd7\x00\xb8\xff\xd7\x00\xba\xff\xd7\x00\xbb\xff\xec\x00\xbc\xff\xec\x00\xbd\xff\xec\x00\xbe\xff\xec\x00\xc9\x00f\x00\xcc\x00f\x00 \x00\x05\x00)\x00\n\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00F\xff\xec\x00G\xff\xec\x00H\xff\xec\x00R\xff\xec\x00T\xff\xec\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa8\xff\xec\x00\xa9\xff\xec\x00\xaa\xff\xec\x00\xab\xff\xec\x00\xac\xff\xec\x00\xad\xff\xec\x00\xb4\xff\xec\x00\xb5\xff\xec\x00\xb6\xff\xec\x00\xb7\xff\xec\x00\xb8\xff\xec\x00\xba\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00D\x00\x05\x00R\x00\n\x00R\x00\x0f\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x9a\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x006\xff\xec\x00D\xff\x9a\x00F\xff\x9a\x00G\xff\x9a\x00H\xff\x9a\x00J\xff\x9a\x00P\xff\xc3\x00Q\xff\xc3\x00R\xff\x9a\x00S\xff\xc3\x00T\xff\x9a\x00U\xff\xc3\x00V\xff\xae\x00X\xff\xc3\x00[\xff\xd7\x00\\\xff\xec\x00]\xff\xc3\x00\x82\xff\x9a\x00\x83\xff\x9a\x00\x84\xff\x9a\x00\x85\xff\x9a\x00\x86\xff\x9a\x00\x87\xff\x9a\x00\x88\xffq\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\x9a\x00\xa3\xff\x9a\x00\xa4\xff\x9a\x00\xa5\xff\x9a\x00\xa6\xff\x9a\x00\xa7\xff\x9a\x00\xa8\xff\x9a\x00\xa9\xff\x9a\x00\xaa\xff\x9a\x00\xab\xff\x9a\x00\xac\xff\x9a\x00\xad\xff\x9a\x00\xb3\xff\xc3\x00\xb4\xff\x9a\x00\xb5\xff\x9a\x00\xb6\xff\x9a\x00\xb7\xff\x9a\x00\xb8\xff\x9a\x00\xba\xff\x9a\x00\xbb\xff\xc3\x00\xbc\xff\xc3\x00\xbd\xff\xc3\x00\xbe\xff\xc3\x00\xbf\xff\xec\x00\xc1\xff\xec\x00\xc9\x00R\x00\xcc\x00R\x00\t\x00\x05\x00f\x00\n\x00f\x00Y\x00\x14\x00Z\x00\x14\x00\\\x00\x14\x00\xbf\x00\x14\x00\xc1\x00\x14\x00\xc9\x00f\x00\xcc\x00f\x00\x05\x00\x05\x00)\x00\n\x00)\x00J\x00\x14\x00\xc9\x00)\x00\xcc\x00)\x00\x01\x00\n\xff\xc3\x00\x04\x00\x05\x00)\x00\n\x00)\x00\xc9\x00)\x00\xcc\x00)\x00\f\x00\x05\x00f\x00\n\x00f\x00D\xff\xec\x00J\xff\xec\x00\xa2\xff\xec\x00\xa3\xff\xec\x00\xa4\xff\xec\x00\xa5\xff\xec\x00\xa6\xff\xec\x00\xa7\xff\xec\x00\xc9\x00f\x00\xcc\x00f\x00\x05\x00\x05\x00R\x00\n\x00R\x00W\x00\x14\x00\xc9\x00R\x00\xcc\x00R\x00\x05\x00\x05\x00R\x00\n\x00R\x00I\x00\x14\x00\xc9\x00R\x00\xcc\x00R\x00\f\x00\x05\x00)\x00\n\x00)\x00R\xff\xd7\x00\xa8\xff\xd7\x00\xb4\xff\xd7\x00\xb5\xff\xd7\x00\xb6\xff\xd7\x00\xb7\xff\xd7\x00\xb8\xff\xd7\x00\xba\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x05\x00\x05\x00=\x00\n\x00=\x00I\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\b\x00R\xff\xec\x00\xa8\xff\xec\x00\xb4\xff\xec\x00\xb5\xff\xec\x00\xb6\xff\xec\x00\xb7\xff\xec\x00\xb8\xff\xec\x00\xba\xff\xec\x00\x01\x00-\x00{\x00%\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\x85\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xc3\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00I\xff\xec\x00W\xff\xec\x00Y\xff\xd7\x00Z\xff\xec\x00\\\xff\xd7\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xd7\x00\xc1\xff\xd7\x00\xc9\xff\xae\x00\xcc\xff\xae\x00'\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\x85\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xc3\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00I\xff\xec\x00W\xff\xec\x00Y\xff\xd7\x00Z\xff\xec\x00\\\xff\xd7\x00\x82\xff\xd7\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xd7\x00\xc1\xff\xd7\x00\xc9\xff\xae\x00\xcc\xff\xae\x00%\x00\x05\xff\xae\x00\n\xff\xae\x00\r\xff\u007f\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xd7\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00W\xff\xe5\x00Y\xff\xd5\x00Z\xff\xe5\x00\\\xff\xdb\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xdb\x00\xc1\xff\xdb\x00\xc9\xff\xae\x00\xcc\xff\xae\x00'\x00\x05\xfff\x00\n\xfff\x00\r\xff\u007f\x00\x0f\x00D\x00\x1e\x00D\x00\"\xff\xd7\x00&\xff\xec\x00*\xff\xec\x00-\x00^\x002\xff\xec\x004\xff\xec\x007\xff\x85\x008\xff\xec\x009\xff\xc3\x00:\xff\xd7\x00<\xff\x9a\x00=\x00;\x00W\xff\xe5\x00Y\xff\xd5\x00Z\xff\xe5\x00\\\xff\xdb\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\x9b\xff\xec\x00\x9c\xff\xec\x00\x9d\xff\xec\x00\x9e\xff\xec\x00\x9f\xff\x9a\x00\xbf\xff\xdb\x00\xc1\xff\xdb\x00\xc8\xfff\x00\xc9\xff\xae\x00\xcb\xfff\x00\xcc\xff\xae\x00\x12\x00\x05\x00)\x00\n\x00)\x00\f\x00)\x00&\xff\xd7\x00*\xff\xd7\x002\xff\xd7\x004\xff\xd7\x00@\x00)\x00`\x00)\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xc9\x00)\x00\xcc\x00)\x00\x10\x00\x05\x00)\x00\n\x00)\x00\x10\xff\xd7\x00&\xff\xec\x002\xff\xec\x004\xff\xec\x00\x89\xff\xec\x00\x8b\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\x12\x00\x05\x00)\x00\n\x00)\x00\x10\xff\xd7\x00&\xff\xec\x002\xff\xec\x004\xff\xec\x00\x84\xff\xec\x00\x89\xff\xec\x00\x8a\xff\xec\x00\x8f\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\x0f\x00\x05\x00)\x00\n\x00)\x00&\xff\xec\x00*\xff\xec\x002\xff\xec\x004\xff\xec\x00\x89\xff\xec\x00\x94\xff\xec\x00\x95\xff\xec\x00\x96\xff\xec\x00\x97\xff\xec\x00\x98\xff\xec\x00\x9a\xff\xec\x00\xc9\x00)\x00\xcc\x00)\x00\a\x00$\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x1b\x00\f\xff\xd7\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x00-\xff\xf6\x006\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00@\xff\xd7\x00`\xff\xd7\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x16\x00\x0f\xff\xc3\x00\x11\xff\xc3\x00$\xff\xec\x00,\xff\xec\x007\xff\xc3\x009\xff\xd7\x00:\xff\xec\x00;\xff\xd7\x00<\xff\xd7\x00=\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\x8e\xff\xec\x00\x8f\xff\xec\x00\x90\xff\xec\x00\x91\xff\xec\x00\x9f\xff\xd7\x00\x13\x00\x0f\xff\xd7\x00\x11\xff\xd7\x00$\xff\xec\x000\xff\xec\x00=\xff\xec\x00D\xff\xec\x00\x82\xff\xec\x00\x83\xff\xec\x00\x84\xff\xec\x00\x85\xff\xec\x00\x86\xff\xec\x00\x87\xff\xec\x00\x88\xff\xd7\x00\xa2\xff\xec\x00\xa3\xff\xec\x00\xa4\xff\xec\x00\xa5\xff\xec\x00\xa6\xff\xec\x00\xa7\xff\xec\x00R\x00\x05\x00R\x00\t\xff\xc3\x00\n\x00R\x00\f\x00=\x00\r\x00)\x00\x0f\xff\x9a\x00\x10\xff\x9a\x00\x11\xff\x9a\x00\"\x00)\x00$\xff\x9a\x00&\xff\xd7\x00*\xff\xd7\x00-\xff\xbe\x000\xff\xc3\x002\xff\xd7\x004\xff\xd7\x006\xff\xec\x007\x00'\x009\x00)\x00:\x00\x14\x00@\x00=\x00D\xff\x9a\x00F\xff\x9a\x00G\xff\x9a\x00H\xff\x9a\x00I\xff\xe5\x00J\xff\x9a\x00P\xff\xc3\x00Q\xff\xc3\x00R\xff\x9a\x00S\xff\xc3\x00T\xff\x9a\x00U\xff\xc3\x00V\xff\xae\x00X\xff\xc3\x00Y\xff\xd7\x00Z\xff\xec\x00[\xff\xd7\x00\\\xff\xec\x00]\xff\xc3\x00`\x00=\x00\x82\xff\x9a\x00\x83\xff\x9a\x00\x84\xff\x9a\x00\x85\xff\x9a\x00\x86\xff\x9a\x00\x87\xff\x9a\x00\x88\xffq\x00\x89\xff\xd7\x00\x94\xff\xd7\x00\x95\xff\xd7\x00\x96\xff\xd7\x00\x97\xff\xd7\x00\x98\xff\xd7\x00\x9a\xff\xd7\x00\xa2\xff\x9a\x00\xa3\xff\x9a\x00\xa4\xff\x9a\x00\xa5\xff\x9a\x00\xa6\xff\x9a\x00\xa7\xff\x9a\x00\xa8\xff\x9a\x00\xa9\xff\x9a\x00\xaa\xff\x9a\x00\xab\xff\x9a\x00\xac\xff\x9a\x00\xad\xff\x9a\x00\xb3\xff\xc3\x00\xb4\xff\x9a\x00\xb5\xff\x9a\x00\xb6\xff\x9a\x00\xb7\xff\x9a\x00\xb8\xff\x9a\x00\xba\xff\x9a\x00\xbb\xff\xc3\x00\xbc\xff\xc3\x00\xbd\xff\xc3\x00\xbe\xff\xc3\x00\xbf\xff\xec\x00\xc1\xff\xec\x00\xc9\x00R\x00\xcc\x00R\x00\x01\x00\n\xff\xd7\x00\x04\x00\x05\x00=\x00\n\x00=\x00\xc9\x00=\x00\xcc\x00=\x00\x02\x00\x05\xff\x98\x00\n\xff\xd7\x00\x03\x00\x05\xff\x98\x00\n\xff\xd7\x00\xcc\xff\xd7\x00\x05\x00\x05\xffo\x00\n\xffo\x00I\xff\xdb\x00[\xff\xd7\x00]\xff\xec\x00\x02\x00[\xff\xd7\x00]\xff\xec\x00\x02\x00\x05\xff\xbe\x00\n\xff\xbe\x00\x1e\x00\x05\x00=\x00\n\x00=\x00\x0f\xff\xbe\x00\x11\xff\xbe\x00\"\xff\xb4\x00F\xff\xf6\x00G\xff\xf6\x00H\xff\xf6\x00I\x00\x14\x00J\xff\xf6\x00R\xff\xf6\x00T\xff\xf6\x00W\x00\x06\x00\xa8\xff\xf6\x00\xa9\xff\xf6\x00\xaa\xff\xf6\x00\xab\xff\xf6\x00\xac\xff\xf6\x00\xad\xff\xf6\x00\xb4\xff\xf6\x00\xb5\xff\xf6\x00\xb6\xff\xf6\x00\xb7\xff\xf6\x00\xb8\xff\xf6\x00\xba\xff\xf6\x00\xc9\x00=\x00\xca\xff\x8d\x00\xcc\x00=\x00\xcd\xff\x8d\x00\xd0\x00\f\x00\a\x00\x05\x00=\x00\n\x00=\x00\x0f\xff\xbe\x00\x11\xff\xbe\x00I\x00\x14\x00\xc9\x00=\x00\xcc\x00=\x00\x01\x007\xff\x9a\x00)\x00$\xff\xae\x00,\x00)\x007\x00R\x009\x00R\x00:\x00f\x00;\x00)\x00<\x00R\x00=\x00)\x00F\xff\xc3\x00G\xff\xc3\x00H\xff\xc3\x00J\xff\xd7\x00R\xff\xc3\x00T\xff\xc3\x00W\x00)\x00Y\x00)\x00Z\x00\x14\x00\x82\xff\xae\x00\x83\xff\xae\x00\x84\xff\xae\x00\x85\xff\xae\x00\x86\xff\xae\x00\x87\xff\xae\x00\x88\xff\\\x00\x8e\x00)\x00\x8f\x00)\x00\x90\x00)\x00\x91\x00)\x00\x9f\x00R\x00\xa8\xff\xc3\x00\xa9\xff\xc3\x00\xaa\xff\xc3\x00\xab\xff\xc3\x00\xac\xff\xc3\x00\xad\xff\xc3\x00\xb4\xff\xc3\x00\xb5\xff\xc3\x00\xb6\xff\xc3\x00\xb7\xff\xc3\x00\xb8\xff\xc3\x00\xba\xff\xc3\x00\x01\x00\x00\x00\n\x00\n\x00\n\x00\x00") + +func third_partySwaggerUiFontsDroidSansV6LatinRegularTtfBytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6LatinRegularTtf, nil +} + +func third_partySwaggerUiFontsDroidSansV6LatinRegularTtf() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6LatinRegularTtfBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.ttf", size: 39072, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiFontsDroidSansV6LatinRegularWoff = []byte("wOFF\x00\x01\x00\x00\x00\x00a$\x00\x11\x00\x00\x00\x00\x98\xa0\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00GDEF\x00\x00\x01\x80\x00\x00\x00\x16\x00\x00\x00\x16\x00\x10\x00\xd2GPOS\x00\x00\x01\x98\x00\x00\x06$\x00\x00\x12\xc0\xf2ZM^GSUB\x00\x00\a\xbc\x00\x00\x00\f\x00\x00\x00\f\x00\x15\x00\nOS/2\x00\x00\a\xc8\x00\x00\x00^\x00\x00\x00`\xa0\u04f5ecmap\x00\x00\b(\x00\x00\x00j\x00\x00\x00\x8cmag\xdacvt \x00\x00\b\x94\x00\x00\x00\xf3\x00\x00\x01\xfc9~>Lfpgm\x00\x00\t\x88\x00\x00\x04'\x00\x00\a\x05s\xd3#\xb0gasp\x00\x00\r\xb0\x00\x00\x00\f\x00\x00\x00\f\x00\x04\x00\aglyf\x00\x00\r\xbc\x00\x00J\xeb\x00\x00o(I;\f|head\x00\x00X\xa8\x00\x00\x003\x00\x00\x006\xf5\xf5 \xd3hhea\x00\x00X\xdc\x00\x00\x00\x1f\x00\x00\x00$\r\xc4\x05\x8ahmtx\x00\x00X\xfc\x00\x00\x01\xe6\x00\x00\x03LmsT\xd3loca\x00\x00Z\xe4\x00\x00\x01\xa8\x00\x00\x01\xa8\xbe\x8a\u06c8maxp\x00\x00\\\x8c\x00\x00\x00 \x00\x00\x00 \x03i\x01\xd3name\x00\x00\\\xac\x00\x00\x00\xb0\x00\x00\x018\x14\x910\xdepost\x00\x00]\\\x00\x00\x01Y\x00\x00\x01\xe7\xa2\xc2\x0f;prep\x00\x00^\xb8\x00\x00\x02k\x00\x00\x02\xec\x82\xdc!\x13\x00\x01\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x00\x00\x00\xd1\x00\x01\x00\x00x\x01<\xcc\x03\xac\x1cQ\x14\x80\xe1\u007f\xb0\x1a\xed\xdcF\xb5m\u06f6m\xdb\x0ek\x86\xb5\x19\xa7\xb6m\xc6\rj\x04\u0573\xc2}g\x99\xef\xf2\b\r\xb0\xa8LC\xb4\x85\xd3V.&\x8c\t\x10\x8b\xa1\x01\u0682Y\xcb%\x06\xc9\x1f&\xba\xfc\xb4\xc4\xfe ?\x98\xad-\u0556Z\u007f\xf4\xea\xea\x93^]_\xab\u007fq\xc7\xea%\xc6p\xaf\xb1q\xd6\xf8\u3558C\xcd\xdd\xe6?3/X1\xd8;\xd45\xdc>|\xd7kl\xfd\xf1\xe3r\xfc?\x91\xf7\x91\x02\u02f2\xfc\xf8_5\xb5\xaa\xfb9\xd6Hk\xbeXo]\xb6^Z\u007f\xec\xadV\x8e\x95couj:\xb7\u0771\xee/\xf7\xb4\xec_^\u3505\xde\u038c\x92\xe8\xf0\x94\x932-C5\xf5s\x94\x9e\xe2\xa8\xf2\x19MU\xfb\x94\x9e\xea\xbe\xfa$~\xa8\x1f\xe8\x94# \xc0\xc2F#\x8a\u00a0&u\bROX4\x146\x8di\x82CsZ\xe1\u0446\u0394\xa1'\xbd)O_\x06P\x89\xc1\xa2\x1aC\x19NuF1\x86Z\x8cc2u\xd9\xc86\x1a\xb3\x83\u0774d/\a\xe9\xccaN\u0403\u04dc\xa3\x1fW\xb8)\u0577y\xc0\x04\x1e\x89i<\xe7%\xd3y#f\u0450\x9a\xb1\xf3r\u05a3\r\xc3i'\xbb=\xb3\xe9 \xff\x8e\f\xa7\xb4\x1a\xbb\x86\x8e\xe3Z\x03\x00\x85\xd13A\x89XF\xa5\xbajj\x82\x1f\x06\xb3\xc5Z\xe3\xd4QO\x03\x8d4\xb1 :;X\xa6~9+X\xc9vc7\x1b\xa3\x85V\xdah\xa7\x83N\xba\u8987^\xfa\x19\xd1\xef ?\n\xfe\xec\xe8\xef\xfc\x9fGy\"\xba)xRfS\u0129\xce8]\\\xa8|\rkY\xc7z6\xb0\x89\xcd\xdana+\xdb\u062e\xbd\xfb\xa3g\x84?G\xbf\t\xfe\xce\xffy\x94'\xa2\r\xc1\x93\xe2\x14=\xa7j\x1d\x1b\xdd\xf1\x1a\u05b2\x8e\xf5l`\x13\x9b\xd9\xc2V\xb6a\xf4\xe0\xa4q?d|\xf0\xcf\u0608Fc\x1a\xd3\xd9\u038f\x83t\xe3g\xf2GG\xb1V~O\x11\xa7\x86-\xcf\x043\xc4Z\uaa27\x81F\x9aX\xa0\xfd2q9+X\x19\x1b\xf9\x8c\x91\u01f9\x8f\x11\xd2\xcc^\xbal2\xf9\xbd\xdf\u007fT;\xc5\u075b\xcat\x9eV6\x9fZ\xe5u\xd4\xd3@#M8C\xb0]\xbb\x93\xc6\xfa\x90t#[\xbb\xfcY\xed\xdf\xf9?\x8f\xb2\x905\xace\x1d\xeb\xd9\xc0&Nj\xff!f\\\x1e\x11\x92\xcf\xf8\u06ee\xfe\xf0\xad\xcd8\x1f\x92\xe1\x8a\x1f\t2\xb1\u039d)\x9cusy&\u015a}\xc9\x19S\u07d93\x97\xee\x8cx\xabwfTl%\x14\x9a\u0152 B\xfa\xf7\xf9^u\u007f\x1a\x12\xd6\xfa\xe3z<\xe1\x1ed\xab\xcb%\x8f|\n\xf5)\x92y1%\x8eK\xc52\xb1\\\xac\x10\xab\xc4j\xfdk\x98\xc5l\xe6P\xab\xae\x8ez\x1ah\xa4\t3\x90\xf2\x19\u06a5\xcdn\xf6\xb0\x97}\uc9d9\x16Zi\xa3\x9d\x0e>p\xfeN\xb1\x8bnz\u895f\x01u\x83\f1\u0308\xf1\x0fr\xcc\xef\xe3\xae\ub939\xf9\x90H\x90n\xd62\xf9c\xaa\xd9V?3\x9c\u04eb\xd7\xfb\u1115\x9a\xad\xec\xaa7\x1cE\u028b)\xf1\xbbT,\x13\xcb\xc5\n\xaa\xa8u\\G=\r4\xd2\xc4\x02\u05d2j\xe5\xef\xd2f7{\xd8\xcb>\xf6\x93\xecM\xf8\x81>\xc9\u0786\x03\xea\x06\x19b\x98\xf8\x1c\xb9r\xef\xef\b\xe9f/\x13Oy\xc2\x13\x96\xad,\x97<\xf2)TVD1%\x8eK\xc52\xb1\\\x8c]\xb58\x87\xe4o\x86\xb7S>\xa1\xbb\xb4\xd9\xcd\x1e\xf6\xb2\x8f\xfd4\xd3B+m\xb4\xd3\xc1\a\xfat\x8a]t\xd3C/\xfd\f\xa8\x1bd\x88aN\xba\xd6\x0f\xf9m\u04b7Q\xaeVy\xe4SB\x19\xa9\xeeS\xb3\xfa\x16Zi\xa3\x9d\x0e:\u989b\x1ez\xe9'\xfeF\xcbN\xb2\xea6%d\xf4\xb8^\xd9\xcas\xc9#\x9fB\x8a\xdc\xd9bJ\xfc.\x15\xcb\xc4r\xb1\xc2\xfcV\x89\xb3\xf4\x9d\xado\xec\xc9UWG=\r4\u0484'7\xf5*\xd4f7{\xd8\xcb>\xf6\xd3L\v\xad\xb4\xd1N\a\x1f8W\xa7\xd8E7=\xf4\xd2\u03c0\xbaA\x86\x18fDn\a\x89\xaf\xc6I\xe1j\xac\xf6\u03aaa6#\x1c$~\xe7\u0185w\xaePi|6G\x05\x11#\x8e\x8d\u05c5\xe5i\xe1\x98\xd9\xceT\xc8.v\xb3\x87\xbd\xecc?\xe1\xf8\xe1}\xa94~<\xb7\u02e5\x05W\x94\xa6\x85\xe7+\xb9\xb4>\x93\xad\xc30\x9fq\xe1\xf7\xb5\xe0\x8ao\xe3\xc4\xd8JkN\xbej\\\u07ff\x82W\x82?\x85\xfb\x8e\xc9\xde\x1e\xe9\xd6\u042f\xf9\xbd+\xbf\x91}\xc8\f;\xb5\x02e\x95T+\xab\x11g\x8b7\xfb\xb5\x1c\xd1\xe7 \xf1}\xca_\xae\x97\x95\xdc\xe7\xdeRf\xb5w \xbb+\xe7\xec\x8d+\xb2;s3\xd9\xc9\xec\xa2\u033e\x92\xd9E\x99]\xb8\xf9\xac\xf49\u0215sf]\xf2 duB\x1e2\vN\x8b\x1f\x8aY\xe1\xbaNK|C\x86;\xbf\x1b\u0677e\x84#e\\\xba\xb6\xf0\x9a\x16\xb28y\xbe\xe1\bYIG\xa8g!\x8bX~\x03#\x85;\u0404\xa7e\xe1\r\xf4\x9e\x90r\x1f\xf1\x8b -z&a\xef\xf7\xaf\xe8\xb7\xc1\xe3)\xf6\x80O\x8b\xf3I\xb1;I\xb2K\xbf\xf5]f\xea\x91\u007fp\u056e\xe9\xbf\xcc ;\xf5HI\u07e9\u079bL\x92[DL\xb3f'\x9b\xc9p\xe7\x9a\xf8\xcd3c\xc3\xcez\xf8\xaao\xdf\x13\x9e\x96)\xdaM\x8d\xfd\xd51#\xe1[X`\xf5\xdf\xc0\xf70|\xb3\\\xf9]\x9co\xbc\x87\xe1\xdb\xe8\xfb\xe6\x8cc\xe3_\x8f\xf0\xcb1\xda{dC\xacnL\xf8\xebC\xc69z!\x88P\xe0\xf9v\u0141\x1d\x99\xd6\xe1/\xf5\xc3A\x84_\x87c\xa6;\xca\xe4\xf7\xd1\xce \xd7\xca\xcd#\x1f_\xaa\xa0P,\xa1\x8cJ\u007f\x996\x8b-\xb4\xd2F;\x1dt\xd2E7=\xf4\u048f|\x83S\u0465\xb1\x9c?\x12?\xb5\x1a&$\x9c9\xfc&\xe2\xef\x1d\xf3\xf2\xb7;\xf1\x1f\x87\xbb\xfd\u07c6\xef\x00\xe8\x11\x93\xb0\x00\x01\x00\x00\x00\n\x00\n\x00\n\x00\x00x\x01c`fQc\x9c\xc0\xc0\xca\xc0\xc1:\x8b\u0558\x81\x81Q\x0eB3_`Hc\xfc\xc4\xc0\xc0\xc4\xcd\xc6\xc6\xcc\xc1\xc2\xc4\xc4\xf2\x80\x81\xe9\xbd\x03\x83B4\x03\x03\x83\x06\x03\x10\x18:\x06;3\x00\x05\x14\\\xd8\xe4\xff\x890\xb4\xb0\x173\xbeQ``\x9c\x0f\x92c\xf1b\xdd\x06\xa4\x14\x18\x98\x00\x9b\xf6\x0e\x82\x00\x00x\x01c```\x02bf \x16\x01\x92\x8c`\x9a\x85\xa1\x02HK1\b\x00E\xb8\x18\xea\x18\xfe3\x1a2\x1dc\xba\xc5tGADAJANAI\xc1J\xc1\xe5\xff\u007f\xa0\x1a\x05\x86\x05p9a\x05\t\x05\x19\xa0\x9c%H\xee\xff\xe3\xff\x87\xfeO\xfc\xfb\xf7\ufaff/\x1fl~\xb0\xe1\xc1\xfa\ak\x1eL{\xd0\v\xb4\x01'\x00\x00;\x03#\xf4\x00\x00x\x01\xad\xc6\x03l\x9dq\x1c\x05\xd0\xf3\u007fo\xb6\xbd\xd86\x16k\u0782y1f\u06f6m\u06f6\xbdF\r\xcbX\x8d\xaa\xb0Q\xf3\xa1f\xdc\xf3\u00fd]\x06\xe9ij\xe7\xf7\x86Z\xd7\xf9}\xe7\\\xcd\xe94\xd1 '\x88\xcbh\xfe\xa3A\x91\x8e\xd4\rx\uaf6f\xc8\a\u0330\xc7\x057lS\xe2y:\xab\u0481\xcf\xfe\xa5\aw\xddp\x14\u4933-\x9d\xe6^\xfa\xe40\xb8\xe2\xbe\x136hr^\x93E\x96;\xe9\xad_\xf2\x01\u0337\xc2F\xe7\xfd\x94\x1f\xc6\x01\xa20\xc6?\x1b\xd3\x1c\x12\xaa\xb4\xaf\x02\xe7\x1d\xf4\xdcy\x87B/\xe7\xc30\xb2\xa3\x9d\xcd\u0335;{\x1e\x0f\x1d\x85\xcc&\xc5\u0786\x1e\x84=\x96\xd9\xe1&\xa4\xed\xa0\xd6\u03b8\x89\xdd\x0e\x01\xd0\xf9}\xf5Y\xfd\xe3J{\x9c\x00\xcbl\xd1\xe4kx\x9c\x9d^\u05fc\x0f\x85\xe1\x1c\xce\a\x9ew~\x1f}\x8dVD{\xac\xc8U.\xbeP\xe9\x9bJJ\xe5\xb4\xe5\xf0\xcb\xecr\xab\xc9\x05p\xfc5\x00>\xb1\xee\xf7%\xc5?\x05\x10q\\7\xf1-\x1dS\x87\x01\xdb\bx\x1eupQ\x1f\a\x1c\xad\x98\v\f?\x19+\x11\a\xa4\x97n\xd9\u0701\xce\xc2\xe6V\x93\xa5\x9b\xb7P\xb8\x85\"<\b\u02e9u\xf0\xaae\x02\xfb\xa0\xb8\x98\u06ac\xbaM/\x8b\x85\x86H\xe6\xf1n_\x8a\xc0\xf5\xbc\xa8\xd5\xec\xe1v\bL\x8au\x8c$\x96;X1\x92|Io\x9d\xad\xf2\xb4\xf9H=\x988l6>\xb2u\x1e\xe6\x93\xf7$\x16\x12\xeaU\x05\xa1\xd4\xf7X;\x82\x87 \xc0C_\xfc]\xa7\x93/`\x13\x02\x81G\xb4\xea\x8d\xc1\x93un<]\xd2\xc2R\xc3\x01\xae6\x18\x1d\a\xd6\xffy\x9eI2\xa6\xdcp6\x98\x0eC\xb2W\xa9\x10x\xa8b\x95L\x1e\xaf\xcc\x02w@\xa5[\xb7\xaaeA\x0e\xb3\xbb\x12-\xe2\u007fYu1|\x10\xa1\x13\x8f\xad\x8b\xd9a\xc3\xc1\r\xdc\xd5\u007fW\xa2\xdd\b\xf98!\x86>\xd7\xc0;\xefz\xb5(\xaf\xb9\xfb\xba4##\xb0\xac=\xf5<}\xf0\u0549\xcff\t\xe0J_N1g\xb3\xeeC\xe6\x1f;\x12\xa1\x1d\xeb\u0323<\xb3\xe7\x9e\u03ac\xe4\x99'\xed1xd\xc6P*,6z\xf3 \xc8\xe3\xd5\x04Wf\x91'\x1f\xe9Q\x80\x83\xdb\xffu=P;k\xfc\u00b1\xc8\xd4r,P\xed\x12\xc7\xd2\f\x96u\u05f3\rtSt\x8br4\xa0`\xfa\xb7\xee*J\xd4v\xf2\v@2ZG\x80\x88\xb3\xcf'\xe3:\t\xf0V\x13\xbbG\xa6\xa3\x1fI\xf4\x03\n\xfc$\x9b\x91H\x8f\x1f\xa3\x8e$\xa6\x11-\x05f|x\f\x96q7\xb4\xf3y\x9am\x89\xa5\xa14-Y\x1b\xee\xee \x8b\xe7\xb2.<&\x02\"\x81\v\x15\x9b@\xc4Z\v\xfar\x8d\x9dz\xfc{z\x9a\xbb?\x9fb\xa7Y\x14\xe8\xe2\xbd\x1d\x89\x85\x19\xa1\xe4\xfc\"\xbe\x19\xbb\xf3\xc8\xe3E.]\x0f\xfd\x88\x06\x1c\x81\\\x88\xf0\x90q\xe8\xd0\ufd1cgVD\xbb3\x927\x86p\xa3\u007f_\x9e7\x1b\xc9\x13$G\x1e\x8b\x17d@\xbaS\x19\xbarXmT\xb9\xb4\xddBD\x85\x0e\x11<\xa4\x00\u0697\xe9\x17+\x8d*}\x1d,OY:\x11%\xb8\xb4\\\x96W\xd36\xf0\x10\x17\vAVG\xf8yQ\x02\x85F\xa7\x9b\xab\x955$\x9dN\xd7\xf5\"o\xfaj5mJ\xf3la\xea\xa8jS\xbbY\x8ab\x8eE\xe2l\x92\u0454\xf1\xb2\xae\xef<\x97\xb0\x00\x11\x8c9\xfaw%\x9d\xcd\xd8c\\\xce\xcc0\x9eg\xb3\x1a=\x87r\xb3\fB\xe6QZ\x83\xdcL\f\x8f\x10z\x06_'\xfc\f\ucf90\xee\xe5i\xae\xaapc\xa8\xb48d\x82\x8cv\xdeC\xa6\xaf\xb0\u007f\xbe\xe6j\xca\xd2\xcf3\x84\tp\x87\x87\xd3\xe7Y\xa5\xbe\xaf\x9f\xe5\xf1E-\x02\xbdy\x05Cy\xd9T\xdf\x18\u022f\xdd/(\xc0\x9d\xec\x86uc\xd4n5S\x9b\xb5S\xb0~\u89fe\xf5\xc3\xf0\xbe\\s\x18\xe3?\x8c\xe4C\u06f2;q;J\xf7SN\xaeq\xc6|\xc3\u069a%\xd2\x00\xae\x81V\x1a\x10\xa8\x9azw\xcdgl\xc5d\x8b\x860xnb1\xc3Us\xcebs\x13{\xca99g\x13W\x9cr\xbe\xe1\xf4\x8b\xa6T\x1f\x93\xc7\x12\xb8\xe0\xf3z>_Ec\x15G\x81v{/9B\x1f\v-\xb8J\xee\xc0\xd5\u0532\xcb[q3,\xb4q\v\xb45\u007fM\xf3\u05e6|Y\xf3\x15h\xa3\xb5\xd7j5\xbfP\x8e\x80\x8dz\xeb?v\xf0\xf3\xb7\x00\x00\x00\x00\x02\x00\x05\x00\x02\xff\xff\x00\x03x\x01\x8c|\t\\SW\xbe\xff\xf9\x9ds\x97\xec\xb9\xd9\x13B6B\b\x18 \x90\xcb*K\x02\xa8DD\x04ET\x14\x88\x16q\x17\xadmm\xebX\xb1\x8em\xe9\xaaS\xb5\xd6.\xe3t{]\x1c\xb5\x1bc\x1d\xffUg\xb1\xb3\xb7}\x1dg\xeb\xa7\xcf\xfa\xe6u\xfa\xfa^\x17;\xd3\xcet\x91\xf8?\xe7&(u\xfe\u02cb\xdc\u071b{!\xf7\xb7\xff\xbe\xe7{\xce\x15at\xff\xa5?\xc3n~\f\x11\xe4@S_Ap\xe9B\u00a2\xb1&%\u05c8k\x97\ub80b#\x86\x03\x1c\xc6\u0731K\xa7\x12\x1aQ\x93\xe4@\xfd\x90\x05\x13\x14\x8f~\xfe\x1b\x88F\xe4\xa8t>\xd6W^\x16\x81 \x91IE#\x96c^l\xb3\x1ap0\xaf\x14C\xe7M\xf2\xb9\v\u05bcRwN4\xcfj\u034b\xe6\xb8K\xf3\xac\xf0(\xe7\xfc\ua542\u0280\xd1\x18\xa8,\bU\xe6IR^%\xa2/\x8cv\x92\xa7\xf0\v\x8a,\"\xaaN\x04\xb9\xfd\xa2\xa8~C\xfd\xae\x1aG\xd5\xc3\xeamj\x82\xf6#\"\x91w\xc9\x05\xc2\x11\x01c\x91P9d9*C\xb4\xef|_\x9f\xb96z\xbe\xbc\fH\x90\x04\xe8\x06mE\x9b\x8apI\u0475E\xfc\xd8\xf8\x05,\xb1\x8d\xddCF\x88\xfb\x82\xde\u00cd|\xe8\xc1\xc4BBrr\x9cv\xafG\xe4\x04\x87Cp!\xe08\xfey\xa73`\xf3\xe5\xaa8\xb5\xd5j6\x1a\xb4\x9c\xe5yM\xa7\x04\x92\xa4\u04e9;5\xa0\u0245\xa4\x1e\xf4\x87u*N\xe7C\xd2a\x93\xcbf\x8a\x9b\xe6\x98\u0399\x88\u03a43\xf1\x0e\x8b\xa0\xe1QT\x8e\xcb\xe6\xda\xdah\xb4\xcf$\xcb\xd4H1e\xd7\x17\x8bQa\x99\xcc\xd1>\xe9?\x1c\xb51\x93\xd9Qk\x92\xa3\xecPV\x8e\xd9%\xa6E\xc0F\xb5\xb0([e@\xd9d\xa2l6\xa0\x1f\xc9\xef\xe3\xe0L\xffz\xee\xfd\xdd\xe9w\xe6\xee\xeaH\xa7\xc1\u04d4\xfe\x18\"s\xef\x9f\v\xa1\xee]\xdd \\\xfco\b&\xd2\uf42d\xe9c\xa3\xe9n8\u0136QH\x8e\xc2\xd1t'\xdbF\xd3\xc7 \x89\b\xdari\x94\xfcQ0\xa3\x12T\x85\xe2\u8944\\\x11-\x82\xa2h\x00\x02\u0086h=\xd4G\xbd\xe0\xb5\xf8E\x10E}\xe9\xfa|#\xb5\x1a\xbe\x84\x00!\x10Q\x93^_\xbd\xfe]\x17\xb8Xp\x94\xa9\xb4I\x97l\xb5\x16\xd5\xd7[J\xabU\r\x85\x9b\x02\xa1\x80/a0%}>og\x00\x8c\x01_\x00\xab\x02\x15\x96M*\x83J\x10x\x15\xfd\xa3\x175\xfa\xa4\n\xd1(\x92\xa3&f\xa3h\u007f\x1f\xb3MD\xf9@\x8dg\xa6\xe6\x90M2\x8d\xb3\xbe\xf34\xd2~G/o\x8c\x9d7\xd52\v\xf6\xc9}4\xf2\xe8?j,\x1ao\xa2-XIC.\\\xe9%\xb2\xa9\x94T\xd2P\xac\xae\x94m^p\x88\xa5\x106y\x89XA\xaf\x9a\x1a\x01\xac^\xec0\x19\x80\xfc1\u05b7\xb3\xfb\xce\xd8P\xaa\xdb\x1fX\x90Z\x1e]\xb4\xa3gJ\xf9\xe2\xeds\xee\x1c|\xa6\xa5\xb9\xe6\ued85\xb7/.=j\x8d\u0310\xfb\x16\xa7\u0366\xc2\xe6\xf2E\xf3\xe0\xd5\x19\xd7vW\xeb\xfe\xf2\x8e\u069cc:$\x05rL\xf0\x82\xb7y\xfe\xfa\xb6\x96\xe1y\x95\ua5ce\xf2S|\xbb]EB\xba\xd7\xd7\x9b\x9a\x95\xd9T\x85\xff\xeb\x155\x04\xe1\xab\xd6\u0387\x1f\xeel\x85\xd7\xf2\xdb6\u0359\xb9\xa1\xbd 8sc\u01ec\x8d\xb3\xc3p({\xe5L\x90^i\xdb0+{\xa5=|\t]<\xfb()\xe6\xf0\x93OB\x1b$\x1f\u007fr\xed\xa1\x1b\xe2\xf1\x1b\x0e\xad]\xfb\xec\xf5\x8d\x8d\xd7?;\xde\xf6\xe4\x130S\xb9\xf0\x1c\xbb\xf0\xdc\xc4\x05\xf2\x9d\xaf\xdahZ\xd2\x17A\xeb.}\xc8o\xe5\u007f\x8dL(\x80\u6851\xc4\xec\xb0\xd3\xd1\xc6\xcd,\x9e\x99\u0534V5\xb56\xfb\x9b\xa1\xaa\xb9\xaa\xd9\xc3\xd7\u0577rI\u050a\x8a\xa5b\xac*.\xce\xf3'!9\u07d3\x94\xf2\xfcy8\xaf\xa9\xa9\xdc\xdc5\u01ee\xfc\xad\xb1\xb5\xbe\x8e\xe7\xcag\u068c\x9d\xe5(z>N3\x8d\xfe\xc4Y,1\x93Ig\xfa\xe8Q\u007f\xdfy\x13=\xaf$\xadt^:oR2\x92\xc6\x17\v\x99FRI#\x88\x1a\xca\x12\xa3\xa1\x05\x06b\xa3gC,\xccX\xb4])|\"4\x92j\xd9@D\b\x86\rD)\x83OI\x81\x8a\xfc\xba\x9e\x9a\\W\xb4yJ\xcf\xe0\xedS\x97u'\xfd\xe9\xad\x15\x9d\u0579\xc1\xe6Tzk\xe1\xec\xe1V_}In\xac\xff\u0385\xf3v,.\x8bu\xaf\xab\x87\x94;\x92\xe7\xd6\x1c3\x16U6\x85\xc1v\xfe\xe9\xf2\xd4\xdaou\xac\xfa\x97M\r\xdc=T\xb3\x96P\xb011\xa3(\xbf\xa1\u0635\xe8\xeb#\x8e\xc2*\x1f<\x10\x88'\xe7\xd7T-n\u02bf\xd0q\xf3`\u03d4\xfc\xd9\v\xae\xa9\x9d\xb5y^$2o\xf3\xac\u013a\xbe9\xf9\xe9\xbb=\xf5\xd3:\xa2\xcd\xc3\xcb\xe6\x17\xa5\xdf>T\xd2Z\xee\xae\\\xb1\x17\x01\xab\xbb\xc0\x8cO\u0414D\xee)\xfe\r\xfe]\x9eD\xf9a\x1eO.\xb8\x18+\xe56\x9a)\xb6\xd4*\xd9\"\x9b\xad\xaf\b\x01\x9a\x9b>\x81#\xf4{,('\xa1\x17\f\u007fU_\x88\u04f3\x86/\xf9/P&4\xff#F\x83\x91\xd9L\x160\xb3\x9f#XJ\xe6\xe6\xb7m\xec8t\xf7\xeeP\xeb\xea\xe9\xcfvll\xcb\xc7\xe5[\xff\xf6\xde[}\xa7\u04f1\xcf6\u007f\xf8\xef\xbf\xed\xef\xfd\xcd\xf9\v,.\x005\xd0\xefw(\u07df\x9b0\xd0\xef\xd7^8J\xcf\xda\f_\xf0_\xb2\x1bH\xff\xc6\ue42d\aA\xe60\x1c\x96\xbd\x04;\xf2gm\xecxv\xfa\xead\xfe\xae{\x0eul\x9cE\xef\xf0\xad\v\xe7\u007f\xd3\xdb\xff\xdb\u007f\xffp\xf3g\xf0\x9b\xd3}o\xbd\xf77E~\xbc\x99\xb3\nVd@\xf9\t\x9bO\x02\xaa\xbea\u0130\xcb@T\x06\x9f\x00\x82@\x85\x88\u01e2}@#\xe5=\xc5\x02!\ao\x11\xb5\x10\xb6\x84\xaay\x82\xf7G\xe0\x9e\x9c\xf4m\x9f\xbfp\xf4\xd1c\u007fM\x8fz\xe0\xf6\x88`Mo\x1e>\x9d\x9b>\x9e\x82\xa1\xf4\x81\x14\xcc\xc8==\f\xa3\xec^C p\x98{\fiQQ\xc2)\xe9AP?K>A\xe0G)t\x10\x11\xa4F\xdf\x17\u020b\xd4\xde\xe7Y\xc3\xe8\x8b)]\x16h\x1b\xa0AI[\x83)\b\x1f\xa4\xb7\u008e}\xb0#\xbdu\x1f\xbe}\x1f\xecLo\u0657\u0796\xb1S<\xfd\x05\u0704>F:T\x93\xb0\xben\x00\x89\xeap\xd0@\u073a\x88\x0e\xeb\xe0\x01Ad\x05[/Y\x93\x03\"H\"\x88\xc2\xc3:\x14\xfd\x88\xdd'\"\u007f\x14\xebc\xde\r9\f\x84\u0670\x1aV\x1b\r\xe1\xa8\xec\xba\xd3\xe8q\xdbU\x1f;\xaan\xfe\u0596\x9a\x86o\xef\xd8\xcaz6\xb3\x19\xbc\x89\x9b\xf1MTd[B\x8d\xf9\x04\xeb\r\xaf\x00\xcd1\xa0I\xf4\x1b\xea\xee\u0280m.\\\x807\x9f~\x9a\xfd~\x06o\xa0\xaf\xa8\x0f+\x13\xee\x11\xdb.\xdbA\x1b1\xd9@\xb3\xef\x14z\x03\xe1\n4\r\r\xa2\xeb\x10\x87\xa8\x88c\x14o \xfe!\xa3\"[\xa4\xaf\xef#&X\xf5U \xe3\xfe\xab\xf1\xc5\xf0\xd5\xd0\x02\x90\x15!\xfc\xbe\x12\xdf\xde\xe7\x01\xb32\xab\xc6\x04I\x88\a\u0110\x8c\t\xe4\x9aX\xb4F./cE\x0f\xbf?\xfe\xee\x8b8\xc0\x8fM\xd4#\x8c\x96]\xfa\x90S\xd1zdAaT\x90\xb0y\x87Q\x91T\x04\xd6a?\x05\x03\xc1MF\u0475\x89w\xd1\"\x1cg:+\u0157\xc5 6\x00\x95\x0fhA57\x02\x95\x18\xcc<\x8dx\x99V\x8fL!1`N%o|a\xdb\rG6\xd5\xca\xc3\xcf\u07f2\xf9\xe8uS\xc7-\xde\xe65\xb3g\xaf\x9d\xee\xf3M_;{\xf6\x9af/~\xe7\xf9\xf4\u007f\xfehh\xe8G\xe0|\xfeyp\x9e\x1eZ~:\xfd\x9f/\xec{w\ufb36=\xe7\x1f\xd8\xf7\ue7b6\xb6=\xef2\xbb\xbe@\x05}\x8d\n,Q\xbb\x06\x12f0\x82\xc1\x80\u059f\x84K\x80o\x01@ \x81\x1f\x12\xc0\t\xa07\n\xc8I\xd3\xe5\xd7\xc0\xda-k\xac&\x99\xda5\x104\xb1\xc44\x10#\x84A\u01af\x1d\x05B\xc0\x94\xe3\xf6\xda\xf6\xa4`\xdb>\xb2;\xb2l\xe9\xa2\u007f\xac\xe9\u06ff\xb8s\xdd\xe9\xf9\v~\u0677\xe4\xb6\x05E\x95\xcb\xeeY\xb4sg\xd7-\xf3\x8b\xf3\x9b\x97\u052cy\xbcmIA\xdf\xfa\xad3\xd6>\xbe\xbe\x86K\u037cqa\xadN\xb0\xbf\xbc;u\xf0\xbaD^\u0273\xa5\xb1\u00b6\xb5-\u04d6\u01bd\x0f\x14\xb6\r5T\u032d\xf5\xb6Tm\xf5U\x159\xab\x96\xeeD\x189\x10\xe2\xe2\xfc\xabHC\x1d\u07d1(V\xf7\xb0$\xc5\xebM:\xad\xe8'@!\xb0\x94\x03\x9b\x9d\xb7;\xb1s\x80\a^-8\xaf\x03\x9e\xc7&Q\xc0,P\x98\xba\xf2\xf9\fpe(\x9b\xee\u82e25\x05{\x05MAS\xa0\x12(L\v(\x01\x14d\xad\x8f\x8b\x9f=:\u0787\x1f8q6\xbd\x85p<\xa8E\x9b+G\x9b^\x0eI\x86:\xbfK~\u007f\xb1\f\x06k\xb6\\?\x94g-//\x95\xc6\x0ff|\xb4\x83\xfa\xe8\xef4\x86\xa7P)\x9d\x059\xc3<\xed\xeb\x10\xce\xcf/\\\x19\x84EA\b\x06/\x18\xc1\xc8\x1cf\xa6`\xd3\xe8\u0644\x90-|]\xbe`\xdb$i\xb2\xaeac\x00V+d\xea\x18\x06\x1dY2\xd2\b\x83I\x05\x83A\u010c\x1b\nX\x12\x8aa\v\x83\u068d\x80\x03\xd7<\xb7-9\xed\xb6\x9f\x8e\xc8\xd7,\x9e\x1b\b,Zv\u03549\xdf\xea)=\xfa\xb4;\x1e\xaf\xb5\xf5V\xe3\x17\xc6?\f\xfbW\x91\xed\xd5k\x0f\xae\xbav\xec\x96\x16\x8d\xc5k=\xe4\xc8w\xeaC\x1d7t\xdd\xf7\x00\xafRs\xb5\xf8\xe8S\xe9>\xc1\x90\xa9\x1b\x1bi\xdd\xd0\u0418\x8b\xa08\xaaN\xf8\xcb\xd7\xeb\xf2\x9a\xa4&p\xd4\r#$!?\"\xa8\xeaz\x8fG,\xde\x14vI\x9bD\x86\xe3\x14D\xa2\x94\x91\x18\x15=v^i\x97\x1c\v\x13\x87\xad\x14\xa8\xbc\x9c(7\x92o\f\xb2&\x15\x14\xd6R7\xda*\x97\xdc{f\xa7\xa5\x94\xc2\xe8\xe0\xc2H\xef\xe8`\xcb\x14+\xd1Yk\xdb\a\xea\x06\x0e\xac\xadk\xbc\ue261\xc1##m\xf0v\xfd5\xc9p\xa0\xf9\x9a\xe6\x96\xe1\x8eHh\xe6z\xbcq\xd5\x1b'\x9f\xb8i:\xe6E\xfe!\x9d.\u04b1v\u01de\xce\xfcxIN\u0775O\xae\xbevl\u06f4\x8e\x83\u007fM\xbfR4o\u06c2\x19\xc3\x1dS\xa2\xb3Re-;W\xb7(~\xebE\x88\x13\xa8\xdf\x04\x14y^@\xac\xbe\x9a\xa8\xfa\xc0\xab$\x15`\x1e_G2\x15\x87\xb52\x96.TEVl\x03\xac\x9d\xd9\x00\\X\x1e7\x90C\xe3gy\xe9\xa9\xdd_\xbd\x8d\bZM\xed\x86h\xbd\r\xa3\xa9\xa8\x8d\xe2\xbfy\xde`l\xbdQS\x98\\\xffc\xfe-\x1e\xbf\xcc\x03\xcf\x1b\u06e5v(\\\xefj\\\u007f6\b\xbf\n\xc2q\x16\x1f\x92\xcb\xef\xc2.\x8dwe\xcd\xfe\x1a\xbc\xa8\x06\nkjj\x925\xa4\xe6\xfe\x16(h\xe9i\xc1--\xa8d\x93\xd5U\xb7\t]6v_\xdfi\x9a\u02b5\x99\xaaD\x8fh&3\x19\xe9!\r&\x96\xd5W\xa2G\xf4\x92\t\xabW^\x01~dRU\x8f\x82\x01 O\xb0M\x00\xc6\x02\\\u067dwcs\xe1\x8cT\xcd\xd4\xe1\x05\x95-7=3\xb4\xfe\xb9\xeb\x1bJ\xdaWN-\uf247Z\xae\xdd\xfb\x9a\u007f\xda\xca\xe4\x8c5\xc9\xfc\xf0\u0321\xb8\xf7\x96\x11\xb0\xaf\xde\x1al\\ \x97\u034f\xe7\xdf\xc2\xff\xbax\xe1\xb7\x17\xb6\xac]0=\xd7\xd7>p\xc3\xcc%{W\xd6T-\xff\u0392Y7\xa6\xdar}3{\xd75/\u0631\xb0\xf8\xeb\xa7*\x17\u0143\xc1\xa6%5\x15\xdd\u0244\xcfP\xff\x10\xe9^\xbd\xbcvnBv\xda+\x9a\xbb\xab\x96\xafF\b+6\xe5h,\x16\xa1\x06\xda!\xbc\xb5\xb6a\x14\x97(([\xaf\x93\xfc~?\xf6W\\\xefv\x8bS6\x85D\xe9z1gr$\xcaJG\xcb\xc0*\x8e\xe9\x9e-iJ\xaa\u007fc,\xc1\"p\x9218n\"\x14K\x8bY(\xde~x(\xc2\xeb\xad5\xed)%\x10\u36de\x1cZ~x\xa4-\x1d\x9a\b\xc4i\xeb\x95@$3V\xbd\xf9\xea\x937\xd2@\x14\xf8\x87\xf5\xba\xfe\xef\xfdns~ci&\f\u007f\xc0\xc2\xf0o\xd0Z\xd8=9\f\xd74#\x84&\xb8\fnH\xe9\u04cd\x89\\\xa9h\xa4hW\xd1\xc1\"\u03ab\xd9g\xfdgx\x91\xd02|\x11|\xc8%e0F<\x832\xe4\xf7b\xff\a\x98a\xfa\xff\xc1\x8e\xff\x1f\f!\xbb\u00d5\x01\x83!P\x19\x0eU\xb0\x13\x15\b3\x9c\xa6\u022bC~\xb44\x11\x95\xf2F\xf2v\xe5\x1d\xcc\xe3\x1c\xfbN\xe9\xdf\xd0\xe3A\xfduz\u0729\x87iz\xa8\u04c3O\x1f\xd5c\xbd\xfe\x9b \xcet\x05\xc4\xe5>d\x962@.~\x05\u02b1\x90f\xaf\xf7&C\xba\xaby\x9aoB<\xd3\u055aL\xc6|\xf8\xa3\xab\xb5P\xb0,\xfa\x98\xc3\xdc;H\xa0u\xbb\f\xa9\x12*H\x00\x00\x06\x9e'\xc20\u0686p\x19k8\x9c\x9f@'\xd9@F\xc8\x1bt@\xc1\xc7\t \x02\x02AJ/\xdd(3Q\u983f!*\xcb\xe0T\xfa*\x15\x19*\xc1\xa6\x06\x0e_\x1c$\x0f\x8f\a\xf0\xb9\x8f\xe1\xe9!8\u007f0\xbd'\xfd*\xc2h\b\x8es\x98|\xa0\xf0EK\x12\r\"V'\xe8/\x9fA\xf0C\x04\xcf \xb8\r\xc1\x16\x04+\x114#\xa8E\x80\xb8\xef\xfb\xf8(\x8f\xb7\xf1\x80x\x89\xc7\x02\u03e3\xef_\x000\xc20`@Q\x05\v1\x8a\x81E}\xf6%\xb3Z\x90\x01\xb1@\xb7!\xf20\x93\x84t\xef\u075b\x1e\u06b7\xef\x9ft\xe7\x15\xdd\x05\x10x\x0e\x80\xa0aa\x9b\x80\xcb\xd8\xc8\x01\xff\xffu\x97\xaf\xd2\u0762f\xca\xc3\x10~w\xdc\xcfn\v\xf7A3\xac=\x98\xf6\r\xa5\x17R\xddC\x97\xfeLB4\x9f\x19\u007f\u0418\b\xc4\x0e\x14\x16\x86g d\xd5\xce\xc8m\x886\x80U\xeb0\"\x10\x10*y\xa8\xda\"u98\x14\xa7\u06bd\xc7(\x16\x86\xc0XJ\xb3\xfc\x96\x15\xcaL\xa9f\x93\x11\x18\\F`\x06\xe2\x81\u007f\x8a\x17\x971\xdc\x1c+\x9b\x16\xb1yk\xe7\xd7\xcc\xdb7#\xdeubi\x1f\xadM\xee\xaa\u03aa\x8a\xe6\x02\xc3\x0f\xff\x99\xf3\v\xd5.\xe9\x9c=\xa5\xa8e\xfa\x9c\u02b29\xb5\xbe\x8a\xbc\xddS\xea\xe4\xd4]\vZV\xf5vGKZ\xe2\xcd\xc5\xe6\xf4\x9b\xffL\nb\xca\x05\xb4\t\xdbioY\x80V\xa2\xe1D|\xa1#\x15\xf69`[\x18\x1c\xe1\x193\xc2\x0e\xd2Q\xeeG\x80V'VC]\xa2\x03:\x8au\x8b\u0362y0\xd7h\xf6\x99O\x9a\x89\x80rA4\xe7\x9as\x13U\xf3Hb\xfaL\x14\x95O\xc7O\xb3!>5D\u007f\x9ft\x9a\xe2\xd0\xd3\n\xb49MM\xb2\xf1\xb4\xc9A\xaf0\a\x9c\x96NO\xaaxWU:\a1@.\u063e\x01\xe79\xe1r\xf1\xab\xb61\xe8\x9f_\xc0\xa0\u007fU\xbe\x1c\xe3\xecf\xb0\xda\u06558(M\x1c\v\xdb-\xa1\xda\xf6\xa5SKfV\x04\x04\xce\\\u057a\xa8r\xf6\u6e51\xba\xe1G\x97\x95\xf4\u039d\xeep\x00\xd8\xf2\"\x8e\xd2\x19Qg\xcf\xfe7\xb7<\x93N\x1f\xe9\x9d\xf3\xe0\x9f\xefo\xd8<<\x18\xe9\xf9\u00ed/\xa6\xdf\xff\xf1\xd0\roC\xf5\xe9\x87A8\xb9\xfa\xa2m\xf9\xfc\xea\x8eX\x0eg\u021d=\xa5my<\x17\xbf\u0778u\xe3\xd2d\x917\xd6\x14\f5\x97\xe7\xd6,\xbf\xb7g\xf9\xd37OS\x19L\xaat\xca\xee\x96T\xa4rZ\xa1\xb1a\xe5\xdd\x1d\xf7\xbe\xb3\u007f\xce\xf0k\xe9O\x1e{\xe0\xbf\x0e\xce58}\xa6{\n\x8a\x87~\f\xae\x17O\xc0\xf4\x8f\xefX\xfe\xbf\u049f\xa6\xcf\xee\xdc\\2o\xd3\xf4q\x95~j\xff\x8d\xcc'\xf4\u017d\u00df@\"\xb2\xa2o'\xf2\x05~\x06\x86\x19V\xc0V2S\x053\x01T\x80\f\x06\x82\x90$\u0088\xb8K|C$J\xb1r\n\x9a\xa4(\x89\xa2\xddh\xf7\u0663\xf6\xfb\xec\u07f5\x9f\xb3\v\"\xe1\x14\xc4\xc0\xe1\x01\x83_cH\x1ax\xab\x95'\x1c2\xa3x,^\x1b5\xd7F\xce\x03\xc5\v\xfdl\xb4P\x13\xa1\xc9bb\x89B]\xd8\u05e7\xbc\xc9\fJ0\xca\x17d5\x90RBY\x17\xfa\x95\xbe\x83\xe3\xe7\x1e;\x81]\xcf\xe2\x9c\xf4\x8a=\x82\xc9lV\x89f\xb3I\xd8\r?M\xd7\xf1'\xbe\x9a\x86W\xc3\xd3\xe6\x8a\xfa&\x9f\xaf\xb9A6\u0454B\x04\xbdF\xf5\xba\x9d\u019a\x03\xe5\xa1(Z\x96h\xd4z{y\x01\xde\x13>\x17\xf0\xefX\x1a\xe7OY\xbc\xc14b\u00a6\x15\xe5\xdb\xca\xef+\xc7R98\xf3{\x1d\x83e\xda`\xea&'h\x9d\xa0r:Q~\xcaa\xceK!2\xd1E\xfb\x95\xa1\x82\xf4w\x8a\xe9\xfa\xa4\xbf3\\\x11eU\x86\u0555\xc0D\x9e\u0672\xd8\"`\xc9b\xd3\b\xb8 0\x11]\xaf\xc1}#?\xde\xd1\x1cn[7}\xfaM\xbd\x15M[\x8e\x0e\xa7\xdd\xc7?\xeb\xbev\x86\xef\xc0S\xe7@\xb3p\xf3L\u007f`\u05b7\x96\xf0c\xe1\x05\xf7\xach\\;\xb7Z\xad\u0455\u0339\xb1g\xf0\x91uSI\x9b\xb7nQ\u074d+\xc7\x1f\x18\xbfP\x98\\\xdeP\xd3\xdf\x12\xca\xe0\xed\xad\x14\x13\xecW\xc6o\xed\t\xeb\x11\x03\x18\x126g\xd2`p\x1e\xf7C\u02bf\x81\x82\x82\t\xaf\xf9\xfd\xa1#!\xe0\x17;\x87\xf2\x03h\xc0\xc3\xe95\x03\x16\v\xab(\xf4\x87)\xc6|\x13a\xfe\xa0\xef\xe5eW\x80@\x15M\x052y\x14lgt,q\xad9\xbc\xa5\xa5\ue1a37,:\xd8\x11\ue63f\xb4\xee\x89\v\x8f\xb4/x\xe6\xab\xc7\xd6\xfedNG|\x0f\x1f\xee\xda\xff\xa7\xd1{\xde\xde\xd7\x11tq%\x96\xfe\xaa\x8cu\xaa\x13\xdeHDW\xd4k\xc5+J\xa4\x12\xf0-\xd6\r\x15G\x06\x10\xca\xcf\x190q\xf9\x03\xa2e\xc2\x0e\x13\xaeQ(}\xc6n\x99\xae\x04KU~&XHp\x12\xaa\xac\xa6\xd61\xc0\u007fTo\xb8\xe1\xd6Y\x8f\xfc\xf5\xa9\x9e\x811\xd0>7\xfc\xab\x85\xc9\xfcy\v\xfbJo>\xb1\xad\xb9\xfa\xc6Wo+\x9e\xd9X\x9d\x93>K\xb8q\u065ck\u046c\xfa18\x0e\x1f\x02\xfb\x8fW\x15Oy\xcc\xe4u\x18Xp\xdd\xfa\x87\x87{x\x95\x96\x87\x97\xb2v\xe5\xce*\xbelH\x04\xd5\u040b\x96\xebO\xe9\xe1\xa4\x1e\xfczPq\xbd\xfc\xa0\x8e\f\x18\x99\x8bU\x1a\x81\xf0\x99\xca$+|q6\xab\xfb\xd8.c$:\x1c\x96\xe9\xbb\u031d=>>t\xfc8>p\x1c?;\xdeC9\xd2\xfdx\xa5\xc2C \x84\a\x95{-H\x14h\xf5\x11=\u07a2\u007fH\xff\x9c\xfek=\u05ed\x87\x88\xbeN?KO|z\xc0*\xad\xa6\x97\xc7?'@\x1d\xfbEB\xd2KI\x052\xa89\x81\x10\r\x93\xe1t\x8c\xfe\x00\x95\"\xd2w:\xf6\xe9\xe9\xd8@\x1f\xc3\x12\n\x9dRm\xa20\xcd&\x9a\x1cxp\xfc\xe3C\x87\xb0\xf9\u0421\xa1\"n\u007f\xd1\xd0P\xd1\xd7+\x8b\x98\xbf.%\xd3[`\x93\u00a5F\x13\xb9\xe7l\x90\xb2m\xb0\xe1\xa8\r\x8c\xbd:B\x90N\xd2aQ\xa7'\xe2\x00bt9\xbb\v\x9b\xeaS\xa8A2\x89\u0560\xba\u04aa\xe5\x91\xdbs\xf3:JB\xb3\x1a\n~X\xb7\xea\xfe\xf4\x16\xbd\xf6\xa0Zk\x89-\x9cFY\xb4\xfeU\a\x96\x97_\xce\x19\xee1%g\a\x13%X7\xa4\x03\x1d\xd2h%\xad\x16\xd8x\x18\x8b\xf4\r\x19\x8e\x1a \xca(\u02cc\xe5\xf5X\xd2JI\x15\xeb\x10:z\x80U\xb9&\x16[\xfd\u0135\xd7>\xb5\xb6\x02\xbf\xf3L\xfa\xbf\u03ac\xa5\xfd\xcb\xf1\xec\xb3`\xfb\u025a5?M\xff\xf7s\xa3o?\xd8\xd5\xf5\xe0\u06e3w\xfe\u906e\xae\a\xfe\x84.\xf73\x99\xda\xd5@#hF\xa2\u0636\xb8\x10\xd5 6A\xbb\xc2\xfd\xba\x1b\x12J\x90\bF\xb1W5\x98cL\x95\t\t\x01\v\x82\xe8J\xa9\x89H-\x9aa2&\xeav\x06ed\xa8\xc8\b0\u05f3\xd1\xf9e\\\xc1\xc9\u0577\xbc\xbe\u007f\xdfqX}\u06cfn\xa9\x1f\xef\xd8\xdew\xd7\xe2\xd2'\x0e\x1f\xe44\x8b\x9f\xde>{\x9c\x92\u0235\xeb\x0e\xa6W\xf8[7v\xdd;\x9a\xb1gz\x99bO\x0f*G5\x89\xbcBjO\xf9\x94\f'e\xd8 CT\x1e\x90\xb1w\xb1u(V2\xe0\xe2\x82\x03\xbc\u0462F\u0478\xfc\xcf6\xa50';\x1f\xfb?0n\xf9\xc0\xbd}\x91\xd1\u079bV|_6\x15\x99\xff\u007ff\xde\xf1\xef/\u007f\xbb\xa0\xff\xbe\xfa{g\x9e\u0646\xf1\xff\xd4\xde\a\xa9\xbd\x8d(\x17\u075a\xe8Q\x1b]F\xfc\xa5\x11\x8c*\xad1i\u0529u \xea\xc0\xbeX%:E,\x8aj\x03|`\xf8\u0480\r\xec\xaaA/\xe9\xbdq\xef}\xde\xefzOz\xcfyy\xbf\x17$\xe8\u0143\x1e\x1d\x91R\b\x81\x8an\xb9)B\f\xc0\xaaT\x16\x01\x9e7_F\x80\xbf\xa9\x89Q\x18\x1b\x8b\xb2s\xac\xc9FX\xd1V\xdc\xe4\xb7gX\xef \x84\xafp\u01b4\xdf\xc2 h\xd2\xe5]+\xab\xe1\u07b7\xd3\xdf{\xef\x89\xde[\xbaB\x8c\x88;\x88\x97\x8c?\xc1\x8f\xfd\xe6\xcd\x05\xb7\xf65Z\xc77\xe2%\x8f\x06\xa7\xaf\x98\x9e\x1cLx\x94z\xbb\x92\xf2\xa9?\xa7=Y\xa6\x18%\xcc\bTS/ZQy\xb2\xf2R%NUB\xbc\x12\xa6\xf4\xaa\xddC\x15\xa6)|x \xdf\xcf\x19Rj\x96\f\xf2y\xfaCK+\xb0\u039c\xf1\x9e\xccP\xddeB\x9bP`\xc7d\vg\b\xb0,\xaa\vfy//!?\x9f>rl\xd3\xf0\u99bc\x05\xa9\xa1\xd8\xc1\a=3o\xee[\xb4c~Q\xe2\xba\xef-\xdd\xfcj[K\u04d3\vo\xbe\xcd;cS\xf7\xe2\xd1%Q\xb8}\u90eb\xab\x83y/H>\xa7\xf1\xc6\rU\x9d-\xf1Pp\xde\xcaow/\xbcs V\x12|\xd8\x13\u0658\xaa\x9d\xd7R\x17\xc8oO\u0752\x99\xcb\xe1\xcc\xd4o\"\xeaO\u010cjxC\rs\u052f\xab\xb1\xa4\xf6\xab\xcb\xd4\xe4\x88\xf0\x89\x80\xbf\u0370\xba\u060b\x13\xe4]\x82\x8d\x04T\x84,\xc0+\xf0fL\xf0\x04\xef\x83E2\xc0eqO,\xc3\x18\xd3\u0111\x18\xab\x9dm\xa3\xac\x99\xd3&\x1a\xc0\x1b\u007f\x98\xee'\xe9\xf4\x00o~\"\x8bu\x8eQ\xac\xf3\x0e\u007f\f9X\xef\xb4\xf7\x82R\xfe\x86]G\\Xr\x81\xa1W;\xe84\r\b\x16\x1d\x1b\x01\xc42Yp9\tL\x13\x04\"\xeb\x9c\xf6\f\xa8\xe1\xdei\xde\xf9\xf3;F~\xb2s\xda\x0f\xbf\u007fd\xd1\xc8\xdcB\xe0\x8f]l\xbf\xf6'\xbb\xe6\u03be\xf7\xb5\x9b\xc9\xe1\x8b\xc9#\xa7\xaa\x96\xdd\xd1E\x8e!P\xc6^w)=tmB\"X\xad\xe6P\n6\xc0Q\xb8\x00\x1c0\xed\xec\x14\xaf\x83\x04`\x88\x1a\xb6\x19N\x1a\x88!!\xa8\x93<\x1bc\xbd\xc4\xf1\x1cQ\x1f\xbb\xf4\xee\x8b\x1aSR\xcdZ\xaa\x86^RcbF@\x94\x86*Ghef\xa3\xadHv\xb4\x95%%\xa8\xe02\x04\xe9F\xf3\xb7\x11\xaa\xc9O\u03e4\x1d?L\xbb~\na\xcf\x14\x93\xb1\u0517\x99,\xbb\xb8t\xf13mm\xcf,E(\xe3'!\xadp\xf9\xe7\xc6$\x15\x1dWHF\xda\xe1^\xa6\aF\x11X\xaf3\xd3C@\xec\n\xb2{\xd8\u0393\xcbNG\xe9Qn\xc8*\x02'N\x13_\x12\x89\u0205\xac\xa1\xfc\u0434Pw\x88\x17\xed\xa1\x90]$^=2\xc0\x06:3{\x8aj\xa7\fQ\xa8C\r\x92\xc1P<\\\xbc\xad\x18\xfb\x8b\u02ca\xb1\xb1\x18T>/\xd3\xd1\xe2\xb5\xfb\xa9\xbev\x89\xeaj\xd7#/\x11C\xa1\xac\rB\xac-\xd1\xd3!\xc9cF\x8a\xf6&j\x04\xb6\u03cc8\xfb.\x8f9\xcd\x0ej\aJ\fPt\xac4\xd8+o\xcc4\x16/qP^\xcdBmDhu+\b\v\xa2\x01D\x12\xbc|\x85\x14\xfd\xf4=\xa3\xc7e\x118\x9dd\xd1\xfe\xec\xb5\xf4\xee\x13iC\x8eV\xa7\xd5j5.\xc3_O\xa4o\xf9\xe99\x9d\xd5d\xe0y\xa3\u0561\xa7\x96|\xbaf\u00ea\xfe\x82\x82\xdekV\x94\x93ki\x03~V^\x1b\xad\xae\x90\xab\xa3\x1b\xaa..\xa1\xd7o/\xbdf\xd9\xe2\x82\u0432\xb5\xc3\xe5\u0658H)\x98r{\u00a3\xd6H\x1a\r\xaa\xa6(BU\xc3\x03\x8f1\xbd\x0e\x1b\xd0\b:\x85\x88B{Z\xa9\xb5\x18\xd2\xd2\x1b\xf5\x8cS\u0726\xe7T\xa2@-\xf1\xa2 d\x86\xe2\x12W\x88!\xac\x02\xac\xe2\xd4\xf4T\x16\xef*\x83mj\x97X\xec\x1b\xa3q\x16\x1f\x14u\xd1\xcf\xce\f\xabO\x014\xfd\x91\xe9\x0fp\xa9\xb7\u048fR]\u963b\xf7\f\xb4C\u01eb\xe9\xc5x\xcb\xf8N|\x11\x1f\x1f\u007f\x13G\xc7\u06d9\xe8\x19\xf9\xab\xa9\xfc*\xb4)\xe1\xfaD\x03\x9a\x84Z\x97T='\xc2~\x11\x12\"\xb8E\xa01#2\u0462\xa2\xc8\xc3\b\x869\x18\xdc\x18\xb0\x841\xe2z7\xf3\xb7\xf3\x0f\xf0dN\x96\xd7\x13\xf9*\x04\b8\xb3\x98\x89jsm\x1fd\xe7\xeb\xa8\xe8t/3\xd93\xf4\x1e\x1b\xae2Ii\xf5\x05\x19\xbb\xa1\xfbg\xe9\xe6\x1f\xa6\x9b\u007f\x89\xdf\xc2\u007f\xbe\xb8c\xfc5\x1c%\xb7#\x94\xc5\xed\x84\u0173\x9av@\xbf\x9a\xb6\xdd\x15t\x94\x15\xd7\xce\xd1~W\u02e9T\x1c\aC\x1a\x91\x1b\xe0\tVeFz\xb5\xf4\a\xe8\x00/J\x1b2\xdd\u0162\n0\xcfLy\x04H\xfab7~m|6\xd91>\x15\xbf\xbd\x9b\xdb\xf6\xd4\uebf7g\xee\xf3D\xfa\x04\xaeU\xea[A\xc2\xc1\xa1\xbf\t\x9f\"\x90hz\x9f\x02\x0e\xf8\xcf\xf1\x17\xc2\xe7\xf0\xe5\xe5\xb9\xe6\x8f\x18-\xcfFe\x14/\xe1\xda\xf4\x1a\xd8{\xee\\\xfa\x84\xf0\xd5\u07af\xca\xd9w9\x10\xc2\x1f(\xf3\u0781\x1f`\x00\txDX\x1d 83\xf1\x1d\x05\x06\x96\xe5\x1a\x86h-\x10\x84\x9fc\xff\v\xe3\xefN\xcc|\x03\x92\xd3'\xe0\xe7\x8a,\xf9\t+A\u007f\x83OS\xc2\x06\x01\vj\xf4\xb9\xf8%\xf9\x9c\xfb\"\x8b\x9c~\x97\x91\xc4!\x9b\x82\x95T\x1a\xf9\xdc9\u0617^}\x98\u007f}\xef\x97\x02\xfb\x9e\"\x1c\xe2\\\xfci$ \xf3\x18!\xac?\n\x88\xcd?S?\xb0\x1b\xcb,`\x8a\xe0\x97Cp\xf2{\xe9#\xe9\xc7q\x88\xf1\x9d\xf8\xdcx\x00\xc1\xa5\x8b\xe9\x13\xa4\xe3\x12\x03Bf*\x13\x0fp\x1c\xd3\x11I\xf6o\x999I\xc7\xc5\u00c4\xae<\xb9[\xb1\x1f\x8cr\u007f$f!\x80\xf4\u021e\xd0 A5bD\x03\x8c\xb2\x8a\xf6\xe5\xfc\n\xa2\xbff3\x96\x94#\xaa\x94ib\x12\xf3\x8d\xc1\xb9\xb3\xe3\xd2\xdbR\xa4\xb4\xcc\xc6\xfd1w\xde\xc2.\xb7-\xaf\xab\xab\u0753\xc1\b\xfd\xb4\u007f>\xcc\xf5\xa3 \x8a\xa1n\u02b5CQkp~\x85\xb1b\xb8\x02\veI]\u03b1Ko$\xbczS2G\xa2\U0005a4e3\xeb\x91]\xf6N\u03d4\xb9\x92\xe4\x91\xf2;\xb1hG6\x14g\xfd\x94\x8euikQ\xc2!\x12\x91\xce\xf7+\x88\x97\x01\xde+\xccbU\x1c\xae\xe6_M!\xda\x1e\x1a@dk\x8d\xec\xc4\x15R\x05\x9a;R\xf1\xe9\xd7\xcd/{\xff\xc3c\x9e\uab8ay\xf75'\xda\xc6\x06\x87\xf6.-KG\x1bV\xb6G\xee\xeb\xbdy\xa6\u007f\xe9\xfe\x92\xa6)\xd6p\u05d6\xee'\x8e\xaa\xc4\xe9-\xbd\xd5\u03b2\xbc\xd1\u009a\xa2Ew.\x1b\x97\xb6\x15\u033e~\xce5\"\xe7\xaf\ud497\xf4d\xf4\xa4OY\xa7J\x11c-\x03\x8d\u0675\x10\xc1\xca\xeao\x80b\x03\xd5X\xc6w}\xfe\x83\x1f\xfd\xa8d\xfe\xb7:\xea\xae\tG}3\v\v\xa7\x16X>'\xa7/\xc6\xc9\xe9Y\xd3Rk\xee\xe9\x0e:\f\xf7hM\x96\xb2yM+3k Ci+\xb9H}\x10\xa7\x9d\xa7\x1f\xfdK\u00a5\x8f\xf1\xf3Z\xab\xcd\xd1T\xf5\x86\xea\x91jR\x1d\xad\x8e\x86\x93\x9eE\xad<\xeb\xe9\xb3iO\xe7y\xd0x`\xdc\x03G=p\x87\a\xfc\x9e2O\xc2C<\x9e\x94/\x05'S\xe7R\xf8`\n\x12\xe1\x04\xa5\x18\u0098\x8f\xe9\xb9\xfa\x9e\xb9\x1aM\u07929\xf5\xc5\x1dF\a\x88\x0eG\xbd4}N\x9e\x1b\x90\x91rKTS\xe6\xc8\u04f5\x922OD\xf1\x0f\x05\u0267\xfb\x18\xfca\u02b2\xc6\xcfV\xbd\x9cVV\xbd\xb0\xe9\x126b\xa0&\xb0\x89W\x96\xbed\xd6H\u05b1\xc2\xf0\xcdys\xa0\xe5\xae\xfa\xca\xe0\x01\xb2\xa5A\x19\xeeP\x83Y\x94\x1cT\xd6g\b\xe4\xe2Os\v\xa2\x03w\xf7\u064b\r\xa6\x80\xdb\xe4,\xaa\xf1\x1d\xed\x1b\xe9\xcao\xba\xed\xd7w\xad9\xb8\xba2\u073c :\xa5*1=BW3\u0196}gih\x8e;\x9d\u0229[\x9a<\xfe\x8a\xb3\xba\xb7\xe9h\xb0=^\xb4d\xed5\x83+V\r^\xb3\x9ak\xdb\xe8\x0e\xae\x9b\u07be\xbd\xbf\x12\x88\xc6\xe5/t\xba\x03f!\u06b9\xaea\xe1\xddK+\xa6tnl\xad_\xdc\x92r3\xcb?\x11\x86\x96\u0277n.\x8b;r\xaa\x82\xee\u04a0e,/\xb9\xcerE\x8a\xb4\u0560\u0763\xd1\x1a\xc3M2\xf7\xd9\xd7\xce\xd9[\x16D\u0141\xc9be\xecO.(k6\xfb\xe9\xc0\x8e\xe30!\xc24\x1e\x94\xacp\xb0\xac\x90x^2JQ\t\x8bzu\xab\xa6\u06e8EH!Ti\x1e\x88\n\x15'\x12Ac#4\u8cc4b\xa6\xabe\x11\xae\xb2\x8a\xa8\x96\x01$\xa8f\xa0v\x82R$\xd0s;\x84\xdeJ\x0f\u00e17\xd3G\u05fd\xf4\x92\x84\xab\x9f\x85U\xe9\xd0\xf8n\xf8bn\xbaW\xb0\x8eW\xa5?\xca\xc8\a\x83T>\x82r\x12\x06\x89\xf7\xf3\x18\xb5B7\x87\x91\xe2\x13v\xab\xac;\x98\a\x04\xeb\x84N\xc2\xed4\xf7\x8b\xd1\xf2D<\xa8i}E\v\xfb\xb4Oi\xf1\xa8\x16Vh7k\xb1VkG\xad\xc5\xf3K/\x94\xc2\xeb\xa5\xe0/\xed,\xc5\xc6RP\xb9l\xad\xf6\xee\x92`N\x0eg\xec,\xf4I\x0e\xa3=\x13u1\xaa\x99\xf2\x00BF\xb1,#\xc3\x18#\x06\x8ac\xdf\b\xc3\xc9\x01\xe9\xc8\u0123c\",\xf97\aW\xcd\x1cj\xf2\xfe\xe0\x9aU\xb3W\xc6\xddc{r4\xce\xe69\x8bJo\xfcn\x81*g\xe6\x82T\xec\xc8\xf3,L\xa3\x8bo_8\xfe\u0615\x80\xe5\xda\xf6\xb0p]\xd8\x1f\x9dVb\xcf\x06m6o\xa8\x8eNT\x96\xc8E\xad\xce\xf99RN*g$\x87(i\xe32r\x9dV\ua8ab\xd2\xe6\xff\x905\x8e\xab\x93\x86\x8959i&\xcb\xc0\xee\x9e\xed\xcf%\xf4\xde\x16\u05a1\x13\x9e\x9c$Z\x10H\x04\xde\b\xbc\x1b \xc6\x00\b\u05a4\xa6\xc7\xef\xe94J\x8eN\xfe\nd\xe8\x9f\xc4cM\xee\xcd\xfc\xa4j\u0155\xb4l}ax\xc5\xe1m\xad-\xdfzQ\u064f\xa3\xd1\x03\ang\x1b\x0e\x8f\x9e\xdd\xdd\u07be\xfb\xec\xe8\x1do\xed\x9e5k\xf7[w\xbc\xf9\xd6[o\xbe\xf9\xfa\xebY\f\x96\xb6rq\x05\xbf\x94\xa1\xaa\x84\xb74\xe9^\xc0\x10C\x81$\xe8Z\xf5\xdd\xe5\xfeN\x93]2\x18u\xeeH'\x8f\xec\n\x00c^\xcd\x14\x93\xac]x\x86\xbc\xae\x10\xa8\x8eI+\xc5\b5\x978\x19\x82e\xa0\x17\xc3\t\xd4^\n\xf4\xaa\u03e2\xb2\xed\x93A\x835'\x92\x05\n\xe9\x88P\xb5'\xd8P\u2780\x10\xe4\xed\xd2\xfe\xbb\a\x8a\xae\x800jW\xaa\x03\xa6:H\x19\x1d\"~>\u051a\xaf\x00\x1fC\xd2\xdeS\x9e\xef\xce3\xfa\xb5\x9dn\xa9\x18Qm\xb2\u04c7\x93\x81\x0f\r\u016b\xe0\x8d\xe3\x1b \xa8Z\xbe\xcc_\x1b\b\xae\x9c,\xe8\xd0\x15\x00\xd4^\xefP\xb9\xef\x1fc\x95@\u01f0\xd17\xe1\xcd\x03\x13\xf2\xbbK\x1a\x82{\xbe\xfc\x05\x9c\xb5Lu\xfb\xf3\x188\xba\\OTT\a;jJh_ ?\"\x98\xa1\x01\xac\u032e\xb9Em\x92\x10g\x99\xb3\xd39\xe2$&}\xab\xa1\xdba4\xeamf\x91a\xe2\xd3Y]b\u06493\x1a*Y\x1009V\xf1\xa8'\x99\xe3\u032d\u02c9\xaf\x9cU4\xb6\u01eer\u0576.\xe4\xfay\xfei^\x94\avv\x8d\x1f\xe5\xda~\x1e\xe9l\b\xb1uu\x14\x87\xb1\x98\xa8D\xc9DI\xc8\u04ba\x8bVz\x8c\x16T\u01eb\a\xaa\xbf[M\xa4j(nU\u007f\xd7s\u0103==U\x05E\x9d\x96b>OR\x1b2Q\x1b\x8b\xd3jv>F%\xa2\xab\xc73\x94\xb0|\x15\x8b\u05c8\xff\x9f4^|\xea\xba\x03\xa9u\x0f\xd7\xf9\u06bb\x17\x157-\xae\u0371V.I&7uF\xaa\a\xef\xeeY\xfa\xbdd\xbci\xb4uh\x99\xa3\xa6\u007fFrc\xe7\x14(\u9f31\xab0\x98\xf7\x14#\xf2\xecEu\xf9\xbeXy\xcc\xe7\xabo[\xda2c][\xc1\x94\xbc\xfb=\x91\x96\xc6`Ei\xd4\u3b5f\x95b\xb6\x0e\\\xfa\x10\xdf\xc7\xcf@\x1e\xd4\xf9\xbcK\xa9\xd8Q\x95\x96\xe2\x18_\xdc7\u01c7\x1d\xeeV\xab\xcf\x1c5c3\x92(X\x96\x8eJ\xa7\xa47$A\x90r\xccs\xecV\x87\x11uj\x95\uc533\x80\xecL\x9f\x9c\xb5\xbd\x9c\x8d#[\x16ESP\x16\a\xd9\xc6&0\xadv\xf8\xca\\2%\xa8\xd6\x17\x96U\xb8\x1aW\xcf.~\u884eU`M\u007f\x18\xdf\xce\t*r\xa7\xa0S\xf3\xfe\x8e\x9d\xcb\xf1\u05ae\x8e\xbf\\\x1c\x1d\u07f1tYf\\\xce\u0580sm(\x87\xd5+p\xb4\xe6\xcc\u03d5rS\xb9#\xb9\x846\xc1n\xb7So4O\x1e\xf1\xc9\x13Q=y\x94w\x85\xf4cG\xe4zw\xa6P-\xbesItl\xf5\xb0R\xbc\xee\x8f\u010b\xac\xa5\xcb\xf6\xaf\u00bf\x1eo\xa0\xd5k\xf9\x9e\x14\x9e\xfa\xf5\xd8e\x9e\x84\x9c\xa52\x98\u043aW\x90\x8961\xa3\u01904!\x15}Gj5\x18%\xf6L\x95\u0656d\xfbD.\rV\x89\xbe,'-\xaf[>\xb1\x90N\v\x18-Q\xcb\x1c\v\x111(\xe4\x1f\xb4\xaaAm\x84,:\xa8e\xe4\xce\xe9\u02e4W\xe44\xa3\xfe2\fW Cd\xc9\x19\x8e\v6\xa7GO\xbc\xa6\xf5z]\x9c\xc8;\xbd^\xedk'\u04a3\\\xdb\xf8#\x81\x95kS.Wj\xed\xca\x00\xbe\x86\x8a\xacp\x80\xfc\x9f\xa9\xbcQ\xf4\xe3WP\x94\u02ab\xa3\x92F\x91JM\xe5\r\xfb\x15\x12\x90\x1e\xfa}\xec\x84O-1=$#;\xad\xa6'\x8c\xce\xee0\x84)S\x97\xb0\xd16\xbe\xd8\tN?\u0747\xd5N\xa7:LL%\xa5Y]\xd9>a\xa1\xba\x96J\xa5\xa5\xe5\xfe\xf2\xb2rl,\a\xd1lb*\xdaM%>5U\xd2d\f\xbb\x04\u05d0\xeb\x06\x17q!\x89\xaa\xab\x10VqF\\e\x98\xbe\xac\xce\x13<_\x84\u03a9\xfe\x13\xcf\x17 \xa5\x84r{\xc1\xc9\xe4^\xc6&\x93\xadC.<\xcd\xe9tz\xc1`\x14\fz\xadK{\xe8\xad\xf4\xfb'wh\xacf\x03'\xf0&\x9b]\xf3\xe2O\x0e\xa9\x1dv3'\x10\xbd\u0666\x1d=\x9e\xfe\x0f\xbc\xd2\\\x12\xabpMm\x8cO\x8d\xad\x0e\x8d?Lmy\xacd\u054a\u015e\x9c\x05K\a\x02x\xcd\xf8\u07bc%\x03\v\u99d5\xeb\xa28\xa9\x04\x03\xa0 B\xe4mj[-z/\xf1\xbdQ5\xdcF@\xe0\xe0\x1f\x1c\xbc\xc7A\x15\a\x1c\xff\x9f\x02\b\xe4}\x04420|\x81\xe1\xbf0\xd4b\xc0\xb0\x86\xdf\xc2\xe3\x05L\xf1\x17Y\xfe4\xf6\xefQ\xc6\xccX\x95%\uf912a\xbd\xcaX\x15\xddg\n\xba\x8d\xb1J\xec\xf9\n\xf8\xccY\xd2T8{\xc7@\u054e\xad[wT\r\xec\x98]\xd8T\xe2\u073ci\xd3f\xa9\xac!\xa8\x87}\x10h]\xdf\x01\x1d+z\x1e\xeaY\x01\xb3;\u05b7\x06`/\xe8\x83\re\xe9\x97Vm\xb1\xea\xac7\xafF\b\xe0\x83\xb4\x15oS\xf0yI\u0087x(\xe3\x13\xfc\x06~\x84\xe7\xf0\xb3\x8c\x0eH\x90\x11r\x8a\xf0\"\xc1n\x84X\x14\xb3\xb9<\x16\x92 \xb3g\xb0\xf6\xed\x13\xac_\xa0,W\x8a\xf7S\u074b\x98\xee\xfa\xfc\xfc\u007f\x88\xe8\u04dc\xbf[\xc9.\x0fx\xb8\x9c\xcf?q]r\xe1?\xba\xc0\xe52\xe4\u007f\x1e\xfcR\xff\xb9!C\x9e\x9a.\xeb.\xcb\u007f\xc9\xean\xa1\x10\xa7\xb2\x14\xa8\xca\xcabk\xa62\x05n6\u0698\xd9\xd8I\xacl$\x95\u765e\x13\xfa\a\x9aR\x8dW,\x00u\xabo\xa6\xdamY\x05\xed\x8a\x1d\xf6*vH\xbfX\x91,\xb1RK\xa4_P,\xb1O\xb1\x04[\xbf\x8a\xdb8Lz\x95gx\xf4\x1e\xf6\xfc\x8eD3\xd8\xf1}\x8dO\x99L\x92,I\x9f\x8f\xff~.\x9b+\x88\xeb\xe7\xe8\x87\xf5\xf7\xe9\x05=\xa2\xe2~\xfa\xb3h$v\x1e\xb2\xabU\x81\xb1gL86\xb0c\xe8!C\xf1\b\xac\xedas\xa8\xba\xa4\u021e[_W\xe3\x1a\xdc\xe3\x89U\xb7DC\xd5\xd1B\xe5\x84\xf3\x9a\xbd\xec\x04\xbeK\xb2\xebyK\xa0\xd8\xf5\xd8Z^\xef\xb2~\xe3Sfmw\xfa.\xd8\xcd\xf5+\u03e97\xbd\x82P\xf69\xf52\xd7A:\xf9v\xca\xc5a\ue001d\xa6\x83\x8cl:\b\xd1\xe7\xd4\x11\x9b \x101\xa2>\xbb\xeaqu\x9a\xaaA\xcbU@\xfe,}Z\xfd\x13K\x90\xae\\-\rZ\xad\xc1\xd2\x1c6\"\xc5O|\xfd>\x9f\x9cX\x98zy\xd13\xa0\x13\x14\x9b\x1d\xa7s\xab!\u051b\b\x99\xc9\f#\xc7iB\xb6p\"\f\xde$\u0494i\x12\x9a74\x9c\xa0qo2\x9a\x8d\x81M<\u6552\xa33\x9a\x93F\xde\xc8\x13I$.\x14g\x10-\x9ay\u0799m\x99\xe0\x92\u03b0Ua2C\x0e\xf9\x02{\xae\xf9\xaa\u01d9'\u04d4\xe4\x86\xf5\xed\xa3\v\xee\\VQ\xb9\xf4\xae\x9e\xd1\xe4\x1d\xa5\x95\x94\xa8\xacse\x89\xca\xdfz\xf1\xcf~\xa3\x9f\xb5\xf3\xb5\xd1{~y\xc7,\xfd\xa1'H\xc0\xa1\xf0\x95\xbf\xf8\xed\xbf\xfe8\xe4\xfc\x1e\xd3c\x1aB\\\x90\xff9*D\xd7'Lz\xd3p\xd0h\xf4\x19\xb1\xe8\xa3\xef.\xe2`\xe5\x92ve\xba\xffY\xa2LP'\x1d\x8e)\xd2\x14\b\xb8\x12ZC\xd2\xe5*\x92\x02\xd7\xeb\xa3y\xdb\xf2\xee\xcb;\x92w2\xef\\\u07a5<1/\x0f\u066fs9\xc5\u024fXP]L\xc0J\x89RP\"\xb2\xa2\xb5B\xa4]\x85\x91)BSf\xc0\xe9\x9eFy\x03\x04+e\x96\xf7\xf8\xc0\xea\xc3\xcd\xcd5\xf7\xcc*\x9b[\x1f\x80\x1b\xd3w8\u00b2\x1b\u007fx1P<\xb3\xd2{\xe6L\u076a\xef\xf0?/\t\xee\xf2D\xdcu\xfd\xcd\xe9?\x8e\xbe\u0578(\x11\x91\x9e:\xa0-\x9a\xb6\xb4\xe5\xec(L[0:\x10C\x18m\x01\x0f\xf9\x90\xbb\x8b\xc6z5\xba-\x114\xdcg\a\xbb\xbd\xf49\x9bQ\xe7\x14\xbc\x01\xa2B\x1b\xcc`6\xd7J\xb5\xc0\xf9\xf3\x9f\x1dA\x80\x98\xcf\xca\x05M\x12\xa1\x1a\u01c8\x0f|:\xc1\xe95\n\x9c\xba\xe80r\x83[\xcf\u02c7_W\u007f\xa2\u01bb\xd4\a\xd5G\xd5\u0127\x8e\xab\x87\xd5D\x8d\x94\aI\xce(S\xfc\xec\x91\xfe3}\x19\xfd\xd99f\x82>z\xf6\xd3S\u047el\xae\x87\xab\x1d\x99\xb5\x91\xd5\x0e\x85=\x13D\x87\x186\x00\xeb\x1fb\x98\xb2e\xd5W-\x8e8\x1e\xf4m_\xb6-\xba\xb6\xbe~M\xe9\xf6kn\xf5\x85\x82\x81m\xa9\xed\xa5k\xe8\xf8\xa7d[j\x9b/xg\xa8iAL^\xd4\\P\u043cH\x8e-h\n\xe1\xb7\xea\xd6D\xb7/\xdb\xee\xcf\xcf\xf7o\xa7\xbf\xba\xee\xf2\xaf\xe6\xfb\xe9\xaedm=\xfd\xad\x82\x82+\u007f\x85&\xb8T\xae\x9d\xd64;\u069bX\\\xe6\xa4\xf8Qg\u007f\xd6\x066\x9b\x8eS\xc1s\x18|\x180\u078f\x00\x89D\xdb\xfb\xa0\x15\xac\x92Q\aw\xea\x80-\x1fK\xe8\x88H\xe1^\xca(\x1a\x05s\xcaB\x90e\x9b\xf1>#.\xb3\xc0\x1b\f\x88\xfa,\xd8h1Z@k\xb6eg\xe9XL\xd0f\x9f\xfd\xef\x12L\xec\r\x94\xe5\xf82{\xd2?V\xdb\u01e6\xe6\xe5\xdaZf?\x16A\x99\x99;\x06\xeb\xd9?\xe5)4\xf6\x8f\x9e\xc12\xf4\x9eLo\xfb$\xfd\x16\x94\xa4\xdfz!\xb3\xfb\xaf\xf4\xceSlV\x8f\x0e\xc8\x1f\x1dM\u007f\x05\x02\xdd\x11\xc4^xR\x0f\x10Qm\"\x84\xd4P\xa6N\xa87\xa8G\xd4\x1c\x16\x9e\xa5g%1!\x8e\x88\xa7D^\x14\xd9\x1a)!\xd3\v\x98\u0110\x89\u324e`\xcav\x05\xd6\x17.~\x96v]\xfc\x1b\xab]7]\xfa;\xe9\x17|h:\xeaE7%f\xf1=\xaa\xae\x19\x81\x82\xf6\x19\xf53\x8a\x8a\xa4K\x018\x188\x1a\xc0\x81%\xa7\x96\xc0\xc9%0c\x06r\xccP\xa9\x94\t\xc0*\x00\x8fn\xb3\x1d'\xb9#X\x91\u021a%\xd4\x1f\xd9\x04;\u007f \xa7O\x91MJ+\u0763,\x9e\xb3W*\u0585C\r\r\xa1p\x1d\xdcW\x176\x05\x9c\xfa\x86`\xb8\x8e\xdb]SY\x15\x8bE\xa3\xb1\x9a\xca\xa25\xea\x94mW=\xbay\xe3\x97\xf6\xb7\xfb\u0747\x9d\x05\xa9\x97\xe7\t\xb9a},\xb6\xfe\x06|\x9c\x91B_\xe9^Y\a\xd23m\xdck\xc0\x03\xcaA\x8f$\x94C\xfe\x1cp\xeb\u074c[\xe0\x05\xaf\xd0+\x1c\x16N\b\\\xd19\xad\xcd6\xa2\x85\u068a\xf2\x8fx\xde\tC\x1f\x01\u0144\xe9#\xe7\x87 \x8e'\xf8\xf4T\xbd\xcco\xd3c\xdbL\x12[q\f[\x8e\xbc\xc1\u041c\x80l0\x13\x8f%;\x8cr V\x94\x83\xb2\xf0'\x05\u0190P\x17\x88$\xaa\u0777\x8c]\xd6\\W\xb9\xaa\xb4R\xdc\xd3th\xdf\x1bbG\x891ZZ\xd8\x10q \xf7\x805\xe0\xc8w\x8aK\xc4M[9\u059b\xa8w[78\x8bF\xafJ5\xc0zd\xf4D\xdcb\xb9\xa5\xac\xb5\xac\n0`\x00\xecFw\xa0\u05c0\x02\xe4\x83\x11\xc9\xc0\xb0\xf9\xbf\xd0\xf4\xb1#,\xc3jX\x8dB\xab&w\"?\x0e3\xaby\x9e?\u039f\xe0\x91\xe2\x17\xc7\x11D\n\x80\xf2\x95\x1a\r\x87\x10\xcc\xe3T\x10\b\xa2 \xe7\xec\xd0\xd2)\x94ND\\\x8aH4\x1d\xa9\x99\xa2\xc1~\x1b2)a1}\x19\x80\xb1=\xbf\xfe\xf5\x9e\xd4[\xf0\u04f0\xe6\xca_\xfd\xea\xca\u051bL\t|\xb0'\xf5\xf9\xd4\xe7{\xe0}\xae\xd9\u00d9\xba\x05\xc8\r8l)\x8b\x98G!\xb6\x8d\xf0\x18\vob\xe1\x01\x16\x0e\xb1p\x11\v\xebXhd\xa1\x9a\x85,\xfb\x04\xf7\x14\x88g\xf1\xa9\xd2\xe4x\xd9Z\xb3\xcc]\x17\xfe\x86\xdc\x17\u007f\x06\xaf9\x06\x00\x98\x9e\x9e\xa9%`T\x00=\x00\x80\u036c\x1d\x15\xf0\x80\x06\xd0\x03^\x91\x0e}\xde:n=mE\xe3\xb6\xd36\xc6f\x85\x03\x16\x9dMg=c\u0459-\x16\x9dN\r\x1cg\x9c\xea3\xac\x85\x05N\b\x9c\x13\xce\xf7\x9dH9\xc6B'\xebd\xbd\x9d\x93\xa0\x1cN\x94\xc3\xf2\xbe\xc6I\xaf\xce\xfe\x06\x00V\x97\xd5\xe2T\xbd\xe1\xc2`\xde\xe9u\n\xce\xc3\xce1\xe7q'^vr\fg\a\x8e\xe2pN\x97\xd3\x15\x94^\xaf6-|=\xc8\x12k\x9bYw;\xc9P\x122\n\xb9Qe\xad?\x9a$\x84\xdf%w\xb1\xfa\xa3\xfa\x88\x1e|\xf5(\x17\u045f\x86\xf8\x8e5\f\xe9\x06l\x04r\xc4\xe2Zm\u0132\x06\x10\t\x1cb\x15\xfbwk\x92\xf9Ibu\xef\u0495]\xf0vWy\xbd\xb7=f+\xf5k4O\xbd\x9b|\xe0g\x0f?\xf8\x8f_\xfc\u01eb\x11\x81D\xe7\xc2\xc6k*\x17\u0547\xf3\xafX^\xdc]g0\xc0\x91\xd4C\xe8\xd0'S\x93\xff\xc5:\x84\xd3\u007fW\x98Y\x85\xe2\xa1\u007f\x9e\x9b\xc1*\xfe\xf1G6Oa\xbe\x99\xae\u06c3h\x88!\x1c\x01\x93\x1cW.\xf3<\xa6)9^\x02\u034fV\x02\t0\xc0\xf1\xa4\x9e\xf7\xf1\xcc9\xfe\xb7<\xb3\x9d\x87\x80'\u007f\"\x05\xcf\a\x9e\xe4d\xfa\x1a%\xcb\x11m\"\xeb\x95p\xa3\xe7\x11\xd3\xe6\x8f\xd7\xc1\xe8\xe0\xee\xd6\xd6\xddC\xd1\xe8\x10y\x1d\x8c\x1e\xf4Tw\x85\xc3]1\x8f'F^\xab=\xecX\xe6\xbfw\rVU\r\xeej\ruV{<\u055d\xa1pw\xcc\xeb\x8du\xcb\xed\xde\x04@\xbaV\a\x0f\x1a$\xbf\xde\x00y\x95\n\x17\xec\u02030\xbbfG\xfe\x13yYe;\xc8@\xc8$t\x1a{\x99W\xbe\x83\xb0\t\xb3Kx\xa4\x0e\xa1\xfbg\xcbx\xa4\xfe\x8e\u0245\x10T1\v\x99m\xd87\xf7\x00I\xb2\xa8\xa6\x80\xcd\xd7\xeb;\xecc|\x12\xf6H\xddS\x90\xe7\xe5\x84?\x1dI\xa4S\xb9\xb5\xe7\x8d\x1f\xba\xcf\xc3\x1f\xa6\x1f\xa9\xd3O;\x11J#'\u05d6\x19~\xc1y\x04?\x1e\xfa\x99m\x17O\u007fP\x9f\b\xf3m5\xe2pyO\xcdu\x03M\xeb:\x8a\xdd5\xbd\xe2\x9d\xf0ff\u138fZ\x06\xdb\x1b\v[\xa5hpme\xab?\xbe\xba>:4\xb8\xba\xf6\x01\x00\x81\x97\xa9g\xb6\xe0\xf6U\x82uR\x13\x02\xf8\xd9V\xe1\x99\x02\xc02\xa5\x88&\xa3cQ&J\x1a\x1a\n\xe9$\x87/\xa1C\x8e\x8f\xe8*K:\xcf:9\x95\xd3i\f\x06\u0397}h<\xcfk\xcff\xd7U\x98\xa2M'\r'\xf4D\x03~\xd3(\x17\xe1Q\xccqP2\v)\x86\x0f\xe6\x95T`z\xfa;W\xac\b/\xbdz\xa8\xeb`}\xfc\xda\xd8\xfa\x15\x1f\x1bY\xbf~\xcd2s@p5\xae\x13;\xdd\xcd\x1d\x8b\xcb:/\xef\n\xb0?\xe9\x19\xb5\xdbF{\x9a6t\x87\x1d\xde\xeb\n\x83K\x17,l\xdf\xd9+\xf9\x04\x8f\xae\xa4x\xc4V\xec\xe4\v\x9b\x96^\x9aW\xa4\x00\xdc'\xf8\xbc$&\u24bc\xa2wh^\x11\xa9\xfbc!\x14[x\x83U\x10JqZQ|I\u007f\xe0\x00\xfbG\xf7\xe2\xfe\xfeB\x8b\xab\u007f\xc5\xd2\x02@d\u0271\x1e#\xbb\x10\xb8A\xadTH\xa2\x92\x83\xf8>\uf6f9\u04db\xdd\xdd\x05\xcb\x88\xa6\xb7\x94\xe1\xec6r \x14\xa0\xcf\n\xb3\x99\xf3\x1bF\xb7\x0f\\\xd1^\xf0\xf4\x1d.M\u5b5b\x13\xa3\x01\xc80\xf0\xe9\xa7\xe1\xd1\xd9\r\xe5;\x96.\xab(\r\x86\x03\x83\xa5\xa9\tE\r\u025fI]`7)\xcc\xc0\x84\xdb\xe4g\xef\x01\x1c\xd9\b\xe9\xe3X\x05\xc7\xe5\xc3{\x80Eo\x81 _\x8f\x19\xc8\xc8\b8\x00\x04L>\xc1\xfaM\xd6!\x9d\xb5\x99\xf4\a\x83\"\xe3h\xf8\xd9M\xfb\xdf;\xd0<\x98\xbco[S\xeb\xbe/n`\xc4\xd4\x05\u0141\xbf\x1dE\xa2Q\xdc;q\xf3\x1dg\xf6G\x01\xad\t\xc3$\xe0m\x88\xc4\xe3D\u0269\xb7\u042a0\xec\xbf.\ts>]\x12\x86X\x81\u007fC\xcdf\xbe\x9e\xe3\xf9=\x902\u00fb\x01\x00\x0eP/y\xcd&\x93\xe5\xb0q\f\x87\x1a\x8c\x8a\xfck\x81K\xe14\xdel\x91\u053a\x84\xc5b\xd2\u0702\xb0Q\x13p\xba\x03\xf1\x16p\u007fi\xfd1\x83(\xebd\x962\x12\xef\xb8VTz\x10\xbc\xfb\x96c\xd6r\x9e\xaf\xd2w\xf79+\xe2\u016b\x0e\xd4\x13o 5\xb5n\xab\x02mE(Re\x0f8M\ua4fbU\u0392\x06\u04968\xb3\x10>/\xe7\xfeWK\xfe^\xfda=\xa3'+G\xa7c\xa6\xc0a4\x86\x18\x1f\xaaD\fb~\x98\xaf>\x0f~\x80\x17\xf8;q\u0676L\x91eB\x1f\xa7\xf1\xd9>\xe2&\xdc\x1f\xf1\xd4W\"\x19~\xc4\xe2F\xfeM\xf4\x93\xb9\xa9d\u0276\x8e\xf8hO\xa4d\U00076396\x8f\xf5\x94\xa5\x1a\x16\r\r.Z48\xb4\x88\u0776\xf4\x93+\x05a\xe5'\x97.\xbdfEE\u014ak\x96\xee;p`\xdf\xfe\u077bI{\x96\x81\xdd\xe8X\xda\xf7\x19\x92\x84\xb4\x83\xa3\xfc\x05\xcbh\xf0\x17\u04aau\x808;$9GB\x888<\n\x804\xf8+\xdb\xe7!\x1b\xf7\xb3>\x0f\xa9\xe9\x15M\xbb\xc3S\xf2\xa3b\u0204j!G_\u0431\u051b\xc4\u04415\xa9-\xa9\xb7\x88\xf3\x03c\x8c.\xb5\xb1\a\xae\x81kzR\xeb]\xb3\x87\xc4/\x89\x03\xc0\xe1\x9ck}\x10\x1c\x04@\x1f\x02\x1f0\v\x010(\xc1\u05d8\v\x17\x9f!\x11d\xc4X\xed\x889e\x85cV\x18\xb7B+\x94\f\x10\x18\xa0\x01H\x00\xbf\x0e\xc7\f\xc3\xe4\a\xff\x8a\x818\xfe!2\u02f0\u0307\xa8\xcc_Q\x991Y\xe6\x95H\xc42\u00d2\x9d1\xdb\x19`\x86fx\xd2\x00%\"k\a\x80T\u070c<\"L\x96\xe5\u0172\xde\xe5\xde\xc0\xb2\xf6\xa4\xdb\xf70m\x1f\x8acYMR\b1u\xb8};\xea`_\x1d\xac\x83\xe3\"\xfc\xbc\b\xaf\xc5vB\x84}\"\xac\x14\xa1O\x84\"\xbf\x18\x0e\x1b\xa8\x93F\x84g\xdaJ\xfc\xed\xd4>\xd4\xc1\xae\x95\xb9\xe6\x1d\x92q\x86k\xae57\xf3\xcdP\x85\x19\xe7D\u007f\xf4\xbc+Q\xa0\xb5\x85B\x98q\xae'\x94s \xe0\xe8.f\x9c\xcb\xf7\"\x92\xf3\xf8\xee,\xe3<\xcd-\x9fa\x89\xdat0\x93\x1dD\xf6}\xe6o\xcd1}\xfaP\xeb\f\xe3\xbcv\u0671Ni\x800\xce7\u05f9b\xfd2\xe3\xfc\xf9K\xf7\xed\x8a\x1bV\xf7/\x9ee\x9c\x8b\x81\xdbK\x1b\u0111\x1bWtl\x91\x19\xe7-\xed\x11\x13\x14\xe6\x19\x86\xe9i\xcamV\xee6\x06A\x91<\x86\xed\xd3/\xc1\x01`\x19g,\\\x10o\xa2\xdf?\uecb0\xcab\x18\x89\x01\xfc\x9d\x03\xbf\x17\u0702\xf1&I\xcb\xf8\xf1\t[-\xaeY4\u0205\x9f\x04\xdel\xf9\xd3\xe3\xee\\\xf2c\x19\xfc\x19\xa0H\xcbw\xe3\x13\xa0\xa7,\xa7\xfcH\x06?\n\xfc\x18o\x93\xf2\x11\xe3\u1088\x81\x96\x12z\x069e\xce9l\xfa\x1c\x058\xed=\x04\xaa$\x1fb~\xe3\x84g\x9d\xb0\xcf\t%'\xf49\xa1\x9ex\xd5\u0409\x18\xe0\xb5\xcc\b\u0268\f\xad\xe19\x9d\x02@1$\xf3jL\x98\x1b^\xaa0it\xab\xa0\x01\xea\x11kz\xc4\x04\x8bL\u0566e&\xa4\x87\u041c\aM0\x0f\xffB\x9c\nl\xb6\xb0\x1c\tJ\xf88\xb5)\xa9@I}~R\u04eb\x81\xbc\u6106Q\xe9qB\xbb\x02\xb1\xba$'\x13j\xa6\x04y\xe3Ev\xc0\xc9W\x94D\xf0\b\x93\x96R\xf7\xf1\xbfCGO\x9f6@\xba\x8bD\xb9\xb5(\x003\xfcZB\x82S\f]T\xa5\x8a\xdfz\x9e\x19Co`*\xab\xf5\xe2\u03d9\xe6\u007f\xec\x81wl\x95\xd9\xe1i\xca-|\x95y\x98\x8e\u03e1\x94\x99\xf0\xa4\xf1\xf8\x04\xe51\xbd\n^\x00\x00h\x9f\x86\xbd\xa5Ev\x1f\x19\a\x8a\x939\x84\xf2\u0706\u04fa\xf3\x8c<\xb7\xd8L\x05\xb1\xab\xf6\u02b81\x0f\x82\xf4l\xe5\xc2\xef\x05q:\xb7\u040eOX\x98g\u0320s\u02df\x9c\xfe]\xb6\xfc\x8b\xe3\xe6\\\xf2#\x19\xfc\xe8\xf4\x9f\xa8.0\x90h\x1b\x84y>\b\xe6\xe9B\v\xe1\xa7\xca\xd7(\xa3}H\xfdo\xf65\x1e\x9e\xdf\a\xc2g\xbd1\v\xbfwz\u007fV\x1fF/\xe9\x83\x01\xe3\x1f\xc9\xe0I\x1fx\x8a\x97/\xc0\x98\xf3\xe6\xe1%\x8c\xdf'\xf7\xa1,\u0747\xfc9}\x00\xf3\xfb\x00\x18 \xa4\xb9\xe1z\xe0\x05\xc3R\x83\u04e93\xacVm\xf6\xfb\xfc\xd0^\xb0J\xa7\xd7C\xdd\x06\x9fK\x9f\xb4\xf3\x80D&\xc1vp\x02\x9c\x05\xd3d\x8b\x8d\x10\xa3\xb1\x84\x82\x11\x9d\xd16\xc2d\x18\xfc\x84\x15-\xd2\x04\xee\xa8\x1cB\xa0\xf9S$\xe4G\xd9\xe4\x964\xb5R\x93#59B\xcfR\x10\"\xa0J\xfc\x86\x94\x0f\x95\x1c\x87\xb4\x10\xf6\x91h\xaaF\xc32\x8c\x0f@\x00|\xa0\x0f\x10\xe2\xccC\xe9-X\xb5\x02<\x05\x1cq\xb2\xc9j\x10\xf17\t\xda\x19\xe4/\xec`\x80\b\xfe\a\xc9/5\xacUC\x9b\x1a*\xb1\xcf\x01\xdfJ\xbdr9l\x86m[R\xa7`|S\xea\xe5\xd4\xe4f\xe6\xeb0~y\xea\x15\u06329u*5\xb1\t6\xa7\xcel&}A\xb8\xff\xe3\x98gy\x018\x01\x99\xf15RC\x89\xb7\xd4\u00faB\xab\xa1C\xabc\r\xec|\u05a5k\xb5aS\xd4[\xe2)e\xcb\v\x93\x0e\xa8\u04f2j\xa7\x95-O\xe6\xa9)\x8d\x8f\xa43\x90\x92\xa6\xb3\xe8A_v\xfb0\x1b\xf3F\b?}aY\x81\a\x134\x89\xcePn\x9d\xaccui\x1dn\xa6\xf6\xc7.\u06df\x89q\x8f]\x9b\u0459\x1c\xf8\xbd\xe0Lz\x8d\x14\xe1\x13\x12v\xcf,:\xa7\xfcIp [\xfe\xc5q_.\xf9\x91\f~\x14\x1c\x9a\xb1?~\u0646\xda\u02f4 \xc7\xfd\xb4V\xbeFS\xbaMU\xb4M\xc4d\xc1\xcb\u053c\x92\u0274)\x9b\xfb\xab\a.\xd0$\xf9m\x98_\xeb>\xee\x86z74h\t\xe3\xb7\xc00\xa2p\x8dh\x15\xf8KI\t\xbf4\\Bn\u007f3,j\xfc\x92\xc5\xf8\x15-bN\xce\xef\xf3'\xe7r~\x91\x8ep~S\x93\xf89!C\xfa\x1d\xbb\x1e\x00(sB\xf6(\xbc`\x11\xd8&%\x94]\x15\xb1n\xc0;\xbc\x0e\xc1\x81\x1cR\xbe)\x91\xac\xd8^\xc1\xf02c\x04\xa9\x1c\x15\x00T8PkQ\xb7a\xf9\x12\xfd\x12\u07d2\x89%H\xean]\xb6\xb8H\x19C\u0586\xben\xd8j\xf1\xf69\xad\x94\xec \a,\xd2\xe9Q\xe4P\x10\xc8\xc6N\x84ld\xd3.\xb0YA\x89\x9c\xb9j,9\xcc$\xacR\x17\x11\xfd>\x12_\x14\x8f\xe8B]\xf5u+\x9a\xfdu\x1bo\x19\\wS\xcc\u065aX\\\\\xd7_m7D\x12u\xf1\xc1\x98\xb5\xa4%\xd1R\xe2oZ*V\xadh\v=\x1d\xdfy\xff\x9a5womb\u007fY\xbfrASm\x8d\xc7\xe2\x0fU\x05\x8b\x13\x03#-\u02ef\xee\x0f\xa5\x93\xd9\x1c\xe5R\xb8\xa8\xb1\xae!\x10\xeeh\xef*\xad\xe9\x8d\xd74\xb4\x97\x95\xb6\x94\x98H\xba\xfe?z\u0613[n\x19,\x0e.\xbe\x92\xcc=\xe5\f)\xfcx\xee;d_\xaa\xfdN@,\x9eh \x16\xef\xfcx\xbd\x98W\x98\x99\xfb\\\xf8\xbd1 [\xd48>\xe1:\xb1>\x83\u0385\x9d\xfc\x11\xc5\x12\xe1b\xa3x)\x96\xfbq\x06{\xe6%\x8am\xc4\u0612\xa6\x859\xb0\xdf\xcd`G?\x04\xd4\xea6\x19\x82\x88\x11\xc4n\x8a&\xf0\xacv\x1c\xcd\xe0O\xcf\xe0\xeb\b\xbe\xb2Y\xcc\xc6\x03D\xf0\n\xf2\xfcP\a\xbaA\x1f\xf8\xb8\xe4\x14\u030b<\t\xb6\xad\r,N\x04\xdd\xcb\az\a\x92\x03\xc7\aP}\x02\xc8\xf1\xfb\nL\xa9\xd2\xe9\xc0P?h\u04f71m\x9e>\xc0\xeaY\x86\xe5\x17y\x171\xcaE\x8b\f\xfe\xa6>\xa1\xac\u068a\xab\t\xf4\xd9\xcc\x06=\x903\x00\xa3\xf2o\u00b5\xa6\x95\xc1)\xd9J\x9f\xa9/\x82\xff\x93\x06\xc1\xe6\x13\xad\xac$\xf8:\x9f\x98B\xe9\vtO\xd1*\xce\u0430`\x9a\xae\xb2v.\xff\xea\xc8\x17#\xe2\x177\xaf\xbbwk\xfd\xc5\x11\xee\x8e;\xaa\x06{\x16\x16\x87\x16\xf5\x0eV\xdd\xf8fK\xe1\xe2\xe4\x95\v\xbb\x0f\xae\xaa~i]o\x86\xa1\x85\xae\xbb\xe2\xb0\x16~\xdbY\xbb\f\x8as9Z\x83\u00c3\xc3\xf3\xe9-\xbbv\xd7\f6z1\x9fk`\xcd\xd0,y\x8b\xb9,Mz\x99\x9e&y\xb7\x84\xfb\x84\xe7\xa3+\ud7f6Q\xffT\b\xfa\xb8\xfc\x8c\u007fJy=\xb2\xfe$\xb2u3,\xeb\xe6s\xd8;\xe0x\x19\xfc\xcf\xf0{\a\x00\xf5\x0e\xf0\t{\xc3\x15\x19t.\xec\xe4\x87\x14K\x84\xa3\xca\xf0\xa5XY\xdf(v\xf4{ }\x97'\xfa\x03\xc2M2:\xa3o\xd3X\x14\xdc,\xcb~%\xed\x93\x0e\x02\xd2r\xc8\x1a\x88\u037ew\\\xc3\xce\xf1I\x9f\x04\x80i\xcb\xc2\uf76e\x04rk\xa0\x1e\x9fp%\xab\x99\xebcN\xbf\x84\xf1\x83Y\xf8\xc9\xd4\v\x14/_\x00\xe4\xb1\xf3\xf0\xbf\xc6\xf8b\xb9\xfd\x14?J\xf0\xf4\x9e\x90\x8f\xbb\v\x01k\xbf\xc4'\xddNr\xce\x15\x01\x10\x02\xf5\xe0J\xa9\xcb\x18N\x80\x80\xcf\xea`\v\n\xed\x05\x85\x85\x05v\xa4\x01\xcb\x1b\xa5\xc6\xf7\x1b\xcf5\"\xbe\x11*\xa28\t\xbd\xc1\xe7\bXY\x9b\xdf\xef.\xef\xe3\x8dxO\xe4\x14\xcfT\xf2\xd0\xc6\xdbx7\xacM'\xa7\u04f8\xb9A\x9c\xa9W>\x93\xab\xfe\u007f\U0010123c\x85=\xd6y;7\xe4>\x8f\x99\xca\\\x88\xfc\xae\xf5@\x92z@k\xe4\af\xb9z4\x9b}\u02c9\xc3\xdd\xf1\xbd\x0f_\xbe\xe9\u0788\u02bb\u007f\xd54X\xf8\xdd\xf0\xa0\xd0\xd5zU\xe3\x8f\x17N\xb6o\xef-{\xb1\xb0\xeb\x8aEK\xb6u\xf9\xfd\xdd\xdb\x16\xe3<\xf7\xe6\xff\xf9\xc1\u077dm\x87\x9f\u06f7\xef\u066b[\x1b\x9b\u063d\x13\xfd\xf7\xec:RP\xeb<\xe8K\x94\u0778sO\xeb\xfd/\xfc\xf0d\xdd\xc7\x06\xa2\x15+\x8e\f.>\xb4\xaa\xea\xb5\xf4\x9c\xb1F\xd9^\xf5S{\xf57:\x03~<\x03La\xa5\xd66W\u007f\xd8ry\xbe\x06\xa8\x1e\u007fG\xd6c\x9f\xac\xc7\xdf\x1e\x0f\xfa\xe6\xf9\xa1\xf3\xf1{\xfb\xa8n\x96\xe1\x13z|\xc1\f:\x17v\xf2\x1fY\xb2\xff>\x1e\xce)[n7\u015f\xf9Q\u059a\xba8^R\x9b\x13\xff\xdd\f~\x14\xf7\xd3\xf14bJ\xb0\xea\xe33\xfe6\ueade\xe7\xe3\"\xb0\t\xfc\x95e\xd8\xc7\xe5\u0727\b\x18\x91,\x95\xe5\xb0\xf0Q\xbb]\xf7\xe8\x10\u0684\x980\xaaC\f\x92\x13\x16\xc38\xd9\x0f\xb0\xa1'\xf4n\x88U\xc4\xed\x86\xea'\x80\x89\xf0\x81FL'M\x13\xa6\xf7MJ\xa5\xc9\x04\x9e\x80O\xa5\xe3)Xg\x04\x12R!\x89\xber\xfd\u00e9\xe1t\xb5\xc3\u007fS\xff\x12WB\xbcx\xca\xe8-\xb1\xdbJ}F\xa3\xaf\xd4f/\xf1\x1a\xe7\xff\x8d\x03\x1a\xc7R\xbf\x0e\b\x9e\xfc|\x8f\x10\xf0\v^\x9d\xce+0\u07df\xf7\x06\xed\xe3\xee\xe9qV`o\x03NP\x04\u02b1\xef\xdb\x18\xf2\x86\xb1\xef[\x9c\xb0\u066d\x16\xa5J\xa3V\xe5\x83\xe5\x82$\xbc/\x9c\x13\x10/@\x85+\x91?T\x11\xf6\x84\xbcl\xa4\xb0O\xa9\xb1[X\xcej\xd4G\xfaTdY\xbc:\x15\u007f5\xcb\xf9];\xd7\xf7\x95\xfb@sk\xc8j\u0224\xdep3\x9e\xaf\x82\xab\xa6\x8eo\r+\x905ph}\u01d1\xbex\x17!u\xc4wV\xe1\xe3\x96\u038b\xc0d\x85\xb7\xb8\x17\x95c\x8d\xef\b\xa5vy\x13\xe53\x1c\x8f\u0636\x85G\x12\x94\xe6\xe1.\u063a\xe0\x9a\x05\x1f|j\xd9\x11\x919j0\xbe\xf7\xc1\xf1\xcb.\x1e4\xe8\xbfNuA\xce)\x97um\x05\xd5\xe3\xcf\xc9V\xcd%[\xb5\xfb\xc6\xfd\xae\xaf\u0145c\x1dQ7p\xb9\xca\xfa,\xbc\xd5\xdf\a8\xfd\x1cFl4\xc3n\x81s\xeb\x1eg\x11]\f\xca\xe2\xb9\xf4\x16\xb8!\x9b\u04326\x8b\xeb\xf2\xb4\nz\xb3i#\xe8\xe9lJK\x16\xd9E\x05R5w\x1a\xe61\\2\xfd\x96\u01ca\xf6{\xf4\xcbi\xcbO\x8c\t\xd4\x06jA\u05bdk\x86\xff\xc5.\xbc\x84\xff\xc5\xe7\xe2\u007fa\x1c\x86C\x06\u01da\xeeU\xf8\x81\x19\x14K\x06^\u01f2`B\xc5\xea>\x01xUR\u0168H\xf2\xa5\xf3\xed(\x14\x9co\xcf\x14\xe7\b\xc85u\x94\x81\x18\x89A\x11f\xfb\xbd\a\u012d\xd55\xa3\xe2\x01gG{#\xe6M4\xb6w:\xd8\xef\x16\xae\xab\xad]W\xe8\x92\xe3Q\x94\xe6\xce\xc0m\xf8ZU\x8a\xa3r,@\x92\xca\xcdG\u020eH/H\x02\x168\x8fT\x92T\u041bIF`\x9c\xef\xe5\x93\xf8\x0e4\xcd+\x15\xbc\xfbf\x9eKr\f\x87[2\xf5\rR\x05\x8d\xbc\x0e\xe7\x88\x0e(\xab\x83\x99dET\x15h^V\x15\x1dh\xf4\xf9\x1a\a\xa2\x95\xcbZ\x02{\xe2U\xb8\xc2c]U\x9c\xfb\x8a\xd8_\xe7v\xd7\xf5\x8ab/~\xad\xed\xad\x8e55\xc5\xf0Oz,>\xe0~\f\\Xs\x02\xbcM\xb016\xa0\xf6\xa9\x19\xa5\xda\u028d\xe9$\x9c\x9f\xaa\x93p\x1e\xb7Ng\x1aS\xf3\x00\x12\xa2\u007f\x94\xc4E\"S\"\xc9\xe5y[\xaeGH\u077d\x00\xd5 \xb2\xe1,\xea\x10\x93\n\xf7.\xee\xf2\x95W\xea\xb6p\xfe\xd8\u008a\xd2\xfe\u015d\xee\xf2\n\xfer\xf2\x17\xfb\xfd@\x04\x8ff\xd3\xfa\xce\xe2@i\xa0\xba\xa5i]g0\xf3y\a\xe8I\xf9\xf3\x0e\xdc\xcf\x01\x86T\x93Q\xe4%\x18\x86\x03\xe09\xf8\x12\x88\xd3\xe8w$\xfd\xb9\ah\r\xfd\xdc\x03z\x9e\xf2?>O9{\x9e\r}\x15\xf6\xc9\xf5^\x8a%[RGj@%\x95\u06d5\xa7\x94\xef)9e\xde\xdd0\xef~\x05\x02q\x1c\r\x9b\xc2jA\x8cw(\xfd\xf9#\xc5:]\xa8\xa2\xdaq\x03\xefvZU\xe8\xab\u0599\"\xbe\x1f\x8f\u558b\x85\xf10\t\xb7\xc3S\xf0=\xc8A\xc5\xfd\x80\xca\x1d\x9e\x12\x88\\\x98\xf9@\x886\x9d\\-\xf8\x06\x1d\xa9\x16\xcc=m\xad=p\u8aba\xa6k\xaf%\x82\xb3?{\"\xf6\x1c\u0411\xb8\x92\u019e\x98\x11}X\x16\x8d\xafE\xb2\xd1\xf5\x96\x84\x12_\xe5a\xf9*\x11Q\xc4W\x8a\xfc\xa7\x1f<\xc1\x90\xf63\x1f\xc8\xedw\x80\xf5R\xe2\x94\v\xdeJjd%]\xdb]\xc8\u011b\x93\xe6\xed\xe6\xc3\xe6S\xe6\xf7\xccg\xcdJ\xb3\xd9q\xb7.\xefn\x00\xfb \xad\x953\x01\u07c7J8w,\x1dy\xf7\x9b\xc8P\xcaI`\xc3rsp\xb4\x02\x1fQn\xf7\u0330\xfag\x0e\xe0\x17\xb3\a\xf8\xe2\xb3\xfft\xb8\xb3\x0e\xff]\xbb\x81\xb9\xcfi\x9e0\xbfO\xdb\xcd\ub4ba\xed\xb8\x8e\xcf{:N\x97\x19Fy\x8e\xce\xca]P\x9a\x14\xf7\xe7\u02d5\x86H\xbbi\xb3\x87\xd3\xed\u039e6\u007f\xee\xf9c\x12\xfft6\xb3\x0ei\xadj\xe6\xef\xf2\xbc:\xc0\xd5R\xff\xfb\xaes\xae\u07fa\xd0\xe7]\xe3\xae\xd3.\x84\xbb\xc0\xf8\\\x95.)\x9d6\xa3\xc8\xf4\x84\xf4CA\xfaq\xab\xee\x9c\xee\xb7:D\xba\xc3du\x84tC\x91\xd6\bI\xa3\xb7'h\u007f\x1eN\xf7'\x92\xeeP\xbaG\u0279\x9fM\xe2\u03e5+\xd9}\x9a\xaf9s\x94\b\x82c\xf0<\xb3\r\xfd\x1e\x98@\x97T$X\x92\x96\xed8\xf3\xee=\xcbo,\xd3\x16\xa5\xde\x02\x93\x9a\xed\x9a\xe38\x04qV\xf3\x1b\x8dB\xf3~:\x1d8\x8f\x84\xa0\xbd<\xe4\xf5\x1c$\x16\xf0\xcc0n&\xfe=\x9c#\x14}\xac(>\x14\xad\x1a\x92\x8a\x8b\xa5\xa1\xaa\xe8P\xbc\x88\xf9e\xf7\x86xAA|Cw\u05c6\xb8\xc7\x13\u07d0\xe6t\xec\x86\x17\xe4\xf8g\u04d7e\xa6\x86\xe4U\x13NF\\u\\uBuV\xf5\x1b\u0574J\x91\xc9\xf7B\x90\x83@\x10d\xd6IV~\x17\xbe\xfa\xbct\xae\xec$\xaey\u05c9Ka\xf0\x8b\xb3\xe87h\x1a\xc95\x0f\x184\xe7Z,\xa1\x89\u4e948L\xe6\"\x13N\x85\x17p\xf4\xf4W\xbf\x9a\x17=%\xd7J=\x04\x00\xb3E\xae=\xe3\x9e\xf3\x99+\xd0\b\x90\u0323\xc8\xfe\u0215-\x17\xbe\xf9\x00\x8a\xa4\v\xcf0 \x8fY\u020c\xe1\xfa\xc2\x1a`\xc13S\xaaf\xa6\xb4J\x84lI\xdb\x18\xb6\xfe$2n\x99\xe2 {^\xcdk\xbdZA\x8bTZ-\u00dfW\xfe\x80\xf9a\xba\x8ai\xbaF\x03N~\xc1\u007f\x884\xcd<\x80\x13\xe9\u04dfSA\xaa\x0f`M\x84\xcc\u0621\xb1\xd4\r\xf0\xc0-\x87R\u007fD\b;\u007fv\xf5}H31\xb1\x9di\xbf\xf8\xced\xe9eU\xda\xe2\xd20O>{\xe8\xff\x01|@\x8d\xa4\x00x\x01c`d`\x00\xe1\x94=\u036a\xf1\xfc6_\x19\xe49\x18@\xe0\x84\xb8\xff70\x1d\xd3\x16\xf9o\xc1?\x11\xf6u\xec\xc5@.\a\x03\x13H\x14\x009l\v\xa1\x00x\x01c`d``/\xfe'\xc2\xc0\xc0\xc1\xf0o\xc1\xbfE\xec\xeb\x80\"\xa8\xe02\x00\x87\x94\x06]\x00x\x01m\x91\x03\f\x1eA\x14\x84\xe7\xf6\xbd\xbb\xda\nj\u06f6\xed6\xa8m\xb7Am#\xa8m\xdbf\xf4\a5\xc2\xdan\x83\x1a\xd7y?\xeaM\xbe\xccz\xf7\xcd$E\xac\x99\xba\x8c\xa4\x00\x16H\x05L\U000cb80c\xf6\u0158`9z\xfb\xab1\u023b\x84i\xae/Z\x93jJ%\xbd\x1dP\xc3-\xe0\\>,p_\x91\x91s\xdd\xc9~\u0495\xb4&Y\xc8\x142\x8c\xb4'\xfd\r\xdbOj\xd8\x1d\t\xa4/\xf2\x05\xaf1Ho\x01\xfa\x11\x11\xbd\x86q\xfe(j%D\xe45\"\xfe4\x8eW\"\xe2\x0e\xf3\xbd\"aC]\x1f\x9b\x0f\xdes\xed\x06y\x8bq\xba\x92\xfa\x9az\x94\xe7\n\xa0/\xc9\xe8/\xc6Q\x9d\x03$I\xcf\xffu\x05\xb4\x02i\xc9;\x06a#\xff\x9c\x85ZFk\xa3\x904\x0e\xbf\xeajo\x96\xd6@g\u074b\xddr\x90\u007f\xdeK\x1ab\x98[\x8fl\x9a\x0f\xf9\xf40v\xbb\xf4X\xeb\u0487'\xe5c\xb4\xbf;I\x11\xec\xb6y]m\xfb\xa9<#\xa5x~%\xda\U000efe78\xb6Qn\x00\xfeG\xbe\x0f\xe4\x91gH.3\xf8\xfe\r\xf3\xd1{F5\x9f{'\xbcg\xff$\xa9K\u0190l\xb6G\x1e`\x14\xffV&\u060a\x9en3\xea\u02a3\xb8\xff\xf4\xde\xe6\x14\xe1g\x19\x14\xdd\u07db\xeb\xa5H\x8eh-\xe7\xb0\u06ef\x86a\u6df7\x11y8_\xc3]@m\x9eo\xeb?B\rR\x94\xe4\x10\xbeg\xbe\xff\x8f\xe0J\xf8\u0772\xb0\x1c~\xc3r\xa8NZ\x93t\xa4&\xb3*\x91\xc8\xe1o\xf8\xafy\xa6\x96\xc5\xefD\xb3`fz\x05\xbb\xcd\xf7\xff\x11lG\xe7h\x16\r\xff\x84\x19\xdc6\xff\xa9\xa7\xc8k\xfa?$\x91\xc3?\xd0\x17\xea\b\xcb\xe2w,\x8bh\xd6T\xbb\x8b\x9e92(\xaa@\xeb\xa4\xc4\xeb\x8d,\x86\x03\xbd{B%2\t5\xc4a\xb1k\x8e\u0586\x97\xfc\xfbZz\x9b\xf2\a1\r\xcf=\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x00x\x01\x00\x01\xba\x02J\x03\x02\x03&\x03V\x03\x86\x03\xbc\x03\xea\x04 \x048\x04r\x04\x92\x04\xe4\x05\x1e\x05t\x05\xf2\x06F\x06\xae\a\"\aJ\a\xf4\bf\b\xbe\t\"\t^\t\xa0\t\xdc\nP\v\x1a\v\x86\v\xfe\f\\\f\x9c\f\xd6\r$\r\x82\r\xb8\r\xfc\x0e6\x0e\x84\x0e\xa4\x0f\x18\x0fj\x0f\xc4\x10\x12\x10|\x10\xee\x11X\x11\x9a\x11\xd8\x12,\x12\xe2\x13B\x13\x94\x13\xc8\x13\xee\x14\x0e\x142\x14P\x14h\x14\x8e\x15\x02\x15d\x15\xaa\x16\n\x16h\x16\xcc\x17\xa0\x17\xe2\x18\x14\x18`\x18\xb0\x18\xca\x19<\x19z\x19\xc4\x1a&\x1a\x88\x1a\xce\x1b>\x1b\x94\x1b\xd6\x1c.\x1c\xdc\x1dn\x1d\xd8\x1e&\x1e\x80\x1e\xa4\x1f\x00\x1fT\x1fT\x1f\x9c \x00 v!\x0e!\x82!\xb2\"l\"\xb0#Z#\xc4$\x18$F$N%\x1e%6%\x92%\xce&\x1e&\x94&\xba'\x04'B'|'\xc2'\xfa(B(\x92(\xbc(\xe2)\x12)\x88)\xa0)\xb8)\xd0)\xe8*\x02*(*\x92*\xa6*\xbe*\xd6*\xee+\b+ +8+P+j+\xce+\xe6+\xfe,\x16,.,F,`,\xc6-H-`-x-\x90-\xaa-\xc2.\f.\xa8.\xc0.\xd6.\xec/\x02/\x1a/2/\xe2/\xf60\x0e0$0:0R0j0\x820\x9a0\xb41D1Z1r1\x881\xa01\xb81\xd22D2\xbe2\xd62\xec3\x023\x1c323\x983\xb03\xca4\x004P4\x984\xb44\xd04\xfc5(5\\5\xb86\x146~6\xc26\xf67,7J7\x94\x00\x01\x00\x00\x00\xd3\x00i\x00\x05\x00S\x00\x04\x00\x02\x00\x10\x00/\x00Z\x00\x00\x02\x1f\x00\xe5\x00\x03\x00\x01x\x01m\x8e\x83n\x03P\x18\x85\xbf\xd9^\x8c!\x9c\x15.\x9aW\xdbQm\xfb\x19\xfa\xd4=5\xf3\xfb \xf7\x02[\x84Xce}\x87\x15\xcea\xb8\xafr\xa8k\xb0\xafq\xcb\xf5p_\x9f\xd2lp\x8fe\xb8orJ{\xb8\x1f\xe2\xa1\xc3\x0fUJd\x88s\x89\x9b\bEj\xb8H\x90\xa2A^w\x95O!1!Ei\x12\xba/yP-\xf3\xf9\xfa|MhI\xf7%/<\xf2\xac\xb8$JCh^j\xa1\x8a\xb7\x89\u007f\xecNSW\x94y\xe7I\xd1\xea\u01e3\xb8\xb2*&6\xa1\xab$WJl\x9e\xcc\xf0O5\xf5\x9a\x10\vF\xbe\xf9\u0146[\xfd\x81W\xf4v\x17Y\xd5)\x8cx\x01l\xc1\x83\x01\x03A\x00\x00\xb0\xf4k\u06f6\x8d\x91n\xe1\x0e\xd4.\xf0\x89\b\xf8\x05A\x9c/\x12\"I)i\x19Y9y\x05E%e\x15U5u\rM-m\x1d]=}\x03C#c\x13S3s\vK+k\x1b[;{\aG'g\x17W7w\x0fO/o\x9f\u007fA\xf0\xb0\x05\x05\x00\x00\x00p2?fo\u0676\xed\xb5\xbd\x9b\xf5\xb2]\x97l\u06f6\xf92\xcf\xf9\xe5s3\x9ah\xaa\x99\xe6Zh\xa9\x95\xd6\xdah\xab\x9d\xf6:\u8a13\u03ba\u8a9b\xeez\u8a57\xde\xfa\u8adf\xfe\x06\x18h\x90\xc1\x86\x18j\x98\xe1F\x18i\x94\xd1\xc6\x18k\x9c\xfd\xb6\x99m\x8e\v\xd6\xfah\xae\xa5\x16\xd9`\x8f\xed5jZX\xa3\x96YV\xf9\xe5\xb7%\u0599\xef\x9a\x0f~\xdah\xaf\xbf\xfe\xf8g\xab\x03\xee\xb8\u5820\x90\xe5\xc2\ue278\xed\xaeG\xee{\xe0\xa1O\xa2\x9ez\xec\x89Cb~X\xe1\x85g\x9e\x8b\xfb\xe2\x9b\x05\x92\x12R2\u04b26\xcb)\xc8+*\xa9(\xab\x1a\xef\xb3\t&\x99h\xb2\xa9\xa68m\x8b\u9999a\xa6\xaf\xbe;\xeb\xa5W\xde{\xed\xa8cN:\xe5\xba\xe3N\xb8a\x9e\x8b.9_\xa3v\xbdJ6\x11\b\xb4\xeb\xd8 W\x8d\x14K\xa1\\1\xd28\x9a\xab\x14K\x95|\xa4\x98\xc8\x15\xff\x03@m\nTz\xe0\xcd\n<\xc0\xca\x027\x03\xf7\xf5l\xf8\a\x80\x95\xfb\xbdf\u00d7\xe4\xc1~`TUU\x1d\xdfa\xb6\x06+hO\x15\xb9}\x05\x1cF\xd4\xf6\xc1\xb6\xe9\xb0|\x94\x11\r\x87:\u0550Ns\x95\xac'\x84aiY\xa3\xb6Qwg9>\xc9zGv\u0210|\x80\u481d\xa7\x84m\x17d(!K\xb1\x03\xcfv\x1e\xfdE\xa7\xcc\x1b\xd3\xc6\xc3\u07ae\xdd\a\x82\xb5\u00f2\x94\a\xfa\xb9R\xbf\xa2\xae\x90_V\xaep-K\xbb\x93\xcbd&\xf3/\x13}@\xf2\x17\x00r\xd9\xc3l\xc9\x01+4\xe6\xa6\nU\x15\x81\xaa0\xae\xb6\xc2\x16\xfe\xcd\xff\xad\x9c\x14X\xb1\xf6]:\xc1\xb2\xae_&\xebP\xad\xe9\xdf\xff\f1\xe4\xa6\x1e\xb2\x98\x95Y\xd4a\xe7.c\xc3\xc80i\xa1G\x88\xf8U\x05\x8c8\x10\xe2-\xfcv\x87\xe7\xdb\xd61\xbf@&\x87\xef[Q\x04\xacd\xa8\u07fc\xf9\xe1\xb0\x03\xcb\xee\x9b\xdc\x1a+\x8bB8\x16>\x88\xca:(\x94\xb4j\x9dW\x119\xf9\xa3w_\xac\x8e\xcfFU\xf1_I6\x16\x9c\x96\u04eb\xb1\u007feI\xee\xcfo\xf2\xa7\u01ab\xe1\xb4\xe8\xed\xc8\xf6\x89\xb1\xe0\u03ab\t0~\xa0t\u3b61\u03dd\xcaO\xdc\xd6p\xc0[#'>t\xe4\x9d\xfc\xa2\xd6\xd89\u0539\xd2y5\xbc\xad\xf3\xc1\u062e1\x82\x1e96\xaa\x1a\xfdmtV\u067f\x8d\x05\xbb\xd1\xfa\xb1\u0391\xff\x1a\x971f&^-\u4037\xff0\x19G\x8f8\xcc=\x12\xef\x109\x95\xedp\xca\xc1\x92\xfc\x11\x9fs\x99rg\x11\x1f0\xd8\u0104\x1d\af\xd0\xfcX\xc2\xd9Pk\x81\x89o\x12,\x04\x04\x11\x85\xad04\x8e\xd88<\xf0\b\xc1\x88\xed\xd1F\x90\x90ARP\xc2H\x92\x0e\xabY\xbb`\x06\xfd\xc8\x06\x8d\xa2\x197\x8de\xd6~|\x87\x1d\xa5p\xcci)\xce\xda\xd2\x19.\xb9\"\xd3uw\xad@\xe8\xeb\xee8ad\"\\;R\x8e(8\xd1d\xa81f\xe2,\x17\xbc$\x88\x8cRNP\xc2IJ\u0260RI\u0377\x05\xad\xdal\xd3\xde\xdb\xf1\xb1\x1d\xce\x0e\xbd\xfaz\xa7\xc9,\xec>\x8b\x96,\xdbo\xcd:\xa3#\x8e:\x16N\xc39\xbb\xb53\xdf\xf5GD>;l\xc2\x13A\x88\xbc\xd1\u0270\x83\x182l\u0128\xf10\x91ISv\xceM\xcfK3w\xad\t\xbe\xf5GD~_\xd8\to\xc4F\x06\x99$I\x92\\oyu\xe2\u0184\xa5@\xb4\f)\x18\xd5,\xb8\xb6.\xec\xd6a\u0456G\xaco\x1d\x19\xb5\x05\xea\xefknK[\xdb\xd6mmo\xc7n\xef\x8e\xf6\xb6\x0f\x15\xc9\x02\x95\xb5z!p\xec\xc6am$\x1ct\"@E\x9a\xe8\xfdt8\x9a\"\x02\x00\"\xe8gO\x83\xba\x8a\xea\x86O\u0631\x90m\x9f\xe0\x1b\u007fDd\x06\x83\x86\f\x1b1j\xbc\xbcZ\xca\x1bdl\u02ee\xc6\xee\x8d\xca\u0671g\xf7\xe6@\x85.k\xc1\xf8\xbdR#\xd7\xf8\xea\xacuQ6\xb2w\x88&\"8_\xc0\x82\x8c5\xd9\xeer\xfb\u04ac<2_;\xb4a\xa0\u0607#\\\xbc^\xc1H\xae\xf4\xe3d'\xe1\u028f\xe2&\x1e\xd5M\xdad\x93\"UZh>-Z\xb5\u0666=\u03fee\xffI\xb3g\xb7\x9b\xb3\u01fc\xbd\x16\xec\xb3h\u0272\xfd\xbd\x87\xef\xdaYgt\xc4Q\xc7\xc2\xf1{\xc2I\xa7\xc2\xe9=\xfb\xeaK\xf7\xf2\\%s\x83\x9fd\x17\a\xba\xa3\x99\xbe\x1d\x1a\x9fWp\xb9rEZ\xb2\xbdA\xddN\xae$R\x95\x9bH\x88\u049d\xafHbT\x82QUU\xed>\xa2/g\xddns\xf6\x98\xb7\xb7\x95\n\xde\xdb\xe1(\u1acf\xe7DN\xe6T\x8f\xca\xf9\u0272\x96#\xc7\xc6\xed\u137d+\xb1\xc3\x01\x17\xefk\x04\x95TZY\x12*\x8f\xa2\x19O\x98\xc6w+U\u8fbd\xf3\xcf\xccfw\xe6\xb2'\xf3\u065b\x85\xec\xcbb\x96\xb2\x9c\xfd9\u0735\xc9\u01ed\u01d8#9\x9ac9\xde\x13=iN\xa5\xabr\xdcP7\xb8\x12\x9d\xcf)\xb7\xbc\u0332\xac\xba[\xa2\x0f[\xe8\xbe.v\xa9\xcb\xddO\x86$Y\xabf]\x88l\xc1\xed8\xf1\u03bf\x88T\u9f6a\xa2\xa26\xeb\xb5\u0628\x88\x88lLk\x01\x8a\x88\x88\x88\x88\x88\xa8\x88\x88\x88\xaa\x96Ei\xd6\nq\xf3\u01a9$P\x930\x06uZ3gA\x8b\xb6\xd9\"\n<9\x93\xa7\x9b\xb0^s\u007f\xe1\xab!x\x13\xec\x8a\u05ac\xdda\xae{\x9e\x9e\xef^Q\xd4\x16%\x89J\xec\x9c\xd6\x15\x9em\xf95\xa4\xabJ&\xcdV\x12,\xa8\xd4\x16\xb5u)\xbf.F+\x91u]\x10\xcc\xe9&\x82\xd4\xc1X\x8e\xb3m\x8e\x1d6oE\xa4J\rhA\x02U\x14>eHJrL\xad\xbd\vX)O?\x9d\xb3\xb1(\xc3\xf9\x11z\xf0A\xd2I]\xeffbW\xf1\xb5\xed\xfb\xda\x01}\\~\xae=}:\xb7?\x1d\xff\xfeAh\xe2\u0283Ty};\x1b\u05ce\x92^\r\xa2\x8e\x85\xe9\x1b\u0632\xd5\xf6(\x95}^\x85{YC\xbb\xa8\x16\u027b\xe6X\xb5\"T\x9dFi \x94\xab\xccgCO\x19\u0590\xd8}\x83\x85\x18\xf3\x04Yk\xb4}\x93A\xff\xedW\x1b\xfb\xb7\x9f\x1e\x8d\xc4[\x1a\x93\x16\x06}\x91\rf\v\xd4\xe5N\x86\t>C\x18\x86\x8d\xd2JO\xa3L1'6\xaej\x1e\x84\xa0\xb2i(\xba\xd8\u05fb\xfdA\xbfx\xf3zE\xdd\xeb\xb3\xdfO\x04\\\xd3qg:j\x1d\xbc\u007f\xfe\xab\x16\x16\xaarUM\xfc\xffiP\xeb\xe2~\x13\u05a9my\xe5(\xaa\xc6~S\x16?\xfe\xda\xec2\u0748E\xf2\xeck\x82\xff\xccV\xdaR\xd3q\xb2\xf8\xb5\xf6\xda\x1b\xaf\xb4K\xa5\x83\xf7\"\xaf\xc9\x1aN\xfd\a.^\xe2\x83\x12l\x93\x95r\x92\x92\xa5\xbb\xb0\xaf\\\u0112e\xfb\xadYgt\xc4Q\xc72\xaa\x13\xd7j\x0f\xdd\xf2f<\xff\x0e\x88V\xa7W\xd5\xc3h\u04a4_\u007f\u073b\r\u007f\xf5;\r\xf9{W\xd9\xe1\xebHy\xf1\xd0\xcbB\xbb\\SH\xbb\xa3\xf3\x9f\xff\xac\xf4\x96\x9c\xf0\t\x88\xc3M\x93\xda9\xc6\xfc\x15\xd3\x1f7\x04\xf0\xdd\x01\xb0$\xc0J\x1b%\xb0\xc0\xbe\xcf^\x90m\xe93\x98\xa9\xb5U\x1e\xde,\bLn\x04\u021b\x15#`A\xa6\x1c\xa7\x84\x99=\x86\xf1\xef2w\x12`n\xf6\xcct\x9c\xe1\x9b\t!^\x8aO\xe2\x8f\vB\xe1\x1epo8\x12\x1e\tg\u007f\xfb\x96\\\xcf\xf8\x83\x13\xdc\r\xee\xb5.\xe2\xc8\xfam=W\xfb\xfe\xafo{\xf5\xff\x97/\xf4\x17\a^\xac\xbeX~1\xfc\xa2\a\xbd%\x1c\x1f\x15\xb1\xa6\xf2z\xde\x05\bw\x00\xbe\x06&w\xde\x18}k=o\x15\xbeK\xc8\x0e'\x92B\xbe\x11\x96\xc6\xf3\xec\xb8J\xb1\u017d<\ud298\xc6\xdd\"\xb2\xe5a\x81\x94#/\x0f\xb1\x03%V\x02W\xd1\x18\x89~R-q\xae\u010b\xf5\xa08\x9f\xf7\xd6\xfc\xc1\xdb\\\xf2\xdf,\u0307\x8b\xd4\x1d\xc4\bZ#k\r\u067a\x98j| \b\xf4qt\u03b3i\xa0*\xae \xb3\xc4\xc3:#\xcb\xf97\xa4\u075ef]\x17[\xab\xc6H\x03\xac\xc4\xc7\u007f\xdf\xc6v\x88\xf3\x18\xc4\xefE\x18u\xb7}\x81\xe7d\x18\xb2\x88w\u06ce;q\xde\xc2\x1a\xa4y\x1e\x17\xe3q9r\xfd\x9f\xf7\xd2Eb\xca8t(\xe3\xb2\x1c\xb7\x9e\xc3^u\x96\x99_c;\a\x97\x9b9[\xc0\xaf\xb3\xa4e\x9f\xa3l\x8cv\xcd\xfe:h\vF\x974$\xbb\x99b\xae{\xbd\x05\xca,=\te\xf8\x8b\xc8n]\x1d\xdf~\u03fbI\x89\x06\xa5\x0f\u0103d\xd0\x18@\x15\xa2V,Q1\xd1Cv\x9b\u0300*Z\xf1\x1b\xad\xb4\x82\xdab*\xd6xZ\x8eCG@\x1e,\xf4\a\xa7?\x85\x92\xa8^\xcd\xe2\x18|\x0e\"\x90\x97iL5\xac\xe3P\x1c\xafC\xe0dm\x06$\x1eJ*/I3^l\xcfH\xa2\x05\xc9d\xbc\xa9\xd5X\r\xa0\xd1|\x16\xdf\xf9\u0528\x9ad8\x022\xb0\xf1\xeb\b0\xa6\x11w\xf35,)\x80#\x94\x1c#\xfa\xa6\xfbN\x8d\u07d8\x9e\xc8Y\xbe\xd6Wi\xc5Z\x8d\x91\xea\x10D\xb0\xa7\"CH*\x98!\u02b4\\\xb5\x92_\x01\xb9o\x17\x8e\xeb\xdeOJ\u051evE\xa4I\xa4:\x87\xeb\\\x14\x914\xa0zT\x80\x80\x1c\xa2\xb6\xf0#s4\xd0t\x81)M\xb6\u0275\x19\x8e*\xcau{\x1eSG\xa6:q7|'g\x16b\xbc\xd6/U\xb5\x9e\xb0}\xa6\u0644\x90\x95\xd1t\xe7\x040\xea\xc0r\x16B\u02f5E\"\x16A\x164EF\xbf\xb2\xe4r\xc1\x17\xd5\u008ej\xb8@G\xee\xcc0_~\x06\xf1Z\xac\x8f\u96c5\x97\x99\x14\xbeI\xe3\xd6\x00\xb2\x05$4Z\xd59i\xb2\x8ex\xf6\f\x17\u02a1e^\x94\xa0\x053\xbf\xee\v\xd5\xd4\xf5\xf6{\xc8\x1a\x9f{\xd6\x02\x8b\xedR\xd6\f<\xd7K)\xff\t\x91\xf0\xe6\n>\xaa}\u03df^g\xb7\xd0r\r\xa7\x02X\xc8\u0320\x14 9\x85|\\\x8e\x95\xd7S\x16\xf6\xac\xaf\xad\x89\xc6#\xd3\xdd\xe2;\xbcQ\xd7\xd2#pL\x9f $\xfe\x89\x8f4o|\xe6dz\xea\xe4\xb3\xca\u033b!2E\x1d\xf9>M\xa3\xec\x1e\b(\xdd*v\x00\x97)\xa4\u007f2O\x86\u0119`Y\x0e\u03c02\xec\xd91\x11\x01\xf0\xc3r\x01S\x02\xff\xe0C\xbai_\x04\xa8ZY\xea\xfeKw\xeb\x14T\x8f\x8fUu`\xbeD\x93u'\xfd\xa6\x9e\xf5z\u00a1\x84/t\x14\xc1\nv\"z\x86Q\xe9Y\xf2\u01b0\xc8\xd8O\xbd\x10tK_\xb5>\xd2w\xa4\x8d\xe2{\u07fc\u0201\x12\x82(dK\u0176\xe5\xf4)\f3)\xf1z\\'\f6\xfc\x1a\x03\xb1;f\xce\u048e\x1d*\xe1\xcd\\\bL+D\xe8\xf0\xc8\xda+X\xa0\x904D\xa3a\xfa\xfcZd*\xd8\x06_@*\x9dz9\x1b\xa5\xa1Q+\xc3T\xc4\x12E\x88\xe0\x17P\xddc\x14\xa5\xcc\x1b\x06?\x1a\x8c0F\xf9c\xa33\u00d3P8\xc7<8\x01\xac\xab\u0486\x9d\x1d\xd4\xdeIm\xff\xe4*Z\x98*\x955}\xda\xc7i\xf7\xc3fGX\xff\x88#,\x05\xc4\bNd\xd7\xd2\x06\x04\x1eQ\x0580\xfa\u05de\r\x9b\xa8]\xb8\xcaW\xb8\x1d\xf6\xc7\xc0t\nY\xf3s\xeft\xf9\x1c\x12>rY\xde{5\xca\xefk\x181\xe4\x0e\xf4\xe7\xa8\x00\x1a:g\x81\x936bj\x15\xa3\x9c\xca^_\x9b\b\\]\x92Y\xdc\n\x9eI\"\xbeU\xd1\xce\xde\xf1C)(B\xde+\x98\x8f\xc0\xad7\xb5*)\x81\xb9\x89X\xf7(\b\xe1/\x03q\x10\x9bpLc\x06A_X\xdad2\xb6\x93>\x04`T\x82\xecW\xe0\r\xb3:\xe7\x9c\xf3k\xd17n\x02\x97W\x84g\xed\xd84\x8brS`yY1V\v\xba5\u040a:B\x19\x1e\xd7e}>w@z\xea\xcd.\x04\x88\x83BC\xd22Ir@^\x98\xa3|R\xc32/nD\x97\x11\xab#\xe5d9\xecI`\xd9!\x86\ae\xe3\x93@>\xd9\u029an\xa5\xa6vl\x91FJI\xa1\xf3\xaad\xea-\xbfrr\x14\xf0I\xf98\x15 _\x93\xa7\x04\xb2\x1a\x04\xe5\xba\n\xa6\r\u7ea6z\xc6\x0e\x84\xd8`A\r\xe2\xfd\x14\x95\xc4\xcfA\xb7\xfc\xb4w\x1a\xf9\xad\x8e\x94\x14\xa1\x99\x1c\xf5M\f\xb9\x1cs;\x9e\xac\x9cJJfX\x94\xd3\x06\x93l\xa5\x97\xb0\x95\u00e9F\x1bp\x03:\u031a\xeb\xb2\xeb*]`\xd00\xe2w\xefuA\u041a\x84\x8dA2\xc6tU\xe0\xb3\x17\xb2R\x10|\xb9\xb2N\x89\xaac\u1ad8E\x13\xacTA-\x15\xfd\x9a\xbe\xdd\xc3\xc3\xde\xd9Q\xeb\x99\xe1\x19\u022d\xc2I_\xa8 \x16\xfbT\x16\x80\x83p\xd3\t\x1a\xe9\x9d\xc7\xd5\x18\xbd\x875\xf9\xe5\xa2@\xfb\xae\t\xdb\xe0%*_\xdf\xd4Y\u06c4N\xee\x91\x10\xf2.~\xb7\xb2\xca\xf0\u51ca\x18\u0748\xc0\xe8-+$\xcc\x00E\u0582\xd4\x0eWXN\x81\xd7|l\x9d\x80\xb4\x1e!\b\xac\xf1\x89.}W\xb31\v\xe6\x89=>V\xc2\x0fX\x89+\u0675\x92\x89\x9am\u02bd\xbc\u0508\a\x88\xc9k}\x8a\x99\x99\xd7B\xb3\xb4>\n\xff\xad\xa9\xafv4hW\u029ax\xbd\x01\x1d\xfc\xca\x17X\xb7\xb65\xc2\xe9c\xa9\a\xec\x85\xd7T\n:\x02\u9c29\xa9\x84\x1b\x94\x0e\xb6\x18\v\xbbt\x10s\x1fZo \xd5: R\xb7Tz\x89X.\x06EMj#\x9a\xa8-\\\x9fi\x83\x036P\a1\xa5\xd1x\xbeF\x9c\xf0\xc5KE \xf4\xbc\xb9\x12\xd0 ^K#9\xc0\x14F\x03n\x8bZ,V+\x92~\x9f\x0e\x85\xf4;X%\x1a:~e\xb1\xa9\x84U\x89;~\xee\xdbi^\xec\x9c{U\xe07 u\xf3P!\xe6\u0497\x97\xa8\xb4\xe5\\\x92w\x03g\xc6U\x9d;\n\xadk\xe9\xe2j\xc6\xef\xd0X\xf1\x9e\u007fq\xf5lX\xa7\xba\xd2\x00\xe3}\f\x89k\xd1\x05\xc7E=a\u8d6dAX)[\x1a\xdfVg\v\xcd\n\xa8JV+\xea\x1d\xf0\x89\xfbB\x17\xf1,\xeb+&\xa3\x81\x19\xea\xc2\u015c\xcd;p\xe2\x8d?B\x04g\xe2\xdbJ\xcfU\x88\xa3\xbc\x8a\xe6}\xc9&\xf0E\x95-\xe8'\xd3n\xf68q\xaf\xba\xa3pU\x0e\xe9p\f\xc4\x1f\\\x06\xe5Zj\xe0\x14\xc9k\xddL\xb2\xa8\xf9\x12?\x1fAC\t\x8c\x9e\xb8\x13s#\u0581\n)\x94\xf5\x0f\x0eLan\u028b\x90\xb1\xadP\x9e{\xe3\x98\xee\xdam\x9fu\xa1\xb1\xe0g\x9b\f%\xc4\xd5\u0376k\x92+\x99#\x15XY\xa9\xe4\xa8\xda\xfaF\xfd\xfb\x05\xbf\xa5q\xaf\xd3\rx\x93*\xe4us\u075b\xf0\xef(\u0372\r\x0fd\xa5\xa3\xb0\x80\xf4\x16\xd9\xef\xf8BA/D\\\x93E[\xd3\x0e\x91\xfd\x16\xadf\xc9I!Sj\x1bg\x02-\x1d\xf8\xa3oC\x90\xa1\xc1\xf1&\xd6Ztsk\xd0\xd4,[\x9a\x14K\x94<\x81(\xc7S\xcbM\u1aba\x18#\xe5\xcd\xdbr\xdf\u007f\xb9z\xc3|\u0736\t\xda\xec\x18\u0166\xdb\x1b\u007f=\x05\xbd\x13@\xeb\x8d\xff}\x94\xe2\tQ\xddv+|\xc0!=\xfa\xbc\xc6\x10{\x8a\xadB\x8d5\x14\xe1\xd0u\x1bn\xae\x94\xfb@S\xe2\xa6\xc3\xcc\xd7t\xdf\x0e\xc9\x1f\xfa\xfc\xaak\x1ce\x93\xba\xf5\vZu w\xce>\xdb\xd8\xc6S\xe0\x8b\x92\xa6\xbb+\xbb\xaeZ\xae\xcf]pJ\x97\xb7\r]N\x002d\u02bd`\xa4;\xcfz\x8cM\x9ds\xae\x8dD\u039b=\t\xc1\xff\x9by\xd5\u03135dc\x95\x84-@\x14\xc6[\xddu\x0f\x16\x84\x00G\xcd\x18\xe0\x9a\xf1*2\x01\xffq\x87\xdf\u0508XE,\x83\xae`\xd5xY%k\xb8p\xa7\x84\u0139\xb0b%\xb4{\xe2\xc7\xf6E.\x13\x16\xdccXh\xe9\x1e\xa5\x90\xffWy\ufcbc\xe7\x84\u7887\xe7a{\x0f\x9ak\x97j\x06\xcb\xe72\x95\xa93:\xd0\xce]\x05\x85\xb5\xdb\xd0I\x16\xf5\u0484!\x15jp\xb9\xdeGPy\xfcT\x8d\x19\xd9\xed\xb9\x9d\x05\u05d7l\xff\xcc\xd3\xe3\x9d=\xd9\x17Cvx\xef\xe1\xf9\u0701\f\xa0{\x8cX\xbb\xf2\x81\b\"\xca:\x03\xd4\xf2z\x1a\xd7\xcd@\x92.\r$,\xa1\xbc\x93^\u0452\xa9\x01F\xe7:\x1a\x02\xa4\xab\x03\x8c\xc1$\xac\xf6\xfe\x8cY\x1a\bR\x1e*\x86\x8b\x02\u053eS\x1cBijBkh\u00a6?:\u007f\"j\xad\xd4\x0e\t\xee\x1f\x96\xed\x12\xe1j\xf7l\xfb\x90C*X3C!\xc7\x15\nX\xf8\xa2dY#Yl\xb5\xd6y \xcb|\x01\xc7\xf4f\xf4Vwa\xf9\x16\xf3J\xefm\x8cdYP\xfe*\x17\x11\xba\x1c\x8bAT\xa6\xda$g\xbc\x9dE[500\xa0Te'S\x01\xbb9\xd3=\x9c9\u0264\x807)\xe1\xcc^\x9a\u04e3\x96\xf8\x95e\xb4x~1MX\x89Y\xd2\xeb\x91\xfbx\x15%T\xb1P\x11\xe3*|\xf7-\xad\xef\xe1\xec\x96L\xf2\x11\x89\x8b\xfd\x91\x8b\x84\x80\x10\xecm\x91\x14\xfe%\u065b\xf5\x13\u05cd;\x89\x17\x8d\xc0#\xbb\aiG\x87\xd3IL\U000ac0ba\xd53\x16\x87\xee~\xcdp\xf3O\xccRYUH#3\\\x12\xfc\xb8\x94\xaf\xcd\xc3\xf8xZ(\xd7S\x1e\x1e\x8aLf\xd0\u0568\xe6\xf7b\xbf\x9a\xb8\xac\"\x05\a\xf7kT\\`\xa2gf\x84\x90\xb09Mf\xf0W%4\xfb'\xcbB6\v\xe9\x04}B\xaa^|X]\xbe\xbc\x84`y\x88v\x1e\xb5e`\x8b\xc8\x19ty\x1e\x14\xfd\xf3\xde%\x88\x9aS\x80\xaf\xf3\x10\xeb\xe6\xc9e9\u0443>\xb9\u03c0\x14_\x8f\xfa\xc4\xff\xad\xe4\x9e(u\xb9\xebL\xef\xcd\xcfU\xe8\u05dc\x9fu\xf7\xd9i\x8b\xa2\xa4\x92\x9b\xfc\x17\xa8\xf7\xc0\x05\xbf\xa5\xa7\n^\xa4g\x83(i\x91\x9d\xa6\xbb\xcf\xfd\x19\xf5\xba\xea\xf3\x8e\x9b\xddg\x96E\xa9%\xf7\x04\xbf\xa1>\x01\xdc6\xa8\u007fGw\x91\xfb\x99\x1a\xcf\u03f1\a\u056b\xda)\xed\x11\xf5\xc7\xd8\u035e^g\xb6\x15\xf9w\x80\xbf\xb6\xb5\f\xb7\xb4\r\xb7\x1d~m\x9b\x86\x81\xee\xed\x1f\x0f}k\x82\ub235\xed\x9do\xbcZ<\x9a\x9d\xb7T\x00\u9745\x0f\v\xa0\xbf\bB\t\x06W\x1a\x91\x16\xc6\xc3Hg#\xa07\xfft\x90\xe8Zr\xf6\xa0v\xeb\xe6\x15m\xd9\xd9p\u05c3\xbfw\xbf\xe8\xcc\x01mC\xd5jv\xf9\x99\b\xd77\a\x87a\xcf\x19\x83\xf9\x02\x91\xa8\x80\xcf\x1e\xf0~12\xec\xfd\x92KG\xa5\x84\x93}\x13x\\m\u033b\x9f\ua8f6\x8e;d\xc9\xf3\xb7\xe8\xb4\x11H\xe9\xf3D\xa2\xdf\x179\x89\xc6@%\x84j\xebu\x80\xce\xe2\xe8\xa0w\xc8'S\xe6z\xaaT\x9d\xfa`\xdd|2\xf0\xbd\xb6\xefO\xd3\xce\xf8?4\xdflC\xaa\x17\x06\xa9\u055cB3\x965\xcc\xf5\xd3\xee\xd7}b\xfaq\x13h\xec\xc2S\x91_\xc8\b\xe3\xe8}~d\xfb\x9f<=\xde\u0693\xfd0\xa4nhR*\x1c\xa3\xfd\x1b\xa4\xeat\xf8\xbb\x88\xb3\v9R\xffy\xe6Y\xc13\x06\xb0\u0312\x0fM\x0e\xadj\x8e\x0fO\x0e\x03\xed\xf6\xe7\x8c\xe7\x053#`\xf4G\xe0\x02p\x9b\xc2D\u0626\xf8\xc63\xe2\xdc\xff\xc5b\xfa\xb3\xa1b\n\x1e&\xee\x90{\x87'\f\x91b\x11\xb4^\t\xeexdF\xda 1W\x1d\u05a9dy\xe4Q\x92\xe2\x13\u04a3\x19\xcct\x1bF\xa0\xe3\xb1\xe0(\xfc\xbb\x9d\xe7\xf8\x94\xe6\xb8\x05]\x12\xae\x11r5\xd8\xc8 \x1e\x8c\x00\xa7\xcb\u0321\x14\x06\a\xaf\xf2\xa4\x886\x87I\xb3\xfd{\x12\xb5\x91{\x8bj\xa6X\x99AI\x1b\xa46l\xfb\\\x97i\vk{+3\n\x94\xe5\xba\xe2\x1a\x1c\x1b\x1d\x9c\xeb\xda%\u07ae\xf8qd\u43b8n\x9fI\xd1\u02a5$\xfb\xd9\x11\xf1\xcb\xd1\xe9_\xa4\x03\xd4\xcd6E\xaeY\xde3=\n\xcc\x0f\x01\u0347\u0774\xe7\xcei\xdd\x0e\x9f\xa8d?y\x1b\xda~v\xd2\"\xfb\xd4\t\x9d-\xed`@[\xf6fE\x98(\x90 s/3c\xdb\xfc\xefH\x1c\xc4_\x90\x1dAK\xf3\xac\x02>\xd3\x17\x10\xbb.\x9c@\f\x9dXD\xec91\xaa\x1b\xd8+5\xf3t\xa07\x1490\xbcL%\xbd{\x01\xa4\u04b8\xa3\xf1\x9cos\"\xa3;\x97\xe6[\xc0\x97\xeaC\xd9V\xd6\xecM\u0541IbRUb6}\xb2V\xbf\x1aQ\xfc\xfb\xa6\u0742\xcf\xf2RXl\xa4\xb7*\xaaz,w\xfe\xb9\xce\xdeZ\xb5\u064f\xc7\xf5\u0266\x86\xc3\xd3\x04\xcc:t* \f\xf9\x15\xec\x97\u050e0\x1f\x1bz\"\x9fT\x0e\xad\x8a6'M#E.\xb3Ez\x16\xc9m4\x96Qs\xef\v&/\n\x9d\xf7\xcd'\xae\xab\xd3\xc2\xc5\u007f\x17\x8e\xe9\xcf\a\x88q\xa2\x89\xf7\x03A \xfe\xf9\x97\xae\xdae\xfd\x98U\xda]E\xc0\xe2\xe1+\xc7\xfe\x99\xb2\xb8\x96\xbe\xe9\xc2C\xfd\x8c\a\xf5\x86#\xcc\u02abU\xb3V\x9b\x16q\xea\u03c9\xa8\u007f\xceQ/\xb8\u03baZQ5=\xfe\xf3\xb9f\xeez\x9b+\xc0\u007fk\xfe\xdb\xeb3\u015e\x95\x8eM\x1b\x85\xd7\u007f\u031b<\xa7pYYNw^?g\x9dwo\xf1\xf5\x00%\x8e\xbb\v/\x83)]Rm\x82O9.i\x18a<64\x87\xfeP5qR\xb1-\x90g\xfeCwp-\x00<||q|\x91\xa1\xea\xe3y\xe3y\xc7@\xf6T\xce\x12vt\x10s\xde\xe3\x01^\u7444\x90c7\xb9\x89\xac\x83\x16\x138\x9e\xc5(\xd9h\xdb\xf2\x04\xb0\xb8\xe5\xd0\u0231\xbc\xec~<\x98}\xf7\x9c\xdbY\xca\xc3o\xe5i\xf5\xde\xf3\u013b\x1b\xb6\xb8\xfc+>`1\xb1\xde<@\u0373\x0e\xac\u02a6\x89\xb7\xbey\xe7Z\xf9\u02fdug\xba_X\xb0t\xffn\x01:c\x8f\xab\xc8fm\u02daq\"\xaf\xed\xf9\xdb\x00H\xbe\x02?,\xfb\xf9q+\x8b-\x920\xd1s\xcfZ\xee\xb3U\xdf\x0f\xbc\xb0\xb6\xc1t\xf3\xc4\x1f7\xedrd\xb6.\xd8x\xc0W\x80\xd2\xf1\xa7}\x12\xe7\xe9\x8bo\n&v\xbf\xb3\xf0\xee\xb9,.\n\xa1S\xe7\xdf\xe7\xef\x9ex\x95?}A\x02e~X2\x90\x9e\xe4\x8f\xceI\xca\xca\xc4Fm\xc2\x13C'\xe1\xb1nx\xf7\xef.\xed\x91\x14\f\x93\x1e\x03\x16\xd9:%to}\u3b78\xd1\xe1\x88\xc5w9\u007f\xdb\xd9\xf0z}\xd4\xf4\xc1\u0466\xb4N\x9fdNP\x89t\xfb\ue395\x19^\u07c3Z\xf0?\xa7\xaf\xf5\xb4\xa4b\xfc\xd3:\xb6'EU\xf7\xe4\xf0\x96/\x12\x1bL\x9a\x1c\xb9\xdb\x1bSRy\xbe\xfa\xb3\xad\xff\u007f\xf3\xae\x12\xdf$I\u0365f\xf5l\u007f\x9a\x9e\xf2\xdb\xd4\\r=R\xc2F\xe7\xc4\xf2\xb0Y\xb2\x98\x06/\xe5\f\x88\xeek\xcf`\x8fn\xd5\x1d\t-/>\x83\xa4#\x0e\xf9$z\xab]\xb5\xb6\u0119\u046a\x92P\xafx\x1e\xb3\x86\x96\x8aV!\x9be\xf2\\l\x8b\\\x15c(O\x9f!dT\x9d\f\xe4#\x99\x13t\xaf9\u007fUm[\x89&\x02&\x8be\x96E&\xc0\x93Q\x1d\xc2\x14up=(\xf5\xe5\u03f0\xe3\xec\xdc\u05f9]@\xf4\xf0\xe8Z\x19\xe3|\xeb\x8e+\u048e\xc6\xf3q\xad=\xacK\xb5+\u01cf\xae.\x9f^M\xdaJ\x91f\xf8\xb5\x03\xc9Q\x10\xad0^\xf2\x1e2\x1e\xf7\xae4^t,\x9f\xf6J\xc6-\xd8\xf3m\xf9A\v\xde\x1a@\x1c2^\xb4MP\xfd\xe9U\xec\x96\u7626\xa0lJ\xb2\xcbt\u0319\x81\xb4\x94]v\xf9b\x03\xe4\x9f\u0672n\x19 \xa0\x1fW\aHeqJ\x9a\xe4?\xceO?\xfaK\x82$!\xc28\xe0\x8e\x1e\xb1\x820\xe8\"\x9c\xda)&\xb6\xdcW.\t\xa9\x95\xcf\xfd\xb1\xfaz\xc3\x11\xcbX\x96WR\x8e\u0115\x9c\xb0=\x84\x81\x88\xe9\xe0\xfb\xad\x87e\xe7\fb5\xaa\x10C\xe6\x87;\r\xd4\\\x8c0\u03bf\">k\xbbe\x92Y\x8d\x0f/\xdcGBJ\xd5(\x00\xee\xb7\xf4\xf41\xae~{\xd4\xfd\ue7a8\a\xfa\x1dc\xbc\xf4(\xb5{\x9c\xff\xbeb\b\xba\xb3\rXB\x8d\xd5(\x13\xb1\x83\xab\xb3U\xe6D\\\x80\xda\xcdmX\x92O\xa4\xe7zL\xe8\xb4\x1e\x93\xf4\xfc\x82Pi{\xc3\xe3\x1bw\x1an\x02\xa9\x93v\x95\xd6\xd4\xc1\u007f0<%|\xd2\xdaq\x90\x9a#\x1eD\xb8Q\xc6te\xa7F=\xa6v\\yp\xbf\xf7\u0720\xb4\x19\xad\x9aM\xad\x85\x01\n}\xc0J\xba\x1cW\xd9*\xa2\xd3\u01b8\x85\xa2\xc9B]\x9aV\xc0wj\b\"\xd8=\xd4~\xcd(\xfe\xf5\rD4\xc7\xe5\x05\xd1\u04fc\xbbM\xd2p\"\xff%\xdem\xb8\x01\xd4NE\xeb\xfc\xe6\x1e\xee\xdd\xf6\x0e\xc6\u00ea\xc1y\x916k\x8aS\xd8\x18\xb9VT\xbaf~ft}\x84\x94\xb8Q\xe2(\xf4\u0298-\x8b\xf3\x948$n\xb04{Z\xd6:a=\xf8\x86\xedQ\x12\x1e\xaf\f\x00\xd8\xc3g\xbf\x9c=r\xf6\x9c\xf0,KS\x10\xd8-O\xa8C\x8a\xa32]\n\x83\xbb_\xf1\xec\xb1\xd8~\xb5\xa3\x8c\x91\xf7\x05\xc4\\\x10\x94^\xf08\x84\xd1\xc7\xc6\x057\xa6\xa7u\x91\xd3\\\x0e\xdc\xdbh\xb5\xba\xc1\u0373\xa4\xa9\xd2\xe7@\xda\xd6`I\xd8$L\x8d\x14\x87\"t\xdb>t\xde\xfd\xde'KEw\xe3\xff\xa9\x97\u03af\t\xc8[\xbbf\xe7\xc8\x12\x8a\x8a\x05\xa4\u0643\xf3\xcdYM:\xbe6\x98\x9e\f\u06e6J?\xb2Jdz\x88rI4\xad\x87D{&\x18t\x1f\xb0\xaee\xd0\xc48\x95Sp\xf5N%&\xcdj'\x8f\x95\x18\xa8v&\xae\x1eX\x9cO\x15\xd0l\x1fw\t0\xef\xf9\x19\x98\x0f\xb6\xf4\x1e\x14\x16\xe7\xee\x176\xf4r\x1e\x18:\x98\xf7\xeaz\x0f\t~\x93\x02\xb5{\xdf\xda\xdf:\ue34fo\xbbw7\xc8[\u0177\xc0\x94\x13x\x11x\u02078\x94\xe9\u0372\u029c\x8c\vT{D\x87\xba\xd3\xca\xe9)\xac\u03b6\xcb$\x1d\a\xe70\u0250;\x06\xed0dk{\b\x03OdZy\f\f\bk`|\xe8\x14\xe1\x11\x82\x80\x04x\x9c\x00;\x98\x0e\xe3\x9a\x0f\xba\xee]\x9b\xf7\x88\xc9%\n\u04b1\xadR\x89\xb6\xf7\xb9\xf3\x15\xab\xce\xf0xN\xb4\x12\rH\x1f\x83$\x11Uz\u0258\x9f\xa6p\x02\xb9k\xfe\xbd\xd0;\xc1Ue\x1b\xc8Hv\xee\x18G\xfb\x10\xe8)\x04\xaew{\u0796E\xc5\xf3\xfd5,N\xa8>\x8b\u07c5I\u0318\xc1q\x11\xb4~\xbaW\x87?7'\x83ICe\u0567\x05\xc7zqa%Q\xf1\x02\x9c\x1a\xfc\xbb\xd1\xf1\xfc\x90_s\xe7\u017a\u007f\x91\xddi:\x9f8Q@\xab\xb6~B:.\x12\xfd\xae\xfb\x1f\xd4\x00\xad\u03e0e\x80J\x8f~\xab\x93\xd8\r\xa5\x18\x82R2\x82Gt7\x8d\xe7\x9buM\u017e!\xb3\x89\u0204@\x95k\x85\xe0\u0125\xcc\x19X.\xac\xc0M\x1d\xbe\x81\u7a86\x15\xc0rg.e\x9e\x18|D\xc0\x87\xbd\xb9\x84\x13\a\u03eb\x1e\xbf\xb5|vu\x97\x9bnn)\xeb\xbe\u00e0\xe0t3w\xd2)\xcf!\xc7&9\u0692o\x9f\b\xd58\xa7\xf7\x1e\u02bf\xb0\x94\xdf\u44b2\xd8\r\ae\xb4%\x0e\x92\xe8\x90\v\u056ftp\x8f9\\\x10\x80\x11\xa2\xc6\xe5\xf6\xbf\xc7Z7\xdc\xcet\xa9 \xde\xdet\xd8\xe6\xf0m\x00\xe6\x04'\xbf\xcf\xfe\xc1K\xe9\xa6t\x90\x12-y\xce\n\x0f\x8dW\x1a\xdfg\x86'\xfa\xb1\xa7\x84\u07a8H*\xc7K\xc8B\xeb=}\xec\u007f\xa0\xf0\xb1.Q\xf1\u007f\x85O\x03\u02af\xf5\x88\x16\xf6?\r\a\xfa\xe1\xe7C\xbc\xc1\xdfv\xf8-\xe7\u8412\xe18\xd0\fO\xe7P\n\xc5\xe2\xdcfE\xfdD\xfd4\xf6\\\x91\x98R\x98\xcei\x86\u01c1\xa1\x12:\xe4\xdc\x16|\x9cnsm\x99\x13d\xe8tsM>\xf0\x1e\x86\x0e\x03+0\f^D\xe6g}\x9f\xb3V\x17G\xab\xf7P}\x11\x19\u03a5\a\xaa\x9dh\xf4z\x8b{\f\xdf\x19\xe0\xd0\x19\xaf\xbd\xd1\xea\xe2uh\xa6\xaec6\xab`\x10\x06\xd53\xdd~\x8d\u05fe\xa9\xe8N\xaf\x9e\xcd,\x18\xb2\x81\a\xbb\xa1\u007f\xd3X\xca\xfd\xb9\xed\x17\x9e/\x1a\xde\xf7\x19|(\t\xf1\xbc\xdb\x10(\x10\xa6yP\b\x13\x9a\\1\xdcJ\x84\x18\x04\x19\xad\xa4K\x86\x1e\xf25M{\xa7@\x01Y6\xccqM\xdb\xe1\u07d3_y\xfb,\xb8\x8f\xb8\xfa\xe0\xde3N\xb9\v\xe0\xf6\\\xcd\xdf\x1f\xc8@2vl\xe9\xf6\x17\xe2\xa5\x1e\xc7\xe0iL\xbfjC\xf5}\x9a\x8b\xaa\xd8\u007f\xf5\xcd\xfc\xf3\xf1c<,\x99\x05\u04f0\x1e^2\\b+#;\xf2\xd2\xfb\b\xe0\xbb{Q\xc8\xfcw\x8d\x8d\x19\x19\r\x8d\xef\vP\xd1\xd1\xf9\xa8\xe7i\xceLuS\xe3[\xb4^\x15Y\bihP\xab\x1b\x1b\x9e\xe5#mX!\xea6\xab\xddx\x83,0D\x11\u0449tz\"\x86HRa\x18tL\"\x91\x84Q1\x18\u06f1\x91\x88\x89\x18:\x03\xad\x02\xc4{I\xbf\x9cn\xfc\xf6\xde\x10\xb43\x88\x02\xcbC\x96A\x97\x05\xafj\xbf\xeds.C\x86\xff\x1c\xb6y\xe2\xbbo\x00Gr\x97\u075e|'\xc0\xc8K\xe5\xd4\u040c,V\x17:1c\u048f\xeb\x13\xd6I\xf7\xec\xf2\xe5fi##<\xeb\xbb\xd2\xc5\xff*\xf2,\xa1\x8bD8\r\x8d\xec*\u01f2\xf0\xa7\xd9\x18\xa1^\u030d,*\x88\x1b\xf7\xd3\xe8'\xe0\xab;\xdf\ta\t.*\x9b\x80\xd8T\u05dcLO\x18$0\r/\xf4\xe6y\x97Q\xe3E\u062c1\x15\xe6\xd4\xcb\xecP.,8\xba\u0146\x8b\xf4\x9d\xa6G\x16\x84Ka\xed\xefRu\xc0\x89R\x1e\xba\x15\xeb\xd7K\xa1\xf4\xf9aK7\x93WJ\x9d\x02F\xbfx\xae\x11\xbe\xcf\x18\x10\xb6\x06\xa3\xa6\x05\xc4\xc8\xe0UB\xb1WU\xb44\u075f\xe5\x9a\xd8U\xd2\xd1Rk\"2\xa2rF\x18\xd95\xc4}\xb9Z\xca|^\xd5(3;\xa6\x05\xbeLm\x88\xd0x\x92\x11\xcc<\xcai\u037c\xc10\xaf9M\xc9\xcbS\xc3y\x8d\xc1\xa0\x99\xa7\x9c\xce\xf3M\xed\x98\xcf8M\x9eF\x9e\xcf0t\xa8\xe9s\u06f2_\xae\xac\xbc\xccnk\x83\x8d\x93\xcb~\xd9v\xfb>\x05\xde\xe50O\xa9s\xe6_[P\x01\\w\xa2W\x1c)\xa7\xbb`\xbby\xa6\x99\x0f\xefJ8>\xc9k($\vW\x81\x8a\xae\u07ec\xab\xbd4\x8e\x1d\xc9r\xe8\U0004047c\xfc\x91\x83Kn\xf4@\x02\x90b\xc9S\x15\xa2\xb7)\x8d\xed*\xe4\xf1a\x0f\xcaT\xb9\xe8M\n,\xff\u06e2\x8c\x03:\n\xe6:\u0534a\x18\xfc\xf1\x8dW\x10sc\x05\xb2\xc8$N_#\xdeCp\xa5\xfd\r\xb3\x90\x9c\x98\x8d\xe3l\xe8\xed=|S\xad\xd6L\u057f\\\x98jbH\xa9\xcf.\x16z\x0e\x14\xd2\r\x01\x1b\xd6v0\berE\x19\x81\xc1P\xaaB\xb1\xac\xc5`\x10J\x15\xf22|\xce\xc2\xcb\xe5\xa8\xd4\xd2\xfd`lR,\f\x8b-\x1a,\x18\xdb\x0f\v\xe3\xb0c\xbdw\xce\u019b\f\xe3\xbc/di\xb6hb\u007fm\xf4\xfc\xe8\x92;\xbf\xf6p\xe5~\xccWH\x06#&\x94\x94J\xb8(JS\xb7\xd2e\xd1\x1a8\x8b\x86N\x8e z)(rq\xb2\xef\xc0d7@\xff\xf6\xa7X\xa2c\xbb*]\x94:q\xb4_\x96\x8cS\xef\x97\u0229u\xdb\xde\xf6s\v\x86\x92\xa9\x94\xf1\x05\xf9LMfifj\x82\x98\x0e\xa7\x05\xbd\xf5\x8c\xd2`\xd1l\xf5\xa5\v,w\xa1m`l\x1e\"6\n)\x03n\x83\x9fS\x83\x85\xc1\x12\x9c\xe4\xe3S\xe7\xff\xd0$qJ\x89,\xa0\x06dmSa\x9d\x8c\xf2\xc4\x03\xaf\xd5\x1b\f\x91\xedH\xc8\xe5\xe9\x82p\x16\xae\x8e@\xeeO\xafq\x1aF\xc0\xc90\xaf\x06\x965\xb7\xf5\x99\u05d0\xce*\xd4\xe3D}e\xd4\xe9\xee\x01\xfa\x85\xcdU{\b\xd9$\xd0\u007f\xaf\xa1Ni\xe8\x9f\xd9#\xde\x19\xdd\x05\xc3.\x17\u007f\xd1\xffbj\u03cd\xf7'\xb8\xf5?\xfe\x85\x97\xb4Z\x13^\xe6:\xb6`\x00N\x14c\xbb\xbe\xcf\xdc}S\x80\x9f\xc5\x1d\xa5$\x8d\xc7W\x03\xecZa\x02\xb6)N\xa5\x0ff\xc7\xe8\x82E*\xff\xa6\x84\x04l\xa3P\xa9\x0fb\xd3\xf2\x83D\u0280\u018b\xb2*Au\xa2\xc2\u7a2a\x16\x94)\x12\xd7\x02\x11\x99\xb6\x94\xf1\x97P\xd5\u0508\ay\xfc\xe5\xf5\x86M\x81\xf8\u0758H\xbbd_\t]\xf8^\xc1\x92a\xf2!\"\x1b\x19\xd3'\xd5E\x109\xcb\x19Tl\x8f\\r\x92\u46a6\xd90\x03\x9c\xbe\v~\x95\xd4\xd6j\xc0\xbf.>\xbdv\xe1\x18\xf6\x8b\xf1\xea7\xd7!.\xb3.\xed\xf2\x0e^\x1aX\xd0\x03\u04ff1\xa3}\x83]\xf3\x81\x06\xb8\xaae\x94\u07a8i|\xcb>If%\xbf6\xbf\x0f\u0175{TZ^^4\x95A\xcd\u0361\xd3i1Z-#::2'\aHcWR\x06\x933\xd3\x10G\x9a\xc0-\x9cl\xe5\x88\x1a:DI\xbd\x9a\xacd\u0729\xa1\xd8\x0e\xa6\xcf\xe0\x18\x98\xf8\x06\xf2\x80OK\u041d\x10\x11\x9at\xf0\u007f\xa5>\xdc\xe1\x97F\xe8L\xa7\x89r\x18\x8dZ~\xfdM\x9f\x1b\xa2\x95\x00\x16\u0276%\xd4QO\xe1\xd8\xff\x0e\u0307\xee\xd8\xdd\xfe\xd3k\f\xfaM\x84\xbf\x8a\xc6\x13D\xfd\xb1\xc7\xdb\xf9NN,\xbe\xadB\u024d\x96\xc2\xd54eX}\xb6\xa4\xdbW\x91\u0449d\xccO\u04fd\xb9\xaeB[L\xb8\xc4-z+\x16m\xbd\x97\x1bQ\xf6\xa7\x9cEf:\xc7\xfa\x87b\xc5\u03f8\x94\xc7Xf\xa0\xbf\xcdQ\x99#\x89\xa0td\x84\xf8\xca\x18\x87\x8c\a\xf2h\xdd%\xf2\ttj\xea\b\xa6@\x18U\x0e\u0488\u00ce\xf5\xb6\xec\x91\xfb\xa7\x12\xe5{Rs3\xc68\x05\x8d\xe1\x9f\u0109\x99$\xf6\xaf\x0f\x10\xe4\x1bE\x8e|/\xc6l\xa6\xc0S\xec \xdf@\xe8\xbcZJ-s\x16\xca\xd3#\u02fd\x05\xdcZ\xdf$\t\xa9\xf6\x84\xf4{I\xa8\xf8vE\x0e\x97e\x155|n\x9f\xf3\a\xb6{Ih|\u00ab\x83y\x8f\xba\x9d\xf9t\xcb\xc8Aqq\xde\n\xa3\xa1\x81s\xb4\xaa\x8av\xa4\xb2~/]\x973\x16\xb9T\xee]Yu:I\xf2\xad\xc7X\xfa\xa8\xb9N\x1e\xfa2\xb6\x96\xeeS\xc3]\xfa\xc5\xc0/9W\xc1\xa4\x17M\x88\x8f\x05\xfcx|5\x1c\x91\x1f+-$\bE\xfa\xa0X%\xbcY\x11\a\xdf\xc2I\xd2\xe3\xe3\u01b7]\x02\xdam\xaf\x05_2\xba\x03\xca\xfbm\xb7\x9b\xeb\xe4\xff\xbdQ\b\xef\xafS\xaen=\uff1f\xde_\t\x98\x9f6W_S}\x06\x99\xa5o\xe6\xc77\u04f8\xb1\x1b\xad\t\u0114xmb\x154\xf3\xe2\x1b\xa9<\xf6\x9dom\u0131Y\u05bd\xed\x8c\xc0!\u84eb\x06\xeb\u03b4ofO\xeb\v\xae]\xba\x14\xf7\x80\v\u02f8\xc9\x1a4\xdd\xde\u078aV\xc0xm\u00c0\xb7\xfd\x86,l\x05b\a\x11s\x8fk\x10\x05\x9a\xd0D\x9d\x06Q\xe39\xc9\x122%\x91\x92\x8fg>NcfJ\xd8\xc2n@r>DBJ.'x\x11\x88R\xaf\xbd>b\x12I\u01bd\xf3G\x93\x88O\xf0\xfa\x1e)\xae Q^\x13\x88\xaf)\x94\xaep\xc2k\x10\xf2\xdbS\xac\x18)\xf4\x8fE\u0083>\xff\x94'\x84g\x90\xd9|t\xb0\xbf\x04)\u0131\x91\xb0\xa0\xfbouB\xb8\xe6 \x8fyW\u0752\xbap\x9a\xbc\xca3`\x01\x98&\x9c}\xf8\u0437&\xa8\x8eT\xdbnx\xe3\xd5\xe2\xde\xec\\W\x01\xa0\x18\xe3\xc3\xef}\xab\x83\xb7\x10k\xda\rO\u007f\u007f\xe4[<\xfe\u07e4?&\x8f\xac'\x1f.<\xbc\u00c3\xb7\x8a\f\xde\xf7w\a\x1a~T\x03C\xaf\xb9\xa8\xacw\nO\"AS\xbe\xa2\xb3\xb8\x9c)_\x150\x02\xf1\xe4\u07a1\xb2\xaa\xa5=\x96\x00\xff\x1dU6\xb8\x8d\xc0\xe6{\xbe\xf1?\x18<\xa5d\x01\ucbdd\xfagw\x9c\xa9*\xaef\xf6\x90\xea!\xe7\x976\xcd\\P@N\xaa\xda>\xfe\x1e86`\x02\x98X\x1c\xd4uy\tp7\n\u00b3\x05\u0789\xff\xfb\xff\x88\xa7\xc7\xf7\x14e\xf8\xf1\x894\xa0\x12\xb50\xe4\x9d\x14C8\n\xe8[\xb37\xa9'\x83\x8c\xd9\xd3\xc3\xec\xf3aN\xb3\x1c\u0745\x90\x1b0k\x81\xfa\t\v\xf4N=%\xfc\x0f\x10\xb1\xd8\u0511\x9eXe\x8cc\xf6\xeb\xc7\xe1\xdd\xfa\x85\ndn2Xg\xf6j5\xb3_\xed\x86w\xab\x8dH HuQ\xc4\x13oB\x0e\xcc^0e\xf6\xad0\xa7\xd5\x0f\xefZ\x14\xc3\x11\x94T`\xf6\\dQ\u0580\xd8\x051:\x8a\"\bl~Vnr\x19\xb8\xa6\xf5V\xa3\xf5\xbf\xa1M?E\xeb~A\xcd\x129\xdcRL%\x0fQ\xefh\xbd\xedh\xfd/\xfau?\x11\xcfqz$\x85\xd8eQ\xe2\x81\xd9\x1f\x1c\xef\xd95II\xe9\xfe\xa6dG\xda\xe4\xa3\x1dZo\x1bZ\xff_\xda\xf47B7\xad\x87Jq+\xd0z\xfb\xd0\xfa\xed~\xddH\xa5\xd2zc'\xed\xde\a\x0ej\x05\xe9\x993\x9fO\xc7(\x01:\x00l\x17\xeeFf\xac\x11\x03\x94K\x8bQ Pn\n\xd2\xe7\xad\xf2F\xb9\n\x90?o\x95\x8fzRz\x06\xac\xcf\xdc\xe9\x03h\x1e-\xd7]\x06\xd2\xd3g9\b\xe0\x1e\x80\x06\xc4\x032\x96A^B:\x90w\x93t|\xe2I\xf2e\xa0\x8c]\xb5\\_\u07d4R\x0e\xc2\xd8\x00C\x02\x1cE\x94\x0e\x82\xd3S\xc3k\x14\"\xfd\\\xa4\xc9\x06\xe1\x06\x96_\xc5\u01f0n\xbb\xd2\x014\x15\xe7t\x00\xf8\xe7\xb3\xf8w\xb5\xca\xe3\xfa\f\b\a\xfb\x94\x15 n,\u0553\x90;\x92\uf30b\x01}R\x9e\xbajp\u05b4\x1c\x94\xe2\xe7\xdc\x10\x02\x05\xcfAZ\xf9\x1f\x03\xb0\xf5]\xc2\xcfAc\x90\xed&\x1co\xd3/w\xb0\x92\xd4v\u047f\xf3i\x03xi\x8e\xf8\u007f\xb8\xfa{lK\xfa:\xf3\x15\xdaZ)[v[\x14\x82K\xeb\xb8\x01\xf4\x0e8\x81\x98\xf5\xfd\v\xa1\x81\xef\xb6\xe1\xb9\x14g\xee%\xba\x84\x81\x14\xa6\xad\x04 \xe5\xf9[\x8f\x11\x1d\x88\xfc\xccG;-\xfa\xe2\xb3\u007f\xfc'X\xe4\xab.[\x91)K\xaf\xec\u007f\x01{\xbc\xaf\xb8\xe6\xb6\x1bn\xba\xe5\xa5\x1c\xf7\xddq\u05ea\\\x1f\xf4\xf9\xde\x03\x0f\xe5y\xed-\x83|:\x05\n\xe9\x15\x99Q\xacT\x89\x04^\t\x95*lV\xe5\x95j\xb5j\u0529\xb7\xc5Q\xbbl\u0560Q\x937\xde9\xe6\a\x8f\xfc\xe4\xb1C\x0e3:\xe2\x825\xeb.jw\xcai'\x82y\xeb\x84#ux<\x83\xbd\xb1\xb8\xa7-+\xcf*.\xd3Br\x8e\xaa,+\xaf,Y\xb5\xeb\x8a\xcb\x00") + +func third_partySwaggerUiFontsDroidSansV6LatinRegularWoff2Bytes() ([]byte, error) { + return _third_partySwaggerUiFontsDroidSansV6LatinRegularWoff2, nil +} + +func third_partySwaggerUiFontsDroidSansV6LatinRegularWoff2() (*asset, error) { + bytes, err := third_partySwaggerUiFontsDroidSansV6LatinRegularWoff2Bytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/fonts/droid-sans-v6-latin-regular.woff2", size: 11304, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiImagesExplorer_iconsPng = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01,\x00\x00\x002\b\x06\x00\x00\x00\xe6\xd6\xe6*\x00\x00\x00\tpHYs\x00\x00\v\x13\x00\x00\v\x13\x01\x00\x9a\x9c\x18\x00\x00\nOiCCPPhotoshop ICC profile\x00\x00x\u069dSgTS\xe9\x16=\xf7\xde\xf4BK\x88\x80\x94KoR\x15\b RB\x8b\x80\x14\x91&*!\t\x10J\x88!\xa1\xd9\x15Q\xc1\x11EE\x04\x1b\u0220\x88\x03\x8e\x8e\x80\x8c\x15Q,\f\x8a\n\xd8\a\xe4!\xa2\x8e\x83\xa3\x88\x8a\xca\xfb\xe1{\xa3k\u05bc\xf7\xe6\xcd\xfe\xb5\xd7>\xe7\xac\xf3\x9d\xb3\xcf\a\xc0\b\f\x96H3Q5\x80\f\xa9B\x1e\x11\xe0\x83\xc7\xc4\xc6\xe1\xe4.@\x81\n$p\x00\x10\b\xb3d!s\xfd#\x01\x00\xf8~<<+\"\xc0\a\xbe\x00\x01x\xd3\v\b\x00\xc0M\x9b\xc00\x1c\x87\xff\x0f\xeaB\x99\\\x01\x80\x84\x01\xc0t\x918K\b\x80\x14\x00@z\x8eB\xa6\x00@F\x01\x80\x9d\x98&S\x00\xa0\x04\x00`\xcbcb\xe3\x00P-\x00`'\u007f\xe6\xd3\x00\x80\x9d\xf8\x99{\x01\x00[\x94!\x15\x01\xa0\x91\x00 \x13e\x88D\x00h;\x00\xac\xcfV\x8aE\x00X0\x00\x14fK\xc49\x00\xd8-\x000IWfH\x00\xb0\xb7\x00\xc0\xce\x10\v\xb2\x00\b\f\x000Q\x88\x85)\x00\x04{\x00`\xc8##x\x00\x84\x99\x00\x14F\xf2W<\xf1+\xae\x10\xe7*\x00\x00x\x99\xb2<\xb9$9E\x81[\b-q\aWW.\x1e(\xceI\x17+\x146a\x02a\x9a@.\xc2y\x99\x192\x814\x0f\xe0\xf3\xcc\x00\x00\xa0\x91\x15\x11\xe0\x83\xf3\xfdx\xce\x0e\xae\xce\xce6\x8e\xb6\x0e_-\xea\xbf\x06\xff\"bb\xe3\xfe\xe5\u03ebp@\x00\x00\xe1t~\xd1\xfe,/\xb3\x1a\x80;\x06\x80m\xfe\xa2%\xee\x04h^\v\xa0u\xf7\x8bf\xb2\x0f@\xb5\x00\xa0\xe9\xdaW\xf3p\xf8~<\xdf5\x00\xb0j>\x01{\x91-\xa8]c\x03\xf6K'\x10Xt\xc0\xe2\xf7\x00\x00\xf2\xbbo\xc1\xd4(\b\x03\x80h\x83\xe1\xcfw\xff\xef?\xfdG\xa0%\x00\x80fI\x92q\x00\x00^D$.T\u02b3?\xc7\b\x00\x00D\xa0\x81*\xb0A\x1b\xf4\xc1\x18,\xc0\x06\x1c\xc1\x05\xdc\xc1\v\xfc`6\x84B$\xc4\xc2B\x10B\nd\x80\x1cr`)\xac\x82B(\x86\u0370\x1d*`/\xd4@\x1d4\xc0Qh\x86\x93p\x0e.\xc2U\xb8\x0e=p\x0f\xfaa\b\x9e\xc1(\xbc\x81\t\x04A\xc8\b\x13a!\u0688\x01b\x8aX#\x8e\b\x17\x99\x85\xf8!\xc1H\x04\x12\x8b$ \u0248\x14Q\"K\x915H1R\x8aT UH\x1d\xf2=r\x029\x87\\F\xba\x91;\xc8\x002\x82\xfc\x86\xbcG1\x94\x81\xb2Q=\xd4\f\xb5C\xb9\xa87\x1a\x84F\xa2\v\xd0dt1\x9a\x8f\x16\xa0\x9b\xd0r\xb4\x1a=\x8c6\xa1\xe7\u042bh\x0f\u068f>C\xc70\xc0\xe8\x18\a3\xc4l0.\xc6\xc3B\xb18,\t\x93c\u02f1\"\xac\f\xab\xc6\x1a\xb0V\xac\x03\xbb\x89\xf5c\u03f1w\x04\x12\x81E\xc0\t6\x04wB a\x1eAHXLXN\xd8H\xa8 \x1c$4\x11\xda\t7\t\x03\x84Q\xc2'\"\x93\xa8K\xb4&\xba\x11\xf9\xc4\x18b21\x87XH,#\xd6\x12\x8f\x13/\x10{\x88C\xc47$\x12\x89C2'\xb9\x90\x02I\xb1\xa4T\xd2\x12\xd2F\xd2nR#\xe9,\xa9\x9b4H\x1a#\x93\xc9\xdadk\xb2\a9\x94, +\u0205\xe4\x9d\xe4\xc3\xe43\xe4\x1b\xe4!\xf2[\n\x9db@q\xa4\xf8S\xe2(R\xcajJ\x19\xe5\x10\xe54\xe5\x06e\x982AU\xa3\x9aR\u0768\xa1T\x115\x8fZB\xad\xa1\xb6R\xafQ\x87\xa8\x134u\x9a9\u0343\x16IK\xa5\xad\xa2\x95\xd3\x1ah\x17h\xf7i\xaf\xe8t\xba\x11\u0755\x1eN\x97\xd0W\xd2\xcb\xe9G\xe8\x97\xe8\x03\xf4w\f\r\x86\x15\x83\u01c8g(\x19\x9b\x18\a\x18g\x19w\x18\xaf\x98L\xa6\x19\u04cb\x19\xc7T071\xeb\x98\xe7\x99\x0f\x99oUX*\xb6*|\x15\x91\xca\n\x95J\x95&\x95\x1b*/T\xa9\xaa\xa6\xaa\u07aa\vU\xf3U\xcbT\x8f\xa9^S}\xaeFU3S\xe3\xa9\t\u0516\xabU\xaa\x9dP\xebS\x1bSg\xa9;\xa8\x87\xaag\xa8oT?\xa4~Y\xfd\x89\x06Y\xc3L\xc3OC\xa4Q\xa0\xb1_\xe3\xbc\xc6 \vc\x19\xb3x,!k\r\xab\x86u\x815\xc4&\xb1\xcd\xd9|v*\xbb\x98\xfd\x1d\xbb\x8b=\xaa\xa9\xa19C3J3W\xb3R\xf3\x94f?\a\xe3\x98q\xf8\x9ctN\t\xe7(\xa7\x97\xf3~\x8a\xde\x14\xef)\xe2)\x1b\xa64L\xb91e\\k\xaa\x96\x97\x96X\xabH\xabQ\xabG\xeb\xbd6\xae\xed\xa7\x9d\xa6\xbdE\xbbY\xfb\x81\x0eA\xc7J'\\'Gg\x8f\xce\x05\x9d\xe7S\xd9S\u0767\n\xa7\x16M=:\xf5\xae.\xaak\xa5\x1b\xa1\xbbDw\xbfn\xa7\ue61e\xbe^\x80\x9eLo\xa7\xdey\xbd\xe7\xfa\x1c}/\xfdT\xfdm\xfa\xa7\xf5G\fX\x06\xb3\f$\x06\xdb\f\xce\x18<\xc55qo<\x1d/\xc7\xdb\xf1QC]\xc3@C\xa5a\x95a\x97\u1111\xb9\xd1<\xa3\xd5F\x8dF\x0f\x8ci\xc6\\\xe3$\xe3m\xc6m\u01a3&\x06&!&KM\xeaM\xee\x9aRM\xb9\xa6)\xa6;L;L\xc7\xcd\xcc\u0362\xcd\u05995\x9b=1\xd72\xe7\x9b\xe7\x9b\u05db\u07f7`ZxZ,\xb6\xa8\xb6\xb8eI\xb2\xe4Z\xa6Y\uedbcn\x85Z9Y\xa5XUZ]\xb3F\xad\x9d\xad%\u05bb\xad\xbb\xa7\x11\xa7\xb9N\x93N\xab\x9e\xd6g\u00f0\xf1\xb6\u0276\xa9\xb7\x19\xb0\xe5\xd8\x06\u06ee\xb6m\xb6}agb\x17g\xb7\u016e\xc3\ue4fd\x93}\xba}\x8d\xfd=\a\r\x87\xd9\x0e\xab\x1dZ\x1d~s\xb4r\x14:V:\u079a\u039c\xee?}\xc5\xf4\x96\xe9/gX\xcf\x10\xcf\xd83\xe3\xb6\x13\xcb)\xc4i\x9dS\x9b\xd3Gg\x17g\xb9s\x83\U000c82c9K\x82\xcb.\x97>.\x9b\x1b\xc6\xdd\u023d\xe4Jt\xf5q]\xe1z\xd2\xf5\x9d\x9b\xb3\x9b\xc2\xed\xa8\u06ef\xee6\xeei\xee\x87\u071f\xcc4\x9f)\x9eY3s\xd0\xc3\xc8C\xe0Q\xe5\xd1?\v\x9f\x950k\u07ec~OCO\x81g\xb5\xe7#/c/\x91W\xad\u05f0\xb7\xa5w\xaa\xf7a\xef\x17>\xf6>r\x9f\xe3>\xe3<7\xde2\xdeY_\xcc7\xc0\xb7\u0237\xcbO\xc3o\x9e_\x85\xdfC\u007f#\xffd\xffz\xff\xd1\x00\xa7\x80%\x01g\x03\x89\x81A\x81[\x02\xfb\xf8z|!\xbf\x8e?:\xdbe\xf6\xb2\xd9\xedA\x8c\xa0\xb9A\x15A\x8f\x82\xad\x82\xe5\xc1\xad!h\xc8\uc42d!\xf7\xe7\x98\u0391\xcei\x0e\x85P~\xe8\xd6\xd0\aa\xe6a\x8b\xc3~\f'\x85\x87\x85W\x86?\x8ep\x88X\x1a\xd11\x975w\xd1\xdcCs\xdfD\xfaD\x96D\u079bg1O9\xaf-J5*>\xaa.j<\xda7\xba4\xba?\xc6.fY\xcc\xd5X\x9dXIlK\x1c9.*\xae6nl\xbe\xdf\xfc\xed\xf3\x87\xe2\x9d\xe2\v\xe3{\x17\x98/\xc8]py\xa1\xce\xc2\xf4\x85\xa7\x16\xa9.\x12,:\x96@L\x88N8\x94\xf0A\x10*\xa8\x16\x8c%\xf2\x13w%\x8e\ny\xc2\x1d\xc2g\"/\xd16\u0448\xd8C\\*\x1eN\xf2H*Mz\x92\uc47c5y$\xc53\xa5,\u5e44'\xa9\x90\xbcL\rL\u075b:\x9e\x16\x9av m2=:\xbd1\x83\x92\x91\x90qB\xaa!M\x93\xb6g\xeag\xe6fv\u02ece\x85\xb2\xfe\xc5n\x8b\xb7/\x1e\x95\a\xc9k\xb3\x90\xac\x05Y-\n\xb6B\xa6\xe8TZ(\xd7*\a\xb2geWf\xbf\u0349\xca9\x96\xab\x9e+\xcd\xed\u0333\xca\u06d07\x9c\xef\x9f\xff\xed\x12\xc2\x12\u14b6\xa5\x86KW-\x1dX\u6f6cj9\xb2\x15\x89\x8a\xae\x14\xdb\x17\x97\x15\u007f\xd8(\xdcx\xe5\x1b\x87o\u02bf\x99\u0714\xb4\xa9\xab\u0139d\xcff\xd2f\xe9\xe6\xde-\x9e[\x0e\x96\xaa\x97\xe6\x97\x0en\r\xd9\u06b4\r\xdfV\xb4\xed\xf5\xf6E\xdb/\x97\xcd(\u06fb\x83\xb6C\xb9\xa3\xbf<\xb8\xbce\xa7\xc9\xce\xcd;?T\xa4T\xf4T\xfaT6\xee\xd2\u0775a\xd7\xf8n\xd1\xee\x1b{\xbc\xf64\xec\xd5\xdb[\xbc\xf7\xfd>\u027e\xdbU\x01UM\xd5f\xd5e\xfbI\xfb\xb3\xf7?\xae\x89\xaa\xe9\xf8\x96\xfbm]\xadNmq\xed\xc7\x03\xd2\x03\xfd\a#\x0e\xb6\u05f9\xd4\xd5\x1d\xd2=TR\x8f\xd6+\xebG\x0e\xc7\x1f\xbe\xfe\x9d\xefw-\r6\rU\x8d\x9c\xc6\xe2#pDy\xe4\xe9\xf7\t\xdf\xf7\x1e\r:\xdav\x8c{\xac\xe1\a\xd3\x1fv\x1dg\x1d/jB\x9a\xf2\x9aF\x9bS\x9a\xfb[b[\xbaO\xcc>\xd1\xd6\xea\xdez\xfcG\xdb\x1f\x0f\x9c499\xe2?r\xfd\xe9\xfc\xa7C\xcfd\xcf&\x9e\x17\xfe\xa2\xfe\u02ee\x17\x16/~\xf8\xd5\xeb\xd7\xce\u0458\u0461\x97\U000974ffm|\xa5\xfd\xea\xc0\xeb\x19\xaf\xdb\xc6\xc2\xc6\x1e\xbe\xc9x31^\xf4V\xfb\xed\xc1w\xdcw\x1d\xef\xa3\xdf\x0fO\xe4| \u007f(\xffh\xf9\xb1\xf5S\u0427\xfb\x93\x19\x93\x93\xff\x04\x03\x98\xf3\xfcc3-\xdb\x00\x00\x00 cHRM\x00\x00z%\x00\x00\x80\x83\x00\x00\xf9\xff\x00\x00\x80\xe9\x00\x00u0\x00\x00\xea`\x00\x00:\x98\x00\x00\x17o\x92_\xc5F\x00\x00\v\xaeIDATx\xda\xec\x9cmpT\xd5\x19\xc7\u007f\xe7\xeeK\xb2y\x01$\x8a6@\xa5\xb5\"H\xaaA\x89B\x03\xd9\xf0\x12,\x90\x88\xa6R\xb4\xd3\xc1\x8c\xad\xf8\xa5\xadL\xedX\x1c:\x05fDtZ\xa7\xe2\ai\x99\xa9\x03\f3\xca\xe8(B\x80vx\x19\x92@-\x06\x92H\x11\xa6(H\xd0RP\t\x91d\xb3I\xf6\xde{\xfaa\xc9%$\xbb!{w!\xd8y~3w\xd8\xec\u067d\xff{\xee\xb9\xe7\xbf\xcf\xf3\xdcsQ\xc4a\xdeRMS\x1aih3\x03\xc3\xdbi\xf9\b\xef\xf9\x8d\xb2\xe3}^kM\"(\xa5b\xbe\u007fx\u079dd\xb7\xe6\xa4i\xc3\xc80,:\xbd>\x15\xce\u0772\xe7\xaa\xeb\xea\xc3\xf3\x80\xce4\xd0\x19\xa0;i'\xac&lI\x99\xae \b\xc9\xd3k\xf6N\u007fA\xa7)eWhX\x02\x8c\xec\xd6d\xa3\xf5:`\xc5\xe4\x0e\xcf\xf1\xe5\xcbUJ\x8d\xa3q\u05944\xad\x8c\nb\xe8*Xg+\xbdb\u0504\xea\xe3jyj\rK\x1f\x9e\x9b\x86eW\xa0\xf4\x12P\x97\xf7W\xb1\x0e[\xad\xe0\xae\xf1\xc7U\x0fa\x17\x86\xa5\xdf{\xef=>\xfa\xe8#\"\x91HR\x83\xa6\xb5\u01b6m\x94R\xce6P\xe4\xe6\xe6RPP@~~~\xcc\uba7f]jhh\xa0\xb6\xb6\x96\u04e7O\x0fX_\xb4\xd6\xcef\x18F\xd2\xe7\xd5\xe7\xf31n\xdc8\xe6\u039d\x9b\u0339\x11b\x1a\x96\xd6L{\xd1.T\xb0\x13H\xef\xfbK\xfau\xdb\xf2,\xdc\xfd;e%k\x1c\x1ah\x9cST\x88VW\xd4\x05\xfd\xba\xc7\xf0.\x1cY\xb9;y]\r\x1c*+D\xd1/]l\x16\xaa\xfcJ\u05fa\xeb\u05ad\u04e6iRTT\xc4-\xb7\u0712\u0520\x9d9s\x86\xea\xeajgBx<\x9e\x01\xbb\x80\u039f?\u03d1#G\xc8\xcb\xcb#\x18\f\xba\x9a\x94UUU\xfa\x95\x86\xb1\x9ck\xb10\ud05b\f\xa6\r\x83\x03\x8aGo\u071a\xd2q\xf2z\xbd<\xfe\xf8\xe3bX)\xc0\xdb\xf5b\xdaJ\xfb\x11\xa5x\xab{c\xc1w\x15\xc3\x06E_\xef>\xa2\tw^\x9c\xac\xa8'\x94\xc7\x1eW\xfc\x92.\xdc\xf3\xdbK\xa6\xe5\x86\xc6Y\xc1G\u0417\xeb\x06\xee\xbd\x0f\xcfM7\x03\x10\xaa\u0689\x0e\x87\xbb\xec\xe6\t\u06f6\xc6}>\xab\xb8p\xc4\xf6=I\xe9\xf2\xaf\xb2G\xe8\xd1_\xb2\xef\x01\xdfM\xd1\xd7\xcdU`\xb7;\xba\x18\x8c\xd3\x1f\xce*Twow\xa5{\xf2\xe4I***hkk\xe3\x93O>I\xea\xd0\xd3\xd3\u04d91c\x06o\xbc\xf1\x06\x93'O&\x10\b\f\xc8\xc5\x13\x89D\xf0\xf9|dddPSSC0\x18t\xb5\x9f\xda\xdaZ\u03b6\x8d\x06 \xcdw\xe5ymY\x1a[\x83\xad\xc1P\xd1\xcd\xe3Q\x97\xb5\xf5|\x0f.\xfd\x1dw2X\x9a\xfc\xf6\x97\x991\xe3\x17)\x1d\xa7\xb5k\u05ca\u04e4\u04b0f\xbch\u07a6{\x98\x06\xc0C\xf7\xc2\xfd\xb7E\a\xb9\xf6\xc4%\u00fa\xc8\xfd\x1e\xdbZ\xbdt\xa9^\xd83=\xec\xbfY\x15\u0766Uo\xdd\xec\xb2r\x02\x05\x13\x01h?\xf8\x01\xa6cX\xa0\xe1~\x13\xbdZ/ea\xcf\xf4\xb0\u07e1\xff\x87\xa5\xb7Ao]rJ!{B\xf4uK]7\u00ca\xf6\x17\xe5]\xad\xf5\u0485\u02a5pkk+\x96e%\x1d\x11E\"\x11Z[[\xe9\xe8\xe8\xc0\xb6\a.$\xf1\xf9|\f\x192\x84H$B(\x14r\xbd\x9fP(\x04\xaa\u007ff\x1515\x9d\x16Xv\u0504\f\x15\x8d\x9a\xfdZc(h7\xa3m\x1eC\x91N\xf43\xe1H\xf4\xdf@?L+\x8b\xac\x94\x8f\x93\x90B\u00da\xf9\a\x8de\xdao\xbb\xcc(\x9f\xacI\xb3^\x04N$\x1c.\u03dcI\xbb\xeap\xa7\xabx\xf2Tm\xf0E\xa8:\x91\xb8Y\xcd\x04\xa5\\\xf6\x97'9\\\u7abf]\xa4:}\xeb+5\xad\xab\xabc\xef\u07bd455\x01\x90\x97\x97Gii)\xe9\xe9\xe9\x1c=z\x94\x8d\x1b7\xf6\xfa\xce\xfc\xf9\xf39}\xfa4555\xbd\xda\x16/^Lz\xfa\xe5\u0673a\x18\xd7\xecb\xb5,M\x87\xa9\x99w_&\x8b\x1e\x18\xe4\xbc\xff\xca\xdf/\xf0\xd6\a!|\x1eE\u0154,~\x1e\xccb\xf5\xae\x166\xee\x0fa(X]\x91\u00f7s\xbc\x94\xaf\xfa\x02\xcf\x00\x8d\x93\x90\"\u00f2Lk\x14\xa8\xfcX\x8d\x9b\x0e\xc2?>\x8eN\x88\x96\xf6\xd8;0\x14K\x80\x9f%*\xdc\xeei\x8f\xab\u06ef\x89\x8av\xa5\x8b\xf2\x8f\x02\xf2\x93p\bw\xba\x80\xd7\xeb\xbdf\x03[__\xcf\xe6\u035b\x99={6\xc5\xc5\u0144\xc3a\u05acY\u00da5kX\xb4h\x91c4s\xe6\xcc!\x18\f:\xc5f\u06f69s\xe6\f\x00O?\xfd4\u00c7\x0fw\xde7M\x13\u02f2\x06\xecb5mX\xf4\xc0 J\xf2\x02\xfc\xfe\x9df\xf6\x1f\xef`\xe4P\x0f\u007f|l(\xe3\x86\xfbX\xbe\xe9k\u7ccfM\xca\xe4\x9d\x03mD\xach\xe4\u056fK\xe3b}\xf3Z\x8e\x93\x90\x18\x86\xd6jN\xbc\xc6\xe3g5u'\xa3[\xa7\x19\xcf8\u0502\xe9/\xe8\xc4sB\x15_\xb7\x9f;X\xf0\xf9\xc3\xd3]\xe4\xa2\xc9\xeb\xea\xa3\x0f\xbb\u0281}>_J\xb7\xb8\x83j\x18\xd4\xd4\xd40b\xc4\b\x82\xc1 \xa6i\xe2\xf7\xfb\x99={6MMM\xd4\xd5\xd59\x86\xa5\xb5\xc64Mg\xd3Zw\xbb1\xa1\x89D\"\x8eQ\rd\xfa\t0$\xc3`\xde}\x99l:\xd8\xc6\xfe\xe3\x1d\x00|\xd6d\xb1a_+%y\x01\x06\a\x94\x13q\x9e:g\xf2\u0624LL;Z\xeb\xeaJ\x1f\xaf\xa7q\x12\\\xfc\xe8+\xa5\xf3\xe3\xddq}f\xb6rjX?y\xcd\xe6\x8b\v\xb1\xf7ax\xc8\x00\x12-b\xe4'{\xecv\x875 \xba\x98\xaet\xaf\xd9/wGG\aMMM\x8c\x1e=\xda1\"\xa5\x14\xb9\xb9\xb9\x00477\x93\x99\x99\t\xc0\xb6m\xdb\u0636m\x9b\x932\u039f?\xdf\xd9\u03eb\xaf\xbe\xea\xbc.))\xa1\xb0\xb0p@/\xd6q\u00e3\x93\xff?\xe7/\x8f\xf2\xba\xfe\xbes\xb8\xbf[v\xd0\u01aff\x0eb\xfd\xde\xc4kH\x12a]\u01c6\x05jh\u04b5\x05\xdb\xf4\x837\xa1\t\xacah\xb2\xf7ymm\xfb\x137\x0e=4\xe9%1\xb6v\xa1{u&\x82\xdf\xef\xc7\xef\xf7\xc7Lm\x94Rx<\x9e\xcb\"\xa6\xae\b\xac\xebX\xca\xca\u0298:u*Zk,\xcbr\xd6 \x01<\xf3\xcc3\xe4\xe6\xe6:m\xb6m\u01ec\x99\xa5\"\x8a\xf0\x1a\u046d\xcf\xc8\u01ebz}\u01f4/EN~\x0f\xf8.\x16\xd5O|a\xd2\xd0\xd8\xc9O\v\xb3\xba\u0565T\x9f\x1a\xa6\x18\xd67\u00b0>\x81\xe4Vm{\xb57\xe1\u026b \xee=\xe3\xce\x13\x1f\xa3.N\x02\x1d\xe9\x8co=^\xc3\u036d\xa9\xf8\xf7\xaa\xc3'@]\x9c|\xba\xb3\xaf\x83wuK\xecj\xa4\a\xb1\f+\x10\b\x90\x93\x93\u00f1c\xc7\xf0\xfb\xfdN*\xf7\xd9g\x9f\x010l\xd80\u01d4\xba/<\xed2\xb7\xeem\x86a8ib\xbc\x02\u007f*\xfa\xa5\x94r\xcc&\xf6o\x04\x9c\xfc2j)cs}\xec8\x1c\xc6\xf6(\"\x96\xe6\xe6\xc1\xd1\x02\xf9\u026fLn\xbf%z,^\x0fl\xdc\x1fb\xe5\x8fo\xa0\xb9\xedR*\u06f7\x86\xbej\xe3$\xa4\u0230\xb4\u05bb\x95\xe2Y\xf7W\x1a\x8d\xe7\x86\u0499\xf8\xd7\xf4n\x8d\x8a\xa9\u06fc\xfe\xaf\xfd\xd9E\xe3\xb9\xd3-\x9d\xa3\x12?\xe0\xdd\x10\xa7\xbfg7\xf4K\x97\xceou\xba:\xd9\xd7\xe8\x97[kMII\to\xbe\xf9&[\xb7ne\u05acY455QYYINN\x0e\x93&M\xa2\xa1\xa1\xc1\xf9l\xbc\xc8\u0276\xed\xb8mW\x03\xfb\n2_\xb6Xl\xfd0L\xf9\x84\f\x0e~\xdaA\u0371\x0e\xa6\x8cN\u3262,\xaa\xff\xddNS\xc8v\"(\xa5\x14\xa7\xceE\xa3\xac\xe2\xb1\xe9\x8ei\xf5\xa5\xd1\xd5&\x11\xd6u]\xc32\xf6B\x12\xc5T\xcd\xf3\a\x9fR\xb00\xc1\x15\xe7\xb6\u06ab\xe3\x84\xe7ic\xf3\x18\xfa\xd4/i?T\xcf\xf9\xd7\xff\x1c\xfb\xfbZ=?\xe1\xe0\xc1\xc4cC\x83\xbdq\xbb\x9b1\x06r\x17B\xeb!8\xb36\xde\x1e\x9eW\x13\u05a0\xf5_\xae\x8b\b+\x9eaM\x9c\x18]\u01f6c\xc7\x0ev\xed\xda\x05\xc0\xf8\xf1\xe3)++\xbb\xa6&\x94\xc81[\xfd\xb8\f_\xdby\x81\xff6[\xac\x98w\x83\xf3\xde\x1b\xff\f\xb1a_\xebe\x8bE\xd3.\xa6\x8fo\u05f6Q<6\xddI9-[_7\xe3$\xb80\xac]\u03e9\xd0\xf4\x95\xf62\xd0\xcbz6\u059e\x80\xafZ..\xbe\x8b\x1dS\xb4\x19\x1ec\x9d\x1b\xe1o\xff\xad*trv\xd12P\xbdt\a\xcd\xfd\x11\xfe\xdb\xef\xc0\u007f\xfb\x1d\\xg#V\xf3\xf9\x18\xba\xb6+]\x95\xb7%\xa4\x0f\x95-\x03z\xe9r\xe3\x83\x10\xf8^t\xfbj\x13\x98\u037dt\xb1\xf4:\xd7'\xfb*\xfcr\xc7z\u07ad+j\x9a8q\"\x93&M\x8a\x195\xdd}\xf7\u076cZ\xb5\u02a9Ou\xa7\xb4\xb4\xd41\xb6\x81\\\xc6\x10\x8fw\x0f\x84x\xf7@\xec\xac|\u00feV6\xec\xbbTh\xff\xf4\xcb\bs^>{]F\u0082\xab\x1a\x16X\xa8\x15\x06\xfaQ\x05c\xba7n:\xa8\xaf\x14]M\xdb\xf1\xacr\xfd$\xaf\xb6\x8d\x15\xca\u040f\xd2C7\xb4g'\xe9\xf7\x14\xd0\xdeP\x87\xf5\xf5\xd71\xa2+\xa6\x8d\xac\xacv\xff\x04\xb1\xe5Y\x81\xc7\xea\xa5Ks\x15d\x8d\x87\xd6\x0f\xc1\xfc:\x96=LS\xe3\xb7D\xdc\x1aK[[\x1b\xd9\xd9\xd9)\x19\xb8\x96\x96\x16\x02\x81@\u0705\x9b]QTwC\ub2aa\xba\xa7\x81]\xdbe\x91\x8ee\xf5Y\xb3\xeaI8\x1cN\xaa_\xd9\xd9\u0668\xf0\xf5\xf1\xa8\xdd\x05.\xa4|\x9c\x06\xf2\xe1\xf4\xff7\x9c39\xed%\x9d\x89m\x1f\xe8iZ}P\xbe\xeb9\u03fb='C\xa2\x91\xc1\x89\xd2)\x99\x86m\x1c\xa0\x9f\xba\x1aU\xfe\x9dm{\x92\xd6\xd5\r\xa5\x99\x18\xaa\u07fa(]\xae\xbe_\xe9Zw\xfd\xfa\xf5\xda0\f\x1e|\xf0A\xb2\xb2\xb2\x92\x1a\xb4\xd6\xd6V6o\xde\xcc\xe0\xc1\x83),,\x1c\xd0\x14\xa6\xa5\xa5\x85\xca\xcaJ\u018c\x19CQQ\x91\xab\x99Y]]\xad\xffT?\x86\va\xbb\xdfk\xa5\xae\x06\xa6\r\x99~\u01637\xefH\xe98\u0676\u0342\x05\v\u0135RiX\x00\xc5+\xb5\u05c3^\x12+=\xecF\xbdR\xba|\xe7b\xef\u025ei\x88\xdbT\xe6\xd3\x1f\x16{\x95a/\x89\x95\x1evs\xaaz\x94.\x1f\xb5\xad:e\xba\xba\xfe!/\x1ekI\xcc\xf4\xb0[\u007f\x81ru\u05d6\xa4t\x01\xbdv\xedZ\x1a\x1b\x1bSR\xef\xe9\xba\xf3\x97\x8a\xff\x06%\x19233)((\xe8z\xf0\xd9\xf5\u007f/SUUEmmmR\xcf$^\x8f\xe7\xf5\xd6[o\xa5\xa2\xa2\"\x99s#\xc43\xac.\xa6\xae\xd4\x19J\xdbS\f\xa5\x826z\xacB\x9fU\xa8z\xad\xf4\xf66\xbf\xe7\xd4\xfb\xbf\x8e]7I\xb6\xf6\xd28gj\x06\u069a\x02*\xa8a,p\x16\xa8\xd7Jm\xf7ft\x9c\x1a\xf9\xd6\xfbWEW\x1f\x9a\x93\x01\xc6\x14 \b\x8c\x05}\x16\xad\xeaAm'\x94vJ\xfd\u0b64u\x05AH\x81a\xc9\xc4\x13\x04\u16c2!\xa7@\x10\x041,A\x10\x041,A\x10\u0130\x04A\x10\u0130\x04A\x10\u0130\x04A\x10\xc3\x12\x04A\x10\xc3\x12\x04A\x10\xc3\x12\x04A\fK\x10\x04A\fK\x10\x04A\fK\x10\x041,A\x10\x041,A\x10\x041,A\x10\u0130\x04A\x10\u0130\x04A\x10\u0130\x04A\x10\xc3\x12\x04A\x10\xc3\x12\x04A\x10\xc3\x12\x04A\fK\x10\x04A\fK\x10\x04A\fK\x10\x041,A\x10\x041,A\x10\x041,A\x10\u0130\x04A\x10\u0130\x04A\x10\xc3\x12\x04A\x10\xc3\x12\x04AH-\xff\x1b\x00\x87\xb8\x03\x91\xaby\u0166\x00\x00\x00\x00IEND\xaeB`\x82") + +func third_partySwaggerUiImagesExplorer_iconsPngBytes() ([]byte, error) { + return _third_partySwaggerUiImagesExplorer_iconsPng, nil +} + +func third_partySwaggerUiImagesExplorer_iconsPng() (*asset, error) { + bytes, err := third_partySwaggerUiImagesExplorer_iconsPngBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/images/explorer_icons.png", size: 5763, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiImagesLogo_smallPng = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x1e\x00\x00\x00\x1e\b\x06\x00\x00\x00;0\xae\xa2\x00\x00\x00\x19tEXtSoftware\x00Adobe ImageReadyq\xc9e<\x00\x00\x02\xa4IDATx\xda\xc4W=l\xd3@\x14~q\x97\x8a.fh\xc5\xe8\x11A\aW\x02)\x12C\u0342@]2t(S\x9c\xad\x88\xa1\xc9\u009avCbH;\xc0\xc2P3\xb1 \x91HT\xea\x16g\"R\x87zi\xd5\r\x8fUY\\\tPG\xde\xe7\xdeU\x96}g'\xb5\x03/:\x9du~\xb9\xef\xfd|\xef\xe5\x85\xe8?I\xed6_Z\xef\x92\u025b\x9d8\x8a\xbe\xecP0\x13`\x06sxk\xf2\xc2ni\xd4\x00\xfe\x89W\x9f\r\tK\x01\v\xc0\xae\x00\x9cF<^;:\x03j\x05\xa0=\xde\xda%R\x19\xf1\xea0\xb87\x11\xb0\xc8\xe10\x95\xc72\x02\u03f7\x93\as*\xad\a\x0e}\xaf\x10\x14\xe2\U0001d5e7#\x1a\xcb\x03C\x13^{\x06\x15\xd4\x13|\u0246Z\xbc\x18\xaa\xbee\u0773ia\u07a4\xf0<\xa0\xdfW\x91\xf2\xe6E\u04e2%^\x17QH?#%\xa7p\xb8\xc2a\x8f\xd2\x1ewU\xda\xee\xf3\x1e\xbd\xdb<\xa6mw\x18\x1b\xa0\x93\xa7\xb6\x1b\xeb|h\xff\xa0\xc7\xf7\x1bJ\xfb%Y\x8d\x94\xb7\u0292Y\xab\xb7c/\xbd\xc3N\xec\xb1N\x86\x81G~\xe0\t#\x9a:\xb5\xadt\x8e\x9by\t\x02\xe0\xc1xW\x1bf\b\xc2\xfb\xbe\u07ca\x9f\xef\u031b:5\x93\x9dl$\x81\x1d\xfaw\xb2j$\xea\xd6\xd2\x11\xe66\xb2\xa0\xf7\x18bK\x8f\xb5\x8cY\xab\xc7)\xa1\xd3pt\xc3\xee\xa4Q\x12\x00\xbb|\x87\xb4\xe0\xf9\xa1\xa5\r\xa23'\x1a\x06\xdcr\xd3o\xc1\xd0'\xcb\x1b\xf1E\x1f\xbf\xbd\xa2g\x8f6\xe9\xcd\xc6W\xfasuI\u046f\xf3\x98\xbdx\u007f0\u07a3\xce\xfagf\xff.\x1d\x9d\rb#\xc1j\xe8\xd7\xf8s\x12\xfa\x19d\xa3\x88P\u04b3EQ\x9f\x10\xb9\x83LR\ag \x1e\x96\xacy<_\xa8\xeb\xf9\xba\x81\xe45\x0e\x87k\xf3uc?f4\xcai\x12A$`\xa8\xfb\xf6\xae\xae\n\xae\x1b\bw\x12_w\xc9\xd1Y?\x93\xdb\"\x01(\u009bSz\x81\x91\xfa\x11\xcfH^\u0756\x90Q\x12\u062f\xe2\u01822\x92\xd2O\x02\xef\xe9\xb4\xe05J\x03\xb9\u03abk\xe8\xa0\x12$\xf1t\x9c\xc5|v\x03,F\x14O9\xc30\xa9\x00\x0e\xa2-\x15\x00\x83\v\x00E\x89\xe9\x86\x02\xd5\xcf\"n=F?\x9dQ\xab\f\xd8\xc1\x95L\x1d\v\xaf;3\x02\x05K[\xda\u0447\u01d3@t\xb2\xaa\xa7\x90\x17\xec\xd88w\xe6b\xf0\x01\x83#\xdc\xf5\x8a<}\u0260\x87\u04cc\xb7\x18#\xf6K\xe4\x1c\xbd\xa1\xa5\xfa\x971\xc9@o\x8aqek\n\x03B1\xd2zU\xfc\x85\x01(\"\xb0*\xf2\x9f\xe6\x80/<\x1c\xe4\xb5`)\u007f\x05\x18\x00\x9a \xff\xd6\t\xfa6\xef\x00\x00\x00\x00IEND\xaeB`\x82") + +func third_partySwaggerUiImagesLogo_smallPngBytes() ([]byte, error) { + return _third_partySwaggerUiImagesLogo_smallPng, nil +} + +func third_partySwaggerUiImagesLogo_smallPng() (*asset, error) { + bytes, err := third_partySwaggerUiImagesLogo_smallPngBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/images/logo_small.png", size: 770, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiImagesPet_store_apiPng = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\b\x06\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\b\b\b\b|\bd\x88\x00\x00\x00\tpHYs\x00\x00\v\x12\x00\x00\v\x12\x01\xd2\xdd~\xfc\x00\x00\x00\x1ctEXtSoftware\x00Adobe Fireworks CS5q\xb5\xe36\x00\x00\x02\xb2IDATH\x89\xad\x95Ih\x14A\x14@_Uwg\xa6b\x96\x89b\x16\xf0`\u0508N\xc6\xfd\"\b\x19\x0f\xde\x04\x83\x97\x80\v\xb8&FQ0(Q\xf1,.\xd1Q\b*\".\aQ\xf0\"\xe8A\x04\x97\xe8Q\xc4\x05\xb2\b\x031\xb8`\x12\x93\xc9b\x92\xae\xccd\xba\xbc\x98[\x06\xa7\x9d\xfck\xfd\xff\u07af\xcf/J\x004\x9f8\xe5\xc4\xe3\xf1\x13\xae\xeb\x1e\xf6\x1d\xaf\u07fc\xe1\xe6\xcd[u\xbd\xbd\xfd\x9f\xa5\xd6n}8\xbc|\xd6\xe0\x00\u045a\x1a\xaa\xc3a\xb4v\x0fH\xcf3\x15\xa1Ph\xd6\xe0\xd3\x11\n\x85\xf0\xe0\x90a\x8b\xc4\xd2M\xe0h\x90C\xe0X0\x05\xa2p\x92\x82\x15+}\xc13\xde\xc0\xd9\u0604\b\x95\xe3\u015f\xa1\x9f=\xc1P\x02c`\xc64\x94\xfa\x13d|\a\xf6\xeamX\xd5[\xc1M\xc0x\x1f\x04%\"\xcf\xf1G\xe7\x1fkj\x85kQ\r1\xd2]m\xd8\x1b\xf6 \x17\xac\xfd?\x81\x10\x99'\xebD\x9bp\xa2M\xbe\xc1\xd3L)\xa5\xf8\x99H\f\xfa\x06\xfc+\x86\x12\t\xa4\x94}R)\xd5\xda\xd1\xd9\u016bWm\xb3\x06ok{M{G'J\xa9Vq\xecx\xb3\xd3\xd3\xd3s'\x10\f\xecX\x11\x89PTT\x94\x13|ttt\xfa\u04ff\xbfd\xc9\xc2]\x02\xe0\xd8\xf1f\xa7\xbb\xbb\xfb\xb4\xeb\xea#\x9e\xe7\xcd\xcdE \xa5L(\x15l\xad\xac\xac<\x13\xbb\u0512\xfa\x03\xb1\xb9\xfa\x1cZ7\xefV\x00\x00\x00\x00IEND\xaeB`\x82") + +func third_partySwaggerUiImagesPet_store_apiPngBytes() ([]byte, error) { + return _third_partySwaggerUiImagesPet_store_apiPng, nil +} + +func third_partySwaggerUiImagesPet_store_apiPng() (*asset, error) { + bytes, err := third_partySwaggerUiImagesPet_store_apiPngBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/images/pet_store_api.png", size: 824, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiImagesThrobberGif = []byte("GIF89a\x80\x00\x10\x00\x84\x00\x00|~|\xcc\xce\u0324\xa2\xa4\xec\xea\uc512\x94\xb4\xb6\xb4\xf4\xf6\U0010c28c\xe4\xe2\u4106\x84\xdc\xda\u072c\xaa\xac\xf4\xf2\xf4\x9c\x9e\x9c\xbc\xbe\xbc\xfc\xfe\xfc\x84\x82\x84\xd4\xd2\u0524\xa6\xa4\xec\xee\uc516\x94\xbc\xba\xbc\xfc\xfa\xfc\x8c\x8e\x8c\xe4\xe6\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xff\vNETSCAPE2.0\x03\x01\x00\x00\x00!\xf9\x04\t\x04\x00\x0f\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x00\x05\xfe\xe0#\x8edi\x9eh\xaa\xael\xeb\xbep,\xcftm\xdfx\xae\xef|\xef\xff4\xcbd0IY\x06\x03F\u0280T\xa2\x18HC\n:\xb0\xa0\x84Dcs\xb9}F\xa7H\xab\xc9\xe2 $(\x111iR\xb8$\x04\n\xf5\b\xb18\x1c\x16\x98\x93B\x90\xb8\x14\x9c$\x16\x11f\x04\x0er\"dfh\x87\x0flnp\x8ctvxz|~\x80#\x82\x84\x86&\x11\x00\x10\x9f\a\n&\x15\xa0\xa0\ry$\x06\v\xa0\x9f\x12\x98\x0f\x03\r\x9f\x9f\x05&\n\x17\xb4\x10\x01\x9d\xba\xa2\xa4\xa6\x00\xa8%\xab\xad\x10\xaf%\xb2\xba\xb6%\xb8\xba\xbc%\x12\xb4\x9f\x15&\a\x00\xd8\x10\x10\x11\xc9\t\xba\t\x03%\x11\xc1\x10\a&\x0e\xad\xd8\x02&\xd2\xc6\xd5%\xd7\xd9\xdb\xdd\xdf\xe1$\xe3\xbe\xe7\xe9\x00\xeb\xd1\xe4\xef$\xae\x19\xe3Fb@\x82t\xe0\xc4\x19\x03`\xaeD\xa9O\xa0\xfa\x91\x90\xf0\xcf\u06b4y\x05\x0fb\x03\x90\xf0\xde\u0086$\x1ej\xe3g\"\x80\xb1\v\xa3\x94J\x14\b6\x8c\x04\x03\x8a\x10\x91\x91\xc0\xd0\xc0\x183\x12\xb8\x8cA#a2\x1bJ\x13+i\xb5\x1c\xf1\xd2\xd41X4m\u07ba\xa0sL\x05\x02\x10\b\x04`\xc4\xe6\xc0\x9b8&$%X\x80`\x8c\x82\x06v\n\xd8\v\x14\x80P\x05F\x16\x9eF\x9dj\xa2\xea\xd5Hu\xb6v-a\xe1k\u0631\x99\xca& p\xf6\xc4\x11\fE\xae\f\xc0\xc0\x80\x91\b\x06\x18\x92LI,\x05\u0150*\x82\x01k!l\xf8\x01b\xc5O\x18\xa7x\\\x19\x88\xe7\u03e0C\x8b\x1eM\xba\xb4\xe9\u04e8S\xbb\b\x01\x00!\xf9\x04\t\x04\x00\x16\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc6\xc4LJL\xa4\xa2\xa4\xe4\xe6\xe4\x1c\x1e\x1c\x94\x92\x94\xdc\xda\xdc\xf4\xf6\xf4\xb4\xb6\xb4\f\x0e\fdfd424\x8c\x8a\x8c\xcc\xce\xcc\xec\xee\uc71a\x9c\f\n\f\xac\xaa\xac$&$\xe4\xe2\xe4\xfc\xfe\xfc\xbc\xbe\xbctvt\x04\x06\x04\x84\x86\x84\xcc\xca\xccTVT\xa4\xa6\xa4\xec\xea\xec$\"$\x94\x96\x94\xdc\xde\xdc\xfc\xfa\xfc\xbc\xba\xbc\x14\x12\x14464\x8c\x8e\x8c\xd4\xd2\xd4\xf4\xf2\xf4\x9c\x9e\x9c|~|\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x8bpH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\x8f\x9b\x88\x86\x80\xb8z\xbf\xe0+\n\xf3YHH\x8d\x8e(\xccn\xbb\x89\x15\x0e`N\xcf`PE\x91\u01c3G&\xf6}G({\tI\x83\x1ekG\"\x10\x1e\x10Iz|I\u007f\x91H\x87\x85\x95{\x89B\"&\x12t\x9f$\nD\x10\n&[\b\x9aC\x15\x13\x0e\x0e\x13\x05G\b\x04\x1a&\n\x81C\"'\a\x1a\a\x17\xa9\x9b\x17\xbb '\xbf\x16\xa4\xa6\\\u016b\xad\xaf\xb1\xb3\xb5\xb7\x9b\xba\xbc\xbeC\x05\x03\x9f\xd9\fD#\x01*\xde\x11\xb0D\t\x13\xde\xdf\x1d\xd1\x1e\x11\xdf\u07e2E\b&\xec\x01\x0fF'\xf2\x0e]E\xdd\xec\xe1E\xe4\xe6\x01\xd0\x15Q'\xcf\x1d\x11x\xf2\xe8\tA@!\u06e7\x06D\x1c\xa8\x98\x18 \xc0\x89\x81\x1a\xe4i\xf0P\xe4DFo\x01\x1c\x18\xb9`n\"\x01#\x1d\xd8}\x1baD\"E\x8b\x185r$\xe2\xf1\xde\u0212*N.l\xe8p\x0e\xd3\xc4!\x12\xcdi\xb8H\u0103\x86\x92\x1b;\x02T!R\x1fHo:\x89t\x00\xb9\xb2\xa5\u02a1\x18\x91\xce\x1crbiSnOsZ\xc3\xd6\x13\xc0\xb6!\n\xa8\xf6#\x82b\uadc0\xd1\n\xa4\x00hp\b<\x80\n\x89<\x00h\"\x1f\x91\xb4\xfc\xc4\ri\xfbT \x11\xb9t\x8d\u0725\x98\x97\x93'\x87\v\xea\x92rpJ\x19+\r\x13*\x18\x11\x81 E+\x05[q=\xd8u`D1\x11#\x0e\x048\xf0\xa0\xd8\xe4\xcaF\x96a\u059c\xa7\xf3\xe7\u041bF\xf32\rGN6;\xd1\xf4\x14@QL\b\x8a\x02\x94\x04!\xbft\x84\x11\"$\xc2\x1dA\xf70\xbc\xb8\x85\xe3\u024d`gn\u0139k\f\x06\xcc,h\x90\x82\xfb\x9b\xf3\xe8\xab\b\xd8\x15\xc1o\xfa\xf7\xf0\xe3\u02dfO\xbf\xbe}7A\x00\x00!\xf9\x04\t\x04\x000\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc2\xc4DBD\xa4\xa2\xa4\xe4\xe2\xe4$&$dbd\x94\x92\x94\xb4\xb2\xb4\xf4\xf2\xf4\x14\x16\x14\xd4\xd2\xd4TRT\f\n\f\x8c\x8a\x8c\xac\xaa\xac\xec\xea\xec424|~|\x9c\x9a\x9c\xbc\xba\xbc\xfc\xfa\xfc\xdc\xda\xdc\xcc\xca\xccLNLljl\x1c\x1e\x1c\\Z\\<:<\x04\x06\x04\x84\x86\x84DFD\xa4\xa6\xa4\xe4\xe6\xe4dfd\x94\x96\x94\xb4\xb6\xb4\xf4\xf6\xf4\x1c\x1a\x1c\xd4\xd6\xd4\f\x0e\f\x8c\x8e\x8c\xac\xae\xac\xec\xee\xec464\x9c\x9e\x9c\xbc\xbe\xbc\xfc\xfe\xfc\xdc\xde\xdc\xcc\xce\xcc\\^\\\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x98pH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xa7\x16\x01\xe2\x93\x10]\xbf\xe00\x93\xd2\xe8\xcc*\xc6H\xe6\x94r,\x06/\xb1|~\xbd\x80\x00x\x80\xe7\xe0\x15\xa2$yy\x0e\x14F&\x11\x11\nI\n\x87&\x8a\x87\x16H\x16,\x11,I\x16\x87\x89H\x86\x88\x8e\x11\x8dH\x8b\x11\x90D,\a\x81x\x0e\x1f\x90\n\x1a\xa7y\v\x11D\x05\x10\x0f\x0f+\x05G\x17\x04\x1f*%\x99D\x16\f[\b/\xa3\xc0/[$\f\xc6C,\t*\x1f\x04\x17\xccB\xb3\xb5\xb7\xb9\xbb\xbd\xbfC\xc1\xc3\xc5D\x02\x06\xae\x00-10\x18\x80\xe4\x00$C&\x10\x01\x13\x13\x01!\xdc0\x11\x14\xf3\xf3\tF\x17*\xfa\x01d\x18a\x00\xf0\xc1\x05#\x15\xe2\u0163\xd0\xc7\x1d\xb8\xbc=\"\n\xd0'YO\xdf\x02\x89\x06\x12pP\x82\x11\"\xac\x91\x82\ao\x94@\x1f\x1d\f6H\x85\t\x15@\x03\x9d\x83\x14Vh\xe1\x85\x18f\xa8\xe1\x86r\x02\x04\x01\x00!\xf9\x04\t\x04\x00\x1c\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc6\xc4DBD\xa4\xa2\xa4\xe4\xe6\xe4dbd424\x14\x12\x14\xd4\xd6\u0534\xb2\xb4\x94\x92\x94TVT\xf4\xf6\xf4trt\f\n\f\x8c\x8a\x8c\xcc\xce\xccLJL\xac\xaa\xac\xec\xee\xec\x1c\x1a\x1c\xdc\xde\u073c\xba\xbcljl<><\x9c\x9e\x9c\\^\\\xfc\xfe\xfc\x04\x06\x04\x84\x86\x84\xcc\xca\xccDFD\xa4\xa6\xa4\xec\xea\xec464\x14\x16\x14\xdc\xda\u0734\xb6\xb4\x94\x96\x94\\Z\\\xfc\xfa\xfc|~|\f\x0e\f\x8c\x8e\x8c\xd4\xd2\xd4LNL\xac\xae\xac\xf4\xf2\xf4\x1c\x1e\x1c\xe4\xe2\u4f3e\xbclnl\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x8epH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xafI\x98\x89\x05\xb9P\xb0\xe0\xf0\x15fI!E,I\xc6\xf11~\x06\x95\u0563\xc2H\x88\xef\xf8\xa5l\xf3\x00<\x02\"E\x111\x00\x85\x00+\x010C\x1f}\x86\x85+mE0\"\"\rY\x94fG)\x14\"_H)\x94\x8aH\r\xa1\x97\x95\xa6\x99D2 \x8e\x1d\x18\x81B2\x03\x8e\x8f\x13B\"\xb3\xb4\x85\x03\x9eB%\x04\x1e,&\xa2D)-\v\x1e\v3\xa9C)3\xc8'-\xccB\x14\n,\x1e\x04%\xd3\x1c2\x13\x10\x10/2G\xbf\xc1\xc3F\xc6\xc8\xca\xd3,+\xb4$\nC\x1a\b\xba\x00\x12B\n$\xf4\x00\xefC\"\x1a*\x01\x00\xc2+R\x82\x05@\x80\x11\x8c\xb48\x18\x00B\t#\x17\x02\x06\xd4P\xa0H\x83\t\x01\x01\x86 v\xeb\x9f\u0101D\n2L8\x04\xc6\x06z\x1e29\u0437B\b;}\x0f \fi!\x11\xa0\xcc\"32\xaaPA\xc0H\xfe\x88\x83\x00/\x18\x81\xb0\x13`\x80\x16EDx`\xe8\x01\xd6\u031a\r\x8d\xe4,\u0293\x88I\x94\x99h\xb0\x14\xb2\xa0\x91\xae\x1579\xd0\xdc\x190\uc408F\xab\x16\t\x01Uh\x11\xa2\x19\x8f&\xf5\xa0\xb3i\x91\xb1\a\xcd\nA\x1b `O\"\x10\xbc\x16\xe2'D\x1e={\x1c\xf0\xe9#\u0321\x80\x86\xb8 \x87\x14\x8cK\x92H\x84\xb8,\x1e\x161Q\x93\xa2$\xb6F7\x16q\f\xd9\xc8d\xb2\x95}\xb12\xd4\xc1@\xc5X\x19\xbe\xda\xe2 b\xb5\xae\x01NS\x94\xd0\xf0MA\xaff\x11\xd2]\u0616\xe2\u0082\x00\v\"l\xabv-\u06f6n\x10\x87\xf7\"p$\t|\x96\u0207I\x16%\x14h\x84\b\x10\x80p\x00\r\xed\x15!\xc0\x00$\xc8A\x82\v\xa9\xe5\xa1\xe1\x86X\x13T\x13\x9d\t\xf9q(\xe2\x88$\x96h\xe2\x89(\xa6\xb8D\x10\x00!\xf9\x04\t\x04\x000\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc2\xc4DBD\xa4\xa2\xa4\xe4\xe2\xe4$\"$\x94\x92\x94dbd\xb4\xb2\xb4\xf4\xf2\xf4\x14\x16\x14\xd4\xd2\xd4424\f\n\f\x8c\x8a\x8c\\^\\\xac\xaa\xac\xec\xea\uc71a\x9c|~|\xbc\xba\xbc\xfc\xfa\xfc\xdc\xda\xdc<:<\xcc\xca\xccLJLljl\x1c\x1e\x1c\x04\x06\x04\x84\x86\x84DFD\xa4\xa6\xa4\xe4\xe6\xe4$&$\x94\x96\x94dfd\xb4\xb6\xb4\xf4\xf6\xf4\x1c\x1a\x1c\xd4\xd6\xd4464\f\x0e\f\x8c\x8e\x8c\xac\xae\xac\xec\xee\uc71e\x9c\xbc\xbe\xbc\xfc\xfe\xfc\xdc\xde\xdc<><\xcc\xce\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x98pH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\xd6P\"p\x10\x98\xb0\xe0\xf0U\x12K^\x02\x83A\xe0R\xb4D0\v\x87\x8aCR\x88\xefwKK\xd2B\n4\x1d\x00\x06\x13}D\x04\v\x00\x89\x00\v\x04D\x13\x0e\x8a\x8a\r(F\n\x12\x12\x16Hz|I\x16\x97vH&\x9fI\x96\x12_H\xa5\x99F\x16/\a\x1e#\f\xaaC\x17\x1c\x91*\x0f\xa70\x17\x88\x91\x8bl0!\xbc\xbd\x1d\x1b\xa00\x16\f\xae\a/\xb2C\xac\xae\xb0\xcdB-\t+\x1e\x04\x17\xd20\x05\x11\x0f\x0f,\x05G\x17\x04\x1e+%\xc6\xce\xc9\x1e\xcb\xda\f\x14\x01\xef\x0f\xbfC\x1b\xbd\x00\"\xf3\x14\xf6\x89\x14B\x13\xfb\x89\x1ad\x98\xb5\xe2\u077b\x19F\xdc\xc1\v \xcfH\x85\x85\x14&\x84(b\"\x02\xbcw \xd0\xc1\x900\xc1`\x80\x04F.\x14\\\x88\xb0\b\b\x83\xef*\x10i\xd1`\x1fH!\x03\x00\xca\x10R\x0f\xe0\x82\x970^\\\xa4@\xa1\x91\xfeI\x94\x01T\x16y\xc0\xf3]\x00\x06E$x\xf0\xe8AB\x11\x06K\x17>0\xa2\xb3hO# \x06]\xd9\xd2^\x89!2\x00\x0e\xa0\tp\x11\u0387F\xaf\x9a\xd4*\x94\b\u044b\x1e\x90\x12Q\xba\xb3\xe9\u04cb\xf0\xa6\x16A\x1b\x00\x9eO\"3\xf0\xae\x98'\x04\x81=\x03\x94\x84\xe8\xdb\xd7\x0f\xc6?\x80\x02\t\xe2-\tX0a!% J,\xa2 \xab\u044cEB\xb8\xc0\x8bS2\xcf\x00\x94\x9dU8\xc0e\x864\x06'l\x050\xb6\xcb\u0782\xc4\xc1\x00\xd6q6CY\x05m\x16V\xb7\xd6F\xcd\x1a6m\xdc\x1ex\x88\x10\xae\xcd\x05\x17\xde\x12\x14\"b\xa1\xf7\xba\xdfG<\x85\x98^\xe4\u0147D\x1cFp\x87\xe1B\xd8\"\x17\x8e\x02\xf5\x9add\x0f&M\x12\xb6w\x8a\xaf@\x9b\x10\x05!$h$\x82\xdfT\x12\xf7\xf6=!\xc1eD\\@\x01\x06\x18P\x90\x983\x11\xa4\x10\x87\x03'@0\x1e\x1e\x14V\x18F\x01 \x94\xf3B.\x16\rv\xe8\xe1\x87 \x86(\xe2\x88$&\x11\x04\x00!\xf9\x04\t\x04\x00\x19\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc6\xc4DFD\xa4\xa2\xa4$\"$\xe4\xe6\u4512\x94\x14\x12\x14dfd\xb4\xb6\xb4\xf4\xf6\xf4\xdc\xda\xdc424\f\n\f\x8c\x8a\x8c\xcc\xce\u032c\xaa\xac\xec\xee\uc71a\x9ctvtTVT,.,\x1c\x1e\x1c\xbc\xbe\xbc\xfc\xfe\xfc<><\x04\x06\x04\x84\x86\x84\xcc\xca\xccLJL\xa4\xa6\xa4$&$\xec\xea\uc516\x94\x14\x16\x14trt\xbc\xba\xbc\xfc\xfa\xfc\xe4\xe2\xe4464\f\x0e\f\x8c\x8e\x8c\xd4\xd2\u052c\xae\xac\xf4\xf2\xf4\x9c\x9e\x9c|~|\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe\xc0\x8cpH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\xd8%\x83\x10\x98t\xb2\xe0p\xd5`HvH\x1a\x8f*T\\\x1c,\bG\xaa\xa0Z\x88\xefM\x93$$I\x9aB!-G&,(\x00\x00(,&D-\x01)\x87\x87\x17_B-$\x1b\x90\x90\x15'Ez|~\x80\x82H\v\xa0I-\x80vH\xa6!\x8bF&\x18\a\x1c\"+\xacD\x12\n*\x1c\x04\f\xb4B,#\x98#\x11D,\b\x98\x87\x1a\x9b\x19%\xc5\xc6\x00\x0e\a\xb4\xae\xb0\xb2\xbcB\xb6\xb8\xba\xd5\x19'\x11\x0f\x0f,\xc9E[\x1c*\n\xa1D&+\xb0\a\x18\xda+/\x01\xf0\x0f\fF%\xf1\xf1\x13eD\r\xcd(D\x1e\xcd\x00 p!$A\xc0C\x03\xf4exwo^\xbd{/\xf2\xb5\x89\x10\x0f\u0787sBBL\x80\aO\x81\x11\x06*8\x06\x80`\xe4\x03Gx%\x8c_\x0f\xb8\x050`b2i\x9a\x1f(R0b\xf9\xb6p\xbe\x81\v\x8fq\x81\xb8q\xe4D.\xccHg\x817w\t\"\xc0\x9bC\xaf\xc0|\f\x05\"H\xa5\x8a\x8fJr\x00G\x1e88\x1f\x82a\x80'\x0f\a<\u00c96\x1e\x84\xc2X|\x00\x11\x01\xdf)I\xec!\x81{xXa\x02\x06\xea\x85GB\x03\x13pP\x82\x11\"\x1f\xacpB\n\x1e\xd4Q\x02\x84\x11\x96h\xe2\x13&X`Kp'\xb6\xe8\xe2\x8b0\xc6(c\x8cA\x00\x00!\xf9\x04\t\x04\x00\x1c\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc6\xc4DBD\xa4\xa2\xa4\xe4\xe6\xe4dbd424\x14\x12\x14\xd4\xd6\u0534\xb2\xb4\x94\x92\x94TVT\xf4\xf6\xf4trt\f\n\f\x8c\x8a\x8c\xcc\xce\xccLJL\xac\xaa\xac\xec\xee\xec\x1c\x1a\x1c\xdc\xde\u073c\xba\xbcljl<><\x9c\x9e\x9c\\^\\\xfc\xfe\xfc\x04\x06\x04\x84\x86\x84\xcc\xca\xccDFD\xa4\xa6\xa4\xec\xea\xec464\x14\x16\x14\xdc\xda\u0734\xb6\xb4\x94\x96\x94\\Z\\\xfc\xfa\xfc|~|\f\x0e\f\x8c\x8e\x8c\xd4\xd2\xd4LNL\xac\xae\xac\xf4\xf2\xf4\x1c\x1e\x1c\xe4\xe2\u4f3e\xbclnl\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x8epH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\xd8,\x16fbA.\x14\xadx\x1c\x85YRH\x11K\x92q|\x8c\x9fAe\xf5\xa80\x12\xe4a\x8a\"\n#S\"\"0I\r\x81\x83H0\x81\rI\x89\"hF2\x1b\x0f\x00\x0f\x01\"E\x111\x00\x9b\x00+\x01\x87\x1c\x1f\x93\x9c\x9b+oE\x8d\x8b\x88\x81\x8fE)3\v\x1e'-\xadC\x14\n,\x1e\x04%\xb5B2\x13\x10\x10/2G%\x04\x1e,&\xa0z-\xb1\v3\xbd2 \xa4\x1d\x18\x97\xbe\x03\xa4\xa5\x13B\"\xd9\u069b\x03~B\xc6\xc8\xcaF)\xcd\x1e\u03fd\x1c-*\x01\xf0\x10%F\x17\xf1\xf1\x1a\x05E\r\x13\xf1\xf0!\xcb8\x88\xd0\x00\x0f\x9e\x02#%X\x14\f\x10\xa1\b\x8b\x15\xdaH\x1c\x14\xa2\x01\x018\x00\x12\x84( q\x11\x80\xc4!\x03\x17N$\x92pa\xc3\"!\n\u00bb`\x04\x82\x8a\x97\x01\x02\xb4(\"\xc2\xc3B\x0f\u05c6\xb4\xb8'\xcf\xc8\xfe\f\u007f/\t\x10\x81\xb1\u1887G\x0e:\xae\x10\xf2\xb0\xe3\x03\b:y\x06\x80Z\xe4\xe7\u02e0FBHeY\u0125?\x994=\x00\xc5Yd'L\x15T\x89\u0603\x17O\xe8\x10\xa2F\x1f\xd1P*d\xc1(p+\u049a-\x98v\xc8\u0698*\xdc\x12\x89\xf0\x95\x05\xbd\"&x\xe6C\xa5\x95-\xc0\"\x054|\x1d9$\xe1\u05d3C \xdc\xdd\xf4\x91\xa2Ep\x199l\xec\u0619C\xe4\xc9\bY\\FwaA\x80\x05\x11\xda\xdd\u02b5\xab\xdd/\b\x1e&\x10sUBC0\x05\xe3\xf4Dpv\xa1W\x89i\x9c:\x18\xd0\xe7+\x03^n\x02\x91\x83\x1b\x903E\xef\xdf\xc1\x85\xa4\x18\xbe\xae\xf8\x11@\x05\xb2\x13\x01\x0f\xa3\x9d\x10\x18\x05\x041J\xaf\xea\b\x1fGG,0\xe8@I\x05\xf3!\x1f4q\xf24N\xc0\xe6R\x02\x18\x81\x9e\b\xed\x19\xf1\x9eyy$\x88J\t\x05\x12!\x02\x04 \x1c@C\x80E\b0\x00\tt\x90\xe0\x02f\n\x15v\xe8\xe1\x14\xb7\xe0f\x82x\x1f\x96h\xe2\x89(\xa6\xa8b\x13A\x00\x00!\xf9\x04\t\x04\x000\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc2\xc4DBD\xa4\xa2\xa4\xe4\xe2\xe4$\"$\x94\x92\x94dbd\xb4\xb2\xb4\xf4\xf2\xf4\x14\x16\x14\xd4\xd2\xd4424\f\n\f\x8c\x8a\x8c\\^\\\xac\xaa\xac\xec\xea\uc71a\x9c|~|\xbc\xba\xbc\xfc\xfa\xfc\xdc\xda\xdc<:<\xcc\xca\xccLJLljl\x1c\x1e\x1c\x04\x06\x04\x84\x86\x84DFD\xa4\xa6\xa4\xe4\xe6\xe4$&$\x94\x96\x94dfd\xb4\xb6\xb4\xf4\xf6\xf4\x1c\x1a\x1c\xd4\xd6\xd4464\f\x0e\f\x8c\x8e\x8c\xac\xae\xac\xec\xee\uc71e\x9c\xbc\xbe\xbc\xfc\xfe\xfc\xdc\xde\xdc<><\xcc\xce\xcc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x98pH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\u062cv\x19J\x04\x0e\x02\xd3vLvJb\xc9K`0\b\\\x8a\x96\bf\xe1PqH\x8a\xa9\xa5%i%-\x12\x12yH&\x81\x83G\n\x81bH\x89\x12\x16H{}H\x02\x1a\x1d\x00\x06\x13~D\x04\v\x00\x9e\x00\v\x04D\x13\x0e\x9f\x9f\r(F\x8d\x8fF\x16/\a\x1e#\f\xacD-\t+\x1e\x04\x17\xb4C\x05\x11\x0f\x0f,\x05G\x17\x04\x1e+%\x87C\x16\f\xb0\a/\xbcB\xae\xb0\xb2\xd1\x17\x1c\xa6*\x0f\x8b0\x17\x9d\xa6\xa0o0!\xdf\xe0\x1d\x1b\x87\xcc\xce\xd0F\f\x14\x01\xef\x0f\xe2D\x15\xf0\xf0\x13!E&\x11\xf0\xef \xca0$Lx\xf7.\x81\x91\v+\b\x06\x98\xd1N\xa1\xbc\"\x1b\xc0\x01\x101\x8f\x82DO\x14\x84L\xb8\xe8\xa9A\x86!\b\x152,\x02\x82\xe0\xbb\nF\x1ePX\x19 \x00\x83\"\x12<(\xf4 \xa1\b\x03\x99\xf6\x1e\x18y\xd1o\xa5\xfe(\x92&\x03\xa0\x1c\u04a2\xc1E\x83B\x06p\x94!$\"\xc7\x05Ha\xf0\\\xe9\xd3\b\b{'S\x9a\xf4\xf0\x92H\u031e4m\xf6\x83\xa7\xb3H\xbdw\xf0~\x12\xb9\xaap\xa8\x90\xa2\x17K\f\x91\xc1q@S\x8e\xa0\xa2\x9emIA\xed\x90\x19cW\xcc\x1bR\x02+\xbe\"\n\u0636\xfcW$\x84\x8b\xb1QA\xae\x18;\x92\b`\x96\x82\x8b \x90h \x95\x10\x8b\x173\xc2\xd8\xc8\u0463d\u02ad*\x1c\xf82#\x1a\f[\xb8t\xb9\xf6\xf5\xc0C\x84ap.\xb8\x00\x96@\x13\x11\v3\x9cUpmA5\xebh\fNd\vp\u021b\xc4\x05\x9e\xc9q\u0133,\xb8\x87\x03\u00cf\x00\n\u1ed5\x84\x10\n\\\vQ\x10BP\x12\xf2\x12\xb8\x19\xe1\xe3\b\xd2\xf7\xeeD^|\xf0\xc4a\x04|\x17\xe5@\xb9\x18e\t\x1c\xaa\xf5\x81\x88W\u0180RH0X\x11\x17P\x80\x01\x06\x14x\xb6L\x04)\xd0\xe1\xc0\t\x10\xc0G\xe0\x85\x18FQ\x00\b\xc7\x0e\xbc\xa0^\x86 \x86(\xe2\x88$\x96(D\x10\x00!\xf9\x04\t\x04\x00\x19\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc6\xc4DFD\xa4\xa2\xa4$\"$\xe4\xe6\u4512\x94\x14\x12\x14dfd\xb4\xb6\xb4\xf4\xf6\xf4\xdc\xda\xdc424\f\n\f\x8c\x8a\x8c\xcc\xce\u032c\xaa\xac\xec\xee\uc71a\x9ctvtTVT,.,\x1c\x1e\x1c\xbc\xbe\xbc\xfc\xfe\xfc<><\x04\x06\x04\x84\x86\x84\xcc\xca\xccLJL\xa4\xa6\xa4$&$\xec\xea\uc516\x94\x14\x16\x14trt\xbc\xba\xbc\xfc\xfa\xfc\xe4\xe2\xe4464\f\x0e\f\x8c\x8e\x8c\xd4\xd2\u052c\xae\xac\xf4\xf2\xf4\x9c\x9e\x9c|~|\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe\xc0\x8cpH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\u062c\x16\xcb \x04&\x9d\xadx\xfc4\x18\x92\x1d\x92\u01a3\n\x15\x17\a\v\u0091*\xa8\x16F\x93$$I\x9aB!-I\v\x80\x82H-\x80x\x87\x80&Hz|~\x85G&,(\x00\x00(,\x8dC-\x01)\x97\x97\x17aB-$\x1b\xa0\xa0\x15'D&\x18\a\x1c\"+\x9bD\x12\n*\x1c\x04\f\xb3C'\x11\x0f\x0f,\xabF]\x1c*\n\x86\xac+\xaf\a\x18\xbbB\xad\xaf\xb1\xce\x19\xb5\xb7\xb9\xce,#\xa8#\x11D,\b\xa8\x97\x1a\xc2%\xe0\xe1\x00\x0e\a\x8a\x19+/\x01\xee\x0f\fF%\xef\xef\x13gD\v\x11\xef\xee\x1f\xc8B!&\xb8s\xa7`\x98\x8a\x81\x01 \x18iW/\u07bcz/\xee\x15ip\x0e\x05\x11\x0f\xe7\x00 p!$A\xc6K\x1e\xf0e\xf80\xd0]\t#\x0f^\xa8\f\x10`E\x91\x10\x1c\x10rpCdE\u0306F0\xf0SI\xc0\b\xfeI~\x01N\x16I\xb9\xb2%\x91\x10\x1fE~\xcaHB\x88\xa5\x8f \\\n\xf9\x001(\u0292\x1c\xa4\x0e\x81\xb9sf\x91\x15@_\xc3\xf6\ue4fe\x877\xa2\x8f\"\x00\v,\xd2w\x8a.\x8a\x13\x85S\xe1\xa8B\u0180\x04\xf2r\x9b\x11\x02\x90`\xc1\x00\x0f\x88D\x8a\n\x16\xa4@\xc7\x05\x1c\xfcS\xe0\x85\x18>\xc1\xc0\x04\x01\r\x88 @\x86 \x86(\xe2\x88$\x8e\x11\x04\x00!\xf9\x04\t\x04\x00-\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xc4\xc2\xc4DBD\xa4\xa2\xa4\xe4\xe2\xe4$\"$dbd\x94\x92\x94\xf4\xf2\xf4TRT\xd4\xd2\u0534\xb6\xb4\x1c\x1e\x1c424\f\n\f\x8c\x8a\x8cLJL\xec\xea\uc71a\x9c\xfc\xfa\xfc\xdc\xda\u072c\xaa\xac|~|\\Z\\\xbc\xbe\xbc<:<\x04\x06\x04\x84\x86\x84\xcc\xce\xccDFD\xa4\xa6\xa4\xe4\xe6\xe4$&$dfd\x94\x96\x94\xf4\xf6\xf4\xd4\xd6\u053c\xba\xbc464\f\x0e\f\x8c\x8e\x8cLNL\xec\xee\uc71e\x9c\xfc\xfe\xfc\xdc\xde\xdc\\^\\\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe\xc0\x96pH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\u062cv\xcb\xedz\xb7\x05I\xd2\xf4\xd2(X\x94#e%Y%)\x12I\"I\x8a\u03d1\x898)\x99\x97\xa4\xd5lnHprtvG\t\x13\x06\x00\x1b\x11\x02E \a\x0f\x00\x94\x00\x1e\x15E\x14\x19\b\x1c#\v\u007fD+\f)\x1c\x04\x15\xa0C\x05\x16\x10\x10\x16 G\x15\x04\x1c)\fwD\x14\v\x9c\b\x19\xa8B\x9a\x9c\x9e\xbd-\xa2\xa4\xa6\u00aa\xac\xaeE$\x10(\x95\x00\r\x98\xbe\x1c\x93\xcf\x00\a\x82B\v\x17\x01\xdc\x10\xd2D&\xdd\xdd\x13\xafD$\x16\xdd\xdc\x1f\xb6B\x12\x13\xdc\xdc\fF\x15)\xf1\x01\x1dF\xdb\xe3\xdfF\xe2\xf1\u55a5\xbb\xb0\xae]\x85\x10\xd6\x00\x88\x18\xe2BCB\x00!2\x10\xf9\x10\x8f\x9b\t#\x10\br\v\xb0\xa0\x88\x04\x0e\xf78\x88!\xb2\x00$?#\x19\xd4\x11$`\x84\xa2\xba\x00\x17\x8bd$\x18\x80\xa3G\x93\xdcD\x12a\xf0\u0401\xe6\xa0\x05\u056cm`9\xe4\xc38\x8b\x18+r\xe8H\xe4\xa3J\x9d$_^\x80\xe0o\\7\xa2\x13\x8f\xc2L\xaan\xe9\u0367#\x85\xf0L\xe8`d\x87\xa0\u03c6\x12\xe9\xf02\x05\xb8!\f\x8e\x06$\x92\xc0\xe8Fv\x90X\xbc\x9cW\xa4\xde\xcb|E\xd8\xd2tk$.@sC\xeaZ\xc5;\xa4\xc2\"k/R\x9dxh@\xe2\x10\n&\x10\x04@\xd0A\x98(\b\xa5N\x19A\xc6\xc1B\x01#\x14*\xb0`\xc5 \xec\xe5\x0e\xbaL\b\u00ec\x99\xb3g\x06\xa0\x8d\x8d^U\xfa4\xdd\x00\xce*5\x00\u0702\x045\xa1\a\\\xb7\x80\x03\"\x1bj\t \x12\b\x13\x92\x00D!<\xd6\xf7 a\xe3g\x10t\u7660K\xc7~\xbd\u020a\x11\r(y\xb0\x9c\xea\xc0\x86g\x03J|\x99O\xdfI\x05\u010518P1bz\xfd\xff\x00\x06(\xe0\x80\x04\x16h\xa0\x80A\x00\x00!\xf9\x04\t\x04\x00\x16\x00,\x00\x00\x00\x00\x80\x00\x10\x00\x85\x04\x02\x04\x84\x82\x84\xcc\xce\u0324\xa2\xa4DBD\xec\xea\ucd32\xb4\x94\x92\x94dfd\x14\x16\x14\xdc\xde\xdc\xf4\xf6\xf4\f\n\f\x8c\x8a\x8c\xac\xaa\xac\\Z\\\xbc\xba\xbc\xdc\xda\xdc\xf4\xf2\xf4\x9c\x9e\x9c|~|\xe4\xe6\xe4\xfc\xfe\xfc\x04\x06\x04\x84\x86\x84\xd4\xd2\u0524\xa6\xa4LJL\xec\xee\ucd36\xb4\x94\x96\x94ljl\x1c\x1a\x1c\xe4\xe2\xe4\xfc\xfa\xfc\f\x0e\f\x8c\x8e\x8c\xac\xae\xac\\^\\\xbc\xbe\xbc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xfe@\x8bpH,\x1a\x8f\u0224r\xc9l:\x9f\u0428tJ\xadZ\xaf\u062cv\xcb\xedz\xbfH\x91B\x92\x14q\n\x9cr\xa1@F.\xd6\xed\xa3d\xbdH\xce\v\xa2\xf09\x1d\x86'\xdflvtG\x05\x18\f\x00\x17&!F\"'\a\x18\x1e\x19yE\x1c\x06$\x18\x03\x11\x93D!\x0e\r\r%\x8bF\x11\x03\x18$\x1dqC\"\x19\x8f\a'\x9b\xaa\x8e\x90\x92F\x95\x97\x99\xb0B\x9d\x9f\xa1G\xa4\xa6\xa8E\x05\x1f\x17\x00\xc6\x00\x04\xa2C\x19\x14\x01\xcd\r\x11F\x10\xce\xce\x13\x15E\v\x0e\xce\xcd\x1a\xa9\x16\x05\x13\xcd\xcd\x06\xa3$\xe2\x01\x02F\xcc\xd4\xd0\xd2\xd4\x14\xd6\xd8\xda\x14\xdc\xde\xe0\xe7\xe4D\x06 \xc7\xc6#$E4\x88k\x06\xc1H\x03z\xcd\x02d\x10\x86\xe1\x1c\x86\x02E2\xbc\v\xd0\xc0\u0209m\xf4\x06\x18\x11\xb8-@\xc1\"\a\xe9\x05P\xc8\xd0!D\"\x12\xcfUT\x85\xa1\u07f1\a\xa94L\xfcH\xe4`\u01c5D\na|\x18\xb1#\u0185\x95D\xa6%\xa4\xa01\xe0L\x83\x03I\xe6\u0130\xf3\xe42\x9f@-\x88h\xe0\xd2\u0603:C\x04t$\x11\xadH\x87w\xf1\x88H\x90\x99\xb0[\x91\n\x13:\xe6#\x12\x81D\xc7tE\xb4\x8a\xe4j\u4af8\xb0C\xc6R\v`\x96\bZ\xb5EJ$py!\xaaT\b\a\x02\x1c\x10\x90\u02c2-L\x9a\x8c\xec\xc2\xe0@\x99\xaa\b\x13>\x19\xe0CD\x84\x80V\x10\x1a\x8b@\xac\x98q-K\x90\x1bO\xae\xcc\b\xb3f\xceB\n (v\x8c\x80\x02F\x05*\xc0.\"\"\xb7\x84\xc6B$T\b\x84Dx\x01\xacG\xce\xe0\xe9\xa3[M\x85\xdf\u0147{\x13;\x1c9\xa7\x00\x87.<\xb8\r\xa6\xbb\xf7+\v\"\xec\xfeN\xbe\xbc\xf9\xf3\xe8\u04eb_\xdf=\b\x00;") + +func third_partySwaggerUiImagesThrobberGifBytes() ([]byte, error) { + return _third_partySwaggerUiImagesThrobberGif, nil +} + +func third_partySwaggerUiImagesThrobberGif() (*asset, error) { + bytes, err := third_partySwaggerUiImagesThrobberGifBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/images/throbber.gif", size: 9257, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiImagesWordnik_apiPng = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\b\x06\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\b\b\b\b|\bd\x88\x00\x00\x00\tpHYs\x00\x00\v\x12\x00\x00\v\x12\x01\xd2\xdd~\xfc\x00\x00\x00\x1ctEXtSoftware\x00Adobe Fireworks CS5q\xb5\xe36\x00\x00\x03NIDATH\x89\xa5\x95Mh\\U\x14\xc7\u007fg&\x8d\x19'3\xa3\xb4\x04\x85Lg\x92n\x94,\xac\x1b\xed\xa2\xad\xa8\x11E\x8cZZ\x17\xd6D\x90\xba(EG\u0115\xb6\xd8\tU\xb0 h\xa5\xf8Aj\xc1\xa6_\v+\xa5\xadH@\x02~!-\n\xe2\xc2n\xecL\u0489\u0608U'\x93\xe9K\x9c{\xdfq\x91\x99\xc9}\xf3\x01\x03\xfe\xe1\xf0\xee\xfd\xbfs\xfe\xe7\u070fw\x9e\xd0!\x96\x8e\xf6o\x03\xc6\x00\x8bp\xb8\u7e79\xaf:\x89\xeb\xea4\x01\xca\xf3\xc0\xa3\u0571\at\x94 \u0509\xd3\u0491\xfe\xb5\xf8\f\xe3C\xd5F\x96\x8e\xf4'\x1a\xfdn|\xd6/\x8d\\`\x05\xde\xd1d\x17\u02dc\x01<\x94\xb7#{\n?\x00hEv\x03\u074e\xeb-\xc0\v\xc0\x9b\x00\xde\a\xc9\a\x81q\xe6)y\x1f'\x1f\x8f\xec*Tj\x8e\xf5\x8c\u07a1d\x940\xe7\x80\a\x1c\xa13@\x12\xb8\xa7\xcd\xe2.\x02\xbf\x03O:\u0717XF\"/\x15\x96\x82+\x10\xba\u0572\xb1A`{\x1b\xe1\x1a\xeem\xc1m\x10Y\xdd\xfa\xfa \x92)\xfc\x8d\x95q\xac\xf0\xff\x8cl$S\xb8\u0454\x00\x00\x13\xfa\x10\xcb\x15,\x04\xccT\xad\xdd|\xd5.\u02ffk\x8e\xbb\x92\x81C6\xb7\xffS\t\xff\x16_\xae\x13\n\"|\n\\\x06\xb6*\xdc\a +W\xf4k\xe0NUv\xac\x9e$a\xfff/p\x93\xea\x93\xf2[\xa9\b\x86\x17\x81\x83\xab\xf2:\x1a\xddw\xf5d\xdd\xe7\x8d\xf5\x93\x00\xd1}W\xc7\x1cn'\xc8qG\xebUB\x1c\x8e\xbe6\xbb\b \xe5lj30\x82\xf0\x140\xe0$\xff6\xba\u007fv\x8b[M9\x9bN\x00D\xb33\xc5\x00?\x9e\xfa\x06\xd8\xecP\xd7P\xce\x02S]\xf8L(\xdc!+%\xbb\x98\xa3\x01\x8d\xc25\xa8\r\xfa\n\xdc\x06\xec\x06\x1e\n\xa9\x95(V\u0426\x83\x95\xe1\u017d\xe9\xbeV\x82.\x16\xf7\xa6\xfb02\xec\u01aa\x05\xb5\x82Z\xe9\ta\xf9\x04\u02ef\x18\x01\xe3\\7\x9fuXN\x97\xb3\xe9\xb6\xfd\xca{'\x1d\xc2rr\u0177\x1aW\xd7\xe1G,\xef\n\xc0\xe2+\xe9\x1e\xc2lQ%\x03<\x16\\?\xa7\x88\xeahl|\xd6w\xe9\xd2\xfeT\x88\xb2L\"\xecl\xc8\xfb\xb9\b\a)\xf2]\xefG3~\xe0J\x952\xe9\x18a\xf2\xc0\u0686\xa0S\xf4\xcah\xec@\xde\a(\x1dH\v\u007fq\x02x\xba\xc1\xef:>\x83\xb1C3\v5\xa2\xa9\xfb\x952\x03\xdf\x03\x9bZ\xec\xc8\x05\xe9b\a\x80\x1aN\x13\xec?5\xfc\x14{/\u007f\xb7K\x04\x12,\xec\x19\u060a0\r\x84[\x04\x03LU\x9f\x0f\xb7y\xaf(O\xc4\xdf\u03dfoJ\xb0\xb0k \xc4\x1a\xa6\x80\xe16\xc1\x9d\xe2g,\x9b\xe2\x13y\x0f\xdcV\x11\x92^,\x83N- \xfc\t\u0100\x9bZ\xd4\n\xc22PBY\xe7\xecE\x1f\x90\x00\x91\xbb\u05b4E5\x14\x9f\x1d\\\x0f\xf8\x89c\xb9\xfa\xd7Y\x1c\x1bL!\xe4\u0702P\x86\x12\x93\xb9_\x1c\x9f[\x11\xba\x13\xc7r\xf3\xae^S\x82v(>\xb3\xe1\v\xe0\x91\xea\xf4R\xe2\u0115V?\x9b&t\xf4\xd3\aP\u02f4\xd6\xdb\x00\u04dd\xc6\xfd\a\xed\xe8X\x9d\xcd\v]\xf3\x00\x00\x00\x00IEND\xaeB`\x82") + +func third_partySwaggerUiImagesWordnik_apiPngBytes() ([]byte, error) { + return _third_partySwaggerUiImagesWordnik_apiPng, nil +} + +func third_partySwaggerUiImagesWordnik_apiPng() (*asset, error) { + bytes, err := third_partySwaggerUiImagesWordnik_apiPngBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/images/wordnik_api.png", size: 980, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiIndexHtml = []byte(` + + + Swagger UI + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
 
+
+ + +`) + +func third_partySwaggerUiIndexHtmlBytes() ([]byte, error) { + return _third_partySwaggerUiIndexHtml, nil +} + +func third_partySwaggerUiIndexHtml() (*asset, error) { + bytes, err := third_partySwaggerUiIndexHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "third_party/swagger-ui/index.html", size: 3561, mode: os.FileMode(420), modTime: time.Unix(1503320355, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _third_partySwaggerUiLibBackboneMinJs = []byte(`// Backbone.js 1.1.2 + +(function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('