├── exec ├── testdata │ └── hello ├── README.md ├── doc.go ├── new_test.go ├── stdiopipe_test.go └── testing │ └── fake_exec_test.go ├── hack ├── .golint_failures ├── verify-govet.sh ├── verify-gofmt.sh ├── lib │ └── util.sh ├── verify-go-directive.sh ├── verify-apidiff.sh └── verify-golint.sh ├── ptr ├── README.md ├── OWNERS ├── ptr.go └── ptr_test.go ├── pointer ├── README.md └── OWNERS ├── clock ├── README.md └── testing │ ├── simple_interval_clock.go │ └── simple_interval_clock_test.go ├── nsenter ├── README.md ├── OWNERS └── nsenter_unsupported.go ├── io ├── README.md ├── read.go └── read_test.go ├── set ├── OWNERS └── ordered.go ├── code-of-conduct.md ├── cpuset └── OWNERS ├── temp ├── README.md ├── temptest │ ├── doc.go │ ├── example_test.go │ ├── file_test.go │ ├── file.go │ ├── dir_test.go │ └── dir.go ├── doc.go ├── dir.go └── dir_test.go ├── inotify ├── README.md ├── PATENTS ├── LICENSE ├── inotify_others.go ├── inotify.go └── inotify_linux_test.go ├── go.mod ├── mount ├── OWNERS ├── README.md ├── doc.go ├── mount_helper_windows_test.go ├── mount_unsupported.go ├── mount_helper_windows.go ├── mount_helper_common.go ├── mount_helper_test.go └── mount_helper_unix.go ├── .gitignore ├── OWNERS ├── third_party └── forked │ └── golang │ ├── reflect │ ├── README.md │ └── deep_equal_test.go │ ├── PATENTS │ └── LICENSE ├── .github ├── ISSUE_TEMPLATE │ ├── support.md │ ├── bug-report.md │ ├── feature-request.md │ └── enhancement.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── test.yml ├── go.sum ├── CONTRIBUTING.md ├── SECURITY_CONTACTS ├── env ├── doc.go ├── env.go └── env_test.go ├── semantic ├── deep_equal_test.go └── deep_equal.go ├── keymutex ├── keymutex.go ├── hashed.go └── keymutex_test.go ├── strings ├── line_delimiter_test.go ├── escape_test.go ├── escape.go ├── strings.go ├── line_delimiter.go ├── strings_test.go └── slices │ ├── slices.go │ └── slices_test.go ├── net ├── parse.go ├── port_test.go ├── net.go ├── parse_test.go └── port.go ├── internal └── third_party │ └── forked │ └── golang │ ├── PATENTS │ ├── LICENSE │ ├── net │ └── parse.go │ └── golang-lru │ └── lru.go ├── Makefile ├── HOWTOMOVE.md ├── README.md ├── trace └── README.md ├── integer ├── integer.go └── integer_test.go ├── path ├── file.go └── file_test.go ├── field ├── path.go └── path_test.go ├── lru ├── lru.go └── lru_test.go ├── buffer ├── ring_fixed.go └── ring_growing.go └── diff └── diff_test.go /exec/testdata/hello: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo -n "hello" 4 | -------------------------------------------------------------------------------- /hack/.golint_failures: -------------------------------------------------------------------------------- 1 | # Apart from this line, only trailing comments are supported 2 | mount 3 | -------------------------------------------------------------------------------- /ptr/README.md: -------------------------------------------------------------------------------- 1 | # Pointer 2 | 3 | This package provides some functions for pointer-based operations. 4 | -------------------------------------------------------------------------------- /pointer/README.md: -------------------------------------------------------------------------------- 1 | # Pointer 2 | 3 | This package provides some functions for pointer-based operations. 4 | -------------------------------------------------------------------------------- /clock/README.md: -------------------------------------------------------------------------------- 1 | # Clock 2 | 3 | This package provides an interface for time-based operations. It allows 4 | mocking time for testing. 5 | -------------------------------------------------------------------------------- /nsenter/README.md: -------------------------------------------------------------------------------- 1 | # NSEnter 2 | 3 | This package provides interfaces for executing and interacting with processes 4 | running within a namespace. 5 | -------------------------------------------------------------------------------- /io/README.md: -------------------------------------------------------------------------------- 1 | # IO 2 | 3 | This package provides interfaces for working with file IO. Currently it 4 | provides functionality for consistently reading a file. 5 | -------------------------------------------------------------------------------- /set/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | reviewers: 4 | - logicalhan 5 | - thockin 6 | approvers: 7 | - logicalhan 8 | - thockin 9 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Community Code of Conduct 2 | 3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /cpuset/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - dchen1107 5 | - derekwaynecarr 6 | - ffromani 7 | - klueska 8 | - SergeyKanzhelev 9 | -------------------------------------------------------------------------------- /temp/README.md: -------------------------------------------------------------------------------- 1 | # Temp 2 | 3 | This package provides an interface to create temporary directories. It also 4 | provides a [FakeDir](temp/temptest) implementation to replace in tests. 5 | -------------------------------------------------------------------------------- /exec/README.md: -------------------------------------------------------------------------------- 1 | # Exec 2 | 3 | This package provides an interface for `os/exec`. It makes it easier to mock 4 | and replace in tests, especially with the [FakeExec](testing/fake_exec.go) 5 | struct. 6 | -------------------------------------------------------------------------------- /inotify/README.md: -------------------------------------------------------------------------------- 1 | This is a fork of golang.org/x/exp/inotify before it was deleted. 2 | 3 | Please use gopkg.in/fsnotify.v1 instead. 4 | 5 | For updates, see: https://github.com/fsnotify/fsnotify 6 | -------------------------------------------------------------------------------- /ptr/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - apelisse 5 | - stewart-yu 6 | - thockin 7 | reviewers: 8 | - apelisse 9 | - stewart-yu 10 | - thockin 11 | -------------------------------------------------------------------------------- /nsenter/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | reviewers: 4 | - jsafrane 5 | - msau42 6 | - cofyc 7 | approvers: 8 | - jsafrane 9 | - msau42 10 | - cofyc 11 | -------------------------------------------------------------------------------- /pointer/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - apelisse 5 | - stewart-yu 6 | - thockin 7 | reviewers: 8 | - apelisse 9 | - stewart-yu 10 | - thockin 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module k8s.io/utils 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.1 7 | k8s.io/klog/v2 v2.80.1 8 | ) 9 | 10 | require github.com/go-logr/logr v1.2.0 // indirect 11 | -------------------------------------------------------------------------------- /mount/OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | reviewers: 4 | - jingxu97 5 | - saad-ali 6 | - jsafrane 7 | - msau42 8 | - andyzhangx 9 | - gnufied 10 | approvers: 11 | - andyzhangx 12 | - jingxu97 13 | - saad-ali 14 | - jsafrane 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX leaves these everywhere on SMB shares 2 | ._* 3 | 4 | # OSX trash 5 | .DS_Store 6 | 7 | # Eclipse files 8 | .classpath 9 | .project 10 | .settings/** 11 | 12 | # Files generated by JetBrains IDEs, e.g. IntelliJ IDEA 13 | .idea/ 14 | *.iml 15 | 16 | # Vscode files 17 | .vscode 18 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | 3 | approvers: 4 | - aojea 5 | - danwinship 6 | - deads2k 7 | - thockin 8 | - dims 9 | reviewers: 10 | - aojea 11 | - danwinship 12 | - deads2k 13 | - thockin 14 | - dims 15 | emeritus_approvers: 16 | - apelisse 17 | - dashpole 18 | - lavalamp 19 | - mengqiy 20 | -------------------------------------------------------------------------------- /third_party/forked/golang/reflect/README.md: -------------------------------------------------------------------------------- 1 | This was originally forked from https://github.com/golang/go/blob/master/src/reflect/deepequal.go in order to 2 | 3 | - consider empty lists and empty maps equal to their nil counterparts 4 | - add a `AddFuncs` mechanism to add custom equality funcs for specific types. 5 | 6 | Meanwhile it has diverged quite a lot while still following the original algorithm at the core though. 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Support Request 3 | about: Ask questions about this project 4 | 5 | --- 6 | 7 | 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= 4 | github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 5 | k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= 6 | k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for taking the time to join our community and start contributing! 4 | 5 | The [Contributor Guide](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md) 6 | provides detailed instructions on how to get your ideas and bug fixes seen and accepted. 7 | 8 | Please remember to sign the [CNCF CLA](https://github.com/kubernetes/community/blob/master/CLA.md) and 9 | read and observe the [Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 10 | -------------------------------------------------------------------------------- /SECURITY_CONTACTS: -------------------------------------------------------------------------------- 1 | # Defined below are the security contacts for this repo. 2 | # 3 | # They are the contact point for the Product Security Committee to reach out 4 | # to for triaging and handling of incoming issues. 5 | # 6 | # The below names agree to abide by the 7 | # [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) 8 | # and will be removed and replaced if they violate that agreement. 9 | # 10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE 11 | # INSTRUCTIONS AT https://kubernetes.io/security/ 12 | 13 | liggitt 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve this project 4 | 5 | --- 6 | 7 | 9 | 10 | 11 | **What happened**: 12 | 13 | **What you expected to happen**: 14 | 15 | **How to reproduce it**: 16 | 17 | **Anything else we need to know?**: 18 | 19 | **Environment**: 20 | - Kubernetes version (use `kubectl version`): 21 | - OS (e.g. from /etc/os-release): 22 | - Kernel (e.g. `uname -a`): 23 | - Install tools: 24 | - Others: 25 | -------------------------------------------------------------------------------- /mount/README.md: -------------------------------------------------------------------------------- 1 | # WARNING ! Please read before using mount functionality 2 | # THIS REPOSITORY is moved : Please use https://github.com/kubernetes/mount-utils for all your work 3 | 4 | This package has been moved to new location. Please use the new repo for bug fixes and enhancements. 5 | All existing dependencies on this repo are being removed. Eventually this repo will be deprecated. 6 | If you are using this repo or planning to use, you must use the new repo mentioned here for this functionality. 7 | 8 | New repo : https://github.com/kubernetes/mount-utils 9 | New go module: k8s.io/mount-utils 10 | For Kubernetes/Kubernetes project the code is available under staging directory. 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | 9 | 10 | **Describe the solution you'd like in detail** 11 | 12 | 13 | **Describe alternatives you've considered** 14 | 15 | 16 | **Additional context** 17 | 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement Request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | 8 | **Is your feature request related to a problem?/Why is this needed** 9 | 10 | 11 | **Describe the solution you'd like in detail** 12 | 13 | 14 | **Describe alternatives you've considered** 15 | 16 | 17 | **Additional context** 18 | 19 | -------------------------------------------------------------------------------- /mount/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package mount defines an interface to mounting filesystems. 18 | package mount // import "k8s.io/utils/mount" 19 | -------------------------------------------------------------------------------- /env/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package env provides utility functions for using environment variables. 18 | package env // import "k8s.io/utils/env" 19 | -------------------------------------------------------------------------------- /temp/temptest/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package temptest provides utilities for testing temp 18 | // files/directories testing. 19 | package temptest 20 | -------------------------------------------------------------------------------- /exec/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package exec provides an injectable interface and implementations for running commands. 18 | package exec // import "k8s.io/utils/exec" 19 | -------------------------------------------------------------------------------- /temp/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package temp provides an interface to handle temporary files and 18 | // directories. 19 | package temp // import "k8s.io/utils/temp" 20 | -------------------------------------------------------------------------------- /hack/verify-govet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # For use with Go 1.12+ 18 | 19 | set -o errexit 20 | set -o nounset 21 | set -o pipefail 22 | 23 | GO_VERSION=${TRAVIS_GO_VERSION:-$(go version | cut -d ' ' -f 3)} 24 | 25 | if [[ ${GO_VERSION} =~ ^(go)?1\.(9|10|11) ]]; then 26 | go tool vet . 27 | else 28 | go vet ./... 29 | fi 30 | -------------------------------------------------------------------------------- /semantic/deep_equal_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package semantic 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | var mod2Equal = EqualitiesOrDie(func(a, b int) bool { 24 | return a%2 == b%2 25 | }) 26 | 27 | func TestEqualities(t *testing.T) { 28 | if !mod2Equal.DeepEqual(3, 5) { 29 | t.Error("expected 3 and 5 to be equal mod 2") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /hack/verify-gofmt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2017 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | if ! which gofmt > /dev/null; then 22 | echo "Can not find gofmt" 23 | exit 1 24 | fi 25 | 26 | diff=$(gofmt -s -d . 2>&1) 27 | if [[ -n "${diff}" ]]; then 28 | echo "${diff}" 29 | echo 30 | echo "Please run 'make update-fmt'" 31 | exit 1 32 | fi 33 | -------------------------------------------------------------------------------- /exec/new_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package exec_test 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | 23 | "k8s.io/utils/exec" 24 | ) 25 | 26 | func ExampleNew() { 27 | exec := exec.New() 28 | 29 | cmd := exec.Command("echo", "Bonjour!") 30 | buff := bytes.Buffer{} 31 | cmd.SetStdout(&buff) 32 | if err := cmd.Run(); err != nil { 33 | panic(err) 34 | } 35 | fmt.Println(buff.String()) 36 | // Output: Bonjour! 37 | } 38 | -------------------------------------------------------------------------------- /semantic/deep_equal.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package semantic 18 | 19 | import ( 20 | "k8s.io/utils/third_party/forked/golang/reflect" 21 | ) 22 | 23 | // Equalities is a map from type to a function comparing two values of 24 | // that type. 25 | type Equalities = reflect.Equalities 26 | 27 | // EqualitiesOrDie adds the given funcs and panics on any error. 28 | func EqualitiesOrDie(funcs ...interface{}) Equalities { 29 | return reflect.EqualitiesOrDie(funcs...) 30 | } 31 | -------------------------------------------------------------------------------- /keymutex/keymutex.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package keymutex 18 | 19 | // KeyMutex is a thread-safe interface for acquiring locks on arbitrary strings. 20 | type KeyMutex interface { 21 | // Acquires a lock associated with the specified ID, creates the lock if one doesn't already exist. 22 | LockKey(id string) 23 | 24 | // Releases the lock associated with the specified ID. 25 | // Returns an error if the specified ID doesn't exist. 26 | UnlockKey(id string) error 27 | } 28 | -------------------------------------------------------------------------------- /strings/line_delimiter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | ) 23 | 24 | func Example_trailingNewline() { 25 | ld := NewLineDelimiter(os.Stdout, "|") 26 | defer ld.Flush() 27 | fmt.Fprint(ld, " Hello \n World \n") 28 | // Output: 29 | // | Hello | 30 | // | World | 31 | // || 32 | } 33 | func Example_noTrailingNewline() { 34 | ld := NewLineDelimiter(os.Stdout, "|") 35 | defer ld.Flush() 36 | fmt.Fprint(ld, " Hello \n World ") 37 | // Output: 38 | // | Hello | 39 | // | World | 40 | } 41 | -------------------------------------------------------------------------------- /clock/testing/simple_interval_clock.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package testing 18 | 19 | import ( 20 | "time" 21 | 22 | "k8s.io/utils/clock" 23 | ) 24 | 25 | var ( 26 | _ = clock.PassiveClock(&SimpleIntervalClock{}) 27 | ) 28 | 29 | // SimpleIntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration 30 | type SimpleIntervalClock struct { 31 | Time time.Time 32 | Duration time.Duration 33 | } 34 | 35 | // Now returns i's time. 36 | func (i *SimpleIntervalClock) Now() time.Time { 37 | i.Time = i.Time.Add(i.Duration) 38 | return i.Time 39 | } 40 | 41 | // Since returns time since the time in i. 42 | func (i *SimpleIntervalClock) Since(ts time.Time) time.Duration { 43 | return i.Time.Sub(ts) 44 | } 45 | -------------------------------------------------------------------------------- /strings/escape_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestEscapeQualifiedNameForDisk(t *testing.T) { 24 | testCases := []struct { 25 | input string 26 | output string 27 | }{ 28 | {"kubernetes.io/blah", "kubernetes.io~blah"}, 29 | {"blah/blerg/borg", "blah~blerg~borg"}, 30 | {"kubernetes.io", "kubernetes.io"}, 31 | } 32 | for i, tc := range testCases { 33 | escapee := EscapeQualifiedName(tc.input) 34 | if escapee != tc.output { 35 | t.Errorf("case[%d]: expected (%q), got (%q)", i, tc.output, escapee) 36 | } 37 | original := UnescapeQualifiedName(escapee) 38 | if original != tc.input { 39 | t.Errorf("case[%d]: expected (%q), got (%q)", i, tc.input, original) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /inotify/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /net/parse.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package net 18 | 19 | import ( 20 | forkednet "k8s.io/utils/internal/third_party/forked/golang/net" 21 | ) 22 | 23 | // ParseIPSloppy is identical to Go's standard net.ParseIP, except that it allows 24 | // leading '0' characters on numbers. Go used to allow this and then changed 25 | // the behavior in 1.17. We're choosing to keep it for compat with potential 26 | // stored values. 27 | var ParseIPSloppy = forkednet.ParseIP 28 | 29 | // ParseCIDRSloppy is identical to Go's standard net.ParseCIDR, except that it allows 30 | // leading '0' characters on numbers. Go used to allow this and then changed 31 | // the behavior in 1.17. We're choosing to keep it for compat with potential 32 | // stored values. 33 | var ParseCIDRSloppy = forkednet.ParseCIDR 34 | -------------------------------------------------------------------------------- /third_party/forked/golang/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /internal/third_party/forked/golang/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /strings/escape.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "strings" 21 | ) 22 | 23 | // EscapeQualifiedName converts a plugin name, which might contain a / into a 24 | // string that is safe to use on-disk. This assumes that the input has already 25 | // been validates as a qualified name. we use "~" rather than ":" here in case 26 | // we ever use a filesystem that doesn't allow ":". 27 | func EscapeQualifiedName(in string) string { 28 | return strings.Replace(in, "/", "~", -1) 29 | } 30 | 31 | // UnescapeQualifiedName converts an escaped plugin name (as per EscapeQualifiedName) 32 | // back to its normal form. This assumes that the input has already been 33 | // validates as a qualified name. 34 | func UnescapeQualifiedName(in string) string { 35 | return strings.Replace(in, "~", "/", -1) 36 | } 37 | -------------------------------------------------------------------------------- /exec/stdiopipe_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package exec_test 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | 23 | "k8s.io/utils/exec" 24 | ) 25 | 26 | func ExampleNew_stderrPipe() { 27 | cmd := exec.New().Command("/bin/sh", "-c", "echo 'We can read from stderr via pipe!' >&2") 28 | 29 | stderrPipe, err := cmd.StderrPipe() 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | stderr := make(chan []byte) 35 | go func() { 36 | b, err := ioutil.ReadAll(stderrPipe) 37 | if err != nil { 38 | panic(err) 39 | } 40 | stderr <- b 41 | }() 42 | 43 | if err := cmd.Start(); err != nil { 44 | panic(err) 45 | } 46 | 47 | received := <-stderr 48 | 49 | if err := cmd.Wait(); err != nil { 50 | panic(err) 51 | } 52 | 53 | fmt.Println(string(received)) 54 | // Output: We can read from stderr via pipe! 55 | } 56 | -------------------------------------------------------------------------------- /temp/temptest/example_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temptest 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "io" 23 | 24 | "k8s.io/utils/temp" 25 | ) 26 | 27 | func TestedCode(dir temp.Directory) error { 28 | f, err := dir.NewFile("filename") 29 | if err != nil { 30 | return err 31 | } 32 | _, err = io.WriteString(f, "Bonjour!") 33 | if err != nil { 34 | return err 35 | } 36 | return dir.Delete() 37 | } 38 | 39 | func Example() { 40 | dir := FakeDir{} 41 | 42 | err := TestedCode(&dir) 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | if dir.Deleted == false { 48 | panic(errors.New("Directory should have been deleted")) 49 | } 50 | 51 | if dir.Files["filename"] == nil { 52 | panic(errors.New(`"filename" should have been created`)) 53 | } 54 | 55 | fmt.Println(dir.Files["filename"].Buffer.String()) 56 | // Output: Bonjour! 57 | } 58 | -------------------------------------------------------------------------------- /temp/temptest/file_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temptest 18 | 19 | import ( 20 | "io" 21 | "testing" 22 | ) 23 | 24 | func TestFakeFile(t *testing.T) { 25 | f := &FakeFile{} 26 | 27 | n, err := io.WriteString(f, "Bonjour!") 28 | if n != 8 || err != nil { 29 | t.Fatalf( 30 | `WriteString(f, "Bonjour!") = (%v, %v), expected (%v, %v)`, 31 | n, err, 32 | 8, nil, 33 | ) 34 | } 35 | 36 | err = f.Close() 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | 41 | // File can't be closed twice. 42 | err = f.Close() 43 | if err == nil { 44 | t.Fatal("FakeFile could be closed twice") 45 | } 46 | 47 | // File is not writable after close. 48 | n, err = io.WriteString(f, "Bonjour!") 49 | if n != 0 || err == nil { 50 | t.Fatalf( 51 | `WriteString(f, "Bonjour!") = (%v, %v), expected (%v, %v)`, 52 | n, err, 53 | 0, "non-nil", 54 | ) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /strings/strings.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "path" 21 | "strings" 22 | ) 23 | 24 | // SplitQualifiedName Splits a fully qualified name and returns its namespace and name. 25 | // Assumes that the input 'str' has been validated. 26 | func SplitQualifiedName(str string) (string, string) { 27 | parts := strings.Split(str, "/") 28 | if len(parts) < 2 { 29 | return "", str 30 | } 31 | return parts[0], parts[1] 32 | } 33 | 34 | // JoinQualifiedName joins 'namespace' and 'name' and returns a fully qualified name 35 | // Assumes that the input is valid. 36 | func JoinQualifiedName(namespace, name string) string { 37 | return path.Join(namespace, name) 38 | } 39 | 40 | // ShortenString returns the first N slice of a string. 41 | func ShortenString(str string, n int) string { 42 | if len(str) <= n { 43 | return str 44 | } 45 | return str[:n] 46 | } 47 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2018 The Kubernetes Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | .PHONY: verify 16 | verify: verify-fmt verify-lint verify-apidiff vet test 17 | 18 | .PHONY: test 19 | test: 20 | GO111MODULE=on go test -v -race ./... 21 | 22 | .PHONY: verify-fmt 23 | verify-fmt: 24 | GO111MODULE=on ./hack/verify-gofmt.sh 25 | 26 | .PHONY: verify-lint 27 | verify-lint: 28 | GO111MODULE=on ./hack/verify-golint.sh 29 | 30 | .PHONY: verify-apidiff 31 | verify-apidiff: 32 | GO111MODULE=on ./hack/verify-apidiff.sh -r master 33 | 34 | .PHONY: vet 35 | vet: 36 | GO111MODULE=on ./hack/verify-govet.sh 37 | 38 | .PHONY: update-fmt 39 | update-fmt: 40 | gofmt -s -w . 41 | 42 | # We set the maximum version of the go directive as 1.23 here 43 | # because the oldest go directive that exists on our supported 44 | # release branches in k/k is 1.23. 45 | .PHONY: verify-go-directive 46 | verify-go-directive: 47 | ./hack/verify-go-directive.sh -g 1.23 48 | -------------------------------------------------------------------------------- /hack/lib/util.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2014 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # arguments: target, item1, item2, item3, ... 18 | # returns 0 if target is in the given items, 1 otherwise. 19 | kube::util::array_contains() { 20 | local search="$1" 21 | local element 22 | shift 23 | for element; do 24 | if [[ "${element}" == "${search}" ]]; then 25 | return 0 26 | fi 27 | done 28 | return 1 29 | } 30 | 31 | # kube::util::check-file-in-alphabetical-order 32 | # Check that the file is in alphabetical order 33 | # 34 | function kube::util::check-file-in-alphabetical-order { 35 | local failure_file="$1" 36 | if ! diff -u "${failure_file}" <(LC_ALL=C sort "${failure_file}"); then 37 | { 38 | echo 39 | echo "${failure_file} is not in alphabetical order. Please sort it:" 40 | echo 41 | echo " LC_ALL=C sort -o ${failure_file} ${failure_file}" 42 | echo 43 | } >&2 44 | false 45 | fi 46 | } 47 | -------------------------------------------------------------------------------- /inotify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /HOWTOMOVE.md: -------------------------------------------------------------------------------- 1 | # How to move a utility pkg from other kubernetes repos 2 | 3 | It has 2 steps to move a pkg from other Kubernetes repos to `k8s.io/utils` repo: 4 | - copy the pkg to `k8s.io/utils` repo 5 | - update the import paths and `vendor/` in the repos that refer this pkg 6 | 7 | ## Copy the pkg to `k8s.io/utils` repo 8 | 9 | Copying should preserve all the git history associated with it. 10 | [Here](http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/) is a working approach. 11 | Note: You may need to use `--allow-unrelated-histories` if you get error when running `git pull` following the post above. 12 | 13 | Then, you may need to restructure the package to make sure it has the following structure. 14 | 15 | . 16 | ├── doc.go # Description for this package 17 | ├── .go # utility go file 18 | ├── _test.go # go unit tests 19 | └── testing # All the testing framework 20 | └── fake_.go # Testing framework go file 21 | 22 | [#5](https://github.com/kubernetes/utils/pull/5) is an example for this step. 23 | 24 | ## Update the repos that refer the pkg 25 | 26 | You should update the import paths. 27 | Then follow [this doc](https://github.com/kubernetes/community/blob/master/contributors/devel/godep.md) to update `vendor/` and `Godeps/`. 28 | 29 | You may want to run `make bazel-test` to make sure all new references work. 30 | 31 | [kubernetes/kubernetes#49234](https://github.com/kubernetes/kubernetes/pull/49234) is an example for this step. 32 | -------------------------------------------------------------------------------- /third_party/forked/golang/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /internal/third_party/forked/golang/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /temp/temptest/file.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temptest 18 | 19 | import ( 20 | "bytes" 21 | "errors" 22 | "io" 23 | ) 24 | 25 | // FakeFile is an implementation of a WriteCloser, that records what has 26 | // been written in the file (in a bytes.Buffer) and if the file has been 27 | // closed. 28 | type FakeFile struct { 29 | Buffer bytes.Buffer 30 | Closed bool 31 | } 32 | 33 | var _ io.WriteCloser = &FakeFile{} 34 | 35 | // Write appends the contents of p to the Buffer. If the file has 36 | // already been closed, an error is returned. 37 | func (f *FakeFile) Write(p []byte) (n int, err error) { 38 | if f.Closed { 39 | return 0, errors.New("can't write to closed FakeFile") 40 | } 41 | return f.Buffer.Write(p) 42 | } 43 | 44 | // Close records that the file has been closed. If the file has already 45 | // been closed, an error is returned. 46 | func (f *FakeFile) Close() error { 47 | if f.Closed { 48 | return errors.New("FakeFile was closed multiple times") 49 | } 50 | f.Closed = true 51 | return nil 52 | } 53 | -------------------------------------------------------------------------------- /temp/temptest/dir_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temptest 18 | 19 | import ( 20 | "io" 21 | "testing" 22 | ) 23 | 24 | func TestFakeDir(t *testing.T) { 25 | d := &FakeDir{} 26 | 27 | f, err := d.NewFile("ONE") 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | 32 | n, err := io.WriteString(f, "Bonjour!") 33 | if n != 8 || err != nil { 34 | t.Fatalf( 35 | `WriteString(f, "Bonjour!") = (%v, %v), expected (%v, %v)`, 36 | n, err, 37 | 0, nil, 38 | ) 39 | } 40 | if got := d.Files["ONE"].Buffer.String(); got != "Bonjour!" { 41 | t.Fatalf(`file content is %q, expected "Bonjour!"`, got) 42 | } 43 | 44 | _, err = d.NewFile("ONE") 45 | if err == nil { 46 | t.Fatal("Same file could be created twice.") 47 | } 48 | 49 | err = d.Delete() 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | 54 | err = d.Delete() 55 | if err == nil { 56 | t.Fatal("FakeDir could be deleted twice.") 57 | } 58 | 59 | _, err = d.NewFile("TWO") 60 | if err == nil { 61 | t.Fatal("NewFile could be created in deleted dir") 62 | } 63 | 64 | if !d.Deleted { 65 | t.Fatal("FakeDir should be deleted.") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /internal/third_party/forked/golang/net/parse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Simple file i/o and string manipulation, to avoid 6 | // depending on strconv and bufio and strings. 7 | 8 | package net 9 | 10 | /////////////////////////////////////////////////////////////////////////////// 11 | // NOTE: This file was forked because it is used by other code that needed to 12 | // be forked, not because it is used on its own. 13 | /////////////////////////////////////////////////////////////////////////////// 14 | 15 | // Bigger than we need, not too big to worry about overflow 16 | const big = 0xFFFFFF 17 | 18 | // Decimal to integer. 19 | // Returns number, characters consumed, success. 20 | func dtoi(s string) (n int, i int, ok bool) { 21 | n = 0 22 | for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { 23 | n = n*10 + int(s[i]-'0') 24 | if n >= big { 25 | return big, i, false 26 | } 27 | } 28 | if i == 0 { 29 | return 0, 0, false 30 | } 31 | return n, i, true 32 | } 33 | 34 | // Hexadecimal to integer. 35 | // Returns number, characters consumed, success. 36 | func xtoi(s string) (n int, i int, ok bool) { 37 | n = 0 38 | for i = 0; i < len(s); i++ { 39 | if '0' <= s[i] && s[i] <= '9' { 40 | n *= 16 41 | n += int(s[i] - '0') 42 | } else if 'a' <= s[i] && s[i] <= 'f' { 43 | n *= 16 44 | n += int(s[i]-'a') + 10 45 | } else if 'A' <= s[i] && s[i] <= 'F' { 46 | n *= 16 47 | n += int(s[i]-'A') + 10 48 | } else { 49 | break 50 | } 51 | if n >= big { 52 | return 0, i, false 53 | } 54 | } 55 | if i == 0 { 56 | return 0, i, false 57 | } 58 | return n, i, true 59 | } 60 | -------------------------------------------------------------------------------- /inotify/inotify_others.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | /* 4 | Copyright 2020 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package inotify // import "k8s.io/utils/inotify" 20 | 21 | import ( 22 | "fmt" 23 | "runtime" 24 | ) 25 | 26 | var errNotSupported = fmt.Errorf("watch not supported on %s", runtime.GOOS) 27 | 28 | // NewWatcher creates and returns a new inotify instance using inotify_init(2) 29 | func NewWatcher() (*Watcher, error) { 30 | return nil, errNotSupported 31 | } 32 | 33 | // Close closes an inotify watcher instance 34 | // It sends a message to the reader goroutine to quit and removes all watches 35 | // associated with the inotify instance 36 | func (w *Watcher) Close() error { 37 | return errNotSupported 38 | } 39 | 40 | // AddWatch adds path to the watched file set. 41 | // The flags are interpreted as described in inotify_add_watch(2). 42 | func (w *Watcher) AddWatch(path string, flags uint32) error { 43 | return errNotSupported 44 | } 45 | 46 | // Watch adds path to the watched file set, watching all events. 47 | func (w *Watcher) Watch(path string) error { 48 | return errNotSupported 49 | } 50 | 51 | // RemoveWatch removes path from the watched file set. 52 | func (w *Watcher) RemoveWatch(path string) error { 53 | return errNotSupported 54 | } 55 | -------------------------------------------------------------------------------- /keymutex/hashed.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package keymutex 18 | 19 | import ( 20 | "hash/fnv" 21 | "runtime" 22 | "sync" 23 | ) 24 | 25 | // NewHashed returns a new instance of KeyMutex which hashes arbitrary keys to 26 | // a fixed set of locks. `n` specifies number of locks, if n <= 0, we use 27 | // number of cpus. 28 | // Note that because it uses fixed set of locks, different keys may share same 29 | // lock, so it's possible to wait on same lock. 30 | func NewHashed(n int) KeyMutex { 31 | if n <= 0 { 32 | n = runtime.NumCPU() 33 | } 34 | return &hashedKeyMutex{ 35 | mutexes: make([]sync.Mutex, n), 36 | } 37 | } 38 | 39 | type hashedKeyMutex struct { 40 | mutexes []sync.Mutex 41 | } 42 | 43 | // Acquires a lock associated with the specified ID. 44 | func (km *hashedKeyMutex) LockKey(id string) { 45 | km.mutexes[km.hash(id)%uint32(len(km.mutexes))].Lock() 46 | } 47 | 48 | // Releases the lock associated with the specified ID. 49 | func (km *hashedKeyMutex) UnlockKey(id string) error { 50 | km.mutexes[km.hash(id)%uint32(len(km.mutexes))].Unlock() 51 | return nil 52 | } 53 | 54 | func (km *hashedKeyMutex) hash(id string) uint32 { 55 | h := fnv.New32a() 56 | h.Write([]byte(id)) 57 | return h.Sum32() 58 | } 59 | -------------------------------------------------------------------------------- /inotify/inotify.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package inotify // import "k8s.io/utils/inotify" 18 | 19 | import ( 20 | "sync" 21 | ) 22 | 23 | // Event represents a notification 24 | type Event struct { 25 | Mask uint32 // Mask of events 26 | Cookie uint32 // Unique cookie associating related events (for rename(2)) 27 | Name string // File name (optional) 28 | } 29 | 30 | type watch struct { 31 | wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) 32 | flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) 33 | } 34 | 35 | // Watcher represents an inotify instance 36 | type Watcher struct { 37 | mu sync.Mutex 38 | fd int // File descriptor (as returned by the inotify_init() syscall) 39 | watches map[string]*watch // Map of inotify watches (key: path) 40 | paths map[int]string // Map of watched paths (key: watch descriptor) 41 | Error chan error // Errors are sent on this channel 42 | Event chan *Event // Events are returned on this channel 43 | done chan bool // Channel for sending a "quit message" to the reader goroutine 44 | isClosed bool // Set to true when Close() is first called 45 | } 46 | -------------------------------------------------------------------------------- /temp/temptest/dir.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temptest 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "io" 23 | 24 | "k8s.io/utils/temp" 25 | ) 26 | 27 | // FakeDir implements a Directory that is not backed on the 28 | // filesystem. This is useful for testing since the created "files" are 29 | // simple bytes.Buffer that can be inspected. 30 | type FakeDir struct { 31 | Files map[string]*FakeFile 32 | Deleted bool 33 | } 34 | 35 | var _ temp.Directory = &FakeDir{} 36 | 37 | // NewFile returns a new FakeFile if the filename doesn't exist already. 38 | // This function will fail if the directory has already been deleted. 39 | func (d *FakeDir) NewFile(name string) (io.WriteCloser, error) { 40 | if d.Deleted { 41 | return nil, errors.New("can't create file in deleted FakeDir") 42 | } 43 | if d.Files == nil { 44 | d.Files = map[string]*FakeFile{} 45 | } 46 | f := d.Files[name] 47 | if f != nil { 48 | return nil, fmt.Errorf( 49 | "FakeDir already has file named %q", 50 | name, 51 | ) 52 | } 53 | f = &FakeFile{} 54 | d.Files[name] = f 55 | return f, nil 56 | } 57 | 58 | // Delete doesn't remove anything, but records that the directory has 59 | // been deleted. 60 | func (d *FakeDir) Delete() error { 61 | if d.Deleted { 62 | return errors.New("failed to re-delete FakeDir") 63 | } 64 | d.Deleted = true 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Utils 2 | 3 | [![Build Status]](https://travis-ci.org/kubernetes/utils) [![GoDoc](https://godoc.org/k8s.io/utils?status.svg)](https://godoc.org/k8s.io/utils) 4 | 5 | A set of Go libraries that provide low-level, kubernetes-independent packages 6 | supplementing the [Go standard libs]. 7 | 8 | ## Purpose 9 | 10 | As Kubernetes grows and spins functionality out of its [core] and into 11 | cooperating repositories like [apiserver], [kubectl], [kubeadm], etc., the need 12 | arises for leaf repositories to house shared code and avoid cycles in repository 13 | relationships. 14 | 15 | This repository is intended to hold shared utilities with _no Kubernetes 16 | dependencies_ that may be of interest to any Go project. See these [instructions 17 | for moving] an existing package to this repository. 18 | 19 | ## Criteria for adding code here 20 | 21 | - Used by multiple Kubernetes repositories. 22 | 23 | - Complex enough to be worth vendoring, rather than copying (e.g. not 5 LOC). 24 | 25 | - Can be fully exercised by unit tests (e.g. no dependencies on kernels). 26 | 27 | - Has full unit test coverage. 28 | 29 | - Stable, or backward compatible, API, with complete godocs. 30 | 31 | - Go tools compliant (`go get`, `go test`, etc.). 32 | 33 | - Very few (ideally zero) external dependencies. 34 | 35 | - _No dependencies on any other Kubernetes repository_. 36 | 37 | [Build Status]: https://travis-ci.org/kubernetes/utils.svg?branch=master 38 | [Go standard libs]: https://pkg.go.dev/std#stdlib 39 | [api]: https://github.com/kubernetes/api 40 | [apiserver]: https://github.com/kubernetes/apiserver 41 | [core]: https://github.com/kubernetes/kubernetes 42 | [ingress]: https://github.com/kubernetes/ingress 43 | [kubeadm]: https://github.com/kubernetes/kubeadm 44 | [kubectl]: https://github.com/kubernetes/kubectl 45 | [instructions for moving]: ./HOWTOMOVE.md 46 | 47 | ## Contributing 48 | 49 | Please see [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to contribute. 50 | -------------------------------------------------------------------------------- /hack/verify-go-directive.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2024 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | function usage { 22 | local script="$(basename $0)" 23 | 24 | echo >&2 "Usage: ${script} [-g ] 25 | 26 | This script should be run at the root of a module. 27 | 28 | -g 29 | Compare the go directive in the local working copy's go.mod 30 | to the specified maximum version it can be. Versions provided 31 | here are of the form 1.x.y, without the 'go' prefix. 32 | 33 | Examples: 34 | ${script} -g 1.20 35 | ${script} -g 1.21.6 36 | " 37 | exit 1 38 | } 39 | 40 | max="" 41 | while getopts g: o 42 | do case "$o" in 43 | g) max="$OPTARG";; 44 | [?]) usage;; 45 | esac 46 | done 47 | 48 | # If max is empty, print usage and error 49 | if [[ -z "${max}" ]]; then 50 | usage; 51 | fi 52 | 53 | # Don't specify the version with the go prefix, just 1.x.y will do. 54 | if ! printf '%s\n' "${max}" | grep -v -q "^go"; then 55 | usage; 56 | fi 57 | 58 | current=$(grep '^go [1-9]*' go.mod | cut -d ' ' -f2) 59 | if [[ -z "${current}" ]]; then 60 | echo >&2 "FAIL: could not get value of go directive from go.mod" 61 | exit 1 62 | fi 63 | 64 | if ! printf '%s\n' "${current}" "${max}" | sort --check=silent --version-sort; then 65 | echo >&2 "FAIL: current Go directive ${current} is greater than ${max}" 66 | exit 1 67 | fi 68 | -------------------------------------------------------------------------------- /set/ordered.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package set 18 | 19 | // ordered is a constraint that permits any ordered type: any type 20 | // that supports the operators < <= >= >. 21 | // If future releases of Go add new ordered types, 22 | // this constraint will be modified to include them. 23 | type ordered interface { 24 | integer | float | ~string 25 | } 26 | 27 | // integer is a constraint that permits any integer type. 28 | // If future releases of Go add new predeclared integer types, 29 | // this constraint will be modified to include them. 30 | type integer interface { 31 | signed | unsigned 32 | } 33 | 34 | // float is a constraint that permits any floating-point type. 35 | // If future releases of Go add new predeclared floating-point types, 36 | // this constraint will be modified to include them. 37 | type float interface { 38 | ~float32 | ~float64 39 | } 40 | 41 | // signed is a constraint that permits any signed integer type. 42 | // If future releases of Go add new predeclared signed integer types, 43 | // this constraint will be modified to include them. 44 | type signed interface { 45 | ~int | ~int8 | ~int16 | ~int32 | ~int64 46 | } 47 | 48 | // unsigned is a constraint that permits any unsigned integer type. 49 | // If future releases of Go add new predeclared unsigned integer types, 50 | // this constraint will be modified to include them. 51 | type unsigned interface { 52 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr 53 | } 54 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | **What type of PR is this?** 13 | > Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line: 14 | > 15 | > /kind api-change 16 | > /kind bug 17 | > /kind cleanup 18 | > /kind design 19 | > /kind documentation 20 | > /kind test 21 | > /kind failing-test 22 | > /kind feature 23 | > /kind flake 24 | 25 | **What this PR does / why we need it**: 26 | 27 | **Which issue(s) this PR fixes**: 28 | 33 | Fixes # 34 | 35 | **Special notes for your reviewer**: 36 | 37 | 38 | **Release note**: 39 | ``` 40 | 41 | ``` 42 | -------------------------------------------------------------------------------- /temp/dir.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temp 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "io/ioutil" 23 | "os" 24 | "path/filepath" 25 | ) 26 | 27 | // Directory is an interface to a temporary directory, in which you can 28 | // create new files. 29 | type Directory interface { 30 | // NewFile creates a new file in that directory. Calling NewFile 31 | // with the same filename twice will result in an error. 32 | NewFile(name string) (io.WriteCloser, error) 33 | // Delete removes the directory and its content. 34 | Delete() error 35 | } 36 | 37 | // Dir is wrapping an temporary directory on disk. 38 | type Dir struct { 39 | // Name is the name (full path) of the created directory. 40 | Name string 41 | } 42 | 43 | var _ Directory = &Dir{} 44 | 45 | // CreateTempDir returns a new Directory wrapping a temporary directory 46 | // on disk. 47 | func CreateTempDir(prefix string) (*Dir, error) { 48 | name, err := ioutil.TempDir("", fmt.Sprintf("%s-", prefix)) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | return &Dir{ 54 | Name: name, 55 | }, nil 56 | } 57 | 58 | // NewFile creates a new file in the specified directory. 59 | func (d *Dir) NewFile(name string) (io.WriteCloser, error) { 60 | return os.OpenFile( 61 | filepath.Join(d.Name, name), 62 | os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 63 | 0700, 64 | ) 65 | } 66 | 67 | // Delete the underlying directory, and all of its content. 68 | func (d *Dir) Delete() error { 69 | return os.RemoveAll(d.Name) 70 | } 71 | -------------------------------------------------------------------------------- /clock/testing/simple_interval_clock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package testing 18 | 19 | import ( 20 | "testing" 21 | "time" 22 | ) 23 | 24 | func TestSimpleIntervalClockNow(t *testing.T) { 25 | cases := []struct { 26 | duration time.Duration 27 | }{ 28 | {duration: 10 * time.Millisecond}, 29 | {duration: 0 * time.Millisecond}, 30 | {duration: -10 * time.Millisecond}, 31 | } 32 | 33 | startTime := time.Now() 34 | for _, c := range cases { 35 | expectedTime := startTime.Add(c.duration) 36 | sic := &SimpleIntervalClock{ 37 | Time: startTime, 38 | Duration: c.duration, 39 | } 40 | actualTime := sic.Now() 41 | if !expectedTime.Equal(actualTime) { 42 | t.Errorf("expected %#v, got %#v", expectedTime, actualTime) 43 | } 44 | } 45 | } 46 | 47 | func TestSimpleIntervalClockSince(t *testing.T) { 48 | cases := []struct { 49 | delta time.Duration 50 | }{ 51 | {delta: 10 * time.Millisecond}, 52 | {delta: 0 * time.Millisecond}, 53 | {delta: -10 * time.Millisecond}, 54 | } 55 | 56 | startTime := time.Now() 57 | duration := time.Millisecond 58 | sic := &SimpleIntervalClock{ 59 | Time: startTime, 60 | Duration: duration, 61 | } 62 | 63 | for _, c := range cases { 64 | // Try and add compute a "since" time by 65 | // Add()ing a -c.delta. 66 | timeSinceDelta := startTime.Add(-c.delta) 67 | expectedDelta := sic.Since(timeSinceDelta) 68 | if expectedDelta != c.delta { 69 | t.Errorf("expected %#v, got %#v", expectedDelta, c.delta) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /trace/README.md: -------------------------------------------------------------------------------- 1 | # Trace 2 | 3 | This package provides an interface for recording the latency of operations and logging details 4 | about all operations where the latency exceeds a limit. 5 | 6 | ## Usage 7 | 8 | To create a trace: 9 | 10 | ```go 11 | func doSomething() { 12 | opTrace := trace.New("operation", Field{Key: "fieldKey1", Value: "fieldValue1"}) 13 | defer opTrace.LogIfLong(100 * time.Millisecond) 14 | // do something 15 | } 16 | ``` 17 | 18 | To split an trace into multiple steps: 19 | 20 | ```go 21 | func doSomething() { 22 | opTrace := trace.New("operation") 23 | defer opTrace.LogIfLong(100 * time.Millisecond) 24 | // do step 1 25 | opTrace.Step("step1", Field{Key: "stepFieldKey1", Value: "stepFieldValue1"}) 26 | // do step 2 27 | opTrace.Step("step2") 28 | } 29 | ``` 30 | 31 | To nest traces: 32 | 33 | ```go 34 | func doSomething() { 35 | rootTrace := trace.New("rootOperation") 36 | defer rootTrace.LogIfLong(100 * time.Millisecond) 37 | 38 | func() { 39 | nestedTrace := rootTrace.Nest("nested", Field{Key: "nestedFieldKey1", Value: "nestedFieldValue1"}) 40 | defer nestedTrace.LogIfLong(50 * time.Millisecond) 41 | // do nested operation 42 | }() 43 | } 44 | ``` 45 | 46 | Traces can also be logged unconditionally or introspected: 47 | 48 | ```go 49 | opTrace.TotalTime() // Duration since the Trace was created 50 | opTrace.Log() // unconditionally log the trace 51 | ``` 52 | 53 | ### Using context.Context to nest traces 54 | 55 | `context.Context` can be used to manage nested traces. Create traces by calling `trace.GetTraceFromContext(ctx).Nest`. 56 | This is safe even if there is no parent trace already in the context because `(*(Trace)nil).Nest()` returns 57 | a top level trace. 58 | 59 | ```go 60 | func doSomething(ctx context.Context) { 61 | opTrace := trace.FromContext(ctx).Nest("operation") // create a trace, possibly nested 62 | ctx = trace.ContextWithTrace(ctx, opTrace) // make this trace the parent trace of the context 63 | defer opTrace.LogIfLong(50 * time.Millisecond) 64 | 65 | doSomethingElse(ctx) 66 | } 67 | ``` -------------------------------------------------------------------------------- /integer/integer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package integer 18 | 19 | import "math" 20 | 21 | // IntMax returns the maximum of the params. 22 | // Deprecated: for new code, use the max() builtin instead. 23 | func IntMax(a, b int) int { 24 | if b > a { 25 | return b 26 | } 27 | return a 28 | } 29 | 30 | // IntMin returns the minimum of the params. 31 | // Deprecated: for new code, use the min() builtin instead. 32 | func IntMin(a, b int) int { 33 | if b < a { 34 | return b 35 | } 36 | return a 37 | } 38 | 39 | // Int32Max returns the maximum of the params. 40 | // Deprecated: for new code, use the max() builtin instead. 41 | func Int32Max(a, b int32) int32 { 42 | if b > a { 43 | return b 44 | } 45 | return a 46 | } 47 | 48 | // Int32Min returns the minimum of the params. 49 | // Deprecated: for new code, use the min() builtin instead. 50 | func Int32Min(a, b int32) int32 { 51 | if b < a { 52 | return b 53 | } 54 | return a 55 | } 56 | 57 | // Int64Max returns the maximum of the params. 58 | // Deprecated: for new code, use the max() builtin instead. 59 | func Int64Max(a, b int64) int64 { 60 | if b > a { 61 | return b 62 | } 63 | return a 64 | } 65 | 66 | // Int64Min returns the minimum of the params. 67 | // Deprecated: for new code, use the min() builtin instead. 68 | func Int64Min(a, b int64) int64 { 69 | if b < a { 70 | return b 71 | } 72 | return a 73 | } 74 | 75 | // RoundToInt32 rounds floats into integer numbers. 76 | // Deprecated: use math.Round() and a cast directly. 77 | func RoundToInt32(a float64) int32 { 78 | return int32(math.Round(a)) 79 | } 80 | -------------------------------------------------------------------------------- /ptr/ptr.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ptr 18 | 19 | import ( 20 | "fmt" 21 | "reflect" 22 | ) 23 | 24 | // AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, 25 | // for example, an API struct is handled by plugins which need to distinguish 26 | // "no plugin accepted this spec" from "this spec is empty". 27 | // 28 | // This function is only valid for structs and pointers to structs. Any other 29 | // type will cause a panic. Passing a typed nil pointer will return true. 30 | func AllPtrFieldsNil(obj interface{}) bool { 31 | v := reflect.ValueOf(obj) 32 | if !v.IsValid() { 33 | panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) 34 | } 35 | if v.Kind() == reflect.Ptr { 36 | if v.IsNil() { 37 | return true 38 | } 39 | v = v.Elem() 40 | } 41 | for i := 0; i < v.NumField(); i++ { 42 | if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { 43 | return false 44 | } 45 | } 46 | return true 47 | } 48 | 49 | // To returns a pointer to the given value. 50 | func To[T any](v T) *T { 51 | return &v 52 | } 53 | 54 | // Deref dereferences ptr and returns the value it points to if no nil, or else 55 | // returns def. 56 | func Deref[T any](ptr *T, def T) T { 57 | if ptr != nil { 58 | return *ptr 59 | } 60 | return def 61 | } 62 | 63 | // Equal returns true if both arguments are nil or both arguments 64 | // dereference to the same value. 65 | func Equal[T comparable](a, b *T) bool { 66 | if (a == nil) != (b == nil) { 67 | return false 68 | } 69 | if a == nil { 70 | return true 71 | } 72 | return *a == *b 73 | } 74 | -------------------------------------------------------------------------------- /strings/line_delimiter.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "bytes" 21 | "io" 22 | "strings" 23 | ) 24 | 25 | // LineDelimiter is a filter that will split input on lines 26 | // and bracket each line with the delimiter string. 27 | type LineDelimiter struct { 28 | output io.Writer 29 | delimiter []byte 30 | buf bytes.Buffer 31 | } 32 | 33 | // NewLineDelimiter allocates a new io.Writer that will split input on lines 34 | // and bracket each line with the delimiter string. This can be useful in 35 | // output tests where it is difficult to see and test trailing whitespace. 36 | func NewLineDelimiter(output io.Writer, delimiter string) *LineDelimiter { 37 | return &LineDelimiter{output: output, delimiter: []byte(delimiter)} 38 | } 39 | 40 | // Write writes buf to the LineDelimiter ld. The only errors returned are ones 41 | // encountered while writing to the underlying output stream. 42 | func (ld *LineDelimiter) Write(buf []byte) (n int, err error) { 43 | return ld.buf.Write(buf) 44 | } 45 | 46 | // Flush all lines up until now. This will assume insert a linebreak at the current point of the stream. 47 | func (ld *LineDelimiter) Flush() (err error) { 48 | lines := strings.Split(ld.buf.String(), "\n") 49 | for _, line := range lines { 50 | if _, err = ld.output.Write(ld.delimiter); err != nil { 51 | return 52 | } 53 | if _, err = ld.output.Write([]byte(line)); err != nil { 54 | return 55 | } 56 | if _, err = ld.output.Write(ld.delimiter); err != nil { 57 | return 58 | } 59 | if _, err = ld.output.Write([]byte("\n")); err != nil { 60 | return 61 | } 62 | } 63 | return 64 | } 65 | -------------------------------------------------------------------------------- /env/env.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package env 18 | 19 | import ( 20 | "os" 21 | "strconv" 22 | ) 23 | 24 | // GetString returns the env variable for the given key 25 | // and falls back to the given defaultValue if not set 26 | func GetString(key, defaultValue string) string { 27 | v, ok := os.LookupEnv(key) 28 | if ok { 29 | return v 30 | } 31 | return defaultValue 32 | } 33 | 34 | // GetInt returns the env variable (parsed as integer) for 35 | // the given key and falls back to the given defaultValue if not set 36 | func GetInt(key string, defaultValue int) (int, error) { 37 | v, ok := os.LookupEnv(key) 38 | if ok { 39 | value, err := strconv.Atoi(v) 40 | if err != nil { 41 | return defaultValue, err 42 | } 43 | return value, nil 44 | } 45 | return defaultValue, nil 46 | } 47 | 48 | // GetFloat64 returns the env variable (parsed as float64) for 49 | // the given key and falls back to the given defaultValue if not set 50 | func GetFloat64(key string, defaultValue float64) (float64, error) { 51 | v, ok := os.LookupEnv(key) 52 | if ok { 53 | value, err := strconv.ParseFloat(v, 64) 54 | if err != nil { 55 | return defaultValue, err 56 | } 57 | return value, nil 58 | } 59 | return defaultValue, nil 60 | } 61 | 62 | // GetBool returns the env variable (parsed as bool) for 63 | // the given key and falls back to the given defaultValue if not set 64 | func GetBool(key string, defaultValue bool) (bool, error) { 65 | v, ok := os.LookupEnv(key) 66 | if ok { 67 | value, err := strconv.ParseBool(v) 68 | if err != nil { 69 | return defaultValue, err 70 | } 71 | return value, nil 72 | } 73 | return defaultValue, nil 74 | } 75 | -------------------------------------------------------------------------------- /strings/strings_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package strings 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestSplitQualifiedName(t *testing.T) { 24 | testCases := []struct { 25 | input string 26 | output []string 27 | }{ 28 | {"kubernetes.io/blah", []string{"kubernetes.io", "blah"}}, 29 | {"blah", []string{"", "blah"}}, 30 | {"kubernetes.io/blah/blah", []string{"kubernetes.io", "blah"}}, 31 | } 32 | for i, tc := range testCases { 33 | namespace, name := SplitQualifiedName(tc.input) 34 | if namespace != tc.output[0] || name != tc.output[1] { 35 | t.Errorf("case[%d]: expected (%q, %q), got (%q, %q)", i, tc.output[0], tc.output[1], namespace, name) 36 | } 37 | } 38 | } 39 | 40 | func TestJoinQualifiedName(t *testing.T) { 41 | testCases := []struct { 42 | input []string 43 | output string 44 | }{ 45 | {[]string{"kubernetes.io", "blah"}, "kubernetes.io/blah"}, 46 | {[]string{"blah", ""}, "blah"}, 47 | {[]string{"kubernetes.io", "blah"}, "kubernetes.io/blah"}, 48 | } 49 | for i, tc := range testCases { 50 | res := JoinQualifiedName(tc.input[0], tc.input[1]) 51 | if res != tc.output { 52 | t.Errorf("case[%d]: expected %q, got %q", i, tc.output, res) 53 | } 54 | } 55 | } 56 | 57 | func TestShortenString(t *testing.T) { 58 | testCases := []struct { 59 | input string 60 | outLen int 61 | output string 62 | }{ 63 | {"kubernetes.io", 5, "kuber"}, 64 | {"blah", 34, "blah"}, 65 | {"kubernetes.io", 13, "kubernetes.io"}, 66 | } 67 | for i, tc := range testCases { 68 | res := ShortenString(tc.input, tc.outLen) 69 | if res != tc.output { 70 | t.Errorf("case[%d]: expected %q, got %q", i, tc.output, res) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /temp/dir_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package temp 18 | 19 | import ( 20 | "io/ioutil" 21 | "os" 22 | "path/filepath" 23 | "strings" 24 | "testing" 25 | ) 26 | 27 | func TestTempDir(t *testing.T) { 28 | dir, err := CreateTempDir("prefix") 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | // Delete the directory no matter what. 34 | defer dir.Delete() 35 | 36 | // Make sure we have created the dir, with the proper name 37 | _, err = os.Stat(dir.Name) 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | if !strings.HasPrefix(filepath.Base(dir.Name), "prefix") { 42 | t.Fatalf(`Directory doesn't start with "prefix": %q`, 43 | dir.Name) 44 | } 45 | 46 | // Verify that the directory is empty 47 | entries, err := ioutil.ReadDir(dir.Name) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | if len(entries) != 0 { 52 | t.Fatalf("Directory should be empty, has %d elements", 53 | len(entries)) 54 | } 55 | 56 | // Create a couple of files 57 | _, err = dir.NewFile("ONE") 58 | if err != nil { 59 | t.Fatal(err) 60 | } 61 | _, err = dir.NewFile("TWO") 62 | if err != nil { 63 | t.Fatal(err) 64 | } 65 | // We can't create the same file twice 66 | _, err = dir.NewFile("TWO") 67 | if err == nil { 68 | t.Fatal("NewFile should fail to create the same file twice") 69 | } 70 | 71 | // We have created only two files 72 | entries, err = ioutil.ReadDir(dir.Name) 73 | if err != nil { 74 | t.Fatal(err) 75 | } 76 | if len(entries) != 2 { 77 | t.Fatalf("ReadDir should have two elements, has %d elements", 78 | len(entries)) 79 | } 80 | 81 | // Verify that deletion works 82 | err = dir.Delete() 83 | if err != nil { 84 | t.Fatal(err) 85 | } 86 | _, err = os.Stat(dir.Name) 87 | if err == nil { 88 | t.Fatal("Directory should be gone, still present.") 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /path/file.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package path 18 | 19 | import ( 20 | "errors" 21 | "os" 22 | ) 23 | 24 | // LinkTreatment is the base type for constants used by Exists that indicate 25 | // how symlinks are treated for existence checks. 26 | type LinkTreatment int 27 | 28 | const ( 29 | // CheckFollowSymlink follows the symlink and verifies that the target of 30 | // the symlink exists. 31 | CheckFollowSymlink LinkTreatment = iota 32 | 33 | // CheckSymlinkOnly does not follow the symlink and verifies only that they 34 | // symlink itself exists. 35 | CheckSymlinkOnly 36 | ) 37 | 38 | // ErrInvalidLinkTreatment indicates that the link treatment behavior requested 39 | // is not a valid behavior. 40 | var ErrInvalidLinkTreatment = errors.New("unknown link behavior") 41 | 42 | // Exists checks if specified file, directory, or symlink exists. The behavior 43 | // of the test depends on the linkBehaviour argument. See LinkTreatment for 44 | // more details. 45 | func Exists(linkBehavior LinkTreatment, filename string) (bool, error) { 46 | var err error 47 | 48 | if linkBehavior == CheckFollowSymlink { 49 | _, err = os.Stat(filename) 50 | } else if linkBehavior == CheckSymlinkOnly { 51 | _, err = os.Lstat(filename) 52 | } else { 53 | return false, ErrInvalidLinkTreatment 54 | } 55 | 56 | if os.IsNotExist(err) { 57 | return false, nil 58 | } else if err != nil { 59 | return false, err 60 | } 61 | return true, nil 62 | } 63 | 64 | // ReadDirNoStat returns a string of files/directories contained 65 | // in dirname without calling lstat on them. 66 | func ReadDirNoStat(dirname string) ([]string, error) { 67 | if dirname == "" { 68 | dirname = "." 69 | } 70 | 71 | f, err := os.Open(dirname) 72 | if err != nil { 73 | return nil, err 74 | } 75 | defer f.Close() 76 | 77 | return f.Readdirnames(-1) 78 | } 79 | -------------------------------------------------------------------------------- /mount/mount_helper_windows_test.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | /* 5 | Copyright 2017 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package mount 21 | 22 | import ( 23 | "testing" 24 | ) 25 | 26 | func TestNormalizeWindowsPath(t *testing.T) { 27 | path := `/var/lib/kubelet/pods/146f8428-83e7-11e7-8dd4-000d3a31dac4/volumes/kubernetes.io~azure-disk` 28 | normalizedPath := NormalizeWindowsPath(path) 29 | if normalizedPath != `c:\var\lib\kubelet\pods\146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk` { 30 | t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath) 31 | } 32 | 33 | path = `/var/lib/kubelet/pods/146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk` 34 | normalizedPath = NormalizeWindowsPath(path) 35 | if normalizedPath != `c:\var\lib\kubelet\pods\146f8428-83e7-11e7-8dd4-000d3a31dac4\volumes\kubernetes.io~azure-disk` { 36 | t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath) 37 | } 38 | 39 | path = `/` 40 | normalizedPath = NormalizeWindowsPath(path) 41 | if normalizedPath != `c:\` { 42 | t.Errorf("normizeWindowsPath test failed, normalizedPath : %q", normalizedPath) 43 | } 44 | } 45 | 46 | func TestValidateDiskNumber(t *testing.T) { 47 | diskNum := "0" 48 | if err := ValidateDiskNumber(diskNum); err != nil { 49 | t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum) 50 | } 51 | 52 | diskNum = "99" 53 | if err := ValidateDiskNumber(diskNum); err != nil { 54 | t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum) 55 | } 56 | 57 | diskNum = "ab" 58 | if err := ValidateDiskNumber(diskNum); err == nil { 59 | t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum) 60 | } 61 | 62 | diskNum = "100" 63 | if err := ValidateDiskNumber(diskNum); err == nil { 64 | t.Errorf("TestValidateDiskNumber test failed, disk number : %s", diskNum) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /nsenter/nsenter_unsupported.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | // +build !linux 3 | 4 | /* 5 | Copyright 2017 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package nsenter 21 | 22 | import ( 23 | "context" 24 | "fmt" 25 | 26 | "k8s.io/utils/exec" 27 | ) 28 | 29 | const ( 30 | // DefaultHostRootFsPath is path to host's filesystem mounted into container 31 | // with kubelet. 32 | DefaultHostRootFsPath = "/rootfs" 33 | ) 34 | 35 | // Nsenter is a type alias for backward compatibility 36 | type Nsenter = NSEnter 37 | 38 | // NSEnter is part of experimental support for running the kubelet 39 | // in a container. 40 | type NSEnter struct { 41 | // a map of commands to their paths on the host filesystem 42 | Paths map[string]string 43 | } 44 | 45 | // NewNsenter constructs a new instance of NSEnter 46 | func NewNsenter(hostRootFsPath string, executor exec.Interface) (*Nsenter, error) { 47 | return &Nsenter{}, nil 48 | } 49 | 50 | // Exec executes nsenter commands in hostProcMountNsPath mount namespace 51 | func (ne *NSEnter) Exec(cmd string, args []string) exec.Cmd { 52 | return nil 53 | } 54 | 55 | // AbsHostPath returns the absolute runnable path for a specified command 56 | func (ne *NSEnter) AbsHostPath(command string) string { 57 | return "" 58 | } 59 | 60 | // SupportsSystemd checks whether command systemd-run exists 61 | func (ne *NSEnter) SupportsSystemd() (string, bool) { 62 | return "", false 63 | } 64 | 65 | // Command returns a command wrapped with nenter 66 | func (ne *NSEnter) Command(cmd string, args ...string) exec.Cmd { 67 | return nil 68 | } 69 | 70 | // CommandContext returns a CommandContext wrapped with nsenter 71 | func (ne *NSEnter) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd { 72 | return nil 73 | } 74 | 75 | // LookPath returns a LookPath wrapped with nsenter 76 | func (ne *NSEnter) LookPath(file string) (string, error) { 77 | return "", fmt.Errorf("not implemented, error looking up : %s", file) 78 | } 79 | 80 | var _ exec.Interface = &NSEnter{} 81 | -------------------------------------------------------------------------------- /net/port_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package net 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func ExampleLocalPort() { 24 | lp, err := NewLocalPort( 25 | "TCP port", 26 | "", 27 | IPv4, 28 | 443, 29 | TCP, 30 | ) 31 | if err != nil { 32 | panic(err) 33 | } 34 | port, err := ListenPortOpener.OpenLocalPort(lp) 35 | if err != nil { 36 | panic(err) 37 | } 38 | port.Close() 39 | } 40 | 41 | func TestLocalPortString(t *testing.T) { 42 | testCases := []struct { 43 | description string 44 | ip string 45 | family IPFamily 46 | port int 47 | protocol Protocol 48 | expectedStr string 49 | expectedErr bool 50 | }{ 51 | {"IPv4 UDP", "1.2.3.4", "", 9999, UDP, `"IPv4 UDP" (1.2.3.4:9999/udp)`, false}, 52 | {"IPv4 TCP", "5.6.7.8", "", 1053, TCP, `"IPv4 TCP" (5.6.7.8:1053/tcp)`, false}, 53 | {"IPv6 TCP", "2001:db8::1", "", 80, TCP, `"IPv6 TCP" ([2001:db8::1]:80/tcp)`, false}, 54 | {"IPv4 TCP, all addresses", "", IPv4, 1053, TCP, `"IPv4 TCP, all addresses" (:1053/tcp4)`, false}, 55 | {"IPv6 TCP, all addresses", "", IPv6, 80, TCP, `"IPv6 TCP, all addresses" (:80/tcp6)`, false}, 56 | {"No ip family TCP, all addresses", "", "", 80, TCP, `"No ip family TCP, all addresses" (:80/tcp)`, false}, 57 | {"IP family mismatch", "2001:db8::2", IPv4, 80, TCP, "", true}, 58 | {"IP family mismatch", "1.2.3.4", IPv6, 80, TCP, "", true}, 59 | {"Unsupported protocol", "2001:db8::2", "", 80, "http", "", true}, 60 | {"Invalid IP", "300", "", 80, TCP, "", true}, 61 | {"Invalid ip family", "", "5", 80, TCP, "", true}, 62 | } 63 | 64 | for _, tc := range testCases { 65 | lp, err := NewLocalPort( 66 | tc.description, 67 | tc.ip, 68 | tc.family, 69 | tc.port, 70 | tc.protocol, 71 | ) 72 | if tc.expectedErr { 73 | if err == nil { 74 | t.Errorf("Expected err when creating LocalPort %v", tc) 75 | } 76 | continue 77 | } 78 | if err != nil { 79 | t.Errorf("Unexpected err when creating LocalPort %s", err) 80 | continue 81 | } 82 | str := lp.String() 83 | if str != tc.expectedStr { 84 | t.Errorf("Unexpected output for %s, expected: %s, got: %s", tc.description, tc.expectedStr, str) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /strings/slices/slices.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package slices defines various functions useful with slices of string type. 18 | // The goal is to be as close as possible to 19 | // https://github.com/golang/go/issues/45955. Ideal would be if we can just 20 | // replace "stringslices" if the "slices" package becomes standard. 21 | package slices 22 | 23 | // Equal reports whether two slices are equal: the same length and all 24 | // elements equal. If the lengths are different, Equal returns false. 25 | // Otherwise, the elements are compared in index order, and the 26 | // comparison stops at the first unequal pair. 27 | func Equal(s1, s2 []string) bool { 28 | if len(s1) != len(s2) { 29 | return false 30 | } 31 | for i, n := range s1 { 32 | if n != s2[i] { 33 | return false 34 | } 35 | } 36 | return true 37 | } 38 | 39 | // Filter appends to d each element e of s for which keep(e) returns true. 40 | // It returns the modified d. d may be s[:0], in which case the kept 41 | // elements will be stored in the same slice. 42 | // if the slices overlap in some other way, the results are unspecified. 43 | // To create a new slice with the filtered results, pass nil for d. 44 | func Filter(d, s []string, keep func(string) bool) []string { 45 | for _, n := range s { 46 | if keep(n) { 47 | d = append(d, n) 48 | } 49 | } 50 | return d 51 | } 52 | 53 | // Contains reports whether v is present in s. 54 | func Contains(s []string, v string) bool { 55 | return Index(s, v) >= 0 56 | } 57 | 58 | // Index returns the index of the first occurrence of v in s, or -1 if 59 | // not present. 60 | func Index(s []string, v string) int { 61 | // "Contains" may be replaced with "Index(s, v) >= 0": 62 | // https://github.com/golang/go/issues/45955#issuecomment-873377947 63 | for i, n := range s { 64 | if n == v { 65 | return i 66 | } 67 | } 68 | return -1 69 | } 70 | 71 | // Functions below are not in https://github.com/golang/go/issues/45955 72 | 73 | // Clone returns a new clone of s. 74 | func Clone(s []string) []string { 75 | // https://github.com/go101/go101/wiki/There-is-not-a-perfect-way-to-clone-slices-in-Go 76 | if s == nil { 77 | return nil 78 | } 79 | c := make([]string, len(s)) 80 | copy(c, s) 81 | return c 82 | } 83 | -------------------------------------------------------------------------------- /mount/mount_unsupported.go: -------------------------------------------------------------------------------- 1 | //go:build !linux && !windows 2 | // +build !linux,!windows 3 | 4 | /* 5 | Copyright 2014 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package mount 21 | 22 | import ( 23 | "errors" 24 | ) 25 | 26 | // Mounter implements mount.Interface for unsupported platforms 27 | type Mounter struct { 28 | mounterPath string 29 | } 30 | 31 | var errUnsupported = errors.New("util/mount on this platform is not supported") 32 | 33 | // New returns a mount.Interface for the current system. 34 | // It provides options to override the default mounter behavior. 35 | // mounterPath allows using an alternative to `/bin/mount` for mounting. 36 | func New(mounterPath string) Interface { 37 | return &Mounter{ 38 | mounterPath: mounterPath, 39 | } 40 | } 41 | 42 | // Mount always returns an error on unsupported platforms 43 | func (mounter *Mounter) Mount(source string, target string, fstype string, options []string) error { 44 | return errUnsupported 45 | } 46 | 47 | // Mount always returns an error on unsupported platforms 48 | func (mounter *Mounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { 49 | return errUnsupported 50 | } 51 | 52 | // Unmount always returns an error on unsupported platforms 53 | func (mounter *Mounter) Unmount(target string) error { 54 | return errUnsupported 55 | } 56 | 57 | // List always returns an error on unsupported platforms 58 | func (mounter *Mounter) List() ([]MountPoint, error) { 59 | return []MountPoint{}, errUnsupported 60 | } 61 | 62 | // IsLikelyNotMountPoint always returns an error on unsupported platforms 63 | func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) { 64 | return true, errUnsupported 65 | } 66 | 67 | // GetMountRefs always returns an error on unsupported platforms 68 | func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) { 69 | return nil, errUnsupported 70 | } 71 | 72 | func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error { 73 | return mounter.Interface.Mount(source, target, fstype, options) 74 | } 75 | 76 | func (mounter *SafeFormatAndMount) diskLooksUnformatted(disk string) (bool, error) { 77 | return true, errUnsupported 78 | } 79 | -------------------------------------------------------------------------------- /field/path.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package field 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "strconv" 23 | ) 24 | 25 | // Path represents the path from some root to a particular field. 26 | type Path struct { 27 | name string // the name of this field or "" if this is an index 28 | index string // if name == "", this is a subscript (index or map key) of the previous element 29 | parent *Path // nil if this is the root element 30 | } 31 | 32 | // NewPath creates a root Path object. 33 | func NewPath(name string, moreNames ...string) *Path { 34 | r := &Path{name: name, parent: nil} 35 | for _, anotherName := range moreNames { 36 | r = &Path{name: anotherName, parent: r} 37 | } 38 | return r 39 | } 40 | 41 | // Root returns the root element of this Path. 42 | func (p *Path) Root() *Path { 43 | for ; p.parent != nil; p = p.parent { 44 | // Do nothing. 45 | } 46 | return p 47 | } 48 | 49 | // Child creates a new Path that is a child of the method receiver. 50 | func (p *Path) Child(name string, moreNames ...string) *Path { 51 | r := NewPath(name, moreNames...) 52 | r.Root().parent = p 53 | return r 54 | } 55 | 56 | // Index indicates that the previous Path is to be subscripted by an int. 57 | // This sets the same underlying value as Key. 58 | func (p *Path) Index(index int) *Path { 59 | return &Path{index: strconv.Itoa(index), parent: p} 60 | } 61 | 62 | // Key indicates that the previous Path is to be subscripted by a string. 63 | // This sets the same underlying value as Index. 64 | func (p *Path) Key(key string) *Path { 65 | return &Path{index: key, parent: p} 66 | } 67 | 68 | // String produces a string representation of the Path. 69 | func (p *Path) String() string { 70 | // make a slice to iterate 71 | elems := []*Path{} 72 | for ; p != nil; p = p.parent { 73 | elems = append(elems, p) 74 | } 75 | 76 | // iterate, but it has to be backwards 77 | buf := bytes.NewBuffer(nil) 78 | for i := range elems { 79 | p := elems[len(elems)-1-i] 80 | if p.parent != nil && len(p.name) > 0 { 81 | // This is either the root or it is a subscript. 82 | buf.WriteString(".") 83 | } 84 | if len(p.name) > 0 { 85 | buf.WriteString(p.name) 86 | } else { 87 | fmt.Fprintf(buf, "[%s]", p.index) 88 | } 89 | } 90 | return buf.String() 91 | } 92 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | strategy: 6 | matrix: 7 | go-version: [1.23.x, 1.25.x] 8 | platform: [windows-latest] 9 | runs-on: ${{ matrix.platform }} 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v3 13 | with: 14 | go-version: ${{ matrix.go-version }} 15 | - name: Checkout code 16 | uses: actions/checkout@v2 17 | - name: Build 18 | run: | 19 | go build ./... 20 | - name: Run Windows Unit Tests 21 | run: | 22 | $env:GH_ACTION="TRUE" 23 | go test -v -race ./mount/... 24 | test: 25 | strategy: 26 | matrix: 27 | go-version: [1.23.x, 1.25.x] 28 | platform: [ubuntu-latest, macos-latest] 29 | runs-on: ${{ matrix.platform }} 30 | steps: 31 | - name: Install Go 32 | uses: actions/setup-go@v3 33 | with: 34 | go-version: ${{ matrix.go-version }} 35 | - name: Checkout code 36 | uses: actions/checkout@v2 37 | - name: Test 38 | run: | 39 | make test 40 | verify-go-directive: 41 | strategy: 42 | matrix: 43 | go-version: [1.23.x, 1.25.x] 44 | platform: [ubuntu-latest, macos-latest] 45 | runs-on: ${{ matrix.platform }} 46 | steps: 47 | - name: Install Go 48 | uses: actions/setup-go@v3 49 | with: 50 | go-version: ${{ matrix.go-version }} 51 | - name: Checkout code 52 | uses: actions/checkout@v2 53 | - name: Verify go directive 54 | run: | 55 | make verify-go-directive 56 | lint: 57 | runs-on: ubuntu-latest 58 | steps: 59 | - name: Install Go 60 | uses: actions/setup-go@v6 61 | with: 62 | go-version: v1.23 63 | - name: Checkout code 64 | uses: actions/checkout@v5 65 | - name: Lint 66 | uses: golangci/golangci-lint-action@v6 67 | with: 68 | version: v1.60.1 69 | args: --disable-all -v -E govet -E misspell -E gofmt -E ineffassign 70 | apidiff: 71 | runs-on: ubuntu-latest 72 | if: github.base_ref 73 | steps: 74 | - name: Install Go 75 | uses: actions/setup-go@v3 76 | with: 77 | go-version: 1.23.x 78 | - name: Add GOBIN to PATH 79 | run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH 80 | - name: Install dependencies 81 | run: go install golang.org/x/exp/cmd/apidiff@latest 82 | - name: Checkout old code 83 | uses: actions/checkout@v2 84 | with: 85 | ref: ${{ github.base_ref }} 86 | path: "old" 87 | - name: Checkout new code 88 | uses: actions/checkout@v2 89 | with: 90 | path: "new" 91 | - name: APIDiff 92 | run: ./hack/verify-apidiff.sh -d ../old 93 | working-directory: "new" 94 | -------------------------------------------------------------------------------- /lru/lru.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package lru 17 | 18 | import ( 19 | "fmt" 20 | "sync" 21 | 22 | groupcache "k8s.io/utils/internal/third_party/forked/golang/golang-lru" 23 | ) 24 | 25 | type Key = groupcache.Key 26 | type EvictionFunc = func(key Key, value interface{}) 27 | 28 | // Cache is a thread-safe fixed size LRU cache. 29 | type Cache struct { 30 | cache *groupcache.Cache 31 | lock sync.RWMutex 32 | } 33 | 34 | // New creates an LRU of the given size. 35 | func New(size int) *Cache { 36 | return &Cache{ 37 | cache: groupcache.New(size), 38 | } 39 | } 40 | 41 | // NewWithEvictionFunc creates an LRU of the given size with the given eviction func. 42 | func NewWithEvictionFunc(size int, f EvictionFunc) *Cache { 43 | c := New(size) 44 | c.cache.OnEvicted = f 45 | return c 46 | } 47 | 48 | // SetEvictionFunc updates the eviction func 49 | func (c *Cache) SetEvictionFunc(f EvictionFunc) error { 50 | c.lock.Lock() 51 | defer c.lock.Unlock() 52 | if c.cache.OnEvicted != nil { 53 | return fmt.Errorf("lru cache eviction function is already set") 54 | } 55 | c.cache.OnEvicted = f 56 | return nil 57 | } 58 | 59 | // Add adds a value to the cache. 60 | func (c *Cache) Add(key Key, value interface{}) { 61 | c.lock.Lock() 62 | defer c.lock.Unlock() 63 | c.cache.Add(key, value) 64 | } 65 | 66 | // Get looks up a key's value from the cache. 67 | func (c *Cache) Get(key Key) (value interface{}, ok bool) { 68 | c.lock.Lock() 69 | defer c.lock.Unlock() 70 | return c.cache.Get(key) 71 | } 72 | 73 | // Remove removes the provided key from the cache. 74 | func (c *Cache) Remove(key Key) { 75 | c.lock.Lock() 76 | defer c.lock.Unlock() 77 | c.cache.Remove(key) 78 | } 79 | 80 | // RemoveOldest removes the oldest item from the cache. 81 | func (c *Cache) RemoveOldest() { 82 | c.lock.Lock() 83 | defer c.lock.Unlock() 84 | c.cache.RemoveOldest() 85 | } 86 | 87 | // Len returns the number of items in the cache. 88 | func (c *Cache) Len() int { 89 | c.lock.RLock() 90 | defer c.lock.RUnlock() 91 | return c.cache.Len() 92 | } 93 | 94 | // Clear purges all stored items from the cache. 95 | func (c *Cache) Clear() { 96 | c.lock.Lock() 97 | defer c.lock.Unlock() 98 | c.cache.Clear() 99 | } 100 | -------------------------------------------------------------------------------- /keymutex/keymutex_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package keymutex 18 | 19 | import ( 20 | "testing" 21 | "time" 22 | ) 23 | 24 | const ( 25 | callbackTimeout = 1 * time.Second 26 | ) 27 | 28 | func newKeyMutexes() []KeyMutex { 29 | return []KeyMutex{ 30 | NewHashed(0), 31 | NewHashed(1), 32 | NewHashed(2), 33 | NewHashed(4), 34 | } 35 | } 36 | 37 | func Test_SingleLock_NoUnlock(t *testing.T) { 38 | for _, km := range newKeyMutexes() { 39 | // Arrange 40 | key := "fakeid" 41 | callbackCh := make(chan interface{}) 42 | 43 | // Act 44 | go lockAndCallback(km, key, callbackCh) 45 | 46 | // Assert 47 | verifyCallbackHappens(t, callbackCh) 48 | } 49 | } 50 | 51 | func Test_SingleLock_SingleUnlock(t *testing.T) { 52 | for _, km := range newKeyMutexes() { 53 | // Arrange 54 | key := "fakeid" 55 | callbackCh := make(chan interface{}) 56 | 57 | // Act & Assert 58 | go lockAndCallback(km, key, callbackCh) 59 | verifyCallbackHappens(t, callbackCh) 60 | km.UnlockKey(key) 61 | } 62 | } 63 | 64 | func Test_DoubleLock_DoubleUnlock(t *testing.T) { 65 | for _, km := range newKeyMutexes() { 66 | // Arrange 67 | key := "fakeid" 68 | callbackCh1stLock := make(chan interface{}) 69 | callbackCh2ndLock := make(chan interface{}) 70 | 71 | // Act & Assert 72 | go lockAndCallback(km, key, callbackCh1stLock) 73 | verifyCallbackHappens(t, callbackCh1stLock) 74 | go lockAndCallback(km, key, callbackCh2ndLock) 75 | verifyCallbackDoesntHappens(t, callbackCh2ndLock) 76 | km.UnlockKey(key) 77 | verifyCallbackHappens(t, callbackCh2ndLock) 78 | km.UnlockKey(key) 79 | } 80 | } 81 | 82 | func lockAndCallback(km KeyMutex, id string, callbackCh chan<- interface{}) { 83 | km.LockKey(id) 84 | callbackCh <- true 85 | } 86 | 87 | func verifyCallbackHappens(t *testing.T, callbackCh <-chan interface{}) bool { 88 | select { 89 | case <-callbackCh: 90 | return true 91 | case <-time.After(callbackTimeout): 92 | t.Fatalf("Timed out waiting for callback.") 93 | return false 94 | } 95 | } 96 | 97 | func verifyCallbackDoesntHappens(t *testing.T, callbackCh <-chan interface{}) bool { 98 | select { 99 | case <-callbackCh: 100 | t.Fatalf("Unexpected callback.") 101 | return false 102 | case <-time.After(callbackTimeout): 103 | return true 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /inotify/inotify_linux_test.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | // +build linux 3 | 4 | // Copyright 2010 The Go Authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | package inotify 9 | 10 | import ( 11 | "io/ioutil" 12 | "os" 13 | "sync/atomic" 14 | "testing" 15 | "time" 16 | ) 17 | 18 | func TestInotifyEvents(t *testing.T) { 19 | // Create an inotify watcher instance and initialize it 20 | watcher, err := NewWatcher() 21 | if err != nil { 22 | t.Fatalf("NewWatcher failed: %s", err) 23 | } 24 | 25 | dir, err := ioutil.TempDir("", "inotify") 26 | if err != nil { 27 | t.Fatalf("TempDir failed: %s", err) 28 | } 29 | defer os.RemoveAll(dir) 30 | 31 | // Add a watch for "_test" 32 | err = watcher.Watch(dir) 33 | if err != nil { 34 | t.Fatalf("Watch failed: %s", err) 35 | } 36 | 37 | // Receive errors on the error channel on a separate goroutine 38 | go func() { 39 | for err := range watcher.Error { 40 | t.Errorf("error received: %s", err) 41 | } 42 | }() 43 | 44 | testFile := dir + "/TestInotifyEvents.testfile" 45 | 46 | // Receive events on the event channel on a separate goroutine 47 | eventstream := watcher.Event 48 | var eventsReceived int32 49 | done := make(chan bool) 50 | go func() { 51 | for event := range eventstream { 52 | // Only count relevant events 53 | if event.Name == testFile { 54 | atomic.AddInt32(&eventsReceived, 1) 55 | t.Logf("event received: %s", event) 56 | } else { 57 | t.Logf("unexpected event received: %s", event) 58 | } 59 | } 60 | done <- true 61 | }() 62 | 63 | // Create a file 64 | // This should add at least one event to the inotify event queue 65 | _, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666) 66 | if err != nil { 67 | t.Fatalf("creating test file: %s", err) 68 | } 69 | 70 | // We expect this event to be received almost immediately, but let's wait 1 s to be sure 71 | time.Sleep(1 * time.Second) 72 | if atomic.AddInt32(&eventsReceived, 0) == 0 { 73 | t.Fatal("inotify event hasn't been received after 1 second") 74 | } 75 | 76 | // Try closing the inotify instance 77 | t.Log("calling Close()") 78 | watcher.Close() 79 | t.Log("waiting for the event channel to become closed...") 80 | select { 81 | case <-done: 82 | t.Log("event channel closed") 83 | case <-time.After(1 * time.Second): 84 | t.Fatal("event stream was not closed after 1 second") 85 | } 86 | } 87 | 88 | func TestInotifyClose(t *testing.T) { 89 | watcher, _ := NewWatcher() 90 | watcher.Close() 91 | 92 | done := make(chan bool) 93 | go func() { 94 | watcher.Close() 95 | done <- true 96 | }() 97 | 98 | select { 99 | case <-done: 100 | case <-time.After(50 * time.Millisecond): 101 | t.Fatal("double Close() test failed: second Close() call didn't return") 102 | } 103 | 104 | err := watcher.Watch(os.TempDir()) 105 | if err == nil { 106 | t.Fatal("expected error on Watch() after Close(), got nil") 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /net/net.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package net 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "math" 23 | "math/big" 24 | "net" 25 | "strconv" 26 | ) 27 | 28 | // ParseCIDRs parses a list of cidrs and return error if any is invalid. 29 | // order is maintained 30 | func ParseCIDRs(cidrsString []string) ([]*net.IPNet, error) { 31 | cidrs := make([]*net.IPNet, 0, len(cidrsString)) 32 | for i, cidrString := range cidrsString { 33 | _, cidr, err := ParseCIDRSloppy(cidrString) 34 | if err != nil { 35 | return nil, fmt.Errorf("invalid CIDR[%d]: %v (%v)", i, cidr, err) 36 | } 37 | cidrs = append(cidrs, cidr) 38 | } 39 | return cidrs, nil 40 | } 41 | 42 | // ParsePort parses a string representing an IP port. If the string is not a 43 | // valid port number, this returns an error. 44 | func ParsePort(port string, allowZero bool) (int, error) { 45 | portInt, err := strconv.ParseUint(port, 10, 16) 46 | if err != nil { 47 | return 0, err 48 | } 49 | if portInt == 0 && !allowZero { 50 | return 0, errors.New("0 is not a valid port number") 51 | } 52 | return int(portInt), nil 53 | } 54 | 55 | // BigForIP creates a big.Int based on the provided net.IP 56 | func BigForIP(ip net.IP) *big.Int { 57 | // NOTE: Convert to 16-byte representation so we can 58 | // handle v4 and v6 values the same way. 59 | return big.NewInt(0).SetBytes(ip.To16()) 60 | } 61 | 62 | // AddIPOffset adds the provided integer offset to a base big.Int representing a net.IP 63 | // NOTE: If you started with a v4 address and overflow it, you get a v6 result. 64 | func AddIPOffset(base *big.Int, offset int) net.IP { 65 | r := big.NewInt(0).Add(base, big.NewInt(int64(offset))).Bytes() 66 | r = append(make([]byte, 16), r...) 67 | return net.IP(r[len(r)-16:]) 68 | } 69 | 70 | // RangeSize returns the size of a range in valid addresses. 71 | // returns the size of the subnet (or math.MaxInt64 if the range size would overflow int64) 72 | func RangeSize(subnet *net.IPNet) int64 { 73 | ones, bits := subnet.Mask.Size() 74 | if bits == 32 && (bits-ones) >= 31 || bits == 128 && (bits-ones) >= 127 { 75 | return 0 76 | } 77 | // this checks that we are not overflowing an int64 78 | if bits-ones >= 63 { 79 | return math.MaxInt64 80 | } 81 | return int64(1) << uint(bits-ones) 82 | } 83 | 84 | // GetIndexedIP returns a net.IP that is subnet.IP + index in the contiguous IP space. 85 | func GetIndexedIP(subnet *net.IPNet, index int) (net.IP, error) { 86 | ip := AddIPOffset(BigForIP(subnet.IP), index) 87 | if !subnet.Contains(ip) { 88 | return nil, fmt.Errorf("can't generate IP with index %d from subnet. subnet too small. subnet: %q", index, subnet) 89 | } 90 | return ip, nil 91 | } 92 | -------------------------------------------------------------------------------- /ptr/ptr_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package ptr_test 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "k8s.io/utils/ptr" 24 | ) 25 | 26 | func TestAllPtrFieldsNil(t *testing.T) { 27 | testCases := []struct { 28 | obj interface{} 29 | expected bool 30 | }{ 31 | {struct{}{}, true}, 32 | {struct{ Foo int }{12345}, true}, 33 | {&struct{ Foo int }{12345}, true}, 34 | {struct{ Foo *int }{nil}, true}, 35 | {&struct{ Foo *int }{nil}, true}, 36 | {struct { 37 | Foo int 38 | Bar *int 39 | }{12345, nil}, true}, 40 | {&struct { 41 | Foo int 42 | Bar *int 43 | }{12345, nil}, true}, 44 | {struct { 45 | Foo *int 46 | Bar *int 47 | }{nil, nil}, true}, 48 | {&struct { 49 | Foo *int 50 | Bar *int 51 | }{nil, nil}, true}, 52 | {struct{ Foo *int }{new(int)}, false}, 53 | {&struct{ Foo *int }{new(int)}, false}, 54 | {struct { 55 | Foo *int 56 | Bar *int 57 | }{nil, new(int)}, false}, 58 | {&struct { 59 | Foo *int 60 | Bar *int 61 | }{nil, new(int)}, false}, 62 | {(*struct{})(nil), true}, 63 | } 64 | for i, tc := range testCases { 65 | name := fmt.Sprintf("case[%d]", i) 66 | t.Run(name, func(t *testing.T) { 67 | if actual := ptr.AllPtrFieldsNil(tc.obj); actual != tc.expected { 68 | t.Errorf("%s: expected %t, got %t", name, tc.expected, actual) 69 | } 70 | }) 71 | } 72 | } 73 | 74 | func TestRef(t *testing.T) { 75 | type T int 76 | 77 | val := T(0) 78 | pointer := ptr.To(val) 79 | if *pointer != val { 80 | t.Errorf("expected %d, got %d", val, *pointer) 81 | } 82 | 83 | val = T(1) 84 | pointer = ptr.To(val) 85 | if *pointer != val { 86 | t.Errorf("expected %d, got %d", val, *pointer) 87 | } 88 | } 89 | 90 | func TestDeref(t *testing.T) { 91 | type T int 92 | 93 | var val, def T = 1, 0 94 | 95 | out := ptr.Deref(&val, def) 96 | if out != val { 97 | t.Errorf("expected %d, got %d", val, out) 98 | } 99 | 100 | out = ptr.Deref(nil, def) 101 | if out != def { 102 | t.Errorf("expected %d, got %d", def, out) 103 | } 104 | } 105 | 106 | func TestEqual(t *testing.T) { 107 | type T int 108 | 109 | if !ptr.Equal[T](nil, nil) { 110 | t.Errorf("expected true (nil == nil)") 111 | } 112 | if !ptr.Equal(ptr.To(T(123)), ptr.To(T(123))) { 113 | t.Errorf("expected true (val == val)") 114 | } 115 | if ptr.Equal(nil, ptr.To(T(123))) { 116 | t.Errorf("expected false (nil != val)") 117 | } 118 | if ptr.Equal(ptr.To(T(123)), nil) { 119 | t.Errorf("expected false (val != nil)") 120 | } 121 | if ptr.Equal(ptr.To(T(123)), ptr.To(T(456))) { 122 | t.Errorf("expected false (val != val)") 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /field/path_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package field 18 | 19 | import "testing" 20 | 21 | func TestPath(t *testing.T) { 22 | testCases := []struct { 23 | op func(*Path) *Path 24 | expected string 25 | }{ 26 | { 27 | func(p *Path) *Path { return p }, 28 | "root", 29 | }, 30 | { 31 | func(p *Path) *Path { return p.Child("first") }, 32 | "root.first", 33 | }, 34 | { 35 | func(p *Path) *Path { return p.Child("second") }, 36 | "root.first.second", 37 | }, 38 | { 39 | func(p *Path) *Path { return p.Index(0) }, 40 | "root.first.second[0]", 41 | }, 42 | { 43 | func(p *Path) *Path { return p.Child("third") }, 44 | "root.first.second[0].third", 45 | }, 46 | { 47 | func(p *Path) *Path { return p.Index(93) }, 48 | "root.first.second[0].third[93]", 49 | }, 50 | { 51 | func(p *Path) *Path { return p.parent }, 52 | "root.first.second[0].third", 53 | }, 54 | { 55 | func(p *Path) *Path { return p.parent }, 56 | "root.first.second[0]", 57 | }, 58 | { 59 | func(p *Path) *Path { return p.Key("key") }, 60 | "root.first.second[0][key]", 61 | }, 62 | } 63 | 64 | root := NewPath("root") 65 | p := root 66 | for i, tc := range testCases { 67 | p = tc.op(p) 68 | if p.String() != tc.expected { 69 | t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) 70 | } 71 | if p.Root() != root { 72 | t.Errorf("[%d] Wrong root: %#v", i, p.Root()) 73 | } 74 | } 75 | } 76 | 77 | func TestPathMultiArg(t *testing.T) { 78 | testCases := []struct { 79 | op func(*Path) *Path 80 | expected string 81 | }{ 82 | { 83 | func(p *Path) *Path { return p }, 84 | "root.first", 85 | }, 86 | { 87 | func(p *Path) *Path { return p.Child("second", "third") }, 88 | "root.first.second.third", 89 | }, 90 | { 91 | func(p *Path) *Path { return p.Index(0) }, 92 | "root.first.second.third[0]", 93 | }, 94 | { 95 | func(p *Path) *Path { return p.parent }, 96 | "root.first.second.third", 97 | }, 98 | { 99 | func(p *Path) *Path { return p.parent }, 100 | "root.first.second", 101 | }, 102 | { 103 | func(p *Path) *Path { return p.parent }, 104 | "root.first", 105 | }, 106 | { 107 | func(p *Path) *Path { return p.parent }, 108 | "root", 109 | }, 110 | } 111 | 112 | root := NewPath("root", "first") 113 | p := root 114 | for i, tc := range testCases { 115 | p = tc.op(p) 116 | if p.String() != tc.expected { 117 | t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) 118 | } 119 | if p.Root() != root.Root() { 120 | t.Errorf("[%d] Wrong root: %#v", i, p.Root()) 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /mount/mount_helper_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | /* 5 | Copyright 2019 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package mount 21 | 22 | import ( 23 | "fmt" 24 | "os" 25 | "strconv" 26 | "strings" 27 | "syscall" 28 | 29 | "k8s.io/klog/v2" 30 | ) 31 | 32 | // following failure codes are from https://docs.microsoft.com/en-us/windows/desktop/debug/system-error-codes--1300-1699- 33 | // ERROR_BAD_NETPATH = 53 34 | // ERROR_NETWORK_BUSY = 54 35 | // ERROR_UNEXP_NET_ERR = 59 36 | // ERROR_NETNAME_DELETED = 64 37 | // ERROR_NETWORK_ACCESS_DENIED = 65 38 | // ERROR_BAD_DEV_TYPE = 66 39 | // ERROR_BAD_NET_NAME = 67 40 | // ERROR_SESSION_CREDENTIAL_CONFLICT = 1219 41 | // ERROR_LOGON_FAILURE = 1326 42 | var errorNoList = [...]int{53, 54, 59, 64, 65, 66, 67, 1219, 1326} 43 | 44 | // IsCorruptedMnt return true if err is about corrupted mount point 45 | func IsCorruptedMnt(err error) bool { 46 | if err == nil { 47 | return false 48 | } 49 | 50 | var underlyingError error 51 | switch pe := err.(type) { 52 | case nil: 53 | return false 54 | case *os.PathError: 55 | underlyingError = pe.Err 56 | case *os.LinkError: 57 | underlyingError = pe.Err 58 | case *os.SyscallError: 59 | underlyingError = pe.Err 60 | } 61 | 62 | if ee, ok := underlyingError.(syscall.Errno); ok { 63 | for _, errno := range errorNoList { 64 | if int(ee) == errno { 65 | klog.Warningf("IsCorruptedMnt failed with error: %v, error code: %v", err, errno) 66 | return true 67 | } 68 | } 69 | } 70 | 71 | return false 72 | } 73 | 74 | // NormalizeWindowsPath makes sure the given path is a valid path on Windows 75 | // systems by making sure all instances of `/` are replaced with `\\`, and the 76 | // path beings with `c:` 77 | func NormalizeWindowsPath(path string) string { 78 | normalizedPath := strings.Replace(path, "/", "\\", -1) 79 | if strings.HasPrefix(normalizedPath, "\\") { 80 | normalizedPath = "c:" + normalizedPath 81 | } 82 | return normalizedPath 83 | } 84 | 85 | // ValidateDiskNumber : disk number should be a number in [0, 99] 86 | func ValidateDiskNumber(disk string) error { 87 | diskNum, err := strconv.Atoi(disk) 88 | if err != nil { 89 | return fmt.Errorf("wrong disk number format: %q, err:%v", disk, err) 90 | } 91 | 92 | if diskNum < 0 || diskNum > 99 { 93 | return fmt.Errorf("disk number out of range: %q", disk) 94 | } 95 | 96 | return nil 97 | } 98 | 99 | // isMountPointMatch determines if the mountpoint matches the dir 100 | func isMountPointMatch(mp MountPoint, dir string) bool { 101 | return mp.Path == dir 102 | } 103 | -------------------------------------------------------------------------------- /io/read.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package io 18 | 19 | import ( 20 | "bytes" 21 | "errors" 22 | "fmt" 23 | "io" 24 | "io/ioutil" 25 | ) 26 | 27 | // ErrLimitReached means that the read limit is reached. 28 | var ErrLimitReached = errors.New("the read limit is reached") 29 | 30 | // ConsistentRead repeatedly reads a file until it gets the same content twice. 31 | // This is useful when reading files in /proc that are larger than page size 32 | // and kernel may modify them between individual read() syscalls. 33 | // It returns InconsistentReadError when it cannot get a consistent read in 34 | // given nr. of attempts. Caller should retry, kernel is probably under heavy 35 | // mount/unmount load. 36 | func ConsistentRead(filename string, attempts int) ([]byte, error) { 37 | return consistentReadSync(filename, attempts, nil) 38 | } 39 | 40 | // consistentReadSync is the main functionality of ConsistentRead but 41 | // introduces a sync callback that can be used by the tests to mutate the file 42 | // from which the test data is being read 43 | func consistentReadSync(filename string, attempts int, sync func(int)) ([]byte, error) { 44 | oldContent, err := ioutil.ReadFile(filename) 45 | if err != nil { 46 | return nil, err 47 | } 48 | for i := 0; i < attempts; i++ { 49 | if sync != nil { 50 | sync(i) 51 | } 52 | newContent, err := ioutil.ReadFile(filename) 53 | if err != nil { 54 | return nil, err 55 | } 56 | if bytes.Compare(oldContent, newContent) == 0 { 57 | return newContent, nil 58 | } 59 | // Files are different, continue reading 60 | oldContent = newContent 61 | } 62 | return nil, InconsistentReadError{filename, attempts} 63 | } 64 | 65 | // InconsistentReadError is returned from ConsistentRead when it cannot get 66 | // a consistent read in given nr. of attempts. Caller should retry, kernel is 67 | // probably under heavy mount/unmount load. 68 | type InconsistentReadError struct { 69 | filename string 70 | attempts int 71 | } 72 | 73 | func (i InconsistentReadError) Error() string { 74 | return fmt.Sprintf("could not get consistent content of %s after %d attempts", i.filename, i.attempts) 75 | } 76 | 77 | var _ error = InconsistentReadError{} 78 | 79 | func IsInconsistentReadError(err error) bool { 80 | if _, ok := err.(InconsistentReadError); ok { 81 | return true 82 | } 83 | return false 84 | } 85 | 86 | // ReadAtMost reads up to `limit` bytes from `r`, and reports an error 87 | // when `limit` bytes are read. 88 | func ReadAtMost(r io.Reader, limit int64) ([]byte, error) { 89 | limitedReader := &io.LimitedReader{R: r, N: limit} 90 | data, err := ioutil.ReadAll(limitedReader) 91 | if err != nil { 92 | return data, err 93 | } 94 | if limitedReader.N <= 0 { 95 | return data, ErrLimitReached 96 | } 97 | return data, nil 98 | } 99 | -------------------------------------------------------------------------------- /net/parse_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package net 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestParseIPSloppy(t *testing.T) { 24 | // See test cases in ips_test.go 25 | for _, tc := range goodTestIPs { 26 | if tc.skipParse { 27 | continue 28 | } 29 | t.Run(tc.desc, func(t *testing.T) { 30 | for i, str := range tc.strings { 31 | ip := ParseIPSloppy(str) 32 | if ip == nil { 33 | t.Errorf("expected %q to parse, but failed", str) 34 | } 35 | if !ip.Equal(tc.ips[0]) { 36 | t.Errorf("expected string %d %q to parse equal to IP %#v %q but got %#v (%q)", i+1, str, tc.ips[0], tc.ips[0].String(), ip, ip.String()) 37 | } 38 | } 39 | }) 40 | } 41 | 42 | // See test cases in ips_test.go 43 | for _, tc := range badTestIPs { 44 | if tc.skipParse { 45 | continue 46 | } 47 | t.Run(tc.desc, func(t *testing.T) { 48 | for i, ip := range tc.ips { 49 | errStr := ip.String() 50 | parsedIP := ParseIPSloppy(errStr) 51 | if parsedIP != nil { 52 | t.Errorf("expected IP %d %#v (%q) to not re-parse but got %#v (%q)", i+1, ip, errStr, parsedIP, parsedIP.String()) 53 | } 54 | } 55 | 56 | for i, str := range tc.strings { 57 | ip := ParseIPSloppy(str) 58 | if ip != nil { 59 | t.Errorf("expected string %d %q to not parse but got %#v (%q)", i+1, str, ip, ip.String()) 60 | } 61 | } 62 | }) 63 | } 64 | } 65 | 66 | func TestParseCIDRSloppy(t *testing.T) { 67 | // See test cases in ips_test.go 68 | for _, tc := range goodTestCIDRs { 69 | if tc.skipParse { 70 | continue 71 | } 72 | t.Run(tc.desc, func(t *testing.T) { 73 | for i, str := range tc.strings { 74 | _, ipnet, err := ParseCIDRSloppy(str) 75 | if err != nil { 76 | t.Errorf("expected %q to parse, but got error %v", str, err) 77 | } 78 | if ipnet.String() != tc.ipnets[0].String() { 79 | t.Errorf("expected string %d %q to parse and re-stringify to %q but got %q", i+1, str, tc.ipnets[0].String(), ipnet.String()) 80 | } 81 | } 82 | }) 83 | } 84 | 85 | // See test cases in ips_test.go 86 | for _, tc := range badTestCIDRs { 87 | if tc.skipParse { 88 | continue 89 | } 90 | t.Run(tc.desc, func(t *testing.T) { 91 | for i, ipnet := range tc.ipnets { 92 | errStr := ipnet.String() 93 | _, parsedIPNet, err := ParseCIDRSloppy(errStr) 94 | if err == nil { 95 | t.Errorf("expected IPNet %d %q to not parse but got %#v (%q)", i+1, errStr, *parsedIPNet, parsedIPNet.String()) 96 | } 97 | } 98 | 99 | for i, str := range tc.strings { 100 | _, ipnet, err := ParseCIDRSloppy(str) 101 | if err == nil { 102 | t.Errorf("expected string %d %q to not parse but got %#v (%q)", i+1, str, *ipnet, ipnet.String()) 103 | } 104 | } 105 | }) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /buffer/ring_fixed.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package buffer 18 | 19 | import ( 20 | "errors" 21 | "io" 22 | ) 23 | 24 | // Compile-time check that *TypedRingFixed[byte] implements io.Writer. 25 | var _ io.Writer = (*TypedRingFixed[byte])(nil) 26 | 27 | // ErrInvalidSize indicates size must be > 0 28 | var ErrInvalidSize = errors.New("size must be positive") 29 | 30 | // TypedRingFixed is a fixed-size circular buffer for elements of type T. 31 | // Writes overwrite older data, keeping only the last N elements. 32 | // Not thread safe. 33 | type TypedRingFixed[T any] struct { 34 | data []T 35 | size int 36 | writeCursor int 37 | written int64 38 | } 39 | 40 | // NewTypedRingFixed creates a circular buffer with the given capacity (must be > 0). 41 | func NewTypedRingFixed[T any](size int) (*TypedRingFixed[T], error) { 42 | if size <= 0 { 43 | return nil, ErrInvalidSize 44 | } 45 | return &TypedRingFixed[T]{ 46 | data: make([]T, size), 47 | size: size, 48 | }, nil 49 | } 50 | 51 | // Write writes p to the buffer, overwriting old data if needed. 52 | func (r *TypedRingFixed[T]) Write(p []T) (int, error) { 53 | originalLen := len(p) 54 | r.written += int64(originalLen) 55 | 56 | // If the input is larger than our buffer, only keep the last 'size' elements 57 | if originalLen > r.size { 58 | p = p[originalLen-r.size:] 59 | } 60 | 61 | // Copy data, handling wrap-around 62 | n := len(p) 63 | remain := r.size - r.writeCursor 64 | if n <= remain { 65 | copy(r.data[r.writeCursor:], p) 66 | } else { 67 | copy(r.data[r.writeCursor:], p[:remain]) 68 | copy(r.data, p[remain:]) 69 | } 70 | 71 | r.writeCursor = (r.writeCursor + n) % r.size 72 | return originalLen, nil 73 | } 74 | 75 | // Slice returns buffer contents in write order. Don't modify the returned slice. 76 | func (r *TypedRingFixed[T]) Slice() []T { 77 | if r.written == 0 { 78 | return nil 79 | } 80 | 81 | // Buffer hasn't wrapped yet 82 | if r.written < int64(r.size) { 83 | return r.data[:r.writeCursor] 84 | } 85 | 86 | // Buffer has wrapped - need to return data in correct order 87 | // Data from writeCursor to end is oldest, data from 0 to writeCursor is newest 88 | if r.writeCursor == 0 { 89 | return r.data 90 | } 91 | 92 | out := make([]T, r.size) 93 | copy(out, r.data[r.writeCursor:]) 94 | copy(out[r.size-r.writeCursor:], r.data[:r.writeCursor]) 95 | return out 96 | } 97 | 98 | // Size returns the buffer capacity. 99 | func (r *TypedRingFixed[T]) Size() int { 100 | return r.size 101 | } 102 | 103 | // Len returns how many elements are currently in the buffer. 104 | func (r *TypedRingFixed[T]) Len() int { 105 | if r.written < int64(r.size) { 106 | return int(r.written) 107 | } 108 | return r.size 109 | } 110 | 111 | // TotalWritten returns total elements ever written (including overwritten ones). 112 | func (r *TypedRingFixed[T]) TotalWritten() int64 { 113 | return r.written 114 | } 115 | 116 | // Reset clears the buffer. 117 | func (r *TypedRingFixed[T]) Reset() { 118 | r.writeCursor = 0 119 | r.written = 0 120 | } 121 | -------------------------------------------------------------------------------- /mount/mount_helper_common.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package mount 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | 23 | "k8s.io/klog/v2" 24 | ) 25 | 26 | // CleanupMountPoint unmounts the given path and deletes the remaining directory 27 | // if successful. If extensiveMountPointCheck is true IsNotMountPoint will be 28 | // called instead of IsLikelyNotMountPoint. IsNotMountPoint is more expensive 29 | // but properly handles bind mounts within the same fs. 30 | func CleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error { 31 | pathExists, pathErr := PathExists(mountPath) 32 | if !pathExists { 33 | klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath) 34 | return nil 35 | } 36 | corruptedMnt := IsCorruptedMnt(pathErr) 37 | if pathErr != nil && !corruptedMnt { 38 | return fmt.Errorf("Error checking path: %v", pathErr) 39 | } 40 | return doCleanupMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt) 41 | } 42 | 43 | // doCleanupMountPoint unmounts the given path and 44 | // deletes the remaining directory if successful. 45 | // if extensiveMountPointCheck is true 46 | // IsNotMountPoint will be called instead of IsLikelyNotMountPoint. 47 | // IsNotMountPoint is more expensive but properly handles bind mounts within the same fs. 48 | // if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, and the mount point check 49 | // will be skipped 50 | func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error { 51 | var notMnt bool 52 | var err error 53 | if !corruptedMnt { 54 | if extensiveMountPointCheck { 55 | notMnt, err = IsNotMountPoint(mounter, mountPath) 56 | } else { 57 | notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) 58 | } 59 | 60 | if err != nil { 61 | return err 62 | } 63 | 64 | if notMnt { 65 | klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath) 66 | return os.Remove(mountPath) 67 | } 68 | } 69 | 70 | // Unmount the mount path 71 | klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath) 72 | if err := mounter.Unmount(mountPath); err != nil { 73 | return err 74 | } 75 | 76 | if extensiveMountPointCheck { 77 | notMnt, err = IsNotMountPoint(mounter, mountPath) 78 | } else { 79 | notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) 80 | } 81 | if err != nil { 82 | return err 83 | } 84 | if notMnt { 85 | klog.V(4).Infof("%q is unmounted, deleting the directory", mountPath) 86 | return os.Remove(mountPath) 87 | } 88 | return fmt.Errorf("Failed to unmount path %v", mountPath) 89 | } 90 | 91 | // PathExists returns true if the specified path exists. 92 | // TODO: clean this up to use pkg/util/file/FileExists 93 | func PathExists(path string) (bool, error) { 94 | _, err := os.Stat(path) 95 | if err == nil { 96 | return true, nil 97 | } else if os.IsNotExist(err) { 98 | return false, nil 99 | } else if IsCorruptedMnt(err) { 100 | return true, err 101 | } 102 | return false, err 103 | } 104 | -------------------------------------------------------------------------------- /env/env_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package env 18 | 19 | import ( 20 | "os" 21 | "strconv" 22 | "testing" 23 | ) 24 | 25 | func TestGetString(t *testing.T) { 26 | const expected = "foo" 27 | 28 | key := "STRING_SET_VAR" 29 | os.Setenv(key, expected) 30 | if e, a := expected, GetString(key, "~"+expected); e != a { 31 | t.Fatalf("expected %#v==%#v", e, a) 32 | } 33 | 34 | key = "STRING_UNSET_VAR" 35 | if e, a := expected, GetString(key, expected); e != a { 36 | t.Fatalf("expected %#v==%#v", e, a) 37 | } 38 | } 39 | 40 | func TestGetInt(t *testing.T) { 41 | const expected = 1 42 | const defaultValue = 2 43 | 44 | key := "INT_SET_VAR" 45 | os.Setenv(key, strconv.Itoa(expected)) 46 | returnVal, _ := GetInt(key, defaultValue) 47 | if e, a := expected, returnVal; e != a { 48 | t.Fatalf("expected %#v==%#v", e, a) 49 | } 50 | 51 | key = "INT_UNSET_VAR" 52 | returnVal, _ = GetInt(key, defaultValue) 53 | if e, a := defaultValue, returnVal; e != a { 54 | t.Fatalf("expected %#v==%#v", e, a) 55 | } 56 | 57 | key = "INT_SET_VAR" 58 | os.Setenv(key, "not-an-int") 59 | returnVal, err := GetInt(key, defaultValue) 60 | if e, a := defaultValue, returnVal; e != a { 61 | t.Fatalf("expected %#v==%#v", e, a) 62 | } 63 | if err == nil { 64 | t.Error("expected error") 65 | } 66 | } 67 | 68 | func TestGetFloat64(t *testing.T) { 69 | const expected = 1.0 70 | const defaultValue = 2.0 71 | 72 | key := "FLOAT_SET_VAR" 73 | os.Setenv(key, "1.0") 74 | returnVal, _ := GetFloat64(key, defaultValue) 75 | if e, a := expected, returnVal; e != a { 76 | t.Fatalf("expected %#v==%#v", e, a) 77 | } 78 | 79 | key = "FLOAT_UNSET_VAR" 80 | returnVal, _ = GetFloat64(key, defaultValue) 81 | if e, a := defaultValue, returnVal; e != a { 82 | t.Fatalf("expected %#v==%#v", e, a) 83 | } 84 | 85 | key = "FLOAT_SET_VAR" 86 | os.Setenv(key, "not-a-float") 87 | returnVal, err := GetFloat64(key, defaultValue) 88 | if e, a := defaultValue, returnVal; e != a { 89 | t.Fatalf("expected %#v==%#v", e, a) 90 | } 91 | if err == nil || err.Error() != "strconv.ParseFloat: parsing \"not-a-float\": invalid syntax" { 92 | t.Fatalf("unexpected error: %#v", err) 93 | } 94 | } 95 | 96 | func TestGetBool(t *testing.T) { 97 | const expected = true 98 | const defaultValue = false 99 | 100 | key := "BOOL_SET_VAR" 101 | os.Setenv(key, "true") 102 | returnVal, _ := GetBool(key, defaultValue) 103 | if e, a := expected, returnVal; e != a { 104 | t.Fatalf("expected %#v==%#v", e, a) 105 | } 106 | 107 | key = "BOOL_UNSET_VAR" 108 | returnVal, _ = GetBool(key, defaultValue) 109 | if e, a := defaultValue, returnVal; e != a { 110 | t.Fatalf("expected %#v==%#v", e, a) 111 | } 112 | 113 | key = "BOOL_SET_VAR" 114 | os.Setenv(key, "not-a-bool") 115 | returnVal, err := GetBool(key, defaultValue) 116 | if e, a := defaultValue, returnVal; e != a { 117 | t.Fatalf("expected %#v==%#v", e, a) 118 | } 119 | if err == nil || err.Error() != "strconv.ParseBool: parsing \"not-a-bool\": invalid syntax" { 120 | t.Fatalf("unexpected error: %#v", err) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /io/read_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package io 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "os" 23 | "path/filepath" 24 | "strings" 25 | "syscall" 26 | "testing" 27 | ) 28 | 29 | func writeToPipe(namedPipe string, flaky bool, i int) { 30 | pipe, err := os.OpenFile(namedPipe, os.O_WRONLY, 0600) 31 | if err != nil { 32 | return 33 | } 34 | 35 | // The first two reads should never be consistent but all 36 | // subsequent reads should be 37 | outstr := fmt.Sprintf("Foobar %t", (i <= 0)) 38 | 39 | if flaky { 40 | outstr = fmt.Sprintf("Foobar %d", i) 41 | } 42 | 43 | pipe.Write([]byte(outstr)) 44 | pipe.Close() 45 | } 46 | 47 | func makePipe(t *testing.T) string { 48 | tmp, err := ioutil.TempDir("", "pipe-test") 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | 53 | pipe := filepath.Join(tmp, "pipe") 54 | syscall.Mkfifo(pipe, 0600) 55 | 56 | return pipe 57 | } 58 | 59 | func writer(namedPipe string, flaky bool, c <-chan int, d <-chan bool) { 60 | // Make sure something is in the fifo otherwise the first iteration of 61 | // ConsistentRead will block forever 62 | writeToPipe(namedPipe, flaky, -1) 63 | 64 | for { 65 | select { 66 | case i := <-c: 67 | writeToPipe(namedPipe, flaky, i) 68 | case <-d: 69 | os.RemoveAll(namedPipe) 70 | return 71 | } 72 | } 73 | } 74 | 75 | func TestConsistentRead(t *testing.T) { 76 | pipe := makePipe(t) 77 | prog, done := make(chan int), make(chan bool) 78 | go writer(pipe, false, prog, done) 79 | 80 | if _, err := consistentReadSync(pipe, 3, func(i int) { prog <- i }); err != nil { 81 | t.Fatal(err) 82 | } 83 | 84 | done <- true 85 | } 86 | 87 | func TestConsistentReadFlakyReader(t *testing.T) { 88 | pipe := makePipe(t) 89 | prog, done := make(chan int), make(chan bool) 90 | go writer(pipe, true, prog, done) 91 | 92 | var err error 93 | if _, err = consistentReadSync(pipe, 3, func(i int) { prog <- i }); err == nil { 94 | t.Fatal("flaky reader returned consistent results") 95 | } 96 | if !IsInconsistentReadError(err) { 97 | t.Errorf("Unexpected error returned, expected InconsistentReadError, got: %T / %q", err, err) 98 | } 99 | } 100 | 101 | func TestReadAtMost(t *testing.T) { 102 | testCases := []struct { 103 | limit int64 104 | data string 105 | errMsg string 106 | }{ 107 | {4, "hell", "the read limit is reached"}, 108 | {5, "hello", "the read limit is reached"}, 109 | {6, "hello", ""}, 110 | } 111 | 112 | for _, tc := range testCases { 113 | r := strings.NewReader("hello") 114 | data, err := ReadAtMost(r, tc.limit) 115 | if string(data) != tc.data { 116 | t.Errorf("Read limit %d: expected \"%s\", got \"%s\"", tc.limit, tc.data, string(data)) 117 | } 118 | 119 | if err == nil && tc.errMsg != "" { 120 | t.Errorf("Read limit %d: expected error with message \"%s\", got no error", tc.limit, tc.errMsg) 121 | } 122 | 123 | if err != nil && err.Error() != tc.errMsg { 124 | t.Errorf("Read limit %d: expected error with message \"%s\", got error with message \"%s\"", tc.limit, tc.errMsg, err.Error()) 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /internal/third_party/forked/golang/golang-lru/lru.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 Google Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package lru implements an LRU cache. 18 | package golang_lru 19 | 20 | import "container/list" 21 | 22 | // Cache is an LRU cache. It is not safe for concurrent access. 23 | type Cache struct { 24 | // MaxEntries is the maximum number of cache entries before 25 | // an item is evicted. Zero means no limit. 26 | MaxEntries int 27 | 28 | // OnEvicted optionally specifies a callback function to be 29 | // executed when an entry is purged from the cache. 30 | OnEvicted func(key Key, value interface{}) 31 | 32 | ll *list.List 33 | cache map[interface{}]*list.Element 34 | } 35 | 36 | // A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators 37 | type Key interface{} 38 | 39 | type entry struct { 40 | key Key 41 | value interface{} 42 | } 43 | 44 | // New creates a new Cache. 45 | // If maxEntries is zero, the cache has no limit and it's assumed 46 | // that eviction is done by the caller. 47 | func New(maxEntries int) *Cache { 48 | return &Cache{ 49 | MaxEntries: maxEntries, 50 | ll: list.New(), 51 | cache: make(map[interface{}]*list.Element), 52 | } 53 | } 54 | 55 | // Add adds a value to the cache. 56 | func (c *Cache) Add(key Key, value interface{}) { 57 | if c.cache == nil { 58 | c.cache = make(map[interface{}]*list.Element) 59 | c.ll = list.New() 60 | } 61 | if ee, ok := c.cache[key]; ok { 62 | c.ll.MoveToFront(ee) 63 | ee.Value.(*entry).value = value 64 | return 65 | } 66 | ele := c.ll.PushFront(&entry{key, value}) 67 | c.cache[key] = ele 68 | if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { 69 | c.RemoveOldest() 70 | } 71 | } 72 | 73 | // Get looks up a key's value from the cache. 74 | func (c *Cache) Get(key Key) (value interface{}, ok bool) { 75 | if c.cache == nil { 76 | return 77 | } 78 | if ele, hit := c.cache[key]; hit { 79 | c.ll.MoveToFront(ele) 80 | return ele.Value.(*entry).value, true 81 | } 82 | return 83 | } 84 | 85 | // Remove removes the provided key from the cache. 86 | func (c *Cache) Remove(key Key) { 87 | if c.cache == nil { 88 | return 89 | } 90 | if ele, hit := c.cache[key]; hit { 91 | c.removeElement(ele) 92 | } 93 | } 94 | 95 | // RemoveOldest removes the oldest item from the cache. 96 | func (c *Cache) RemoveOldest() { 97 | if c.cache == nil { 98 | return 99 | } 100 | ele := c.ll.Back() 101 | if ele != nil { 102 | c.removeElement(ele) 103 | } 104 | } 105 | 106 | func (c *Cache) removeElement(e *list.Element) { 107 | c.ll.Remove(e) 108 | kv := e.Value.(*entry) 109 | delete(c.cache, kv.key) 110 | if c.OnEvicted != nil { 111 | c.OnEvicted(kv.key, kv.value) 112 | } 113 | } 114 | 115 | // Len returns the number of items in the cache. 116 | func (c *Cache) Len() int { 117 | if c.cache == nil { 118 | return 0 119 | } 120 | return c.ll.Len() 121 | } 122 | 123 | // Clear purges all stored items from the cache. 124 | func (c *Cache) Clear() { 125 | if c.OnEvicted != nil { 126 | for _, e := range c.cache { 127 | kv := e.Value.(*entry) 128 | c.OnEvicted(kv.key, kv.value) 129 | } 130 | } 131 | c.ll = nil 132 | c.cache = nil 133 | } 134 | -------------------------------------------------------------------------------- /hack/verify-apidiff.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | function usage { 22 | local script="$(basename $0)" 23 | 24 | echo >&2 "Usage: ${script} [-r | -d ] 25 | 26 | This script should be run at the root of a module. 27 | 28 | -r 29 | Compare the exported API of the local working copy with the 30 | exported API of the local repo at the specified branch or tag. 31 | 32 | -d 33 | Compare the exported API of the local working copy with the 34 | exported API of the specified directory, which should point 35 | to the root of a different version of the same module. 36 | 37 | Examples: 38 | ${script} -r master 39 | ${script} -r v1.10.0 40 | ${script} -r release-1.10 41 | ${script} -d /path/to/historical/version 42 | " 43 | exit 1 44 | } 45 | 46 | ref="" 47 | dir="" 48 | while getopts r:d: o 49 | do case "$o" in 50 | r) ref="$OPTARG";; 51 | d) dir="$OPTARG";; 52 | [?]) usage;; 53 | esac 54 | done 55 | 56 | # If REF and DIR are empty, print usage and error 57 | if [[ -z "${ref}" && -z "${dir}" ]]; then 58 | usage; 59 | fi 60 | # If REF and DIR are both set, print usage and error 61 | if [[ -n "${ref}" && -n "${dir}" ]]; then 62 | usage; 63 | fi 64 | 65 | if ! which apidiff > /dev/null; then 66 | echo "Installing golang.org/x/exp/cmd/apidiff..." 67 | pushd "${TMPDIR:-/tmp}" > /dev/null 68 | go install golang.org/x/exp/cmd/apidiff@latest 69 | popd > /dev/null 70 | fi 71 | 72 | output=$(mktemp -d -t "apidiff.output.XXXX") 73 | cleanup_output () { rm -fr "${output}"; } 74 | trap cleanup_output EXIT 75 | 76 | # If ref is set, clone . to temp dir at $ref, and set $dir to the temp dir 77 | clone="" 78 | base="${dir}" 79 | if [[ -n "${ref}" ]]; then 80 | base="${ref}" 81 | clone=$(mktemp -d -t "apidiff.clone.XXXX") 82 | cleanup_clone_and_output () { rm -fr "${clone}"; cleanup_output; } 83 | trap cleanup_clone_and_output EXIT 84 | git clone . -q --no-tags -b "${ref}" "${clone}" 85 | dir="${clone}" 86 | fi 87 | 88 | pushd "${dir}" >/dev/null 89 | echo "Inspecting API of ${base}..." 90 | go list ./... > packages.txt 91 | for pkg in $(cat packages.txt); do 92 | mkdir -p "${output}/${pkg}" 93 | apidiff -w "${output}/${pkg}/apidiff.output" "${pkg}" 94 | done 95 | popd >/dev/null 96 | 97 | retval=0 98 | 99 | echo "Comparing with ${base}..." 100 | for pkg in $(go list ./...); do 101 | # New packages are ok 102 | if [ ! -f "${output}/${pkg}/apidiff.output" ]; then 103 | continue 104 | fi 105 | 106 | # Check for incompatible changes to previous packages 107 | incompatible=$(apidiff -incompatible "${output}/${pkg}/apidiff.output" "${pkg}") 108 | if [[ -n "${incompatible}" ]]; then 109 | echo >&2 "FAIL: ${pkg} contains incompatible changes: 110 | ${incompatible} 111 | " 112 | retval=1 113 | fi 114 | done 115 | 116 | # Check for removed packages 117 | removed=$(comm -23 "${dir}/packages.txt" <(go list ./...)) 118 | if [[ -n "${removed}" ]]; then 119 | echo >&2 "FAIL: removed packages: 120 | ${removed} 121 | " 122 | retval=1 123 | fi 124 | 125 | exit $retval 126 | -------------------------------------------------------------------------------- /exec/testing/fake_exec_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package testingexec 18 | 19 | import ( 20 | "testing" 21 | 22 | "k8s.io/utils/exec" 23 | ) 24 | 25 | // Test that command order is enforced 26 | func TestCommandOrder(t *testing.T) { 27 | fe := getFakeExecWithScripts(true, false) 28 | 29 | // If we call "cat" first, it should panic 30 | defer func() { 31 | if r := recover(); r == nil { 32 | t.Errorf("The code did not panic") 33 | } 34 | }() 35 | fe.Command("cat") 36 | } 37 | 38 | // Test that a command with different number of args panics 39 | func TestDiffNumArgs(t *testing.T) { 40 | fe := getFakeExecWithScripts(true, false) 41 | 42 | // If we call "ps -e -f -A" instead of "ps -ef" it should panic 43 | defer func() { 44 | if r := recover(); r == nil { 45 | t.Errorf("The code did not panic") 46 | } 47 | }() 48 | fe.Command("ps", "-e", "-f", "-A") 49 | } 50 | 51 | // Test that a command with different args panics 52 | func TestDiffArgs(t *testing.T) { 53 | fe := getFakeExecWithScripts(true, false) 54 | 55 | // If we call "ps -fe" instead of "ps -ef" it should panic 56 | defer func() { 57 | if r := recover(); r == nil { 58 | t.Errorf("The code did not panic") 59 | } 60 | }() 61 | fe.Command("ps", "-fe") 62 | } 63 | 64 | // Test that extra commands panics 65 | func TestExtraCommands(t *testing.T) { 66 | fe := getFakeExecWithScripts(false, false) 67 | 68 | // If we call mnore calls than scripted, should panic 69 | defer func() { 70 | if r := recover(); r == nil { 71 | t.Errorf("The code did not panic") 72 | } 73 | }() 74 | fe.Command("ps") 75 | fe.Command("cat") 76 | fe.Command("unscripted") 77 | } 78 | 79 | // Test that calling a command without a script panics if not disabled 80 | func TestNoScriptPanic(t *testing.T) { 81 | fe := &FakeExec{} 82 | 83 | // If we call mnore calls than scripted, should panic 84 | defer func() { 85 | if r := recover(); r == nil { 86 | t.Errorf("The code did not panic") 87 | } 88 | }() 89 | fe.Command("ps") 90 | } 91 | 92 | // Test that calling a command without a script does not panic if scripts 93 | // are disabled 94 | func TestNoScriptNoPanic(t *testing.T) { 95 | fe := &FakeExec{DisableScripts: true} 96 | 97 | // If we call mnore calls than scripted, should panic 98 | defer func() { 99 | if r := recover(); r != nil { 100 | t.Errorf("The code panic'd") 101 | } 102 | }() 103 | fe.Command("ps") 104 | } 105 | 106 | func getFakeExecWithScripts(exactOrder bool, disableScripts bool) *FakeExec { 107 | scripts := []struct { 108 | cmd string 109 | args []string 110 | }{ 111 | { 112 | cmd: "ps", 113 | args: []string{"-ef"}, 114 | }, 115 | { 116 | cmd: "cat", 117 | args: []string{"/var/log"}, 118 | }, 119 | } 120 | 121 | fakeexec := &FakeExec{ExactOrder: exactOrder, DisableScripts: disableScripts} 122 | for _, s := range scripts { 123 | fakeCmd := &FakeCmd{} 124 | cmdAction := makeFakeCmd(fakeCmd, s.cmd, s.args...) 125 | fakeexec.CommandScript = append(fakeexec.CommandScript, cmdAction) 126 | } 127 | return fakeexec 128 | } 129 | 130 | func makeFakeCmd(fakeCmd *FakeCmd, cmd string, args ...string) FakeCommandAction { 131 | c := cmd 132 | a := args 133 | return func(cmd string, args ...string) exec.Cmd { 134 | command := InitFakeCmd(fakeCmd, c, a...) 135 | return command 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /diff/diff_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package diff 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestObjectReflectDiff(t *testing.T) { 24 | type struct1 struct{ A []int } 25 | 26 | testCases := map[string]struct { 27 | a, b interface{} 28 | out string 29 | }{ 30 | "map": { 31 | a: map[string]int{}, 32 | b: map[string]int{}, 33 | }, 34 | "detect nil map": { 35 | a: map[string]int(nil), 36 | b: map[string]int{}, 37 | out: ` 38 | object: 39 | a: map[string]int(nil) 40 | b: map[string]int{}`, 41 | }, 42 | "detect map changes": { 43 | a: map[string]int{"test": 1, "other": 2}, 44 | b: map[string]int{"test": 2, "third": 3}, 45 | out: ` 46 | object[other]: 47 | a: 2 48 | b: 49 | object[test]: 50 | a: 1 51 | b: 2 52 | object[third]: 53 | a: 54 | b: 3`, 55 | }, 56 | "nil slice": {a: struct1{A: nil}, b: struct1{A: nil}}, 57 | "empty slice": {a: struct1{A: []int{}}, b: struct1{A: []int{}}}, 58 | "detect slice changes 1": {a: struct1{A: []int{1}}, b: struct1{A: []int{2}}, out: ` 59 | object.A[0]: 60 | a: 1 61 | b: 2`, 62 | }, 63 | "detect slice changes 2": {a: struct1{A: []int{}}, b: struct1{A: []int{2}}, out: ` 64 | object.A[0]: 65 | a: 66 | b: 2`, 67 | }, 68 | "detect slice changes 3": {a: struct1{A: []int{1}}, b: struct1{A: []int{}}, out: ` 69 | object.A[0]: 70 | a: 1 71 | b: `, 72 | }, 73 | "detect nil vs empty slices": {a: struct1{A: nil}, b: struct1{A: []int{}}, out: ` 74 | object.A: 75 | a: []int(nil) 76 | b: []int{}`, 77 | }, 78 | "display type differences": {a: []interface{}{int64(1)}, b: []interface{}{uint64(1)}, out: ` 79 | object[0]: 80 | a: 1 (int64) 81 | b: 0x1 (uint64)`, 82 | }, 83 | } 84 | for name, test := range testCases { 85 | expect := test.out 86 | if len(expect) == 0 { 87 | expect = "" 88 | } 89 | if actual := ObjectReflectDiff(test.a, test.b); actual != expect { 90 | t.Errorf("%s: unexpected output: %s", name, actual) 91 | } 92 | } 93 | } 94 | 95 | func TestStringDiff(t *testing.T) { 96 | diff := StringDiff("aaabb", "aaacc") 97 | expect := "aaa\n\nA: bb\n\nB: cc\n\n" 98 | if diff != expect { 99 | t.Errorf("diff returned %v", diff) 100 | } 101 | } 102 | 103 | func TestLimit(t *testing.T) { 104 | testcases := []struct { 105 | a interface{} 106 | b interface{} 107 | expectA string 108 | expectB string 109 | }{ 110 | { 111 | a: `short a`, 112 | b: `short b`, 113 | expectA: `"short a"`, 114 | expectB: `"short b"`, 115 | }, 116 | { 117 | a: `short a`, 118 | b: `long b needs truncating`, 119 | expectA: `"short a"`, 120 | expectB: `"long b ne...`, 121 | }, 122 | { 123 | a: `long a needs truncating`, 124 | b: `long b needs truncating`, 125 | expectA: `...g a needs ...`, 126 | expectB: `...g b needs ...`, 127 | }, 128 | { 129 | a: `long common prefix with different stuff at the end of a`, 130 | b: `long common prefix with different stuff at the end of b`, 131 | expectA: `...end of a"`, 132 | expectB: `...end of b"`, 133 | }, 134 | { 135 | a: `long common prefix with different stuff at the end of a`, 136 | b: `long common prefix with different stuff at the end of b which continues`, 137 | expectA: `...of a"`, 138 | expectB: `...of b which...`, 139 | }, 140 | } 141 | 142 | for _, tc := range testcases { 143 | a, b := limit(tc.a, tc.b, 10) 144 | if a != tc.expectA || b != tc.expectB { 145 | t.Errorf("limit(%q, %q)\n\texpected: %s, %s\n\tgot: %s, %s", tc.a, tc.b, tc.expectA, tc.expectB, a, b) 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /third_party/forked/golang/reflect/deep_equal_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package reflect 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func TestEqualities(t *testing.T) { 12 | e := Equalities{} 13 | type Bar struct { 14 | X int 15 | } 16 | type Baz struct { 17 | Y Bar 18 | } 19 | err := e.AddFuncs( 20 | func(a, b int) bool { 21 | return a+1 == b 22 | }, 23 | func(a, b Bar) bool { 24 | return a.X*10 == b.X 25 | }, 26 | ) 27 | if err != nil { 28 | t.Fatalf("Unexpected: %v", err) 29 | } 30 | 31 | type Foo struct { 32 | X int 33 | } 34 | 35 | table := []struct { 36 | a, b interface{} 37 | equal bool 38 | }{ 39 | {1, 2, true}, 40 | {2, 1, false}, 41 | {"foo", "fo", false}, 42 | {"foo", "foo", true}, 43 | {"foo", "foobar", false}, 44 | {Foo{1}, Foo{2}, true}, 45 | {Foo{2}, Foo{1}, false}, 46 | {Bar{1}, Bar{10}, true}, 47 | {&Bar{1}, &Bar{10}, true}, 48 | {Baz{Bar{1}}, Baz{Bar{10}}, true}, 49 | {[...]string{}, [...]string{"1", "2", "3"}, false}, 50 | {[...]string{"1"}, [...]string{"1", "2", "3"}, false}, 51 | {[...]string{"1", "2", "3"}, [...]string{}, false}, 52 | {[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true}, 53 | {map[string]int{"foo": 1}, map[string]int{}, false}, 54 | {map[string]int{"foo": 1}, map[string]int{"foo": 2}, true}, 55 | {map[string]int{"foo": 2}, map[string]int{"foo": 1}, false}, 56 | {map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, false}, 57 | {map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false}, 58 | {map[string]int{}, map[string]int(nil), true}, 59 | {[]string(nil), []string(nil), true}, 60 | {[]string{}, []string(nil), true}, 61 | {[]string(nil), []string{}, true}, 62 | {[]string{"1"}, []string(nil), false}, 63 | {[]string{}, []string{"1", "2", "3"}, false}, 64 | {[]string{"1"}, []string{"1", "2", "3"}, false}, 65 | {[]string{"1", "2", "3"}, []string{}, false}, 66 | } 67 | 68 | for _, item := range table { 69 | if e, a := item.equal, e.DeepEqual(item.a, item.b); e != a { 70 | t.Errorf("Expected (%+v == %+v) == %v, but got %v", item.a, item.b, e, a) 71 | } 72 | } 73 | } 74 | 75 | func TestDerivates(t *testing.T) { 76 | e := Equalities{} 77 | type Bar struct { 78 | X int 79 | } 80 | type Baz struct { 81 | Y Bar 82 | } 83 | err := e.AddFuncs( 84 | func(a, b int) bool { 85 | return a+1 == b 86 | }, 87 | func(a, b Bar) bool { 88 | return a.X*10 == b.X 89 | }, 90 | ) 91 | if err != nil { 92 | t.Fatalf("Unexpected: %v", err) 93 | } 94 | 95 | type Foo struct { 96 | X int 97 | } 98 | 99 | table := []struct { 100 | a, b interface{} 101 | equal bool 102 | }{ 103 | {1, 2, true}, 104 | {2, 1, false}, 105 | {"foo", "fo", false}, 106 | {"foo", "foo", true}, 107 | {"foo", "foobar", false}, 108 | {Foo{1}, Foo{2}, true}, 109 | {Foo{2}, Foo{1}, false}, 110 | {Bar{1}, Bar{10}, true}, 111 | {&Bar{1}, &Bar{10}, true}, 112 | {Baz{Bar{1}}, Baz{Bar{10}}, true}, 113 | {[...]string{}, [...]string{"1", "2", "3"}, false}, 114 | {[...]string{"1"}, [...]string{"1", "2", "3"}, false}, 115 | {[...]string{"1", "2", "3"}, [...]string{}, false}, 116 | {[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true}, 117 | {map[string]int{"foo": 1}, map[string]int{}, false}, 118 | {map[string]int{"foo": 1}, map[string]int{"foo": 2}, true}, 119 | {map[string]int{"foo": 2}, map[string]int{"foo": 1}, false}, 120 | {map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, true}, 121 | {map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false}, 122 | {map[string]int{}, map[string]int(nil), true}, 123 | {[]string(nil), []string(nil), true}, 124 | {[]string{}, []string(nil), true}, 125 | {[]string(nil), []string{}, true}, 126 | {[]string{"1"}, []string(nil), false}, 127 | {[]string{}, []string{"1", "2", "3"}, true}, 128 | {[]string{"1"}, []string{"1", "2", "3"}, true}, 129 | {[]string{"1", "2", "3"}, []string{}, false}, 130 | } 131 | 132 | for _, item := range table { 133 | if e, a := item.equal, e.DeepDerivative(item.a, item.b); e != a { 134 | t.Errorf("Expected (%+v ~ %+v) == %v, but got %v", item.a, item.b, e, a) 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /net/port.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package net 18 | 19 | import ( 20 | "fmt" 21 | "net" 22 | "strconv" 23 | "strings" 24 | ) 25 | 26 | // Protocol is a network protocol support by LocalPort. 27 | type Protocol string 28 | 29 | // Constants for valid protocols: 30 | const ( 31 | TCP Protocol = "TCP" 32 | UDP Protocol = "UDP" 33 | ) 34 | 35 | // LocalPort represents an IP address and port pair along with a protocol 36 | // and potentially a specific IP family. 37 | // A LocalPort can be opened and subsequently closed. 38 | type LocalPort struct { 39 | // Description is an arbitrary string. 40 | Description string 41 | // IP is the IP address part of a given local port. 42 | // If this string is empty, the port binds to all local IP addresses. 43 | IP string 44 | // If IPFamily is not empty, the port binds only to addresses of this 45 | // family. 46 | // IF empty along with IP, bind to local addresses of any family. 47 | IPFamily IPFamily 48 | // Port is the port number. 49 | // A value of 0 causes a port to be automatically chosen. 50 | Port int 51 | // Protocol is the protocol, e.g. TCP 52 | Protocol Protocol 53 | } 54 | 55 | // NewLocalPort returns a LocalPort instance and ensures IPFamily and IP are 56 | // consistent and that the given protocol is valid. 57 | func NewLocalPort(desc, ip string, ipFamily IPFamily, port int, protocol Protocol) (*LocalPort, error) { 58 | if protocol != TCP && protocol != UDP { 59 | return nil, fmt.Errorf("Unsupported protocol %s", protocol) 60 | } 61 | if ipFamily != IPFamilyUnknown && ipFamily != IPv4 && ipFamily != IPv6 { 62 | return nil, fmt.Errorf("Invalid IP family %s", ipFamily) 63 | } 64 | if ip != "" { 65 | parsedIP := ParseIPSloppy(ip) 66 | if parsedIP == nil { 67 | return nil, fmt.Errorf("invalid ip address %s", ip) 68 | } 69 | if ipFamily != IPFamilyUnknown { 70 | if IPFamily(parsedIP) != ipFamily { 71 | return nil, fmt.Errorf("ip address and family mismatch %s, %s", ip, ipFamily) 72 | } 73 | } 74 | } 75 | return &LocalPort{Description: desc, IP: ip, IPFamily: ipFamily, Port: port, Protocol: protocol}, nil 76 | } 77 | 78 | func (lp *LocalPort) String() string { 79 | ipPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)) 80 | return fmt.Sprintf("%q (%s/%s%s)", lp.Description, ipPort, strings.ToLower(string(lp.Protocol)), lp.IPFamily) 81 | } 82 | 83 | // Closeable closes an opened LocalPort. 84 | type Closeable interface { 85 | Close() error 86 | } 87 | 88 | // PortOpener can open a LocalPort and allows later closing it. 89 | type PortOpener interface { 90 | OpenLocalPort(lp *LocalPort) (Closeable, error) 91 | } 92 | 93 | type listenPortOpener struct{} 94 | 95 | // ListenPortOpener opens ports by calling bind() and listen(). 96 | var ListenPortOpener listenPortOpener 97 | 98 | // OpenLocalPort holds the given local port open. 99 | func (l *listenPortOpener) OpenLocalPort(lp *LocalPort) (Closeable, error) { 100 | return openLocalPort(lp) 101 | } 102 | 103 | func openLocalPort(lp *LocalPort) (Closeable, error) { 104 | var socket Closeable 105 | hostPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)) 106 | switch lp.Protocol { 107 | case TCP: 108 | network := "tcp" + string(lp.IPFamily) 109 | listener, err := net.Listen(network, hostPort) 110 | if err != nil { 111 | return nil, err 112 | } 113 | socket = listener 114 | case UDP: 115 | network := "udp" + string(lp.IPFamily) 116 | addr, err := net.ResolveUDPAddr(network, hostPort) 117 | if err != nil { 118 | return nil, err 119 | } 120 | conn, err := net.ListenUDP(network, addr) 121 | if err != nil { 122 | return nil, err 123 | } 124 | socket = conn 125 | default: 126 | return nil, fmt.Errorf("unknown protocol %q", lp.Protocol) 127 | } 128 | return socket, nil 129 | } 130 | -------------------------------------------------------------------------------- /mount/mount_helper_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package mount 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "os" 23 | "path/filepath" 24 | "runtime" 25 | "syscall" 26 | "testing" 27 | ) 28 | 29 | func TestDoCleanupMountPoint(t *testing.T) { 30 | 31 | if runtime.GOOS == "darwin" { 32 | t.Skipf("not supported on GOOS=%s", runtime.GOOS) 33 | } 34 | 35 | const testMount = "test-mount" 36 | const defaultPerm = 0750 37 | 38 | tests := map[string]struct { 39 | corruptedMnt bool 40 | // Function that prepares the directory structure for the test under 41 | // the given base directory. 42 | // Returns a fake MountPoint, a fake error for the mount point, 43 | // and error if the prepare function encountered a fatal error. 44 | prepare func(base string) (MountPoint, error, error) 45 | expectErr bool 46 | }{ 47 | "mount-ok": { 48 | prepare: func(base string) (MountPoint, error, error) { 49 | path := filepath.Join(base, testMount) 50 | if err := os.MkdirAll(path, defaultPerm); err != nil { 51 | return MountPoint{}, nil, err 52 | } 53 | return MountPoint{Device: "/dev/sdb", Path: path}, nil, nil 54 | }, 55 | }, 56 | "mount-corrupted": { 57 | prepare: func(base string) (MountPoint, error, error) { 58 | path := filepath.Join(base, testMount) 59 | if err := os.MkdirAll(path, defaultPerm); err != nil { 60 | return MountPoint{}, nil, err 61 | } 62 | return MountPoint{Device: "/dev/sdb", Path: path}, os.NewSyscallError("fake", syscall.ESTALE), nil 63 | }, 64 | corruptedMnt: true, 65 | }, 66 | "mount-err-not-corrupted": { 67 | prepare: func(base string) (MountPoint, error, error) { 68 | path := filepath.Join(base, testMount) 69 | if err := os.MkdirAll(path, defaultPerm); err != nil { 70 | return MountPoint{}, nil, err 71 | } 72 | return MountPoint{Device: "/dev/sdb", Path: path}, os.NewSyscallError("fake", syscall.ETIMEDOUT), nil 73 | }, 74 | expectErr: true, 75 | }, 76 | } 77 | 78 | for name, tt := range tests { 79 | t.Run(name, func(t *testing.T) { 80 | 81 | tmpDir, err := ioutil.TempDir("", "unmount-mount-point-test") 82 | if err != nil { 83 | t.Fatalf("failed to create tmpdir: %v", err) 84 | } 85 | defer os.RemoveAll(tmpDir) 86 | 87 | if tt.prepare == nil { 88 | t.Fatalf("prepare function required") 89 | } 90 | 91 | mountPoint, mountError, err := tt.prepare(tmpDir) 92 | if err != nil { 93 | t.Fatalf("failed to prepare test: %v", err) 94 | } 95 | 96 | fake := NewFakeMounter( 97 | []MountPoint{mountPoint}, 98 | ) 99 | fake.MountCheckErrors = map[string]error{mountPoint.Path: mountError} 100 | 101 | err = doCleanupMountPoint(mountPoint.Path, fake, true, tt.corruptedMnt) 102 | if tt.expectErr { 103 | if err == nil { 104 | t.Errorf("test %s failed, expected error, got none", name) 105 | } 106 | if err := validateDirExists(mountPoint.Path); err != nil { 107 | t.Errorf("test %s failed, mount path doesn't exist: %v", name, err) 108 | } 109 | } 110 | if !tt.expectErr { 111 | if err != nil { 112 | t.Errorf("test %s failed: %v", name, err) 113 | } 114 | if err := validateDirNotExists(mountPoint.Path); err != nil { 115 | t.Errorf("test %s failed, mount path still exists: %v", name, err) 116 | } 117 | } 118 | }) 119 | } 120 | } 121 | 122 | func validateDirExists(dir string) error { 123 | _, err := ioutil.ReadDir(dir) 124 | if err != nil { 125 | return err 126 | } 127 | return nil 128 | } 129 | 130 | func validateDirNotExists(dir string) error { 131 | _, err := ioutil.ReadDir(dir) 132 | if os.IsNotExist(err) { 133 | return nil 134 | } 135 | if err != nil { 136 | return err 137 | } 138 | return fmt.Errorf("dir %q still exists", dir) 139 | } 140 | -------------------------------------------------------------------------------- /hack/verify-golint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2018 The Kubernetes Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -o errexit 18 | set -o nounset 19 | set -o pipefail 20 | 21 | KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 22 | source "${KUBE_ROOT}/hack/lib/util.sh" 23 | 24 | if ! which golint > /dev/null; then 25 | echo "installing golint" 26 | go install golang.org/x/lint/golint@latest 27 | fi 28 | 29 | cd "${KUBE_ROOT}" 30 | 31 | # Check that the file is in alphabetical order 32 | failure_file="${KUBE_ROOT}/hack/.golint_failures" 33 | kube::util::check-file-in-alphabetical-order "${failure_file}" 34 | 35 | export IFS=$'\n' 36 | # NOTE: when "go list -e ./..." is run within GOPATH, it turns the k8s.io/utils 37 | # as the prefix, however if we run it outside it returns the full path of the file 38 | # with a leading underscore. We'll need to support both scenarios for all_packages. 39 | all_packages=() 40 | while IFS='' read -r line; do all_packages+=("$line"); done < <(go list -e ./... | grep -vE "/(third_party)" | sed -e 's|^k8s.io/utils/||' -e "s|^_\(${KUBE_ROOT}/\)\{0,1\}||") 41 | # The regex below removes any "#" character and anything behind it and including any 42 | # whitespace before it. Then it removes empty lines. 43 | failing_packages=() 44 | while IFS='' read -r line; do failing_packages+=("$line"); done < <(sed -e 's/[[:blank:]]*#.*//' -e '/^$/d' "$failure_file") 45 | unset IFS 46 | errors=() 47 | not_failing=() 48 | for p in "${all_packages[@]}"; do 49 | # Run golint on package/*.go file explicitly to validate all go files 50 | # and not just the ones for the current platform. This also will ensure that 51 | # _test.go files are linted. 52 | # Generated files are ignored, and each file is passed through golint 53 | # individually, as if one file in the package contains a fatal error (such as 54 | # a foo package with a corresponding foo_test package), golint seems to choke 55 | # completely. 56 | # Ref: https://github.com/kubernetes/kubernetes/pull/67675 57 | # Ref: https://github.com/golang/lint/issues/68 58 | failedLint=$(find "$p"/*.go | xargs -L1 golint 2>/dev/null) 59 | kube::util::array_contains "$p" "${failing_packages[@]}" && in_failing=$? || in_failing=$? 60 | if [[ -n "${failedLint}" ]] && [[ "${in_failing}" -ne "0" ]]; then 61 | errors+=( "${failedLint}" ) 62 | fi 63 | if [[ -z "${failedLint}" ]] && [[ "${in_failing}" -eq "0" ]]; then 64 | not_failing+=( "$p" ) 65 | fi 66 | done 67 | 68 | # Check that all failing_packages actually still exist 69 | gone=() 70 | for p in "${failing_packages[@]}"; do 71 | kube::util::array_contains "$p" "${all_packages[@]}" || gone+=( "$p" ) 72 | done 73 | 74 | # Check to be sure all the packages that should pass lint are. 75 | if [ ${#errors[@]} -eq 0 ]; then 76 | echo 'Congratulations! All Go source files have been linted.' 77 | else 78 | { 79 | echo "Errors from golint:" 80 | for err in "${errors[@]}"; do 81 | echo "$err" 82 | done 83 | echo 84 | echo 'Please review the above warnings. You can test via "golint" and commit the result.' 85 | echo 'If the above warnings do not make sense, you can exempt this package from golint' 86 | echo 'checking by adding it to hack/.golint_failures (if your reviewer is okay with it).' 87 | echo 88 | } >&2 89 | exit 1 90 | fi 91 | 92 | if [[ ${#not_failing[@]} -gt 0 ]]; then 93 | { 94 | echo "Some packages in hack/.golint_failures are passing golint. Please remove them." 95 | echo 96 | for p in "${not_failing[@]}"; do 97 | echo " $p" 98 | done 99 | echo 100 | } >&2 101 | exit 1 102 | fi 103 | 104 | if [[ ${#gone[@]} -gt 0 ]]; then 105 | { 106 | echo "Some packages in hack/.golint_failures do not exist anymore. Please remove them." 107 | echo 108 | for p in "${gone[@]}"; do 109 | echo " $p" 110 | done 111 | echo 112 | } >&2 113 | exit 1 114 | fi 115 | -------------------------------------------------------------------------------- /lru/lru_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | /* 17 | Copyright 2013 Google Inc. 18 | 19 | Licensed under the Apache License, Version 2.0 (the "License"); 20 | you may not use this file except in compliance with the License. 21 | You may obtain a copy of the License at 22 | 23 | http://www.apache.org/licenses/LICENSE-2.0 24 | 25 | Unless required by applicable law or agreed to in writing, software 26 | distributed under the License is distributed on an "AS IS" BASIS, 27 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | See the License for the specific language governing permissions and 29 | limitations under the License. 30 | */ 31 | 32 | package lru 33 | 34 | import ( 35 | "testing" 36 | "time" 37 | ) 38 | 39 | type simpleStruct struct { 40 | int 41 | string 42 | } 43 | 44 | type complexStruct struct { 45 | int 46 | simpleStruct 47 | } 48 | 49 | var getTests = []struct { 50 | name string 51 | keyToAdd interface{} 52 | keyToGet interface{} 53 | expectedOk bool 54 | }{ 55 | {"string_hit", "myKey", "myKey", true}, 56 | {"string_miss", "myKey", "nonsense", false}, 57 | {"simple_struct_hit", simpleStruct{1, "two"}, simpleStruct{1, "two"}, true}, 58 | {"simple_struct_miss", simpleStruct{1, "two"}, simpleStruct{0, "noway"}, false}, 59 | {"complex_struct_hit", complexStruct{1, simpleStruct{2, "three"}}, 60 | complexStruct{1, simpleStruct{2, "three"}}, true}, 61 | } 62 | 63 | func TestGet(t *testing.T) { 64 | for _, tt := range getTests { 65 | lru := New(0) 66 | lru.Add(tt.keyToAdd, 1234) 67 | val, ok := lru.Get(tt.keyToGet) 68 | if ok != tt.expectedOk { 69 | t.Fatalf("%s: cache hit = %v; want %v", tt.name, ok, !ok) 70 | } else if ok && val != 1234 { 71 | t.Fatalf("%s expected get to return 1234 but got %v", tt.name, val) 72 | } 73 | } 74 | } 75 | 76 | func TestRemove(t *testing.T) { 77 | lru := New(0) 78 | lru.Add("myKey", 1234) 79 | if val, ok := lru.Get("myKey"); !ok { 80 | t.Fatal("TestRemove returned no match") 81 | } else if val != 1234 { 82 | t.Fatalf("TestRemove failed. Expected %d, got %v", 1234, val) 83 | } 84 | 85 | lru.Remove("myKey") 86 | if _, ok := lru.Get("myKey"); ok { 87 | t.Fatal("TestRemove returned a removed entry") 88 | } 89 | } 90 | 91 | func TestGetRace(t *testing.T) { 92 | // size to force eviction and exercise next,curr,prev list behavior 93 | lru := New(25) 94 | 95 | stop := make(chan struct{}) 96 | defer close(stop) 97 | 98 | // set up parallel getters/writers on 2x len keys 99 | for key := 0; key < 50; key++ { 100 | go func(key int) { 101 | for { 102 | select { 103 | case <-stop: 104 | return 105 | default: 106 | lru.Get(key) 107 | lru.Add(key, 1) 108 | lru.Get(key) 109 | } 110 | } 111 | }(key) 112 | } 113 | // let them run 114 | time.Sleep(5 * time.Second) 115 | } 116 | 117 | func TestEviction(t *testing.T) { 118 | var seenKey Key 119 | var seenVal interface{} 120 | 121 | lru := NewWithEvictionFunc(1, func(key Key, value interface{}) { 122 | seenKey = key 123 | seenVal = value 124 | }) 125 | 126 | lru.Add(1, 2) 127 | lru.Add(3, 4) 128 | 129 | if seenKey != 1 || seenVal != 2 { 130 | t.Errorf("unexpected eviction data: key=%v val=%v", seenKey, seenVal) 131 | } 132 | } 133 | 134 | func TestSetEviction(t *testing.T) { 135 | var seenKey Key 136 | var seenVal interface{} 137 | 138 | lru := New(1) 139 | 140 | err := lru.SetEvictionFunc(func(key Key, value interface{}) { 141 | seenKey = key 142 | seenVal = value 143 | }) 144 | 145 | if err != nil { 146 | t.Errorf("unexpected error setting eviction function: %v", err) 147 | } 148 | 149 | lru.Add(1, 2) 150 | lru.Add(3, 4) 151 | 152 | if seenKey != 1 || seenVal != 2 { 153 | t.Errorf("unexpected eviction data: key=%v val=%v", seenKey, seenVal) 154 | } 155 | 156 | err = lru.SetEvictionFunc(func(key Key, value interface{}) {}) 157 | if err == nil { 158 | t.Errorf("expected error but got none") 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /strings/slices/slices_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package slices 18 | 19 | import ( 20 | "fmt" 21 | "net" 22 | "reflect" 23 | "regexp" 24 | "strings" 25 | "testing" 26 | 27 | utilnet "k8s.io/utils/net" 28 | ) 29 | 30 | func Example() { 31 | a := []string{ 32 | "10.0.0.0", "FOO", "1000::1", "fd80::4%eth0", "BAR", "192.168.1.300", 33 | "172.12.0.1", "fc00::5000", 34 | } 35 | v := func(s string) bool { return net.ParseIP(s) == nil } 36 | if notIP := Filter(nil, a, v); len(notIP) > 0 { 37 | fmt.Println("Invalid", notIP) 38 | } 39 | fmt.Println(Filter(nil, a, utilnet.IsIPv6String)) 40 | // Output: 41 | // Invalid [FOO fd80::4%eth0 BAR 192.168.1.300] 42 | // [1000::1 fc00::5000] 43 | } 44 | 45 | func Example_regexp() { 46 | a := []string{ 47 | "10.0.0.0", "FOO", "1000::1", "fd80::4%eth0", "BAR", "192.168.1.300", 48 | "172.12.0.1", "fc00::5000", 49 | } 50 | re := regexp.MustCompile("^[A-Z]+$") 51 | fmt.Println(Filter(nil, a, re.MatchString)) 52 | // Output: [FOO BAR] 53 | } 54 | 55 | func ExampleFilter_empty() { 56 | s := []string{"FOO", "", "", "BAR", "fd80::8888", ""} 57 | fmt.Println(Filter(nil, s, func(s string) bool { return s != "" })) 58 | // Output: [FOO BAR fd80::8888] 59 | } 60 | 61 | func TestFilter(t *testing.T) { 62 | testCases := []struct { 63 | validator func(string) bool 64 | input []string 65 | res []string 66 | }{ 67 | // Filter all 68 | { 69 | regexp.MustCompile("zzz.*").MatchString, 70 | []string{"FOO", "1000::", "BAR", "fd80::8888"}, 71 | nil, 72 | }, 73 | // Filter none 74 | { 75 | regexp.MustCompile(".*").MatchString, 76 | []string{"FOO", "1000::", "BAR", "fd80::8888"}, 77 | []string{"FOO", "1000::", "BAR", "fd80::8888"}, 78 | }, 79 | // Filter some 80 | { 81 | func(s string) bool { return strings.Contains(s, ".") }, 82 | []string{"10.0.0.0", "1000::", "8.8.8.8", "fd80::8888"}, 83 | []string{"10.0.0.0", "8.8.8.8"}, 84 | }, 85 | } 86 | for i, tc := range testCases { 87 | res := Filter(nil, tc.input, tc.validator) 88 | if !reflect.DeepEqual(tc.res, res) { 89 | t.Errorf("TC %d: %v expected %v", i, res, tc.res) 90 | } 91 | } 92 | } 93 | 94 | func TestFilterInplace(t *testing.T) { 95 | testCases := []struct { 96 | validator func(string) bool 97 | input []string 98 | res []string 99 | inputAfter []string 100 | }{ 101 | // Filter all 102 | { 103 | func(s string) bool { return s != "" }, 104 | []string{"FOO", "", "", "BAR", "fd80::8888", ""}, 105 | []string{"FOO", "BAR", "fd80::8888"}, 106 | []string{"FOO", "BAR", "fd80::8888", "BAR", "fd80::8888", ""}, 107 | }, 108 | } 109 | for i, tc := range testCases { 110 | res := Filter(tc.input[:0], tc.input, tc.validator) 111 | if !reflect.DeepEqual(tc.res, res) { 112 | t.Errorf("TC %d: %v expected %v", i, res, tc.res) 113 | } 114 | if !reflect.DeepEqual(tc.input, tc.inputAfter) { 115 | t.Errorf("TC %d: mutated input %v expected %v", i, tc.input, tc.inputAfter) 116 | } 117 | } 118 | } 119 | 120 | func TestContains(t *testing.T) { 121 | testCases := []struct { 122 | input []string 123 | what string 124 | res bool 125 | }{ 126 | // Contains special case 127 | { 128 | nil, 129 | "", 130 | false, 131 | }, 132 | // Contains 133 | { 134 | []string{"FOO", "BAR", ""}, 135 | "", 136 | true, 137 | }, 138 | // Not Contains 139 | { 140 | []string{"FOO", "BAR", ""}, 141 | "NOPE", 142 | false, 143 | }, 144 | } 145 | for i, tc := range testCases { 146 | res := Contains(tc.input, tc.what) 147 | if res != tc.res { 148 | t.Errorf("TC %d: %v expected %v", i, res, tc.res) 149 | } 150 | } 151 | } 152 | 153 | func TestClone(t *testing.T) { 154 | testCases := []struct { 155 | input []string 156 | res []string 157 | }{ 158 | { 159 | nil, 160 | nil, 161 | }, 162 | { 163 | []string{}, 164 | []string{}, 165 | }, 166 | { 167 | []string{"", "FOO", "BAR", ""}, 168 | []string{"", "FOO", "BAR", ""}, 169 | }, 170 | } 171 | for i, tc := range testCases { 172 | res := Clone(tc.input) 173 | if !reflect.DeepEqual(tc.res, res) { 174 | t.Errorf("TC %d: %v expected %v", i, res, tc.res) 175 | } 176 | if len(tc.input) > 0 { 177 | tc.input[0] = "NOPE" 178 | if tc.res[0] == "NOPE" { 179 | t.Errorf("TC %d: Clone is not cloned", i) 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /path/file_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package path 18 | 19 | import ( 20 | "os" 21 | "path/filepath" 22 | "reflect" 23 | "sort" 24 | "testing" 25 | ) 26 | 27 | func TestFileUtils(t *testing.T) { 28 | // Create tmp dir 29 | tmpDir, err := os.MkdirTemp(os.TempDir(), "util_file_test_") 30 | if err != nil { 31 | t.Fatal("Failed to test: failed to create temp dir.") 32 | } 33 | 34 | // create tmp file 35 | tmpFile, err := os.CreateTemp(tmpDir, "test_file_exists_") 36 | if err != nil { 37 | t.Fatal("Failed to test: failed to create temp file.") 38 | } 39 | 40 | // create tmp sym link 41 | tmpSymlinkName := filepath.Join(tmpDir, "test_file_exists_sym_link") 42 | err = os.Symlink(tmpFile.Name(), tmpSymlinkName) 43 | if err != nil { 44 | t.Fatal("Failed to test: failed to create sym link.") 45 | } 46 | 47 | // create tmp sub dir 48 | tmpSubDir, err := os.MkdirTemp(tmpDir, "sub_") 49 | if err != nil { 50 | t.Fatal("Failed to test: failed to create temp sub dir.") 51 | } 52 | 53 | // record the current dir 54 | currentDir, err := os.Getwd() 55 | if err != nil { 56 | t.Fatal("Failed to test: failed to get current dir.") 57 | } 58 | 59 | // change the work dir to temp dir 60 | err = os.Chdir(tmpDir) 61 | if err != nil { 62 | t.Fatal("Failed to test: failed to change work dir.") 63 | } 64 | 65 | // recover test environment 66 | defer func() { 67 | os.Chdir(currentDir) 68 | os.RemoveAll(tmpDir) 69 | }() 70 | 71 | t.Run("TestExists", func(t *testing.T) { 72 | tests := []struct { 73 | name string 74 | fileName string 75 | expectedError bool 76 | expectedValue bool 77 | }{ 78 | {"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false}, 79 | {"file_exists", tmpFile.Name(), false, true}, 80 | } 81 | 82 | for _, test := range tests { 83 | realValued, realError := Exists(CheckFollowSymlink, test.fileName) 84 | if test.expectedError { 85 | if realError == nil { 86 | t.Fatalf("Expected error, got none, failed to test with '%s': %s", test.fileName, test.name) 87 | } 88 | } else if test.expectedValue != realValued { 89 | t.Fatalf("Expected %#v==%#v, failed to test with '%s': %s", test.expectedValue, realValued, test.fileName, test.name) 90 | } 91 | } 92 | }) 93 | 94 | t.Run("TestFileOrSymlinkExists", func(t *testing.T) { 95 | tests := []struct { 96 | name string 97 | fileName string 98 | expectedError bool 99 | expectedValue bool 100 | }{ 101 | {"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false}, 102 | {"file_exists", tmpFile.Name(), false, true}, 103 | {"symlink_exists", tmpSymlinkName, false, true}, 104 | } 105 | 106 | for _, test := range tests { 107 | realValued, realError := Exists(CheckSymlinkOnly, test.fileName) 108 | if test.expectedError { 109 | if realError == nil { 110 | t.Fatalf("Expected error, got none, failed to test with '%s': %s", test.fileName, test.name) 111 | } 112 | } else if test.expectedValue != realValued { 113 | t.Fatalf("Expected %#v==%#v, failed to test with '%s': %s", test.expectedValue, realValued, test.fileName, test.name) 114 | } 115 | } 116 | }) 117 | 118 | t.Run("TestReadDirNoStat", func(t *testing.T) { 119 | _, tmpFileSimpleName := filepath.Split(tmpFile.Name()) 120 | _, tmpSymlinkSimpleName := filepath.Split(tmpSymlinkName) 121 | _, tmpSubDirSimpleName := filepath.Split(tmpSubDir) 122 | 123 | tests := []struct { 124 | name string 125 | dirName string 126 | expectedError bool 127 | expectedValue []string 128 | }{ 129 | {"dir_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), true, []string{}}, 130 | {"dir_is_empty", "", false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}}, 131 | {"dir_exists", tmpDir, false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}}, 132 | } 133 | 134 | for _, test := range tests { 135 | realValued, realError := ReadDirNoStat(test.dirName) 136 | 137 | // execute sort action before compare 138 | sort.Strings(realValued) 139 | sort.Strings(test.expectedValue) 140 | 141 | if test.expectedError { 142 | if realError == nil { 143 | t.Fatalf("Expected error, got none, failed to test with '%s': %s", test.dirName, test.name) 144 | } 145 | } else if !reflect.DeepEqual(test.expectedValue, realValued) { 146 | t.Fatalf("Expected %#v==%#v, failed to test with '%s': %s", test.expectedValue, realValued, test.dirName, test.name) 147 | } 148 | } 149 | }) 150 | } 151 | -------------------------------------------------------------------------------- /mount/mount_helper_unix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | /* 5 | Copyright 2019 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package mount 21 | 22 | import ( 23 | "fmt" 24 | "os" 25 | "strconv" 26 | "strings" 27 | "syscall" 28 | 29 | utilio "k8s.io/utils/io" 30 | ) 31 | 32 | const ( 33 | // At least number of fields per line in /proc//mountinfo. 34 | expectedAtLeastNumFieldsPerMountInfo = 10 35 | // How many times to retry for a consistent read of /proc/mounts. 36 | maxListTries = 3 37 | ) 38 | 39 | // IsCorruptedMnt return true if err is about corrupted mount point 40 | func IsCorruptedMnt(err error) bool { 41 | if err == nil { 42 | return false 43 | } 44 | var underlyingError error 45 | switch pe := err.(type) { 46 | case nil: 47 | return false 48 | case *os.PathError: 49 | underlyingError = pe.Err 50 | case *os.LinkError: 51 | underlyingError = pe.Err 52 | case *os.SyscallError: 53 | underlyingError = pe.Err 54 | } 55 | 56 | return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO || underlyingError == syscall.EACCES 57 | } 58 | 59 | // MountInfo represents a single line in /proc//mountinfo. 60 | type MountInfo struct { // nolint: golint 61 | // Unique ID for the mount (maybe reused after umount). 62 | ID int 63 | // The ID of the parent mount (or of self for the root of this mount namespace's mount tree). 64 | ParentID int 65 | // Major indicates one half of the device ID which identifies the device class 66 | // (parsed from `st_dev` for files on this filesystem). 67 | Major int 68 | // Minor indicates one half of the device ID which identifies a specific 69 | // instance of device (parsed from `st_dev` for files on this filesystem). 70 | Minor int 71 | // The pathname of the directory in the filesystem which forms the root of this mount. 72 | Root string 73 | // Mount source, filesystem-specific information. e.g. device, tmpfs name. 74 | Source string 75 | // Mount point, the pathname of the mount point. 76 | MountPoint string 77 | // Optional fieds, zero or more fields of the form "tag[:value]". 78 | OptionalFields []string 79 | // The filesystem type in the form "type[.subtype]". 80 | FsType string 81 | // Per-mount options. 82 | MountOptions []string 83 | // Per-superblock options. 84 | SuperOptions []string 85 | } 86 | 87 | // ParseMountInfo parses /proc/xxx/mountinfo. 88 | func ParseMountInfo(filename string) ([]MountInfo, error) { 89 | content, err := utilio.ConsistentRead(filename, maxListTries) 90 | if err != nil { 91 | return []MountInfo{}, err 92 | } 93 | contentStr := string(content) 94 | infos := []MountInfo{} 95 | 96 | for _, line := range strings.Split(contentStr, "\n") { 97 | if line == "" { 98 | // the last split() item is empty string following the last \n 99 | continue 100 | } 101 | // See `man proc` for authoritative description of format of the file. 102 | fields := strings.Fields(line) 103 | if len(fields) < expectedAtLeastNumFieldsPerMountInfo { 104 | return nil, fmt.Errorf("wrong number of fields in (expected at least %d, got %d): %s", expectedAtLeastNumFieldsPerMountInfo, len(fields), line) 105 | } 106 | id, err := strconv.Atoi(fields[0]) 107 | if err != nil { 108 | return nil, err 109 | } 110 | parentID, err := strconv.Atoi(fields[1]) 111 | if err != nil { 112 | return nil, err 113 | } 114 | mm := strings.Split(fields[2], ":") 115 | if len(mm) != 2 { 116 | return nil, fmt.Errorf("parsing '%s' failed: unexpected minor:major pair %s", line, mm) 117 | } 118 | major, err := strconv.Atoi(mm[0]) 119 | if err != nil { 120 | return nil, fmt.Errorf("parsing '%s' failed: unable to parse major device id, err:%v", mm[0], err) 121 | } 122 | minor, err := strconv.Atoi(mm[1]) 123 | if err != nil { 124 | return nil, fmt.Errorf("parsing '%s' failed: unable to parse minor device id, err:%v", mm[1], err) 125 | } 126 | 127 | info := MountInfo{ 128 | ID: id, 129 | ParentID: parentID, 130 | Major: major, 131 | Minor: minor, 132 | Root: fields[3], 133 | MountPoint: fields[4], 134 | MountOptions: strings.Split(fields[5], ","), 135 | } 136 | // All fields until "-" are "optional fields". 137 | i := 6 138 | for ; i < len(fields) && fields[i] != "-"; i++ { 139 | info.OptionalFields = append(info.OptionalFields, fields[i]) 140 | } 141 | // Parse the rest 3 fields. 142 | i++ 143 | if len(fields)-i < 3 { 144 | return nil, fmt.Errorf("expect 3 fields in %s, got %d", line, len(fields)-i) 145 | } 146 | info.FsType = fields[i] 147 | info.Source = fields[i+1] 148 | info.SuperOptions = strings.Split(fields[i+2], ",") 149 | infos = append(infos, info) 150 | } 151 | return infos, nil 152 | } 153 | 154 | // isMountPointMatch returns true if the path in mp is the same as dir. 155 | // Handles case where mountpoint dir has been renamed due to stale NFS mount. 156 | func isMountPointMatch(mp MountPoint, dir string) bool { 157 | deletedDir := fmt.Sprintf("%s\\040(deleted)", dir) 158 | return ((mp.Path == dir) || (mp.Path == deletedDir)) 159 | } 160 | -------------------------------------------------------------------------------- /integer/integer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package integer 18 | 19 | import "testing" 20 | 21 | func TestIntMax(t *testing.T) { 22 | tests := []struct { 23 | nums []int 24 | expectedMax int 25 | }{ 26 | { 27 | nums: []int{-1, 0}, 28 | expectedMax: 0, 29 | }, 30 | { 31 | nums: []int{-1, -2}, 32 | expectedMax: -1, 33 | }, 34 | { 35 | nums: []int{0, 1}, 36 | expectedMax: 1, 37 | }, 38 | { 39 | nums: []int{1, 2}, 40 | expectedMax: 2, 41 | }, 42 | } 43 | 44 | for i, test := range tests { 45 | t.Logf("executing scenario %d", i) 46 | if max := IntMax(test.nums[0], test.nums[1]); max != test.expectedMax { 47 | t.Errorf("expected %v, got %v", test.expectedMax, max) 48 | } 49 | } 50 | } 51 | 52 | func TestIntMin(t *testing.T) { 53 | tests := []struct { 54 | nums []int 55 | expectedMin int 56 | }{ 57 | { 58 | nums: []int{-1, 0}, 59 | expectedMin: -1, 60 | }, 61 | { 62 | nums: []int{-1, -2}, 63 | expectedMin: -2, 64 | }, 65 | { 66 | nums: []int{0, 1}, 67 | expectedMin: 0, 68 | }, 69 | { 70 | nums: []int{1, 2}, 71 | expectedMin: 1, 72 | }, 73 | } 74 | 75 | for i, test := range tests { 76 | t.Logf("executing scenario %d", i) 77 | if min := IntMin(test.nums[0], test.nums[1]); min != test.expectedMin { 78 | t.Errorf("expected %v, got %v", test.expectedMin, min) 79 | } 80 | } 81 | } 82 | 83 | func TestInt32Max(t *testing.T) { 84 | tests := []struct { 85 | nums []int32 86 | expectedMax int32 87 | }{ 88 | { 89 | nums: []int32{-1, 0}, 90 | expectedMax: 0, 91 | }, 92 | { 93 | nums: []int32{-1, -2}, 94 | expectedMax: -1, 95 | }, 96 | { 97 | nums: []int32{0, 1}, 98 | expectedMax: 1, 99 | }, 100 | { 101 | nums: []int32{1, 2}, 102 | expectedMax: 2, 103 | }, 104 | } 105 | 106 | for i, test := range tests { 107 | t.Logf("executing scenario %d", i) 108 | if max := Int32Max(test.nums[0], test.nums[1]); max != test.expectedMax { 109 | t.Errorf("expected %v, got %v", test.expectedMax, max) 110 | } 111 | } 112 | } 113 | 114 | func TestInt32Min(t *testing.T) { 115 | tests := []struct { 116 | nums []int32 117 | expectedMin int32 118 | }{ 119 | { 120 | nums: []int32{-1, 0}, 121 | expectedMin: -1, 122 | }, 123 | { 124 | nums: []int32{-1, -2}, 125 | expectedMin: -2, 126 | }, 127 | { 128 | nums: []int32{0, 1}, 129 | expectedMin: 0, 130 | }, 131 | { 132 | nums: []int32{1, 2}, 133 | expectedMin: 1, 134 | }, 135 | } 136 | 137 | for i, test := range tests { 138 | t.Logf("executing scenario %d", i) 139 | if min := Int32Min(test.nums[0], test.nums[1]); min != test.expectedMin { 140 | t.Errorf("expected %v, got %v", test.expectedMin, min) 141 | } 142 | } 143 | } 144 | 145 | func TestInt64Max(t *testing.T) { 146 | tests := []struct { 147 | nums []int64 148 | expectedMax int64 149 | }{ 150 | { 151 | nums: []int64{-1, 0}, 152 | expectedMax: 0, 153 | }, 154 | { 155 | nums: []int64{-1, -2}, 156 | expectedMax: -1, 157 | }, 158 | { 159 | nums: []int64{0, 1}, 160 | expectedMax: 1, 161 | }, 162 | { 163 | nums: []int64{1, 2}, 164 | expectedMax: 2, 165 | }, 166 | } 167 | 168 | for i, test := range tests { 169 | t.Logf("executing scenario %d", i) 170 | if max := Int64Max(test.nums[0], test.nums[1]); max != test.expectedMax { 171 | t.Errorf("expected %v, got %v", test.expectedMax, max) 172 | } 173 | } 174 | } 175 | 176 | func TestInt64Min(t *testing.T) { 177 | tests := []struct { 178 | nums []int64 179 | expectedMin int64 180 | }{ 181 | { 182 | nums: []int64{-1, 0}, 183 | expectedMin: -1, 184 | }, 185 | { 186 | nums: []int64{-1, -2}, 187 | expectedMin: -2, 188 | }, 189 | { 190 | nums: []int64{0, 1}, 191 | expectedMin: 0, 192 | }, 193 | { 194 | nums: []int64{1, 2}, 195 | expectedMin: 1, 196 | }, 197 | } 198 | 199 | for i, test := range tests { 200 | t.Logf("executing scenario %d", i) 201 | if min := Int64Min(test.nums[0], test.nums[1]); min != test.expectedMin { 202 | t.Errorf("expected %v, got %v", test.expectedMin, min) 203 | } 204 | } 205 | } 206 | 207 | func TestRoundToInt32(t *testing.T) { 208 | tests := []struct { 209 | num float64 210 | exp int32 211 | }{ 212 | { 213 | num: 5.5, 214 | exp: 6, 215 | }, 216 | { 217 | num: -3.7, 218 | exp: -4, 219 | }, 220 | { 221 | num: 3.49, 222 | exp: 3, 223 | }, 224 | { 225 | num: -7.9, 226 | exp: -8, 227 | }, 228 | { 229 | num: -4.499999, 230 | exp: -4, 231 | }, 232 | { 233 | num: 0, 234 | exp: 0, 235 | }, 236 | { 237 | num: 0.49999999999999994, 238 | exp: 0, 239 | }, 240 | } 241 | 242 | for i, test := range tests { 243 | t.Logf("executing scenario %d", i) 244 | if got := RoundToInt32(test.num); got != test.exp { 245 | t.Errorf("expected %d, got %d", test.exp, got) 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /buffer/ring_growing.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package buffer 18 | 19 | // defaultRingSize defines the default ring size if not specified 20 | const defaultRingSize = 16 21 | 22 | // RingGrowingOptions sets parameters for [RingGrowing] and 23 | // [TypedRingGrowing]. 24 | type RingGrowingOptions struct { 25 | // InitialSize is the number of pre-allocated elements in the 26 | // initial underlying storage buffer. 27 | InitialSize int 28 | } 29 | 30 | // RingGrowing is a growing ring buffer. 31 | // Not thread safe. 32 | // 33 | // Deprecated: Use TypedRingGrowing[any] instead. 34 | type RingGrowing = TypedRingGrowing[any] 35 | 36 | // NewRingGrowing constructs a new RingGrowing instance with provided parameters. 37 | // 38 | // Deprecated: Use NewTypedRingGrowing[any] instead. 39 | func NewRingGrowing(initialSize int) *RingGrowing { 40 | return NewTypedRingGrowing[any](RingGrowingOptions{InitialSize: initialSize}) 41 | } 42 | 43 | // TypedRingGrowing is a growing ring buffer. 44 | // The zero value has an initial size of 0 and is ready to use. 45 | // Not thread safe. 46 | type TypedRingGrowing[T any] struct { 47 | data []T 48 | n int // Size of Data 49 | beg int // First available element 50 | readable int // Number of data items available 51 | } 52 | 53 | // NewTypedRingGrowing constructs a new TypedRingGrowing instance with provided parameters. 54 | func NewTypedRingGrowing[T any](opts RingGrowingOptions) *TypedRingGrowing[T] { 55 | return &TypedRingGrowing[T]{ 56 | data: make([]T, opts.InitialSize), 57 | n: opts.InitialSize, 58 | } 59 | } 60 | 61 | // ReadOne reads (consumes) first item from the buffer if it is available, otherwise returns false. 62 | func (r *TypedRingGrowing[T]) ReadOne() (data T, ok bool) { 63 | if r.readable == 0 { 64 | return 65 | } 66 | r.readable-- 67 | element := r.data[r.beg] 68 | var zero T 69 | r.data[r.beg] = zero // Remove reference to the object to help GC 70 | if r.beg == r.n-1 { 71 | // Was the last element 72 | r.beg = 0 73 | } else { 74 | r.beg++ 75 | } 76 | return element, true 77 | } 78 | 79 | // WriteOne adds an item to the end of the buffer, growing it if it is full. 80 | func (r *TypedRingGrowing[T]) WriteOne(data T) { 81 | if r.readable == r.n { 82 | // Time to grow 83 | newN := r.n * 2 84 | if newN == 0 { 85 | newN = defaultRingSize 86 | } 87 | newData := make([]T, newN) 88 | to := r.beg + r.readable 89 | if to <= r.n { 90 | copy(newData, r.data[r.beg:to]) 91 | } else { 92 | copied := copy(newData, r.data[r.beg:]) 93 | copy(newData[copied:], r.data[:(to%r.n)]) 94 | } 95 | r.beg = 0 96 | r.data = newData 97 | r.n = newN 98 | } 99 | r.data[(r.readable+r.beg)%r.n] = data 100 | r.readable++ 101 | } 102 | 103 | // Len returns the number of items in the buffer. 104 | func (r *TypedRingGrowing[T]) Len() int { 105 | return r.readable 106 | } 107 | 108 | // Cap returns the capacity of the buffer. 109 | func (r *TypedRingGrowing[T]) Cap() int { 110 | return r.n 111 | } 112 | 113 | // RingOptions sets parameters for [Ring]. 114 | type RingOptions struct { 115 | // InitialSize is the number of pre-allocated elements in the 116 | // initial underlying storage buffer. 117 | InitialSize int 118 | // NormalSize is the number of elements to allocate for new storage 119 | // buffers once the Ring is consumed and 120 | // can shrink again. 121 | NormalSize int 122 | } 123 | 124 | // Ring is a dynamically-sized ring buffer which can grow and shrink as-needed. 125 | // The zero value has an initial size and normal size of 0 and is ready to use. 126 | // Not thread safe. 127 | type Ring[T any] struct { 128 | growing TypedRingGrowing[T] 129 | normalSize int // Limits the size of the buffer that is kept for reuse. Read-only. 130 | } 131 | 132 | // NewRing constructs a new Ring instance with provided parameters. 133 | func NewRing[T any](opts RingOptions) *Ring[T] { 134 | return &Ring[T]{ 135 | growing: *NewTypedRingGrowing[T](RingGrowingOptions{InitialSize: opts.InitialSize}), 136 | normalSize: opts.NormalSize, 137 | } 138 | } 139 | 140 | // ReadOne reads (consumes) first item from the buffer if it is available, 141 | // otherwise returns false. When the buffer has been totally consumed and has 142 | // grown in size beyond its normal size, it shrinks down to its normal size again. 143 | func (r *Ring[T]) ReadOne() (data T, ok bool) { 144 | element, ok := r.growing.ReadOne() 145 | 146 | if r.growing.readable == 0 && r.growing.n > r.normalSize { 147 | // The buffer is empty. Reallocate a new buffer so the old one can be 148 | // garbage collected. 149 | r.growing.data = make([]T, r.normalSize) 150 | r.growing.n = r.normalSize 151 | r.growing.beg = 0 152 | } 153 | 154 | return element, ok 155 | } 156 | 157 | // WriteOne adds an item to the end of the buffer, growing it if it is full. 158 | func (r *Ring[T]) WriteOne(data T) { 159 | r.growing.WriteOne(data) 160 | } 161 | 162 | // Len returns the number of items in the buffer. 163 | func (r *Ring[T]) Len() int { 164 | return r.growing.Len() 165 | } 166 | 167 | // Cap returns the capacity of the buffer. 168 | func (r *Ring[T]) Cap() int { 169 | return r.growing.Cap() 170 | } 171 | --------------------------------------------------------------------------------