├── .DS_Store ├── .dockerignore ├── .github └── workflows │ ├── ci.yml │ ├── push-images.yml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── PROJECT ├── README.md ├── api └── v1alpha1 │ ├── groupversion_info.go │ ├── noderegistryconfigs_types.go │ ├── registryconfigs_types.go │ └── zz_generated.deepcopy.go ├── builds ├── copilot │ └── Dockerfile └── daemon │ └── Dockerfile ├── charts └── runtime-copilot │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── crds │ ├── registry.runtime.x-copilot.io_noderegistryconfigs.yaml │ └── registry.runtime.x-copilot.io_registryconfigs.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── daemon.yaml │ ├── deployment.yaml │ └── rbac │ │ ├── auth_proxy_client_clusterrole.yaml │ │ ├── auth_proxy_role.yaml │ │ ├── auth_proxy_role_binding.yaml │ │ ├── auth_proxy_service.yaml │ │ ├── leader_election_role.yaml │ │ ├── leader_election_role_binding.yaml │ │ ├── noderegistryconfigs_editor_role.yaml │ │ ├── noderegistryconfigs_viewer_role.yaml │ │ ├── registryconfigs_editor_role.yaml │ │ ├── registryconfigs_viewer_role.yaml │ │ ├── role.yaml │ │ ├── role_binding.yaml │ │ └── service_account.yaml │ └── values.yaml ├── cmd ├── copilot │ └── main.go └── daemon │ └── main.go ├── config ├── crd │ ├── bases │ │ ├── registry.runtime.x-copilot.io_noderegistryconfigs.yaml │ │ └── registry.runtime.x-copilot.io_registryconfigs.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── cainjection_in_noderegistryconfigs.yaml │ │ ├── cainjection_in_registryconfigs.yaml │ │ ├── webhook_in_noderegistryconfigs.yaml │ │ └── webhook_in_registryconfigs.yaml ├── default │ ├── kustomization.yaml │ ├── manager_auth_proxy_patch.yaml │ └── manager_config_patch.yaml ├── manager │ ├── daemon.yaml │ ├── kustomization.yaml │ └── manager.yaml ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── rbac │ ├── auth_proxy_client_clusterrole.yaml │ ├── auth_proxy_role.yaml │ ├── auth_proxy_role_binding.yaml │ ├── auth_proxy_service.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── noderegistryconfigs_editor_role.yaml │ ├── noderegistryconfigs_viewer_role.yaml │ ├── registryconfigs_editor_role.yaml │ ├── registryconfigs_viewer_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml └── samples │ ├── kustomization.yaml │ ├── registry.runtime_v1alpha1_registryconfigs.yaml │ └── registry.runtimme_v1alpha1_noderegistryconfigs.yaml ├── go.mod ├── go.sum ├── hack ├── .import-aliases ├── boilerplate.go.txt ├── helm-sync.sh ├── tools.go ├── tools │ ├── preferredimports │ │ └── preferredimports.go │ └── tools.go ├── util.sh ├── verify-crds.sh ├── verify-import-aliases.sh ├── verify-staticcheck.sh └── verify-vendor.sh └── internal ├── controller ├── noderegistryconfigs_controller.go └── registryconfigs_controller.go └── utils └── rand.go /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/copilot-io/runtime-copilot/13000501a4f3bfd7f835b6b2b81c16207112ca51/.DS_Store -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file 2 | # Ignore build and test binaries. 3 | bin/ 4 | testbin/ 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | vertify: 8 | name: Vertify import alias, vendor, codegen, crds 9 | runs-on: ubuntu-latest 10 | env: 11 | GOPATH: ${{ github.workspace }} 12 | WORKSPACE: ${{ github.workspace }}/src/github.com/copilot-io/runtime-copilot 13 | defaults: 14 | run: 15 | working-directory: ${{ env.WORKSPACE }} 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v3 19 | with: 20 | path: ${{ env.WORKSPACE }} 21 | - name: Install Go 22 | uses: actions/setup-go@v4 23 | with: 24 | go-version: 1.19 25 | - run: go mod tidy && go mod vendor 26 | - run: hack/verify-staticcheck.sh 27 | - run: hack/verify-import-aliases.sh 28 | - run: hack/verify-vendor.sh 29 | - run: hack/verify-crds.sh 30 | 31 | build: 32 | name: Build binary 33 | needs: vertify 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@v3 38 | with: 39 | # https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches 40 | fetch-depth: 0 41 | - name: Install Go 42 | uses: actions/setup-go@v4 43 | with: 44 | go-version: 1.19 45 | - name: Compile 46 | run: make build 47 | test: 48 | name: Unit test 49 | needs: build 50 | runs-on: ubuntu-latest 51 | steps: 52 | - name: Checkout code 53 | uses: actions/checkout@v3 54 | - name: Install Go 55 | uses: actions/setup-go@v4 56 | with: 57 | go-version: 1.19 58 | - run: make test 59 | -------------------------------------------------------------------------------- /.github/workflows/push-images.yml: -------------------------------------------------------------------------------- 1 | name: Push Images 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - main 8 | jobs: 9 | build-and-push-image: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | packages: write 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v3 17 | with: 18 | # https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches 19 | fetch-depth: 0 20 | - name: Cache Docker layers 21 | uses: actions/cache@v2 22 | with: 23 | path: /tmp/.buildx-cache 24 | key: ${{ runner.os }}-buildx-${{ github.sha }} 25 | restore-keys: | 26 | ${{ runner.os }}-buildx- 27 | - name: Set up qemu 28 | uses: docker/setup-qemu-action@v2 29 | with: 30 | platforms: amd64,arm64 31 | - name: Login registry 32 | run: | 33 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin 34 | - name: Push images 35 | env: 36 | ON_PLUGINS: true 37 | run: | 38 | make docker-buildx 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | branches: 8 | - main 9 | 10 | jobs: 11 | release: 12 | # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions 13 | # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token 14 | permissions: 15 | contents: write 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Configure Git 24 | run: | 25 | git config user.name "$GITHUB_ACTOR" 26 | git config user.email "1275177125@qq.com" 27 | 28 | - name: Install Helm 29 | uses: azure/setup-helm@v3 30 | env: 31 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 32 | 33 | - name: Run chart-releaser 34 | uses: helm/chart-releaser-action@v1.5.0 35 | with: 36 | skip_existing: true 37 | env: 38 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 39 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | ./bin/* 23 | bin/ 24 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 10m 3 | 4 | # The default concurrency value is the number of available CPU. 5 | concurrency: 4 6 | 7 | # which dirs to skip: issues from them won't be reported; 8 | # can use regexp here: generated.*, regexp is applied on full path; 9 | # default value is empty list, but default dirs are skipped independently 10 | # from this option's value (see skip-dirs-use-default). 11 | # "/" will be replaced by current OS file path separator to properly work 12 | # on Windows. 13 | skip-dirs: 14 | - hack/tools/preferredimports # This code is directly lifted from the Kubernetes codebase, skip checking 15 | 16 | # default is true. Enables skipping of directories: 17 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ 18 | skip-dirs-use-default: true 19 | 20 | # One of 'readonly' and 'vendor'. 21 | # - readonly: the go command is disallowed from the implicit automatic updating of go.mod described above. 22 | # Instead, it fails when any changes to go.mod are needed. This setting is most useful to check 23 | # that go.mod does not need updates, such as in a continuous integration and testing system. 24 | # - vendor: the go command assumes that the vendor directory holds the correct copies of dependencies and ignores 25 | # the dependency descriptions in go.mod. 26 | modules-download-mode: readonly 27 | 28 | linters-settings: 29 | depguard: 30 | list-type: blacklist 31 | include-go-root: false 32 | dupl: 33 | threshold: 800 34 | errcheck: 35 | check-type-assertions: true 36 | check-blank: true 37 | # exclude: .errcheckignore 38 | errorlint: 39 | errorf: true 40 | asserts: true 41 | comparison: true 42 | goconst: 43 | min-len: 3 44 | min-occurrences: 3 45 | gocritic: 46 | enabled-tags: 47 | - diagnostic 48 | - experimental 49 | - opinionated 50 | - performance 51 | - style 52 | disabled-checks: 53 | - commentedOutCode 54 | - whyNoLint 55 | settings: 56 | hugeParam: 57 | sizeThreshold: 80 58 | rangeExprCopy: 59 | sizeThreshold: 512 60 | rangeValCopy: 61 | sizeThreshold: 128 62 | godot: 63 | scope: declarations 64 | capital: false 65 | gofmt: 66 | simplify: true 67 | gofumpt: 68 | extra-rules: true 69 | goimports: 70 | local-prefixes: github.com/copilot-io/runtime-copilot 71 | gocyclo: 72 | # minimal code complexity to report, 30 by default (but we recommend 10-20) 73 | min-complexity: 20 74 | nestif: 75 | min-complexity: 20 76 | 77 | output: 78 | format: colored-line-number 79 | print-issued-lines: true 80 | print-linter-name: true 81 | uniq-by-line: true 82 | sort-results: true 83 | 84 | linters: 85 | disable-all: true 86 | disabled: 87 | - exhaustivestruct # Checks if all struct's fields are initialized 88 | - forbidigo # Forbids identifiers 89 | - forcetypeassert # finds forced type assertions 90 | - gci # Gci control golang package import order and make it always deterministic. 91 | - gochecknoglobals # check that no global variables exist 92 | - gochecknoinits # Checks that no init functions are present in Go code 93 | - goconst # Finds repeated strings that could be replaced by a constant 94 | - godox # Tool for detection of FIXME, TODO and other comment keywords 95 | - goerr113 # Golang linter to check the errors handling expressions 96 | - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes 97 | - gomnd # An analyzer to detect magic numbers. 98 | - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. 99 | - gomodguard # Allow and block list linter for direct Go module dependencies. 100 | - interfacer # Linter that suggests narrower interface types 101 | - lll # Reports long lines 102 | - maligned # Tool to detect Go structs that would take less memory if their fields were sorted 103 | - promlinter # Check Prometheus metrics naming via promlint 104 | - scopelint # Scopelint checks for unpinned variables in go programs 105 | - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. 106 | - testpackage # Linter that makes you use a separate _test package 107 | - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes 108 | - wrapcheck # Checks that errors returned from external packages are wrapped 109 | - wsl # Whitespace Linter 110 | - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test 111 | - noctx # noctx finds sending http request without context.Context 112 | - wastedassign # wastedassign finds wasted assignment statements. 113 | - exhaustive # check exhaustiveness of enum switch statements 114 | - cyclop # checks function and package cyclomatic complexity 115 | - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases 116 | - unparam # Reports unused function parameters 117 | - gosec # Inspects source code for security problems 118 | - funlen # Tool for detection of long functions 119 | - gocognit # Computes and checks the cognitive complexity of functions 120 | - gocyclo # Computes and checks the cyclomatic complexity of functions 121 | - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity 122 | - gocritic # Provides many diagnostics that check for bugs, performance and style issues. 123 | - nestif # Reports deeply nested if statements 124 | - bodyclose # checks whether HTTP response body is closed successfully 125 | - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. 126 | - tagliatelle # Checks the struct tags. 127 | enable: 128 | - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers 129 | - deadcode # Finds unused code 130 | - depguard # Go linter that checks if package imports are in a list of acceptable packages 131 | - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) 132 | - dupl # Tool for code clone detection 133 | - durationcheck # check for two durations multiplied together 134 | - exportloopref # checks for pointers to enclosing loop variables 135 | - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification 136 | - gofumpt # Gofumpt checks whether code was gofumpt-ed. 137 | - goheader # Checks is file header matches to pattern 138 | - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports 139 | - goprintffuncname # Checks that printf-like functions are named with `f` at the end 140 | - gosimple # Linter for Go source code that specializes in simplifying a code 141 | - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string 142 | - ifshort # Checks that your code uses short syntax for if-statements whenever possible 143 | - importas # Enforces consistent import aliases 144 | - ineffassign # Detects when assignments to existing variables are not used 145 | - makezero # Finds slice declarations with non-zero initial length 146 | - misspell # Finds commonly misspelled English words in comments 147 | - nakedret # Finds naked returns in functions greater than a specified function length 148 | - nilerr # Finds the code that returns nil even if it checks that the error is not nil. 149 | - nolintlint # Reports ill-formed or insufficient nolint directives 150 | - prealloc # Finds slice declarations that could potentially be preallocated 151 | - predeclared # find code that shadows one of Go's predeclared identifiers 152 | - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. 153 | - rowserrcheck # checks whether Err of rows is checked successfully 154 | - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks 155 | - structcheck # Finds unused struct fields 156 | - stylecheck # Stylecheck is a replacement for golint 157 | - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers 158 | - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code 159 | - unconvert # Remove unnecessary type conversions 160 | - unused # Checks Go code for unused constants, variables, functions and types 161 | - varcheck # Finds unused global variables and constants 162 | - whitespace # Tool for detection of leading and trailing whitespace 163 | - godot # Check if comments end in a period 164 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # Image URL to use all building/pushing image targets 3 | DAEMON_IMG ?= ghcr.io/copilot-io/runtime-copilot/daemon:latest 4 | COPILOT_IMG ?= ghcr.io/copilot-io/runtime-copilot/controller-manager:latest 5 | # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. 6 | ENVTEST_K8S_VERSION = 1.26.1 7 | 8 | # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) 9 | ifeq (,$(shell go env GOBIN)) 10 | GOBIN=$(shell go env GOPATH)/bin 11 | else 12 | GOBIN=$(shell go env GOBIN) 13 | endif 14 | 15 | # Setting SHELL to bash allows bash commands to be executed by recipes. 16 | # Options are set to exit when a recipe line exits non-zero or a piped command fails. 17 | SHELL = /usr/bin/env bash -o pipefail 18 | .SHELLFLAGS = -ec 19 | 20 | .PHONY: all 21 | all: build 22 | 23 | ##@ General 24 | 25 | # The help target prints out all targets with their descriptions organized 26 | # beneath their categories. The categories are represented by '##@' and the 27 | # target descriptions by '##'. The awk commands is responsible for reading the 28 | # entire set of makefiles included in this invocation, looking for lines of the 29 | # file as xyz: ## something, and then pretty-format the target and help. Then, 30 | # if there's a line with ##@ something, that gets pretty-printed as a category. 31 | # More info on the usage of ANSI control characters for terminal formatting: 32 | # https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters 33 | # More info on the awk command: 34 | # http://linuxcommand.org/lc3_adv_awk.php 35 | 36 | .PHONY: help 37 | help: ## Display this help. 38 | @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 39 | 40 | ##@ Development 41 | 42 | .PHONY: manifests 43 | manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. 44 | $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases 45 | 46 | .PHONY: generate 47 | generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. 48 | $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." 49 | 50 | .PHONY: fmt 51 | fmt: ## Run go fmt against code. 52 | go fmt ./... 53 | 54 | .PHONY: vet 55 | vet: ## Run go vet against code. 56 | go vet ./... 57 | 58 | .PHONY: test 59 | test: manifests generate fmt vet envtest ## Run tests. 60 | KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out 61 | 62 | .PHONY: lint 63 | lint: 64 | bash hack/verify-staticcheck.sh 65 | 66 | .PHONY: verify-import-alias 67 | verify-import-alias: 68 | bash hack/verify-import-aliases.sh 69 | 70 | ##@ Build 71 | 72 | .PHONY: build 73 | build: manifests generate fmt vet ## Build manager binary. 74 | go build -o bin/daemon cmd/daemon/main.go 75 | go build -o bin/copilot cmd/copilot/main.go 76 | 77 | .PHONY: run 78 | run: manifests generate fmt vet ## Run a controller from your host. 79 | go run ./cmd/copilot/main.go 80 | 81 | # If you wish built the manager image targeting other platforms you can use the --platform flag. 82 | # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. 83 | # More info: https://docs.docker.com/develop/develop-images/build_enhancements/ 84 | .PHONY: docker-build 85 | docker-build: test ## Build docker image with the manager. 86 | docker build -t ${COPILOT_IMG} -f ./builds/copilot/Dockerfile . 87 | docker build -t ${DAEMON_IMG} -f ./builds/daemon/Dockerfile . 88 | 89 | .PHONY: docker-push 90 | docker-push: ## Push docker image with the manager. 91 | docker push ${COPILOT_IMG} 92 | docker push ${DAEMON_IMG} 93 | 94 | # PLATFORMS defines the target platforms for the manager image be build to provide support to multiple 95 | # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: 96 | # - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ 97 | # - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ 98 | # - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) 99 | # To properly provided solutions that supports more than one platform you should use this option. 100 | PLATFORMS ?= linux/arm64,linux/amd64 101 | .PHONY: docker-buildx 102 | docker-buildx: ## Build and push docker image for the manager for cross-platform support 103 | # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile 104 | sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' ./builds/copilot/Dockerfile > ./builds/copilot/Dockerfile.cross 105 | sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' ./builds/daemon/Dockerfile > ./builds/daemon/Dockerfile.cross 106 | docker buildx create --name project-v3-builder 107 | docker buildx use project-v3-builder 108 | docker buildx build --push --platform=$(PLATFORMS) --tag ${COPILOT_IMG} -f ./builds/copilot/Dockerfile.cross . 109 | docker buildx build --push --platform=$(PLATFORMS) --tag ${DAEMON_IMG} -f ./builds/daemon/Dockerfile.cross . 110 | docker buildx rm project-v3-builder 111 | rm ./builds/copilot/Dockerfile.cross 112 | rm ./builds/daemon/Dockerfile.cross 113 | 114 | ##@ Deployment 115 | 116 | ifndef ignore-not-found 117 | ignore-not-found = false 118 | endif 119 | 120 | .PHONY: install 121 | install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. 122 | $(KUSTOMIZE) build config/crd | kubectl apply -f - 123 | 124 | .PHONY: uninstall 125 | uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. 126 | $(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f - 127 | 128 | .PHONY: deploy 129 | deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. 130 | cd config/manager && $(KUSTOMIZE) edit set image controller=${COPILOT_IMG} 131 | $(KUSTOMIZE) build config/default | kubectl apply -f - 132 | 133 | .PHONY: undeploy 134 | undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. 135 | $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - 136 | 137 | ##@ Build Dependencies 138 | 139 | ## Location to install dependencies to 140 | LOCALBIN ?= $(shell pwd)/bin 141 | $(LOCALBIN): 142 | mkdir -p $(LOCALBIN) 143 | 144 | ## Tool Binaries 145 | KUSTOMIZE ?= $(LOCALBIN)/kustomize 146 | CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen 147 | ENVTEST ?= $(LOCALBIN)/setup-envtest 148 | 149 | ## Tool Versions 150 | KUSTOMIZE_VERSION ?= v5.0.0 151 | CONTROLLER_TOOLS_VERSION ?= v0.11.3 152 | 153 | KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" 154 | .PHONY: kustomize 155 | kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. 156 | $(KUSTOMIZE): $(LOCALBIN) 157 | @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ 158 | echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ 159 | rm -rf $(LOCALBIN)/kustomize; \ 160 | fi 161 | test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) --output install_kustomize.sh && bash install_kustomize.sh $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); rm install_kustomize.sh; } 162 | 163 | .PHONY: controller-gen 164 | controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. 165 | $(CONTROLLER_GEN): $(LOCALBIN) 166 | test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \ 167 | GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) 168 | 169 | .PHONY: envtest 170 | envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. 171 | $(ENVTEST): $(LOCALBIN) 172 | test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest 173 | 174 | ##@ helm chart Dependencies 175 | .PHONY: helm-sync 176 | helm-sync: ## Sync the helm chart dependencies 177 | bash ./hack/helm-sync.sh -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | # Code generated by tool. DO NOT EDIT. 2 | # This file is used to track the info used to scaffold your project 3 | # and allow the plugins properly work. 4 | # More info: https://book.kubebuilder.io/reference/project-config.html 5 | domain: x-copilot.io 6 | layout: 7 | - go.kubebuilder.io/v4 8 | projectName: runtime-copilot 9 | repo: github.com/copilot-io/runtime-copilot 10 | resources: 11 | - api: 12 | crdVersion: v1 13 | namespaced: true 14 | controller: true 15 | domain: x-copilot.io 16 | group: registry.runtime 17 | kind: RegistryConfigs 18 | path: github.com/copilot-io/runtime-copilot/api/v1alpha1 19 | version: v1alpha1 20 | - api: 21 | crdVersion: v1 22 | namespaced: true 23 | controller: true 24 | domain: x-copilot.io 25 | group: registry.runtime 26 | kind: NodeRegistryConfigs 27 | path: github.com/copilot-io/runtime-copilot/api/v1alpha1 28 | version: v1alpha1 29 | version: "3" 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Github Ci Action](https://github.com/copilot-io/runtime-copilot/actions/workflows/ci.yml/badge.svg)![Github Image Action](https://github.com/copilot-io/runtime-copilot/actions/workflows/push-images.yml/badge.svg)![Github Chart Action](https://github.com/copilot-io/runtime-copilot/actions/workflows/release.yml/badge.svg) 2 | 3 | # runtime-copilot 4 | The main function of the runtime copilot is to assist the operation of the container runtime component (containerd), specifically for adding or deleting non-safe registries. 5 | 6 | ## Introduction 7 | 8 | This project is a runtime copilot, auxiliary manager runtime, current function introduce the config insecure registry to runtime(such as: containerd、docker、cri-o), It mainly has the following functions: 9 | 10 | 11 | 12 | - [ ] Manager insecure registry in runtime. 13 | - [ ] Upgrade runtime version. 14 | - [ ] Replace runtime with another runtime. 15 | - [ ] Manager runtime plugins. 16 | 17 | ### Manager insecure registry 18 | 19 | | Runtime | Support | 20 | | --- | --- | 21 | | containerd | Yes | 22 | | docker | No | 23 | | cri-o | No | 24 | 25 | ## Usage 26 | 27 | [Helm](https://helm.sh) must be installed to use the charts. Please refer to 28 | Helm's [documentation](https://helm.sh/docs) to get started. 29 | 30 | Once Helm has been set up correctly, add the repo as follows: 31 | 32 | helm repo add runtime-copilot https://copilot-io.github.io/runtime-copilot 33 | 34 | If you is first time to use this repo, you need to run command as follows: 35 | 36 | helm repo update 37 | helm search repo runtime-copilot 38 | 39 | To install the runtime-copilot chart: 40 | 41 | helm install runtime-copilot runtime-copilot/runtime-copilot --namespace runtime-copilot 42 | 43 | To uninstall the chart: 44 | 45 | helm delete runtime-copilot --namespace runtime-copilot 46 | 47 | ## Examples 48 | 49 | We add `10.6..112.191` this insecret registry to containerd, we can define yaml content follow file. 50 | 51 | ```yaml 52 | apiVersion: registry.runtime.x-copilot.io/v1alpha1 53 | kind: RegistryConfigs 54 | metadata: 55 | name: registryconfigs-sample 56 | spec: 57 | selector: 58 | matchLabels: 59 | app: registryconfigs-sample 60 | template: 61 | spec: 62 | hostConfigs: 63 | - server: "https://10.6.112.191" 64 | capabilities: 65 | - pull 66 | - push 67 | - resolve 68 | skip_verify: true 69 | ``` 70 | 71 | 72 | After executing `kubectl apply`, the following `hosts.toml` file will be generated on each node, the content is as follows: 73 | 74 | ```yaml 75 | server = "https://10.6.112.191" 76 | 77 | [host] 78 | [host."https://10.6.112.191"] 79 | capabilities = ["pull", "push", "resolve"] 80 | skip_verify = true 81 | override_path = false 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /api/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 v1alpha1 contains API Schema definitions for the registry.runtime v1alpha1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=registry.runtime.x-copilot.io 20 | package v1alpha1 21 | 22 | import ( 23 | "k8s.io/apimachinery/pkg/runtime/schema" 24 | "sigs.k8s.io/controller-runtime/pkg/scheme" 25 | ) 26 | 27 | var ( 28 | // GroupVersion is group version used to register these objects. 29 | GroupVersion = schema.GroupVersion{Group: "registry.runtime.x-copilot.io", Version: "v1alpha1"} 30 | 31 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme. 32 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 33 | 34 | // AddToScheme adds the types in this group-version to the given scheme. 35 | AddToScheme = SchemeBuilder.AddToScheme 36 | ) 37 | -------------------------------------------------------------------------------- /api/v1alpha1/noderegistryconfigs_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | type ( 24 | // RuntimeType is the type of runtime. 25 | RuntimeType string 26 | // CapabilitieType is the type of capability. 27 | CapabilitieType string 28 | // StatusState is the state of status. 29 | StatusState string 30 | // ConditionType is the type of condition. 31 | ConditionType string 32 | ) 33 | 34 | const ( 35 | RuntimeTypeDocker RuntimeType = "docker" 36 | RuntimeTypeContainerd RuntimeType = "containerd" 37 | RuntimeTypeCrio RuntimeType = "crio" 38 | RuntimeTypeUnknown RuntimeType = "unknown" 39 | 40 | CapabilitieTypePull CapabilitieType = "pull" 41 | CapabilitieTypePush CapabilitieType = "push" 42 | CapabilitieTypeResolve CapabilitieType = "resolve" 43 | 44 | StatusStateSuccess StatusState = "Success" 45 | StatusStateFailed StatusState = "Failed" 46 | StatusStateRunning StatusState = "Running" 47 | StatusStateUnknown StatusState = "Unknown" 48 | 49 | ConditionTypeWriteDataError ConditionType = "WriteDataError" 50 | ConditionTypeReadDataError ConditionType = "ReadDataError" 51 | 52 | // MaxRetryNum is the max retry num. 53 | MaxRetryNum = 3 54 | ) 55 | 56 | func (rt RuntimeType) String() string { 57 | return string(rt) 58 | } 59 | 60 | func (ct CapabilitieType) String() string { 61 | return string(ct) 62 | } 63 | 64 | func (ss StatusState) String() string { 65 | return string(ss) 66 | } 67 | 68 | // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! 69 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 70 | 71 | // NodeRegistryConfigsSpec defines the desired state of NodeRegistryConfigs. 72 | type NodeRegistryConfigsSpec struct { 73 | // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster 74 | // Important: Run "make" to regenerate code after modifying this file 75 | 76 | // NodeName is registry config exec node name 77 | NodeName string `json:"nodeName"` 78 | // Type is runtime type 79 | Type RuntimeType `json:"type"` 80 | // set retry num 81 | RetryNum int `json:"retry_num,omitempty"` 82 | // HostConfigs store the per-host configuration 83 | HostConfigs []NodeRegistryHostConfig `json:"hostConfigs,omitempty"` 84 | } 85 | 86 | type NodeRegistryHostConfig struct { 87 | // Server specifies the default server. When `host` is 88 | // also specified, those hosts are tried first. 89 | Server string `json:"server,omitempty"` 90 | Capabilities []CapabilitieType `json:"capabilities"` 91 | SkipVerify *bool `json:"skip_verify,omitempty"` 92 | Header map[string]string `json:"header,omitempty"` 93 | OverridePath bool `json:"override_path,omitempty"` 94 | CaSecretRef string `json:"ca_secret_ref,omitempty"` 95 | } 96 | 97 | // NodeRegistryConfigsStatus defines the observed state of NodeRegistryConfigs. 98 | type NodeRegistryConfigsStatus struct { 99 | // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster 100 | // Important: Run "make" to regenerate code after modifying this file 101 | Conditions []metav1.Condition `json:"conditions,omitempty"` 102 | State StatusState `json:"state,omitempty"` 103 | RetryNum int `json:"retry_num,omitempty"` 104 | } 105 | 106 | //+kubebuilder:object:root=true 107 | //+kubebuilder:subresource:status 108 | //+kubebuilder:resource:scope=Cluster 109 | 110 | // NodeRegistryConfigs is the Schema for the noderegistryconfigs API. 111 | type NodeRegistryConfigs struct { 112 | metav1.TypeMeta `json:",inline"` 113 | metav1.ObjectMeta `json:"metadata,omitempty"` 114 | 115 | Spec NodeRegistryConfigsSpec `json:"spec,omitempty"` 116 | Status NodeRegistryConfigsStatus `json:"status,omitempty"` 117 | } 118 | 119 | //+kubebuilder:object:root=true 120 | 121 | // NodeRegistryConfigsList contains a list of NodeRegistryConfigs. 122 | type NodeRegistryConfigsList struct { 123 | metav1.TypeMeta `json:",inline"` 124 | metav1.ListMeta `json:"metadata,omitempty"` 125 | Items []NodeRegistryConfigs `json:"items"` 126 | } 127 | 128 | func init() { 129 | SchemeBuilder.Register(&NodeRegistryConfigs{}, &NodeRegistryConfigsList{}) 130 | } 131 | -------------------------------------------------------------------------------- /api/v1alpha1/registryconfigs_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 v1alpha1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! 24 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 25 | 26 | // RegistryConfigsSpec defines the desired state of RegistryConfigs. 27 | type RegistryConfigsSpec struct { 28 | // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster 29 | // Important: Run "make" to regenerate code after modifying this file 30 | 31 | // Selector is used to select nodes that will be configured 32 | Selector metav1.LabelSelector `json:"selector,omitempty"` 33 | Template RegistryConfigsTemplate `json:"template,omitempty"` 34 | } 35 | 36 | // RegistryConfigsTemplate defines the template for the registry config. 37 | type RegistryConfigsTemplate struct { 38 | metav1.ObjectMeta `json:"metadata,omitempty"` 39 | Spec NodeHostConfigsSpec `json:"spec"` 40 | } 41 | 42 | // NodeHostConfigsSpec defines the host config for the registry. 43 | type NodeHostConfigsSpec struct { 44 | RetryNum int `json:"retry_num,omitempty"` 45 | HostConfigs []NodeRegistryHostConfig `json:"hostConfigs"` 46 | } 47 | 48 | // RegistryConfigsStatus defines the observed state of RegistryConfigs. 49 | type RegistryConfigsStatus struct { 50 | // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster 51 | // Important: Run "make" to regenerate code after modifying this file 52 | // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster 53 | // Important: Run "make" to regenerate code after modifying this file 54 | State StatusState `json:"state,omitempty"` 55 | TotalNodes []RuntimeNum `json:"total_nodes,omitempty"` 56 | SuccessNodes []RuntimeNum `json:"success_nodes,omitempty"` 57 | FailedNodes []RuntimeNum `json:"failed_nodes,omitempty"` 58 | RunningNodes []RuntimeNum `json:"running_nodes,omitempty"` 59 | } 60 | 61 | type RuntimeNum struct { 62 | RuntimeType RuntimeType `json:"runtimeType,omitempty"` 63 | Num int `json:"num,omitempty"` 64 | } 65 | 66 | //+kubebuilder:object:root=true 67 | //+kubebuilder:subresource:status 68 | //+kubebuilder:resource:scope=Cluster 69 | 70 | // RegistryConfigs is the Schema for the registryconfigs API. 71 | type RegistryConfigs struct { 72 | metav1.TypeMeta `json:",inline"` 73 | metav1.ObjectMeta `json:"metadata,omitempty"` 74 | 75 | Spec RegistryConfigsSpec `json:"spec,omitempty"` 76 | Status RegistryConfigsStatus `json:"status,omitempty"` 77 | } 78 | 79 | //+kubebuilder:object:root=true 80 | 81 | // RegistryConfigsList contains a list of RegistryConfigs. 82 | type RegistryConfigsList struct { 83 | metav1.TypeMeta `json:",inline"` 84 | metav1.ListMeta `json:"metadata,omitempty"` 85 | Items []RegistryConfigs `json:"items"` 86 | } 87 | 88 | func init() { 89 | SchemeBuilder.Register(&RegistryConfigs{}, &RegistryConfigsList{}) 90 | } 91 | -------------------------------------------------------------------------------- /api/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright 2023. 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 | // Code generated by controller-gen. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | ) 28 | 29 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 30 | func (in *NodeHostConfigsSpec) DeepCopyInto(out *NodeHostConfigsSpec) { 31 | *out = *in 32 | if in.HostConfigs != nil { 33 | in, out := &in.HostConfigs, &out.HostConfigs 34 | *out = make([]NodeRegistryHostConfig, len(*in)) 35 | for i := range *in { 36 | (*in)[i].DeepCopyInto(&(*out)[i]) 37 | } 38 | } 39 | } 40 | 41 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeHostConfigsSpec. 42 | func (in *NodeHostConfigsSpec) DeepCopy() *NodeHostConfigsSpec { 43 | if in == nil { 44 | return nil 45 | } 46 | out := new(NodeHostConfigsSpec) 47 | in.DeepCopyInto(out) 48 | return out 49 | } 50 | 51 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 52 | func (in *NodeRegistryConfigs) DeepCopyInto(out *NodeRegistryConfigs) { 53 | *out = *in 54 | out.TypeMeta = in.TypeMeta 55 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 56 | in.Spec.DeepCopyInto(&out.Spec) 57 | in.Status.DeepCopyInto(&out.Status) 58 | } 59 | 60 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistryConfigs. 61 | func (in *NodeRegistryConfigs) DeepCopy() *NodeRegistryConfigs { 62 | if in == nil { 63 | return nil 64 | } 65 | out := new(NodeRegistryConfigs) 66 | in.DeepCopyInto(out) 67 | return out 68 | } 69 | 70 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 71 | func (in *NodeRegistryConfigs) DeepCopyObject() runtime.Object { 72 | if c := in.DeepCopy(); c != nil { 73 | return c 74 | } 75 | return nil 76 | } 77 | 78 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 79 | func (in *NodeRegistryConfigsList) DeepCopyInto(out *NodeRegistryConfigsList) { 80 | *out = *in 81 | out.TypeMeta = in.TypeMeta 82 | in.ListMeta.DeepCopyInto(&out.ListMeta) 83 | if in.Items != nil { 84 | in, out := &in.Items, &out.Items 85 | *out = make([]NodeRegistryConfigs, len(*in)) 86 | for i := range *in { 87 | (*in)[i].DeepCopyInto(&(*out)[i]) 88 | } 89 | } 90 | } 91 | 92 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistryConfigsList. 93 | func (in *NodeRegistryConfigsList) DeepCopy() *NodeRegistryConfigsList { 94 | if in == nil { 95 | return nil 96 | } 97 | out := new(NodeRegistryConfigsList) 98 | in.DeepCopyInto(out) 99 | return out 100 | } 101 | 102 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 103 | func (in *NodeRegistryConfigsList) DeepCopyObject() runtime.Object { 104 | if c := in.DeepCopy(); c != nil { 105 | return c 106 | } 107 | return nil 108 | } 109 | 110 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 111 | func (in *NodeRegistryConfigsSpec) DeepCopyInto(out *NodeRegistryConfigsSpec) { 112 | *out = *in 113 | if in.HostConfigs != nil { 114 | in, out := &in.HostConfigs, &out.HostConfigs 115 | *out = make([]NodeRegistryHostConfig, len(*in)) 116 | for i := range *in { 117 | (*in)[i].DeepCopyInto(&(*out)[i]) 118 | } 119 | } 120 | } 121 | 122 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistryConfigsSpec. 123 | func (in *NodeRegistryConfigsSpec) DeepCopy() *NodeRegistryConfigsSpec { 124 | if in == nil { 125 | return nil 126 | } 127 | out := new(NodeRegistryConfigsSpec) 128 | in.DeepCopyInto(out) 129 | return out 130 | } 131 | 132 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 133 | func (in *NodeRegistryConfigsStatus) DeepCopyInto(out *NodeRegistryConfigsStatus) { 134 | *out = *in 135 | if in.Conditions != nil { 136 | in, out := &in.Conditions, &out.Conditions 137 | *out = make([]v1.Condition, len(*in)) 138 | for i := range *in { 139 | (*in)[i].DeepCopyInto(&(*out)[i]) 140 | } 141 | } 142 | } 143 | 144 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistryConfigsStatus. 145 | func (in *NodeRegistryConfigsStatus) DeepCopy() *NodeRegistryConfigsStatus { 146 | if in == nil { 147 | return nil 148 | } 149 | out := new(NodeRegistryConfigsStatus) 150 | in.DeepCopyInto(out) 151 | return out 152 | } 153 | 154 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 155 | func (in *NodeRegistryHostConfig) DeepCopyInto(out *NodeRegistryHostConfig) { 156 | *out = *in 157 | if in.Capabilities != nil { 158 | in, out := &in.Capabilities, &out.Capabilities 159 | *out = make([]CapabilitieType, len(*in)) 160 | copy(*out, *in) 161 | } 162 | if in.SkipVerify != nil { 163 | in, out := &in.SkipVerify, &out.SkipVerify 164 | *out = new(bool) 165 | **out = **in 166 | } 167 | if in.Header != nil { 168 | in, out := &in.Header, &out.Header 169 | *out = make(map[string]string, len(*in)) 170 | for key, val := range *in { 171 | (*out)[key] = val 172 | } 173 | } 174 | } 175 | 176 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRegistryHostConfig. 177 | func (in *NodeRegistryHostConfig) DeepCopy() *NodeRegistryHostConfig { 178 | if in == nil { 179 | return nil 180 | } 181 | out := new(NodeRegistryHostConfig) 182 | in.DeepCopyInto(out) 183 | return out 184 | } 185 | 186 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 187 | func (in *RegistryConfigs) DeepCopyInto(out *RegistryConfigs) { 188 | *out = *in 189 | out.TypeMeta = in.TypeMeta 190 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 191 | in.Spec.DeepCopyInto(&out.Spec) 192 | in.Status.DeepCopyInto(&out.Status) 193 | } 194 | 195 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfigs. 196 | func (in *RegistryConfigs) DeepCopy() *RegistryConfigs { 197 | if in == nil { 198 | return nil 199 | } 200 | out := new(RegistryConfigs) 201 | in.DeepCopyInto(out) 202 | return out 203 | } 204 | 205 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 206 | func (in *RegistryConfigs) DeepCopyObject() runtime.Object { 207 | if c := in.DeepCopy(); c != nil { 208 | return c 209 | } 210 | return nil 211 | } 212 | 213 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 214 | func (in *RegistryConfigsList) DeepCopyInto(out *RegistryConfigsList) { 215 | *out = *in 216 | out.TypeMeta = in.TypeMeta 217 | in.ListMeta.DeepCopyInto(&out.ListMeta) 218 | if in.Items != nil { 219 | in, out := &in.Items, &out.Items 220 | *out = make([]RegistryConfigs, len(*in)) 221 | for i := range *in { 222 | (*in)[i].DeepCopyInto(&(*out)[i]) 223 | } 224 | } 225 | } 226 | 227 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfigsList. 228 | func (in *RegistryConfigsList) DeepCopy() *RegistryConfigsList { 229 | if in == nil { 230 | return nil 231 | } 232 | out := new(RegistryConfigsList) 233 | in.DeepCopyInto(out) 234 | return out 235 | } 236 | 237 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 238 | func (in *RegistryConfigsList) DeepCopyObject() runtime.Object { 239 | if c := in.DeepCopy(); c != nil { 240 | return c 241 | } 242 | return nil 243 | } 244 | 245 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 246 | func (in *RegistryConfigsSpec) DeepCopyInto(out *RegistryConfigsSpec) { 247 | *out = *in 248 | in.Selector.DeepCopyInto(&out.Selector) 249 | in.Template.DeepCopyInto(&out.Template) 250 | } 251 | 252 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfigsSpec. 253 | func (in *RegistryConfigsSpec) DeepCopy() *RegistryConfigsSpec { 254 | if in == nil { 255 | return nil 256 | } 257 | out := new(RegistryConfigsSpec) 258 | in.DeepCopyInto(out) 259 | return out 260 | } 261 | 262 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 263 | func (in *RegistryConfigsStatus) DeepCopyInto(out *RegistryConfigsStatus) { 264 | *out = *in 265 | if in.TotalNodes != nil { 266 | in, out := &in.TotalNodes, &out.TotalNodes 267 | *out = make([]RuntimeNum, len(*in)) 268 | copy(*out, *in) 269 | } 270 | if in.SuccessNodes != nil { 271 | in, out := &in.SuccessNodes, &out.SuccessNodes 272 | *out = make([]RuntimeNum, len(*in)) 273 | copy(*out, *in) 274 | } 275 | if in.FailedNodes != nil { 276 | in, out := &in.FailedNodes, &out.FailedNodes 277 | *out = make([]RuntimeNum, len(*in)) 278 | copy(*out, *in) 279 | } 280 | if in.RunningNodes != nil { 281 | in, out := &in.RunningNodes, &out.RunningNodes 282 | *out = make([]RuntimeNum, len(*in)) 283 | copy(*out, *in) 284 | } 285 | } 286 | 287 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfigsStatus. 288 | func (in *RegistryConfigsStatus) DeepCopy() *RegistryConfigsStatus { 289 | if in == nil { 290 | return nil 291 | } 292 | out := new(RegistryConfigsStatus) 293 | in.DeepCopyInto(out) 294 | return out 295 | } 296 | 297 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 298 | func (in *RegistryConfigsTemplate) DeepCopyInto(out *RegistryConfigsTemplate) { 299 | *out = *in 300 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 301 | in.Spec.DeepCopyInto(&out.Spec) 302 | } 303 | 304 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfigsTemplate. 305 | func (in *RegistryConfigsTemplate) DeepCopy() *RegistryConfigsTemplate { 306 | if in == nil { 307 | return nil 308 | } 309 | out := new(RegistryConfigsTemplate) 310 | in.DeepCopyInto(out) 311 | return out 312 | } 313 | 314 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 315 | func (in *RuntimeNum) DeepCopyInto(out *RuntimeNum) { 316 | *out = *in 317 | } 318 | 319 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeNum. 320 | func (in *RuntimeNum) DeepCopy() *RuntimeNum { 321 | if in == nil { 322 | return nil 323 | } 324 | out := new(RuntimeNum) 325 | in.DeepCopyInto(out) 326 | return out 327 | } 328 | -------------------------------------------------------------------------------- /builds/copilot/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM golang:1.19 as builder 3 | ARG TARGETOS 4 | ARG TARGETARCH 5 | 6 | WORKDIR /workspace 7 | COPY . . 8 | # cache deps before building and copying source so that we don't need to re-download as much 9 | # and so that source changes don't invalidate our downloaded layer 10 | RUN go mod tidy && go mod vendor 11 | 12 | # Copy the go source 13 | #COPY cmd/copilot/main.go cmd/main.go 14 | #COPY ../../api api/ 15 | #COPY ../../internal/controller internal/controller/ 16 | 17 | 18 | # Build 19 | # the GOARCH has not a default value to allow the binary be built according to the host where the command 20 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO 21 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, 22 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. 23 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o copilot cmd/copilot/main.go 24 | 25 | # Use distroless as minimal base image to package the manager binary 26 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 27 | FROM gcr.io/distroless/static:nonroot 28 | WORKDIR / 29 | COPY --from=builder /workspace/copilot . 30 | USER 65532:65532 31 | 32 | ENTRYPOINT ["/copilot"] 33 | -------------------------------------------------------------------------------- /builds/daemon/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM golang:1.19 as builder 3 | ARG TARGETOS 4 | ARG TARGETARCH 5 | 6 | WORKDIR /workspace 7 | # Copy the Go Modules manifests 8 | COPY . . 9 | # cache deps before building and copying source so that we don't need to re-download as much 10 | # and so that source changes don't invalidate our downloaded layer 11 | RUN go mod tidy && go mod vendor 12 | 13 | # Copy the go source 14 | #COPY cmd/daemon/main.go cmd/main.go 15 | #COPY ../../api api/ 16 | #COPY ../../internal/controller internal/controller/ 17 | 18 | 19 | # Build 20 | # the GOARCH has not a default value to allow the binary be built according to the host where the command 21 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO 22 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, 23 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. 24 | RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o daemon cmd/daemon/main.go 25 | 26 | # Use distroless as minimal base image to package the manager binary 27 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 28 | FROM gcr.io/distroless/static:nonroot 29 | WORKDIR / 30 | COPY --from=builder /workspace/daemon . 31 | USER 65532:65532 32 | 33 | ENTRYPOINT ["/daemon"] 34 | -------------------------------------------------------------------------------- /charts/runtime-copilot/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/runtime-copilot/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: runtime-copilot 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "0.0.1" 25 | -------------------------------------------------------------------------------- /charts/runtime-copilot/README.md: -------------------------------------------------------------------------------- 1 | # Runtime Copilot Helm Charts 2 | The main function of the runtime copilot is to assist the operation of the container runtime component (containerd), specifically for adding or deleting non-safe registries. 3 | 4 | ## Usage 5 | 6 | [Helm](https://helm.sh) must be installed to use the charts. Please refer to 7 | Helm's [documentation](https://helm.sh/docs) to get started. 8 | 9 | Once Helm has been set up correctly, add the repo as follows: 10 | 11 | helm repo add runtime-copilot https://copilot-io.github.io/runtime-copilot 12 | 13 | If you is first time to use this repo, you need to run command as follows: 14 | 15 | helm repo update 16 | helm search repo runtime-copilot 17 | 18 | To install the runtime-copilot chart: 19 | 20 | helm install runtime-copilot runtime-copilot/charts --namespace runtime-copilot 21 | 22 | To uninstall the chart: 23 | 24 | helm delete runtime-copilot --namespace runtime-copilot -------------------------------------------------------------------------------- /charts/runtime-copilot/crds/registry.runtime.x-copilot.io_noderegistryconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.11.3 7 | creationTimestamp: null 8 | name: noderegistryconfigs.registry.runtime.x-copilot.io 9 | spec: 10 | group: registry.runtime.x-copilot.io 11 | names: 12 | kind: NodeRegistryConfigs 13 | listKind: NodeRegistryConfigsList 14 | plural: noderegistryconfigs 15 | singular: noderegistryconfigs 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | description: NodeRegistryConfigs is the Schema for the noderegistryconfigs 22 | API 23 | properties: 24 | apiVersion: 25 | description: 'APIVersion defines the versioned schema of this representation 26 | of an object. Servers should convert recognized schemas to the latest 27 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 28 | type: string 29 | kind: 30 | description: 'Kind is a string value representing the REST resource this 31 | object represents. Servers may infer this from the endpoint the client 32 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 33 | type: string 34 | metadata: 35 | type: object 36 | spec: 37 | description: NodeRegistryConfigsSpec defines the desired state of NodeRegistryConfigs 38 | properties: 39 | hostConfigs: 40 | description: HostConfigs store the per-host configuration 41 | items: 42 | properties: 43 | ca_secret_ref: 44 | type: string 45 | capabilities: 46 | items: 47 | description: CapabilitieType is the type of capability 48 | type: string 49 | type: array 50 | header: 51 | additionalProperties: 52 | type: string 53 | type: object 54 | override_path: 55 | type: boolean 56 | server: 57 | description: Server specifies the default server. When `host` 58 | is also specified, those hosts are tried first. 59 | type: string 60 | skip_verify: 61 | type: boolean 62 | required: 63 | - capabilities 64 | type: object 65 | type: array 66 | nodeName: 67 | description: NodeName is registry config exec node name 68 | type: string 69 | retry_num: 70 | description: set retry num 71 | type: integer 72 | type: 73 | description: Type is runtime type 74 | type: string 75 | required: 76 | - nodeName 77 | - type 78 | type: object 79 | status: 80 | description: NodeRegistryConfigsStatus defines the observed state of NodeRegistryConfigs 81 | properties: 82 | conditions: 83 | description: 'INSERT ADDITIONAL STATUS FIELD - define observed state 84 | of cluster Important: Run "make" to regenerate code after modifying 85 | this file' 86 | items: 87 | description: "Condition contains details for one aspect of the current 88 | state of this API Resource. --- This struct is intended for direct 89 | use as an array at the field path .status.conditions. For example, 90 | \n type FooStatus struct{ // Represents the observations of a 91 | foo's current state. // Known .status.conditions.type are: \"Available\", 92 | \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge 93 | // +listType=map // +listMapKey=type Conditions []metav1.Condition 94 | `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" 95 | protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" 96 | properties: 97 | lastTransitionTime: 98 | description: lastTransitionTime is the last time the condition 99 | transitioned from one status to another. This should be when 100 | the underlying condition changed. If that is not known, then 101 | using the time when the API field changed is acceptable. 102 | format: date-time 103 | type: string 104 | message: 105 | description: message is a human readable message indicating 106 | details about the transition. This may be an empty string. 107 | maxLength: 32768 108 | type: string 109 | observedGeneration: 110 | description: observedGeneration represents the .metadata.generation 111 | that the condition was set based upon. For instance, if .metadata.generation 112 | is currently 12, but the .status.conditions[x].observedGeneration 113 | is 9, the condition is out of date with respect to the current 114 | state of the instance. 115 | format: int64 116 | minimum: 0 117 | type: integer 118 | reason: 119 | description: reason contains a programmatic identifier indicating 120 | the reason for the condition's last transition. Producers 121 | of specific condition types may define expected values and 122 | meanings for this field, and whether the values are considered 123 | a guaranteed API. The value should be a CamelCase string. 124 | This field may not be empty. 125 | maxLength: 1024 126 | minLength: 1 127 | pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ 128 | type: string 129 | status: 130 | description: status of the condition, one of True, False, Unknown. 131 | enum: 132 | - "True" 133 | - "False" 134 | - Unknown 135 | type: string 136 | type: 137 | description: type of condition in CamelCase or in foo.example.com/CamelCase. 138 | --- Many .condition.type values are consistent across resources 139 | like Available, but because arbitrary conditions can be useful 140 | (see .node.status.conditions), the ability to deconflict is 141 | important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) 142 | maxLength: 316 143 | pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ 144 | type: string 145 | required: 146 | - lastTransitionTime 147 | - message 148 | - reason 149 | - status 150 | - type 151 | type: object 152 | type: array 153 | retry_num: 154 | type: integer 155 | state: 156 | description: StatusState is the state of status 157 | type: string 158 | type: object 159 | type: object 160 | served: true 161 | storage: true 162 | subresources: 163 | status: {} 164 | -------------------------------------------------------------------------------- /charts/runtime-copilot/crds/registry.runtime.x-copilot.io_registryconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.11.3 7 | creationTimestamp: null 8 | name: registryconfigs.registry.runtime.x-copilot.io 9 | spec: 10 | group: registry.runtime.x-copilot.io 11 | names: 12 | kind: RegistryConfigs 13 | listKind: RegistryConfigsList 14 | plural: registryconfigs 15 | singular: registryconfigs 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | description: RegistryConfigs is the Schema for the registryconfigs API 22 | properties: 23 | apiVersion: 24 | description: 'APIVersion defines the versioned schema of this representation 25 | of an object. Servers should convert recognized schemas to the latest 26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 27 | type: string 28 | kind: 29 | description: 'Kind is a string value representing the REST resource this 30 | object represents. Servers may infer this from the endpoint the client 31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 32 | type: string 33 | metadata: 34 | type: object 35 | spec: 36 | description: RegistryConfigsSpec defines the desired state of RegistryConfigs 37 | properties: 38 | selector: 39 | description: Selector is used to select nodes that will be configured 40 | properties: 41 | matchExpressions: 42 | description: matchExpressions is a list of label selector requirements. 43 | The requirements are ANDed. 44 | items: 45 | description: A label selector requirement is a selector that 46 | contains values, a key, and an operator that relates the key 47 | and values. 48 | properties: 49 | key: 50 | description: key is the label key that the selector applies 51 | to. 52 | type: string 53 | operator: 54 | description: operator represents a key's relationship to 55 | a set of values. Valid operators are In, NotIn, Exists 56 | and DoesNotExist. 57 | type: string 58 | values: 59 | description: values is an array of string values. If the 60 | operator is In or NotIn, the values array must be non-empty. 61 | If the operator is Exists or DoesNotExist, the values 62 | array must be empty. This array is replaced during a strategic 63 | merge patch. 64 | items: 65 | type: string 66 | type: array 67 | required: 68 | - key 69 | - operator 70 | type: object 71 | type: array 72 | matchLabels: 73 | additionalProperties: 74 | type: string 75 | description: matchLabels is a map of {key,value} pairs. A single 76 | {key,value} in the matchLabels map is equivalent to an element 77 | of matchExpressions, whose key field is "key", the operator 78 | is "In", and the values array contains only "value". The requirements 79 | are ANDed. 80 | type: object 81 | type: object 82 | x-kubernetes-map-type: atomic 83 | template: 84 | description: RegistryConfigsTemplate defines the template for the 85 | registry config 86 | properties: 87 | metadata: 88 | type: object 89 | spec: 90 | description: NodeHostConfigsSpec defines the host config for the 91 | registry 92 | properties: 93 | hostConfigs: 94 | items: 95 | properties: 96 | ca_secret_ref: 97 | type: string 98 | capabilities: 99 | items: 100 | description: CapabilitieType is the type of capability 101 | type: string 102 | type: array 103 | header: 104 | additionalProperties: 105 | type: string 106 | type: object 107 | override_path: 108 | type: boolean 109 | server: 110 | description: Server specifies the default server. When 111 | `host` is also specified, those hosts are tried first. 112 | type: string 113 | skip_verify: 114 | type: boolean 115 | required: 116 | - capabilities 117 | type: object 118 | type: array 119 | retry_num: 120 | type: integer 121 | required: 122 | - hostConfigs 123 | type: object 124 | required: 125 | - spec 126 | type: object 127 | type: object 128 | status: 129 | description: RegistryConfigsStatus defines the observed state of RegistryConfigs 130 | properties: 131 | failed_nodes: 132 | items: 133 | properties: 134 | num: 135 | type: integer 136 | runtimeType: 137 | description: RuntimeType is the type of runtime 138 | type: string 139 | type: object 140 | type: array 141 | running_nodes: 142 | items: 143 | properties: 144 | num: 145 | type: integer 146 | runtimeType: 147 | description: RuntimeType is the type of runtime 148 | type: string 149 | type: object 150 | type: array 151 | state: 152 | description: 'INSERT ADDITIONAL STATUS FIELD - define observed state 153 | of cluster Important: Run "make" to regenerate code after modifying 154 | this file INSERT ADDITIONAL STATUS FIELD - define observed state 155 | of cluster Important: Run "make" to regenerate code after modifying 156 | this file' 157 | type: string 158 | success_nodes: 159 | items: 160 | properties: 161 | num: 162 | type: integer 163 | runtimeType: 164 | description: RuntimeType is the type of runtime 165 | type: string 166 | type: object 167 | type: array 168 | total_nodes: 169 | items: 170 | properties: 171 | num: 172 | type: integer 173 | runtimeType: 174 | description: RuntimeType is the type of runtime 175 | type: string 176 | type: object 177 | type: array 178 | type: object 179 | type: object 180 | served: true 181 | storage: true 182 | subresources: 183 | status: {} 184 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "charts.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "charts.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "charts.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "charts.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "charts.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "charts.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "charts.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "charts.labels.daemon" -}} 37 | helm.sh/chart: {{ include "charts.chart" . }} 38 | {{ include "charts.selectorLabels.daemon" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{- define "charts.labels.controllermanagaer" -}} 46 | helm.sh/chart: {{ include "charts.chart" . }} 47 | {{ include "charts.selectorLabels.controllermanagaer" . }} 48 | {{- if .Chart.AppVersion }} 49 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 50 | {{- end }} 51 | app.kubernetes.io/managed-by: {{ .Release.Service }} 52 | {{- end }} 53 | 54 | {{/* 55 | Selector labels 56 | */}} 57 | {{- define "charts.selectorLabels.daemon" -}} 58 | app.kubernetes.io/name: {{ include "charts.name" . }} 59 | app.kubernetes.io/instance: {{ .Release.Name }}-daemon 60 | {{- end }} 61 | 62 | {{- define "charts.selectorLabels.controllermanagaer" -}} 63 | app.kubernetes.io/name: {{ include "charts.name" . }} 64 | app.kubernetes.io/instance: {{ .Release.Name }}-deployment 65 | {{- end }} 66 | 67 | {{/* 68 | Create the name of the service account to use 69 | */}} 70 | {{- define "charts.serviceAccountName" -}} 71 | {{- if .Values.serviceAccount.create }} 72 | {{- default (include "charts.fullname" .) .Values.serviceAccount.name }} 73 | {{- else }} 74 | {{- default "default" .Values.serviceAccount.name }} 75 | {{- end }} 76 | {{- end }} 77 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/daemon.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: {{ include "charts.fullname" . }}-daemon 5 | namespace: {{ .Release.Namespace | default "default"}} 6 | labels: 7 | {{- include "charts.labels.daemon" . | nindent 4 }} 8 | spec: 9 | selector: 10 | matchLabels: 11 | {{- include "charts.selectorLabels.daemon" . | nindent 6 }} 12 | template: 13 | metadata: 14 | labels: 15 | {{- include "charts.selectorLabels.daemon" . | nindent 8 }} 16 | spec: 17 | {{- with .Values.imagePullSecrets }} 18 | imagePullSecrets: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | serviceAccountName: {{ include "charts.serviceAccountName" . }} 22 | securityContext: 23 | {{- toYaml .Values.daemonPodSecurityContext | nindent 8 }} 24 | containers: 25 | - name: {{ .Chart.Name }}-daemon 26 | securityContext: 27 | {{- toYaml .Values.securityContext | nindent 12 }} 28 | image: "{{ .Values.image.registry }}/{{ .Values.image.daemon_repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 29 | imagePullPolicy: {{ .Values.image.pullPolicy }} 30 | command: 31 | - /daemon 32 | env: 33 | - name: NODE_NAME 34 | valueFrom: 35 | fieldRef: 36 | fieldPath: spec.nodeName 37 | ports: 38 | - name: http 39 | containerPort: 8081 40 | protocol: TCP 41 | livenessProbe: 42 | httpGet: 43 | path: /healthz 44 | port: http 45 | readinessProbe: 46 | httpGet: 47 | path: /readyz 48 | port: http 49 | resources: 50 | {{- toYaml .Values.resources | nindent 12 }} 51 | volumeMounts: 52 | - mountPath: /etc/containerd 53 | name: containerd-path 54 | volumes: 55 | - name: containerd-path 56 | hostPath: 57 | path: /etc/containerd 58 | type: DirectoryOrCreate 59 | terminationGracePeriodSeconds: 10 -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "charts.fullname" . }}-deploymment 5 | namespace: {{ .Release.Namespace | default "default"}} 6 | labels: 7 | {{- include "charts.labels.controllermanagaer" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.autoscaling.enabled }} 10 | replicas: {{ .Values.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "charts.selectorLabels.controllermanagaer" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "charts.selectorLabels.controllermanagaer" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "charts.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ .Chart.Name }}-controller-manager 33 | securityContext: 34 | {{- toYaml .Values.securityContext | nindent 12 }} 35 | image: "{{ .Values.image.registry }}/{{ .Values.image.controller_repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 36 | command: 37 | - /copilot 38 | - --leader-elect=true 39 | imagePullPolicy: {{ .Values.image.pullPolicy }} 40 | ports: 41 | - name: http 42 | containerPort: 8081 43 | protocol: TCP 44 | livenessProbe: 45 | httpGet: 46 | path: /healthz 47 | port: http 48 | readinessProbe: 49 | httpGet: 50 | path: /readyz 51 | port: http 52 | resources: 53 | {{- toYaml .Values.resources | nindent 12 }} 54 | {{- with .Values.nodeSelector }} 55 | nodeSelector: 56 | {{- toYaml . | nindent 8 }} 57 | {{- end }} 58 | {{- with .Values.affinity }} 59 | affinity: 60 | {{- toYaml . | nindent 8 }} 61 | {{- end }} 62 | {{- with .Values.tolerations }} 63 | tolerations: 64 | {{- toYaml . | nindent 8 }} 65 | {{- end }} 66 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: metrics-reader 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: metrics-reader 12 | rules: 13 | - nonResourceURLs: 14 | - "/metrics" 15 | verbs: 16 | - get 17 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: proxy-role 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-role 12 | rules: 13 | - apiGroups: 14 | - authentication.k8s.io 15 | resources: 16 | - tokenreviews 17 | verbs: 18 | - create 19 | - apiGroups: 20 | - authorization.k8s.io 21 | resources: 22 | - subjectaccessreviews 23 | verbs: 24 | - create 25 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: proxy-rolebinding 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: proxy-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: {{ include "charts.serviceAccountName" . }} 19 | namespace: {{ .Release.Namespace | default "default"}} 20 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: service 7 | app.kubernetes.io/instance: controller-manager-metrics-service 8 | app.kubernetes.io/component: kube-rbac-proxy 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: controller-manager-metrics-service 13 | namespace: {{ .Release.Namespace | default "default"}} 14 | spec: 15 | ports: 16 | - name: https 17 | port: 8443 18 | protocol: TCP 19 | targetPort: https 20 | selector: 21 | control-plane: controller-manager 22 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: role 7 | app.kubernetes.io/instance: leader-election-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: leader-election-role 13 | rules: 14 | - apiGroups: 15 | - "" 16 | resources: 17 | - configmaps 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - create 23 | - update 24 | - patch 25 | - delete 26 | - apiGroups: 27 | - coordination.k8s.io 28 | resources: 29 | - leases 30 | verbs: 31 | - get 32 | - list 33 | - watch 34 | - create 35 | - update 36 | - patch 37 | - delete 38 | - apiGroups: 39 | - "" 40 | resources: 41 | - events 42 | verbs: 43 | - create 44 | - patch 45 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: rolebinding 6 | app.kubernetes.io/instance: leader-election-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: leader-election-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: leader-election-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: {{ include "charts.serviceAccountName" . }} 19 | namespace: {{ .Release.Namespace | default "default"}} 20 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/noderegistryconfigs_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit noderegistryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: noderegistryconfigs-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: noderegistryconfigs-editor-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - noderegistryconfigs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - config.registry.runtime.copilot.io 28 | resources: 29 | - noderegistryconfigs/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/noderegistryconfigs_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view noderegistryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: noderegistryconfigs-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: noderegistryconfigs-viewer-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - noderegistryconfigs 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - config.registry.runtime.copilot.io 24 | resources: 25 | - noderegistryconfigs/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/registryconfigs_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit registryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: registryconfigs-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: registryconfigs-editor-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - registryconfigs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - config.registry.runtime.copilot.io 28 | resources: 29 | - registryconfigs/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/registryconfigs_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view registryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: registryconfigs-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: registryconfigs-viewer-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - registryconfigs 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - config.registry.runtime.copilot.io 24 | resources: 25 | - registryconfigs/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | creationTimestamp: null 6 | name: manager-role 7 | rules: 8 | - resources: 9 | - nodes 10 | apiGroups: 11 | - "" 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | - apiGroups: 17 | - config.registry.runtime.copilot.io 18 | resources: 19 | - noderegistryconfigs 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - config.registry.runtime.copilot.io 30 | resources: 31 | - noderegistryconfigs/finalizers 32 | verbs: 33 | - update 34 | - apiGroups: 35 | - config.registry.runtime.copilot.io 36 | resources: 37 | - noderegistryconfigs/status 38 | verbs: 39 | - get 40 | - patch 41 | - update 42 | - apiGroups: 43 | - config.registry.runtime.copilot.io 44 | resources: 45 | - registryconfigs 46 | verbs: 47 | - create 48 | - delete 49 | - get 50 | - list 51 | - patch 52 | - update 53 | - watch 54 | - apiGroups: 55 | - config.registry.runtime.copilot.io 56 | resources: 57 | - registryconfigs/finalizers 58 | verbs: 59 | - update 60 | - apiGroups: 61 | - config.registry.runtime.copilot.io 62 | resources: 63 | - registryconfigs/status 64 | verbs: 65 | - get 66 | - patch 67 | - update 68 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: {{ include "charts.serviceAccountName" . }} 12 | namespace: {{ .Release.Namespace | default "default"}} 13 | -------------------------------------------------------------------------------- /charts/runtime-copilot/templates/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "charts.serviceAccountName" . }} 5 | namespace: {{ .Release.Namespace | default "default"}} 6 | -------------------------------------------------------------------------------- /charts/runtime-copilot/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for charts. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 2 6 | 7 | image: 8 | registry: ghcr.io 9 | controller_repository: copilot-io/runtime-copilot/controller-manager 10 | daemon_repository: copilot-io/runtime-copilot/daemon 11 | pullPolicy: IfNotPresent 12 | # Overrides the image tag whose default is the chart appVersion. 13 | tag: latest 14 | 15 | imagePullSecrets: [] 16 | nameOverride: "" 17 | fullnameOverride: "" 18 | 19 | serviceAccount: 20 | # Specifies whether a service account should be created 21 | create: true 22 | # Annotations to add to the service account 23 | annotations: {} 24 | # The name of the service account to use. 25 | # If not set and create is true, a name is generated using the fullname template 26 | name: "" 27 | 28 | podAnnotations: {} 29 | 30 | podSecurityContext: 31 | runAsNonRoot: true 32 | 33 | daemonPodSecurityContext: 34 | runAsUser: 0 35 | runAsGroup: 0 36 | privileged: true 37 | 38 | securityContext: 39 | capabilities: 40 | drop: 41 | - ALL 42 | # readOnlyRootFilesystem: true 43 | # runAsNonRoot: true 44 | # runAsUser: 1000 45 | 46 | service: 47 | type: ClusterIP 48 | port: 80 49 | 50 | ingress: 51 | enabled: false 52 | className: "" 53 | annotations: {} 54 | # kubernetes.io/ingress.class: nginx 55 | # kubernetes.io/tls-acme: "true" 56 | hosts: 57 | - host: chart-example.local 58 | paths: 59 | - path: / 60 | pathType: ImplementationSpecific 61 | tls: [] 62 | # - secretName: chart-example-tls 63 | # hosts: 64 | # - chart-example.local 65 | 66 | resources: 67 | # We usually recommend not to specify default resources and to leave this as a conscious 68 | # choice for the user. This also increases chances charts run on environments with little 69 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 70 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 71 | limits: 72 | cpu: 500m 73 | memory: 128Mi 74 | requests: 75 | cpu: 100m 76 | memory: 128Mi 77 | 78 | autoscaling: 79 | enabled: false 80 | minReplicas: 1 81 | maxReplicas: 100 82 | targetCPUUtilizationPercentage: 80 83 | # targetMemoryUtilizationPercentage: 80 84 | 85 | nodeSelector: {} 86 | 87 | tolerations: [] 88 | 89 | affinity: {} 90 | -------------------------------------------------------------------------------- /cmd/copilot/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 main 18 | 19 | import ( 20 | "flag" 21 | "os" 22 | 23 | // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) 24 | // to ensure that exec-entrypoint and run can make use of them. 25 | _ "k8s.io/client-go/plugin/pkg/client/auth" 26 | 27 | "k8s.io/apimachinery/pkg/runtime" 28 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 29 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 30 | ctrl "sigs.k8s.io/controller-runtime" 31 | "sigs.k8s.io/controller-runtime/pkg/healthz" 32 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 33 | 34 | configregistryv1alpha1 "github.com/copilot-io/runtime-copilot/api/v1alpha1" 35 | "github.com/copilot-io/runtime-copilot/internal/controller" 36 | //+kubebuilder:scaffold:imports 37 | ) 38 | 39 | var ( 40 | scheme = runtime.NewScheme() 41 | setupLog = ctrl.Log.WithName("setup") 42 | ) 43 | 44 | func init() { 45 | utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 46 | 47 | utilruntime.Must(configregistryv1alpha1.AddToScheme(scheme)) 48 | //+kubebuilder:scaffold:scheme 49 | } 50 | 51 | func main() { 52 | var metricsAddr string 53 | var enableLeaderElection bool 54 | var probeAddr string 55 | flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") 56 | flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") 57 | flag.BoolVar(&enableLeaderElection, "leader-elect", false, 58 | "Enable leader election for controller manager. "+ 59 | "Enabling this will ensure there is only one active controller manager.") 60 | opts := zap.Options{ 61 | Development: true, 62 | } 63 | opts.BindFlags(flag.CommandLine) 64 | flag.Parse() 65 | 66 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) 67 | 68 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 69 | Scheme: scheme, 70 | MetricsBindAddress: metricsAddr, 71 | Port: 9443, 72 | HealthProbeBindAddress: probeAddr, 73 | LeaderElection: enableLeaderElection, 74 | LeaderElectionID: "f7a02d95.runtime.copilot.io", 75 | // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily 76 | // when the Manager ends. This requires the binary to immediately end when the 77 | // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly 78 | // speeds up voluntary leader transitions as the new leader don't have to wait 79 | // LeaseDuration time first. 80 | // 81 | // In the default scaffold provided, the program ends immediately after 82 | // the manager stops, so would be fine to enable this option. However, 83 | // if you are doing or is intended to do any operation such as perform cleanups 84 | // after the manager stops then its usage might be unsafe. 85 | // LeaderElectionReleaseOnCancel: true, 86 | }) 87 | if err != nil { 88 | setupLog.Error(err, "unable to start manager") 89 | os.Exit(1) 90 | } 91 | 92 | if err = (&controller.RegistryConfigsReconciler{ 93 | Client: mgr.GetClient(), 94 | Scheme: mgr.GetScheme(), 95 | }).SetupWithManager(mgr); err != nil { 96 | setupLog.Error(err, "unable to create controller", "controller", "RegistryConfigs") 97 | os.Exit(1) 98 | } 99 | //+kubebuilder:scaffold:builder 100 | 101 | if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { 102 | setupLog.Error(err, "unable to set up health check") 103 | os.Exit(1) 104 | } 105 | if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { 106 | setupLog.Error(err, "unable to set up ready check") 107 | os.Exit(1) 108 | } 109 | 110 | setupLog.Info("starting manager") 111 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 112 | setupLog.Error(err, "problem running manager") 113 | os.Exit(1) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /cmd/daemon/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 main 18 | 19 | import ( 20 | "flag" 21 | "os" 22 | 23 | // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) 24 | // to ensure that exec-entrypoint and run can make use of them. 25 | _ "k8s.io/client-go/plugin/pkg/client/auth" 26 | 27 | "k8s.io/apimachinery/pkg/runtime" 28 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 29 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 30 | ctrl "sigs.k8s.io/controller-runtime" 31 | "sigs.k8s.io/controller-runtime/pkg/healthz" 32 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 33 | 34 | configregistryv1alpha1 "github.com/copilot-io/runtime-copilot/api/v1alpha1" 35 | "github.com/copilot-io/runtime-copilot/internal/controller" 36 | //+kubebuilder:scaffold:imports 37 | ) 38 | 39 | var ( 40 | scheme = runtime.NewScheme() 41 | setupLog = ctrl.Log.WithName("setup") 42 | ) 43 | 44 | func init() { 45 | utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 46 | 47 | utilruntime.Must(configregistryv1alpha1.AddToScheme(scheme)) 48 | //+kubebuilder:scaffold:scheme 49 | } 50 | 51 | func main() { 52 | var probeAddr string 53 | flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") 54 | opts := zap.Options{ 55 | Development: true, 56 | } 57 | opts.BindFlags(flag.CommandLine) 58 | flag.Parse() 59 | 60 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) 61 | 62 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 63 | Scheme: scheme, 64 | HealthProbeBindAddress: probeAddr, 65 | // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily 66 | // when the Manager ends. This requires the binary to immediately end when the 67 | // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly 68 | // speeds up voluntary leader transitions as the new leader don't have to wait 69 | // LeaseDuration time first. 70 | // 71 | // In the default scaffold provided, the program ends immediately after 72 | // the manager stops, so would be fine to enable this option. However, 73 | // if you are doing or is intended to do any operation such as perform cleanups 74 | // after the manager stops then its usage might be unsafe. 75 | // LeaderElectionReleaseOnCancel: true, 76 | }) 77 | if err != nil { 78 | setupLog.Error(err, "unable to start manager") 79 | os.Exit(1) 80 | } 81 | 82 | if err = (&controller.NodeRegistryConfigsReconciler{ 83 | Client: mgr.GetClient(), 84 | Scheme: mgr.GetScheme(), 85 | // TODO(lrf) current write a not change value 86 | HostRootDir: "/etc/containerd/certs.d", 87 | }).SetupWithManager(mgr); err != nil { 88 | setupLog.Error(err, "unable to create controller", "controller", "NodeRegistryConfigs") 89 | os.Exit(1) 90 | } 91 | //+kubebuilder:scaffold:builder 92 | 93 | if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { 94 | setupLog.Error(err, "unable to set up health check") 95 | os.Exit(1) 96 | } 97 | if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { 98 | setupLog.Error(err, "unable to set up ready check") 99 | os.Exit(1) 100 | } 101 | 102 | setupLog.Info("starting manager") 103 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 104 | setupLog.Error(err, "problem running manager") 105 | os.Exit(1) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /config/crd/bases/registry.runtime.x-copilot.io_noderegistryconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.11.3 7 | creationTimestamp: null 8 | name: noderegistryconfigs.registry.runtime.x-copilot.io 9 | spec: 10 | group: registry.runtime.x-copilot.io 11 | names: 12 | kind: NodeRegistryConfigs 13 | listKind: NodeRegistryConfigsList 14 | plural: noderegistryconfigs 15 | singular: noderegistryconfigs 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | description: NodeRegistryConfigs is the Schema for the noderegistryconfigs 22 | API 23 | properties: 24 | apiVersion: 25 | description: 'APIVersion defines the versioned schema of this representation 26 | of an object. Servers should convert recognized schemas to the latest 27 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 28 | type: string 29 | kind: 30 | description: 'Kind is a string value representing the REST resource this 31 | object represents. Servers may infer this from the endpoint the client 32 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 33 | type: string 34 | metadata: 35 | type: object 36 | spec: 37 | description: NodeRegistryConfigsSpec defines the desired state of NodeRegistryConfigs 38 | properties: 39 | hostConfigs: 40 | description: HostConfigs store the per-host configuration 41 | items: 42 | properties: 43 | ca_secret_ref: 44 | type: string 45 | capabilities: 46 | items: 47 | description: CapabilitieType is the type of capability 48 | type: string 49 | type: array 50 | header: 51 | additionalProperties: 52 | type: string 53 | type: object 54 | override_path: 55 | type: boolean 56 | server: 57 | description: Server specifies the default server. When `host` 58 | is also specified, those hosts are tried first. 59 | type: string 60 | skip_verify: 61 | type: boolean 62 | required: 63 | - capabilities 64 | type: object 65 | type: array 66 | nodeName: 67 | description: NodeName is registry config exec node name 68 | type: string 69 | retry_num: 70 | description: set retry num 71 | type: integer 72 | type: 73 | description: Type is runtime type 74 | type: string 75 | required: 76 | - nodeName 77 | - type 78 | type: object 79 | status: 80 | description: NodeRegistryConfigsStatus defines the observed state of NodeRegistryConfigs 81 | properties: 82 | conditions: 83 | description: 'INSERT ADDITIONAL STATUS FIELD - define observed state 84 | of cluster Important: Run "make" to regenerate code after modifying 85 | this file' 86 | items: 87 | description: "Condition contains details for one aspect of the current 88 | state of this API Resource. --- This struct is intended for direct 89 | use as an array at the field path .status.conditions. For example, 90 | \n type FooStatus struct{ // Represents the observations of a 91 | foo's current state. // Known .status.conditions.type are: \"Available\", 92 | \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge 93 | // +listType=map // +listMapKey=type Conditions []metav1.Condition 94 | `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" 95 | protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" 96 | properties: 97 | lastTransitionTime: 98 | description: lastTransitionTime is the last time the condition 99 | transitioned from one status to another. This should be when 100 | the underlying condition changed. If that is not known, then 101 | using the time when the API field changed is acceptable. 102 | format: date-time 103 | type: string 104 | message: 105 | description: message is a human readable message indicating 106 | details about the transition. This may be an empty string. 107 | maxLength: 32768 108 | type: string 109 | observedGeneration: 110 | description: observedGeneration represents the .metadata.generation 111 | that the condition was set based upon. For instance, if .metadata.generation 112 | is currently 12, but the .status.conditions[x].observedGeneration 113 | is 9, the condition is out of date with respect to the current 114 | state of the instance. 115 | format: int64 116 | minimum: 0 117 | type: integer 118 | reason: 119 | description: reason contains a programmatic identifier indicating 120 | the reason for the condition's last transition. Producers 121 | of specific condition types may define expected values and 122 | meanings for this field, and whether the values are considered 123 | a guaranteed API. The value should be a CamelCase string. 124 | This field may not be empty. 125 | maxLength: 1024 126 | minLength: 1 127 | pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ 128 | type: string 129 | status: 130 | description: status of the condition, one of True, False, Unknown. 131 | enum: 132 | - "True" 133 | - "False" 134 | - Unknown 135 | type: string 136 | type: 137 | description: type of condition in CamelCase or in foo.example.com/CamelCase. 138 | --- Many .condition.type values are consistent across resources 139 | like Available, but because arbitrary conditions can be useful 140 | (see .node.status.conditions), the ability to deconflict is 141 | important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) 142 | maxLength: 316 143 | pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ 144 | type: string 145 | required: 146 | - lastTransitionTime 147 | - message 148 | - reason 149 | - status 150 | - type 151 | type: object 152 | type: array 153 | retry_num: 154 | type: integer 155 | state: 156 | description: StatusState is the state of status 157 | type: string 158 | type: object 159 | type: object 160 | served: true 161 | storage: true 162 | subresources: 163 | status: {} 164 | -------------------------------------------------------------------------------- /config/crd/bases/registry.runtime.x-copilot.io_registryconfigs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.11.3 7 | creationTimestamp: null 8 | name: registryconfigs.registry.runtime.x-copilot.io 9 | spec: 10 | group: registry.runtime.x-copilot.io 11 | names: 12 | kind: RegistryConfigs 13 | listKind: RegistryConfigsList 14 | plural: registryconfigs 15 | singular: registryconfigs 16 | scope: Cluster 17 | versions: 18 | - name: v1alpha1 19 | schema: 20 | openAPIV3Schema: 21 | description: RegistryConfigs is the Schema for the registryconfigs API 22 | properties: 23 | apiVersion: 24 | description: 'APIVersion defines the versioned schema of this representation 25 | of an object. Servers should convert recognized schemas to the latest 26 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 27 | type: string 28 | kind: 29 | description: 'Kind is a string value representing the REST resource this 30 | object represents. Servers may infer this from the endpoint the client 31 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 32 | type: string 33 | metadata: 34 | type: object 35 | spec: 36 | description: RegistryConfigsSpec defines the desired state of RegistryConfigs 37 | properties: 38 | selector: 39 | description: Selector is used to select nodes that will be configured 40 | properties: 41 | matchExpressions: 42 | description: matchExpressions is a list of label selector requirements. 43 | The requirements are ANDed. 44 | items: 45 | description: A label selector requirement is a selector that 46 | contains values, a key, and an operator that relates the key 47 | and values. 48 | properties: 49 | key: 50 | description: key is the label key that the selector applies 51 | to. 52 | type: string 53 | operator: 54 | description: operator represents a key's relationship to 55 | a set of values. Valid operators are In, NotIn, Exists 56 | and DoesNotExist. 57 | type: string 58 | values: 59 | description: values is an array of string values. If the 60 | operator is In or NotIn, the values array must be non-empty. 61 | If the operator is Exists or DoesNotExist, the values 62 | array must be empty. This array is replaced during a strategic 63 | merge patch. 64 | items: 65 | type: string 66 | type: array 67 | required: 68 | - key 69 | - operator 70 | type: object 71 | type: array 72 | matchLabels: 73 | additionalProperties: 74 | type: string 75 | description: matchLabels is a map of {key,value} pairs. A single 76 | {key,value} in the matchLabels map is equivalent to an element 77 | of matchExpressions, whose key field is "key", the operator 78 | is "In", and the values array contains only "value". The requirements 79 | are ANDed. 80 | type: object 81 | type: object 82 | x-kubernetes-map-type: atomic 83 | template: 84 | description: RegistryConfigsTemplate defines the template for the 85 | registry config 86 | properties: 87 | metadata: 88 | type: object 89 | spec: 90 | description: NodeHostConfigsSpec defines the host config for the 91 | registry 92 | properties: 93 | hostConfigs: 94 | items: 95 | properties: 96 | ca_secret_ref: 97 | type: string 98 | capabilities: 99 | items: 100 | description: CapabilitieType is the type of capability 101 | type: string 102 | type: array 103 | header: 104 | additionalProperties: 105 | type: string 106 | type: object 107 | override_path: 108 | type: boolean 109 | server: 110 | description: Server specifies the default server. When 111 | `host` is also specified, those hosts are tried first. 112 | type: string 113 | skip_verify: 114 | type: boolean 115 | required: 116 | - capabilities 117 | type: object 118 | type: array 119 | retry_num: 120 | type: integer 121 | required: 122 | - hostConfigs 123 | type: object 124 | required: 125 | - spec 126 | type: object 127 | type: object 128 | status: 129 | description: RegistryConfigsStatus defines the observed state of RegistryConfigs 130 | properties: 131 | failed_nodes: 132 | items: 133 | properties: 134 | num: 135 | type: integer 136 | runtimeType: 137 | description: RuntimeType is the type of runtime 138 | type: string 139 | type: object 140 | type: array 141 | running_nodes: 142 | items: 143 | properties: 144 | num: 145 | type: integer 146 | runtimeType: 147 | description: RuntimeType is the type of runtime 148 | type: string 149 | type: object 150 | type: array 151 | state: 152 | description: 'INSERT ADDITIONAL STATUS FIELD - define observed state 153 | of cluster Important: Run "make" to regenerate code after modifying 154 | this file INSERT ADDITIONAL STATUS FIELD - define observed state 155 | of cluster Important: Run "make" to regenerate code after modifying 156 | this file' 157 | type: string 158 | success_nodes: 159 | items: 160 | properties: 161 | num: 162 | type: integer 163 | runtimeType: 164 | description: RuntimeType is the type of runtime 165 | type: string 166 | type: object 167 | type: array 168 | total_nodes: 169 | items: 170 | properties: 171 | num: 172 | type: integer 173 | runtimeType: 174 | description: RuntimeType is the type of runtime 175 | type: string 176 | type: object 177 | type: array 178 | type: object 179 | type: object 180 | served: true 181 | storage: true 182 | subresources: 183 | status: {} 184 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/config.registry.runtime.copilot.io_registryconfigs.yaml 6 | - bases/config.registry.runtime.copilot.io_noderegistryconfigs.yaml 7 | #+kubebuilder:scaffold:crdkustomizeresource 8 | 9 | patchesStrategicMerge: 10 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 11 | # patches here are for enabling the conversion webhook for each CRD 12 | #- patches/webhook_in_registryconfigs.yaml 13 | #- patches/webhook_in_noderegistryconfigs.yaml 14 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 15 | 16 | # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. 17 | # patches here are for enabling the CA injection for each CRD 18 | #- patches/cainjection_in_registryconfigs.yaml 19 | #- patches/cainjection_in_noderegistryconfigs.yaml 20 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 21 | 22 | # the following config is for teaching kustomize how to do kustomization for CRDs. 23 | configurations: 24 | - kustomizeconfig.yaml 25 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_noderegistryconfigs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 7 | name: noderegistryconfigs.config.registry.runtime.copilot.io 8 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_registryconfigs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 7 | name: registryconfigs.config.registry.runtime.copilot.io 8 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_noderegistryconfigs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: noderegistryconfigs.config.registry.runtime.copilot.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_registryconfigs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: registryconfigs.config.registry.runtime.copilot.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: runtime-copilot-system 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: runtime-copilot- 10 | 11 | # Labels to add to all resources and selectors. 12 | #labels: 13 | #- includeSelectors: true 14 | # pairs: 15 | # someName: someValue 16 | 17 | resources: 18 | - ../crd 19 | - ../rbac 20 | - ../manager 21 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 22 | # crd/kustomization.yaml 23 | #- ../webhook 24 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. 25 | #- ../certmanager 26 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 27 | #- ../prometheus 28 | 29 | patchesStrategicMerge: 30 | # Protect the /metrics endpoint by putting it behind auth. 31 | # If you want your controller-manager to expose the /metrics 32 | # endpoint w/o any authn/z, please comment the following line. 33 | - manager_auth_proxy_patch.yaml 34 | 35 | 36 | 37 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 38 | # crd/kustomization.yaml 39 | #- manager_webhook_patch.yaml 40 | 41 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 42 | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. 43 | # 'CERTMANAGER' needs to be enabled to use ca injection 44 | #- webhookcainjection_patch.yaml 45 | 46 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. 47 | # Uncomment the following replacements to add the cert-manager CA injection annotations 48 | #replacements: 49 | # - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs 50 | # kind: Certificate 51 | # group: cert-manager.io 52 | # version: v1 53 | # name: serving-cert # this name should match the one in certificate.yaml 54 | # fieldPath: .metadata.namespace # namespace of the certificate CR 55 | # targets: 56 | # - select: 57 | # kind: ValidatingWebhookConfiguration 58 | # fieldPaths: 59 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 60 | # options: 61 | # delimiter: '/' 62 | # index: 0 63 | # create: true 64 | # - select: 65 | # kind: MutatingWebhookConfiguration 66 | # fieldPaths: 67 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 68 | # options: 69 | # delimiter: '/' 70 | # index: 0 71 | # create: true 72 | # - select: 73 | # kind: CustomResourceDefinition 74 | # fieldPaths: 75 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 76 | # options: 77 | # delimiter: '/' 78 | # index: 0 79 | # create: true 80 | # - source: 81 | # kind: Certificate 82 | # group: cert-manager.io 83 | # version: v1 84 | # name: serving-cert # this name should match the one in certificate.yaml 85 | # fieldPath: .metadata.name 86 | # targets: 87 | # - select: 88 | # kind: ValidatingWebhookConfiguration 89 | # fieldPaths: 90 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 91 | # options: 92 | # delimiter: '/' 93 | # index: 1 94 | # create: true 95 | # - select: 96 | # kind: MutatingWebhookConfiguration 97 | # fieldPaths: 98 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 99 | # options: 100 | # delimiter: '/' 101 | # index: 1 102 | # create: true 103 | # - select: 104 | # kind: CustomResourceDefinition 105 | # fieldPaths: 106 | # - .metadata.annotations.[cert-manager.io/inject-ca-from] 107 | # options: 108 | # delimiter: '/' 109 | # index: 1 110 | # create: true 111 | # - source: # Add cert-manager annotation to the webhook Service 112 | # kind: Service 113 | # version: v1 114 | # name: webhook-service 115 | # fieldPath: .metadata.name # namespace of the service 116 | # targets: 117 | # - select: 118 | # kind: Certificate 119 | # group: cert-manager.io 120 | # version: v1 121 | # fieldPaths: 122 | # - .spec.dnsNames.0 123 | # - .spec.dnsNames.1 124 | # options: 125 | # delimiter: '.' 126 | # index: 0 127 | # create: true 128 | # - source: 129 | # kind: Service 130 | # version: v1 131 | # name: webhook-service 132 | # fieldPath: .metadata.namespace # namespace of the service 133 | # targets: 134 | # - select: 135 | # kind: Certificate 136 | # group: cert-manager.io 137 | # version: v1 138 | # fieldPaths: 139 | # - .spec.dnsNames.0 140 | # - .spec.dnsNames.1 141 | # options: 142 | # delimiter: '.' 143 | # index: 1 144 | # create: true 145 | -------------------------------------------------------------------------------- /config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the 2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | affinity: 12 | nodeAffinity: 13 | requiredDuringSchedulingIgnoredDuringExecution: 14 | nodeSelectorTerms: 15 | - matchExpressions: 16 | - key: kubernetes.io/arch 17 | operator: In 18 | values: 19 | - amd64 20 | - arm64 21 | - ppc64le 22 | - s390x 23 | - key: kubernetes.io/os 24 | operator: In 25 | values: 26 | - linux 27 | containers: 28 | - name: kube-rbac-proxy 29 | securityContext: 30 | allowPrivilegeEscalation: false 31 | capabilities: 32 | drop: 33 | - "ALL" 34 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 35 | args: 36 | - "--secure-listen-address=0.0.0.0:8443" 37 | - "--upstream=http://127.0.0.1:8080/" 38 | - "--logtostderr=true" 39 | - "--v=0" 40 | ports: 41 | - containerPort: 8443 42 | protocol: TCP 43 | name: https 44 | resources: 45 | limits: 46 | cpu: 500m 47 | memory: 128Mi 48 | requests: 49 | cpu: 5m 50 | memory: 64Mi 51 | - name: manager 52 | args: 53 | - "--health-probe-bind-address=:8081" 54 | - "--metrics-bind-address=127.0.0.1:8080" 55 | - "--leader-elect" 56 | -------------------------------------------------------------------------------- /config/default/manager_config_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | -------------------------------------------------------------------------------- /config/manager/daemon.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: runtime-daemon 5 | namespace: runtime-copilot 6 | spec: 7 | selector: 8 | matchLabels: 9 | app.kubernetes.io/name: runtime-daemon 10 | app.kubernetes.io/instance: runtime-daemon 11 | app.kubernetes.io/component: manager 12 | app.kubernetes.io/created-by: runtime-copilot 13 | app.kubernetes.io/part-of: runtime-copilot 14 | app.kubernetes.io/managed-by: kustomize 15 | template: 16 | metadata: 17 | labels: 18 | app.kubernetes.io/name: runtime-daemon 19 | app.kubernetes.io/instance: runtime-daemon 20 | app.kubernetes.io/component: manager 21 | app.kubernetes.io/created-by: runtime-copilot 22 | app.kubernetes.io/part-of: runtime-copilot 23 | app.kubernetes.io/managed-by: kustomize 24 | spec: 25 | containers: 26 | - name: runtime-daemon 27 | image: ghcr.io/copilot-io/runtime-copilot/daemon:latest 28 | imagePullPolicy: IfNotPresent 29 | command: 30 | - /daemon 31 | env: 32 | - name: NODE_NAME 33 | valueFrom: 34 | fieldRef: 35 | fieldPath: spec.nodeName 36 | securityContext: 37 | allowPrivilegeEscalation: false 38 | capabilities: 39 | drop: 40 | - "ALL" 41 | readinessProbe: 42 | httpGet: 43 | path: /readyz 44 | port: 8081 45 | initialDelaySeconds: 5 46 | periodSeconds: 5 47 | timeoutSeconds: 5 48 | livenessProbe: 49 | httpGet: 50 | path: /healthz 51 | port: 8081 52 | initialDelaySeconds: 15 53 | periodSeconds: 20 54 | timeoutSeconds: 5 55 | resources: 56 | limits: 57 | cpu: 500m 58 | memory: 128Mi 59 | requests: 60 | cpu: 10m 61 | memory: 64Mi 62 | volumeMounts: 63 | - mountPath: /etc/containerd 64 | name: containerd-path 65 | volumes: 66 | - name: containerd-path 67 | hostPath: 68 | path: /etc/containerd 69 | type: DirectoryOrCreate 70 | serviceAccountName: controller-manager 71 | terminationGracePeriodSeconds: 10 -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | - daemon.yaml 4 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: namespace 7 | app.kubernetes.io/instance: system 8 | app.kubernetes.io/component: manager 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: runtime-copilot 13 | --- 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: controller-manager 18 | namespace: runtime-copilot 19 | labels: 20 | control-plane: controller-manager 21 | app.kubernetes.io/name: deployment 22 | app.kubernetes.io/instance: controller-manager 23 | app.kubernetes.io/component: manager 24 | app.kubernetes.io/created-by: runtime-copilot 25 | app.kubernetes.io/part-of: runtime-copilot 26 | app.kubernetes.io/managed-by: kustomize 27 | spec: 28 | selector: 29 | matchLabels: 30 | control-plane: controller-manager 31 | replicas: 1 32 | template: 33 | metadata: 34 | annotations: 35 | kubectl.kubernetes.io/default-container: manager 36 | labels: 37 | control-plane: controller-manager 38 | spec: 39 | securityContext: 40 | runAsNonRoot: true 41 | # TODO(user): For common cases that do not require escalating privileges 42 | # it is recommended to ensure that all your Pods/Containers are restrictive. 43 | # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted 44 | # Please uncomment the following code if your project does NOT have to work on old Kubernetes 45 | # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). 46 | # seccompProfile: 47 | # type: RuntimeDefault 48 | containers: 49 | - command: 50 | - /copilot 51 | args: 52 | - --leader-elect 53 | image: ghcr.io/copilot-io/runtime-copilot/controller-manager:latest 54 | name: manager 55 | securityContext: 56 | allowPrivilegeEscalation: false 57 | capabilities: 58 | drop: 59 | - "ALL" 60 | livenessProbe: 61 | httpGet: 62 | path: /healthz 63 | port: 8081 64 | initialDelaySeconds: 15 65 | periodSeconds: 20 66 | readinessProbe: 67 | httpGet: 68 | path: /readyz 69 | port: 8081 70 | initialDelaySeconds: 5 71 | periodSeconds: 10 72 | # TODO(user): Configure the resources accordingly based on the project requirements. 73 | # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ 74 | resources: 75 | limits: 76 | cpu: 500m 77 | memory: 128Mi 78 | requests: 79 | cpu: 10m 80 | memory: 64Mi 81 | serviceAccountName: controller-manager 82 | terminationGracePeriodSeconds: 10 83 | -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Prometheus Monitor Service (Metrics) 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | control-plane: controller-manager 8 | app.kubernetes.io/name: servicemonitor 9 | app.kubernetes.io/instance: controller-manager-metrics-monitor 10 | app.kubernetes.io/component: metrics 11 | app.kubernetes.io/created-by: runtime-copilot 12 | app.kubernetes.io/part-of: runtime-copilot 13 | app.kubernetes.io/managed-by: kustomize 14 | name: controller-manager-metrics-monitor 15 | namespace: system 16 | spec: 17 | endpoints: 18 | - path: /metrics 19 | port: https 20 | scheme: https 21 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 22 | tlsConfig: 23 | insecureSkipVerify: true 24 | selector: 25 | matchLabels: 26 | control-plane: controller-manager 27 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: metrics-reader 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: metrics-reader 12 | rules: 13 | - nonResourceURLs: 14 | - "/metrics" 15 | verbs: 16 | - get 17 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrole 6 | app.kubernetes.io/instance: proxy-role 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-role 12 | rules: 13 | - apiGroups: 14 | - authentication.k8s.io 15 | resources: 16 | - tokenreviews 17 | verbs: 18 | - create 19 | - apiGroups: 20 | - authorization.k8s.io 21 | resources: 22 | - subjectaccessreviews 23 | verbs: 24 | - create 25 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: proxy-rolebinding 7 | app.kubernetes.io/component: kube-rbac-proxy 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: proxy-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: proxy-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: service 7 | app.kubernetes.io/instance: controller-manager-metrics-service 8 | app.kubernetes.io/component: kube-rbac-proxy 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: controller-manager-metrics-service 13 | namespace: system 14 | spec: 15 | ports: 16 | - name: https 17 | port: 8443 18 | protocol: TCP 19 | targetPort: https 20 | selector: 21 | control-plane: controller-manager 22 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # Comment the following 4 lines if you want to disable 13 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 14 | # which protects your /metrics endpoint. 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: role 7 | app.kubernetes.io/instance: leader-election-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: leader-election-role 13 | rules: 14 | - apiGroups: 15 | - "" 16 | resources: 17 | - configmaps 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - create 23 | - update 24 | - patch 25 | - delete 26 | - apiGroups: 27 | - coordination.k8s.io 28 | resources: 29 | - leases 30 | verbs: 31 | - get 32 | - list 33 | - watch 34 | - create 35 | - update 36 | - patch 37 | - delete 38 | - apiGroups: 39 | - "" 40 | resources: 41 | - events 42 | verbs: 43 | - create 44 | - patch 45 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: rolebinding 6 | app.kubernetes.io/instance: leader-election-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: leader-election-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: leader-election-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/noderegistryconfigs_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit noderegistryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: noderegistryconfigs-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: noderegistryconfigs-editor-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - noderegistryconfigs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - config.registry.runtime.copilot.io 28 | resources: 29 | - noderegistryconfigs/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/noderegistryconfigs_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view noderegistryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: noderegistryconfigs-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: noderegistryconfigs-viewer-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - noderegistryconfigs 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - config.registry.runtime.copilot.io 24 | resources: 25 | - noderegistryconfigs/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/registryconfigs_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit registryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: registryconfigs-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: registryconfigs-editor-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - registryconfigs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - config.registry.runtime.copilot.io 28 | resources: 29 | - registryconfigs/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/registryconfigs_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view registryconfigs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: registryconfigs-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: runtime-copilot 10 | app.kubernetes.io/part-of: runtime-copilot 11 | app.kubernetes.io/managed-by: kustomize 12 | name: registryconfigs-viewer-role 13 | rules: 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - registryconfigs 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - config.registry.runtime.copilot.io 24 | resources: 25 | - registryconfigs/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | creationTimestamp: null 6 | name: manager-role 7 | rules: 8 | - resources: 9 | - nodes 10 | verbs: 11 | - get 12 | - list 13 | - watch 14 | - apiGroups: 15 | - config.registry.runtime.copilot.io 16 | resources: 17 | - noderegistryconfigs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - config.registry.runtime.copilot.io 28 | resources: 29 | - noderegistryconfigs/finalizers 30 | verbs: 31 | - update 32 | - apiGroups: 33 | - config.registry.runtime.copilot.io 34 | resources: 35 | - noderegistryconfigs/status 36 | verbs: 37 | - get 38 | - patch 39 | - update 40 | - apiGroups: 41 | - config.registry.runtime.copilot.io 42 | resources: 43 | - registryconfigs 44 | verbs: 45 | - create 46 | - delete 47 | - get 48 | - list 49 | - patch 50 | - update 51 | - watch 52 | - apiGroups: 53 | - config.registry.runtime.copilot.io 54 | resources: 55 | - registryconfigs/finalizers 56 | verbs: 57 | - update 58 | - apiGroups: 59 | - config.registry.runtime.copilot.io 60 | resources: 61 | - registryconfigs/status 62 | verbs: 63 | - get 64 | - patch 65 | - update 66 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: manager-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: manager-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: manager-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: serviceaccount 6 | app.kubernetes.io/instance: controller-manager-sa 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: runtime-copilot 9 | app.kubernetes.io/part-of: runtime-copilot 10 | app.kubernetes.io/managed-by: kustomize 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/samples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Append samples of your project ## 2 | resources: 3 | - config.registry_v1alpha1_registryconfigs.yaml 4 | - config.registry_v1alpha1_noderegistryconfigs.yaml 5 | #+kubebuilder:scaffold:manifestskustomizesamples 6 | -------------------------------------------------------------------------------- /config/samples/registry.runtime_v1alpha1_registryconfigs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: registry.runtime.x-copilot.io/v1alpha1 2 | kind: RegistryConfigs 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: registryconfigs 6 | app.kubernetes.io/instance: registryconfigs-sample 7 | app.kubernetes.io/part-of: runtime-copilot 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: runtime-copilot 10 | name: registryconfigs-sample 11 | spec: 12 | selector: 13 | matchLabels: 14 | app: registryconfigs-sample 15 | template: 16 | spec: 17 | hostConfigs: 18 | - server: "https://10.6.112.191" 19 | capabilities: 20 | - pull 21 | - push 22 | - resolve 23 | skip_verify: true -------------------------------------------------------------------------------- /config/samples/registry.runtimme_v1alpha1_noderegistryconfigs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: registry.runtime.x-copilot.io/v1alpha1 2 | kind: NodeRegistryConfigs 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: noderegistryconfigs 6 | app.kubernetes.io/instance: noderegistryconfigs-sample 7 | app.kubernetes.io/part-of: runtime-copilot 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: runtime-copilot 10 | name: noderegistryconfigs-sample 11 | spec: 12 | # TODO(user): Add fields here 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/copilot-io/runtime-copilot 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/BurntSushi/toml v0.3.1 7 | k8s.io/api v0.27.1 8 | k8s.io/apimachinery v0.27.1 9 | k8s.io/client-go v0.27.1 10 | k8s.io/code-generator v0.27.1 11 | k8s.io/klog/v2 v2.90.1 12 | sigs.k8s.io/controller-runtime v0.15.0-alpha.0.0.20230511153903-92646a561578 13 | sigs.k8s.io/controller-tools v0.12.0 14 | ) 15 | 16 | require ( 17 | github.com/beorn7/perks v1.0.1 // indirect 18 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/emicklei/go-restful/v3 v3.9.0 // indirect 21 | github.com/evanphx/json-patch/v5 v5.6.0 // indirect 22 | github.com/fatih/color v1.15.0 // indirect 23 | github.com/fsnotify/fsnotify v1.6.0 // indirect 24 | github.com/go-logr/logr v1.2.4 // indirect 25 | github.com/go-logr/zapr v1.2.4 // indirect 26 | github.com/go-openapi/jsonpointer v0.19.6 // indirect 27 | github.com/go-openapi/jsonreference v0.20.1 // indirect 28 | github.com/go-openapi/swag v0.22.3 // indirect 29 | github.com/gobuffalo/flect v1.0.2 // indirect 30 | github.com/gogo/protobuf v1.3.2 // indirect 31 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 32 | github.com/golang/protobuf v1.5.3 // indirect 33 | github.com/google/gnostic v0.5.7-v3refs // indirect 34 | github.com/google/go-cmp v0.5.9 // indirect 35 | github.com/google/gofuzz v1.1.0 // indirect 36 | github.com/google/uuid v1.3.0 // indirect 37 | github.com/imdario/mergo v0.3.6 // indirect 38 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 39 | github.com/josharian/intern v1.0.0 // indirect 40 | github.com/json-iterator/go v1.1.12 // indirect 41 | github.com/mailru/easyjson v0.7.7 // indirect 42 | github.com/mattn/go-colorable v0.1.13 // indirect 43 | github.com/mattn/go-isatty v0.0.17 // indirect 44 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 45 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 46 | github.com/modern-go/reflect2 v1.0.2 // indirect 47 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 48 | github.com/pkg/errors v0.9.1 // indirect 49 | github.com/prometheus/client_golang v1.15.1 // indirect 50 | github.com/prometheus/client_model v0.4.0 // indirect 51 | github.com/prometheus/common v0.42.0 // indirect 52 | github.com/prometheus/procfs v0.9.0 // indirect 53 | github.com/spf13/cobra v1.7.0 // indirect 54 | github.com/spf13/pflag v1.0.5 // indirect 55 | go.uber.org/atomic v1.7.0 // indirect 56 | go.uber.org/multierr v1.6.0 // indirect 57 | go.uber.org/zap v1.24.0 // indirect 58 | golang.org/x/mod v0.10.0 // indirect 59 | golang.org/x/net v0.9.0 // indirect 60 | golang.org/x/oauth2 v0.5.0 // indirect 61 | golang.org/x/sys v0.8.0 // indirect 62 | golang.org/x/term v0.7.0 // indirect 63 | golang.org/x/text v0.9.0 // indirect 64 | golang.org/x/time v0.3.0 // indirect 65 | golang.org/x/tools v0.8.0 // indirect 66 | gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect 67 | google.golang.org/appengine v1.6.7 // indirect 68 | google.golang.org/protobuf v1.30.0 // indirect 69 | gopkg.in/inf.v0 v0.9.1 // indirect 70 | gopkg.in/yaml.v2 v2.4.0 // indirect 71 | gopkg.in/yaml.v3 v3.0.1 // indirect 72 | k8s.io/apiextensions-apiserver v0.27.1 // indirect 73 | k8s.io/component-base v0.27.1 // indirect 74 | k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect 75 | k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect 76 | k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect 77 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 78 | sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect 79 | sigs.k8s.io/yaml v1.3.0 // indirect 80 | ) 81 | -------------------------------------------------------------------------------- /hack/.import-aliases: -------------------------------------------------------------------------------- 1 | { 2 | "k8s.io/api/admissionregistration/v1": "admissionregistrationv1", 3 | "k8s.io/api/admissionregistration/v1beta1": "admissionregistrationv1beta1", 4 | "k8s.io/api/admission/v1beta1": "admissionv1beta1", 5 | "k8s.io/api/admission/v1": "admissionv1", 6 | "k8s.io/api/apps/v1": "appsv1", 7 | "k8s.io/api/apps/v1beta1": "appsv1beta1", 8 | "k8s.io/api/apps/v1beta2": "appsv1beta2", 9 | "k8s.io/api/authentication/v1": "authenticationv1", 10 | "k8s.io/api/authentication/v1beta1": "authenticationv1beta1", 11 | "k8s.io/api/authorization/v1": "authorizationv1", 12 | "k8s.io/api/authorization/v1beta1": "authorizationv1beta1", 13 | "k8s.io/api/autoscaling/v1": "autoscalingv1", 14 | "k8s.io/api/batch/v1": "batchv1", 15 | "k8s.io/api/batch/v1beta1": "batchv1beta1", 16 | "k8s.io/api/certificates/v1beta1": "certificatesv1beta1", 17 | "k8s.io/api/coordination/v1": "coordinationv1", 18 | "k8s.io/api/coordination/v1beta1": "coordinationv1beta1", 19 | "k8s.io/api/core/v1": "v1", 20 | "k8s.io/api/discovery/v1alpha1": "discoveryv1alpha1", 21 | "k8s.io/api/discovery/v1beta1": "discoveryv1beta1", 22 | "k8s.io/api/events/v1": "eventsv1", 23 | "k8s.io/api/events/v1beta1": "eventsv1beta1", 24 | "k8s.io/api/extensions/v1beta1": "extensionsv1beta1", 25 | "k8s.io/api/imagepolicy/v1alpha1": "imagepolicyv1alpha1", 26 | "k8s.io/api/networking/v1": "networkingv1", 27 | "k8s.io/api/networking/v1beta1": "networkingv1beta1", 28 | "k8s.io/api/node/v1alpha1": "nodev1alpha1", 29 | "k8s.io/api/node/v1beta1": "nodev1beta1", 30 | "k8s.io/api/node/v1": "nodev1", 31 | "k8s.io/api/policy/v1": "policyv1", 32 | "k8s.io/api/policy/v1beta1": "policyv1beta1", 33 | "k8s.io/api/rbac/v1": "rbacv1", 34 | "k8s.io/api/rbac/v1alpha1": "rbacv1alpha1", 35 | "k8s.io/api/rbac/v1beta1": "rbacv1beta1", 36 | "k8s.io/api/scheduling/v1": "schedulingv1", 37 | "k8s.io/api/scheduling/v1alpha1": "schedulingv1alpha1", 38 | "k8s.io/api/scheduling/v1beta1": "schedulingv1beta1", 39 | "k8s.io/api/storage/v1": "storagev1", 40 | "k8s.io/api/storage/v1alpha1": "storagev1alpha1", 41 | "k8s.io/api/storage/v1beta1": "storagev1beta1", 42 | "k8s.io/apimachinery/pkg/api/errors": "apierrors", 43 | "k8s.io/component-helpers/node/util": "nodeutil", 44 | "k8s.io/kubernetes/pkg/controller/util/node": "controllerutil", 45 | "k8s.io/kubelet/apis/stats/v1alpha1": "kubeletstatsv1alpha1", 46 | "k8s.io/kubernetes/pkg/controller/apis/config/v1alpha1": "controllerconfigv1alpha1", 47 | "k8s.io/kubernetes/pkg/kubelet/apis/config/v1beta1": "kubeletconfigv1beta1", 48 | "k8s.io/kubelet/pkg/apis/deviceplugin/v1alpha": "kubeletdevicepluginv1alpha", 49 | "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1": "kubeletdevicepluginv1beta1", 50 | "k8s.io/kubelet/pkg/apis/pluginregistration/v1": "kubeletpluginregistrationv1", 51 | "k8s.io/kubelet/pkg/apis/pluginregistration/v1alpha1": "kubeletpluginregistrationv1alpha1", 52 | "k8s.io/kubelet/pkg/apis/pluginregistration/v1beta1": "kubeletpluginregistrationv1beta1", 53 | "k8s.io/kubelet/pkg/apis/podresources/v1alpha1": "kubeletpodresourcesv1alpha1", 54 | "k8s.io/kubernetes/pkg/kubelet/apis/resourcemetrics/v1alpha1": "kubeletresourcemetricsv1alpha1", 55 | "k8s.io/kubernetes/pkg/proxy/apis/config/v1alpha1": "proxyconfigv1alpha1", 56 | "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta1": "schedulerconfigv1beta1", 57 | "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2": "schedulerconfigv1beta2", 58 | "k8s.io/kubernetes/test/e2e/framework/auth": "e2eauth", 59 | "k8s.io/kubernetes/test/e2e/framework/autoscaling": "e2eautoscaling", 60 | "k8s.io/kubernetes/test/e2e/framework/config": "e2econfig", 61 | "k8s.io/kubernetes/test/e2e/framework/deployment": "e2edeployment", 62 | "k8s.io/kubernetes/test/e2e/framework/endpoints": "e2eendpoints", 63 | "k8s.io/kubernetes/test/e2e/framework/events": "e2eevents", 64 | "k8s.io/kubernetes/test/e2e/framework/ginkgowrapper": "e2eginkgowrapper", 65 | "k8s.io/kubernetes/test/e2e/framework/gpu": "e2egpu", 66 | "k8s.io/kubernetes/test/e2e/framework/ingress": "e2eingress", 67 | "k8s.io/kubernetes/test/e2e/framework/job": "e2ejob", 68 | "k8s.io/kubernetes/test/e2e/framework/kubectl": "e2ekubectl", 69 | "k8s.io/kubernetes/test/e2e/framework/kubelet": "e2ekubelet", 70 | "k8s.io/kubernetes/test/e2e/framework/log": "e2elog", 71 | "k8s.io/kubernetes/test/e2e/framework/metrics": "e2emetrics", 72 | "k8s.io/kubernetes/test/e2e/framework/network": "e2enetwork", 73 | "k8s.io/kubernetes/test/e2e/framework/node": "e2enode", 74 | "k8s.io/kubernetes/test/e2e/framework/perf": "e2eperf", 75 | "k8s.io/kubernetes/test/e2e/framework/pod": "e2epod", 76 | "k8s.io/kubernetes/test/e2e/framework/pv": "e2epv", 77 | "k8s.io/kubernetes/test/e2e/framework/rc": "e2erc", 78 | "k8s.io/kubernetes/test/e2e/framework/replicaset": "e2ereplicaset", 79 | "k8s.io/kubernetes/test/e2e/framework/resource": "e2eresource", 80 | "k8s.io/kubernetes/test/e2e/framework/security": "e2esecurity", 81 | "k8s.io/kubernetes/test/e2e/framework/service": "e2eservice", 82 | "k8s.io/kubernetes/test/e2e/framework/skipper": "e2eskipper", 83 | "k8s.io/kubernetes/test/e2e/framework/ssh": "e2essh", 84 | "k8s.io/kubernetes/test/e2e/framework/statefulset": "e2estatefulset", 85 | "k8s.io/kubernetes/test/e2e/framework/testfiles": "e2etestfiles", 86 | "k8s.io/kubernetes/test/e2e/framework/timer": "e2etimer", 87 | "k8s.io/kubernetes/test/e2e/framework/volume": "e2evolume" 88 | } 89 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 | */ -------------------------------------------------------------------------------- /hack/helm-sync.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "start sync helm chart to runtime-copilot-helm-chart repo". 4 | 5 | git clone https://copilot-io:${GITHUB_TOKEN}@github.com/copilot-io/runtime-copilot-helm-charts.git 6 | 7 | cd runtime-copilot-helm-charts 8 | 9 | cp -rf ../charts ./ 10 | 11 | if git diff --quiet HEAD 12 | then 13 | echo "Git项目没有发生变化" 14 | exit 0 15 | fi 16 | 17 | git add . 18 | git commit -m "add helm chart" 19 | git push https://copilot-io:${GITHUB_TOKEN}@github.com/copilot-io/runtime-copilot-helm-charts.git main -------------------------------------------------------------------------------- /hack/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package hack 5 | 6 | import ( 7 | _ "k8s.io/code-generator" 8 | _ "sigs.k8s.io/controller-tools/cmd/controller-gen" 9 | ) 10 | -------------------------------------------------------------------------------- /hack/tools/preferredimports/preferredimports.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 | // This code is directly lifted from the Kubernetes codebase in order to avoid relying on the k8s.io/kubernetes package. 18 | // For reference: https://github.com/kubernetes/kubernetes/blob/release-1.22/cmd/preferredimports/preferredimports.go 19 | 20 | // verify that all the imports have our preferred alias(es). 21 | package main 22 | 23 | import ( 24 | "bytes" 25 | "encoding/json" 26 | "flag" 27 | "fmt" 28 | "go/ast" 29 | "go/build" 30 | "go/format" 31 | "go/parser" 32 | "go/token" 33 | "log" 34 | "os" 35 | "path/filepath" 36 | "regexp" 37 | "sort" 38 | "strings" 39 | 40 | "golang.org/x/term" 41 | ) 42 | 43 | var ( 44 | importAliases = flag.String("import-aliases", "hack/.import-aliases", "json file with import aliases") 45 | confirm = flag.Bool("confirm", false, "update file with the preferred aliases for imports") 46 | inRegex = flag.String("include-path", "(test/e2e/|test/e2e_node)", "only files with paths matching this inRegex is touched") 47 | exRegex = flag.String("exclude-path", "(test/e2e/|test/e2e_node)", "only files with paths matching this exRegex is touched") 48 | isTerminal = term.IsTerminal(int(os.Stdout.Fd())) 49 | logPrefix = "" 50 | aliases map[string]string 51 | ) 52 | 53 | type analyzer struct { 54 | fset *token.FileSet // positions are relative to fset 55 | ctx build.Context 56 | failed bool 57 | donePaths map[string]interface{} 58 | } 59 | 60 | func newAnalyzer() *analyzer { 61 | ctx := build.Default 62 | ctx.CgoEnabled = true 63 | 64 | a := &analyzer{ 65 | fset: token.NewFileSet(), 66 | ctx: ctx, 67 | donePaths: make(map[string]interface{}), 68 | } 69 | 70 | return a 71 | } 72 | 73 | // collect extracts test metadata from a file. 74 | func (a *analyzer) collect(dir string) { 75 | if _, ok := a.donePaths[dir]; ok { 76 | return 77 | } 78 | a.donePaths[dir] = nil 79 | 80 | // Create the AST by parsing src. 81 | fs, err := parser.ParseDir(a.fset, dir, nil, parser.AllErrors|parser.ParseComments) 82 | if err != nil { 83 | fmt.Fprintln(os.Stderr, "ERROR(syntax)", logPrefix, err) 84 | a.failed = true 85 | return 86 | } 87 | 88 | for _, p := range fs { 89 | // returns first error, but a.handleError deals with it 90 | files := a.filterFiles(p.Files) 91 | for _, file := range files { 92 | replacements := make(map[string]string) 93 | pathToFile := a.fset.File(file.Pos()).Name() 94 | if strings.Contains(pathToFile, "generated") { 95 | continue 96 | } 97 | for _, imp := range file.Imports { 98 | importPath := strings.Replace(imp.Path.Value, "\"", "", -1) 99 | pathSegments := strings.Split(importPath, "/") 100 | importName := pathSegments[len(pathSegments)-1] 101 | if imp.Name != nil { 102 | importName = imp.Name.Name 103 | } 104 | if alias, ok := aliases[importPath]; ok { 105 | if alias != importName { 106 | if !*confirm { 107 | fmt.Fprintf(os.Stderr, "%sERROR wrong alias for import \"%s\" should be %s in file %s\n", logPrefix, importPath, alias, pathToFile) 108 | a.failed = true 109 | } 110 | replacements[importName] = alias 111 | if imp.Name != nil { 112 | imp.Name.Name = alias 113 | } else { 114 | imp.Name = ast.NewIdent(alias) 115 | } 116 | } 117 | } 118 | } 119 | 120 | if len(replacements) > 0 { 121 | if *confirm { 122 | fmt.Printf("%sReplacing imports with aliases in file %s\n", logPrefix, pathToFile) 123 | for key, value := range replacements { 124 | renameImportUsages(file, key, value) 125 | } 126 | ast.SortImports(a.fset, file) 127 | var buffer bytes.Buffer 128 | if err = format.Node(&buffer, a.fset, file); err != nil { 129 | panic(fmt.Sprintf("Error formatting ast node after rewriting import.\n%s\n", err.Error())) 130 | } 131 | 132 | fileInfo, err := os.Stat(pathToFile) 133 | if err != nil { 134 | panic(fmt.Sprintf("Error stat'ing file: %s\n%s\n", pathToFile, err.Error())) 135 | } 136 | 137 | err = os.WriteFile(pathToFile, buffer.Bytes(), fileInfo.Mode()) 138 | if err != nil { 139 | panic(fmt.Sprintf("Error writing file: %s\n%s\n", pathToFile, err.Error())) 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | func renameImportUsages(f *ast.File, old, new string) { 148 | // use this to avoid renaming the package declaration, eg: 149 | // given: package foo; import foo "bar"; foo.Baz, rename foo->qux 150 | // yield: package foo; import qux "bar"; qux.Baz 151 | var pkg *ast.Ident 152 | 153 | // Rename top-level old to new, both unresolved names 154 | // (probably defined in another file) and names that resolve 155 | // to a declaration we renamed. 156 | ast.Inspect(f, func(node ast.Node) bool { 157 | if node == nil { 158 | return false 159 | } 160 | switch id := node.(type) { 161 | case *ast.File: 162 | pkg = id.Name 163 | case *ast.Ident: 164 | if pkg != nil && id == pkg { 165 | return false 166 | } 167 | if id.Name == old { 168 | id.Name = new 169 | } 170 | } 171 | return true 172 | }) 173 | } 174 | 175 | func (a *analyzer) filterFiles(fs map[string]*ast.File) []*ast.File { 176 | var files []*ast.File 177 | for _, f := range fs { 178 | files = append(files, f) 179 | } 180 | return files 181 | } 182 | 183 | type collector struct { 184 | dirs []string 185 | inRegex *regexp.Regexp 186 | exRegex *regexp.Regexp 187 | } 188 | 189 | // handlePath walks the filesystem recursively, collecting directories, 190 | // ignoring some unneeded directories (hidden/vendored) that are handled 191 | // specially later. 192 | func (c *collector) handlePath(path string, info os.FileInfo, err error) error { 193 | if err != nil { 194 | return err 195 | } 196 | if info.IsDir() { 197 | // Ignore hidden directories (.git, .cache, etc) 198 | if len(path) > 1 && path[0] == '.' || 199 | strings.Contains(path, "generated") || 200 | // Staging code is symlinked from vendor/k8s.io, and uses import 201 | // paths as if it were inside of vendor/. It fails typechecking 202 | // inside of staging/, but works when typechecked as part of vendor/. 203 | path == "staging" || 204 | // OS-specific vendor code tends to be imported by OS-specific 205 | // packages. We recursively typecheck imported vendored packages for 206 | // each OS, but don't typecheck everything for every OS. 207 | path == "vendor" || 208 | path == "_output" || 209 | // This is a weird one. /testdata/ is *mostly* ignored by Go, 210 | // and this translates to kubernetes/vendor not working. 211 | // edit/record.go doesn't compile without gopkg.in/yaml.v2 212 | // in $GOSRC/$GOROOT (both typecheck and the shell script). 213 | path == "pkg/kubectl/cmd/testdata/edit" { 214 | return filepath.SkipDir 215 | } 216 | if c.exRegex.MatchString(path) { 217 | return filepath.SkipDir 218 | } 219 | if c.inRegex.MatchString(path) { 220 | c.dirs = append(c.dirs, path) 221 | } 222 | } 223 | return nil 224 | } 225 | 226 | func main() { 227 | flag.Parse() 228 | args := flag.Args() 229 | 230 | if len(args) == 0 { 231 | args = append(args, ".") 232 | } 233 | 234 | inregex, err := regexp.Compile(*inRegex) 235 | if err != nil { 236 | log.Fatalf("Error compiling include regex: %v", err) 237 | } 238 | exregex, err := regexp.Compile(*exRegex) 239 | if err != nil { 240 | log.Fatalf("Error compiling exclude regex: %v", err) 241 | } 242 | c := collector{ 243 | inRegex: inregex, 244 | exRegex: exregex, 245 | } 246 | for _, arg := range args { 247 | err := filepath.Walk(arg, c.handlePath) 248 | if err != nil { 249 | log.Fatalf("Error walking: %v", err) 250 | } 251 | } 252 | sort.Strings(c.dirs) 253 | 254 | if len(*importAliases) > 0 { 255 | bytes, err := os.ReadFile(*importAliases) 256 | if err != nil { 257 | log.Fatalf("Error reading import aliases: %v", err) 258 | } 259 | err = json.Unmarshal(bytes, &aliases) 260 | if err != nil { 261 | log.Fatalf("Error loading aliases: %v", err) 262 | } 263 | } 264 | if isTerminal { 265 | logPrefix = "\r" // clear status bar when printing 266 | } 267 | fmt.Println("checking-imports: ") 268 | 269 | a := newAnalyzer() 270 | for _, dir := range c.dirs { 271 | if isTerminal { 272 | fmt.Printf("\r\033[0m %-80s", dir) 273 | } 274 | a.collect(dir) 275 | } 276 | fmt.Println() 277 | if a.failed { 278 | os.Exit(1) 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /hack/tools/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package tools 5 | 6 | import ( 7 | _ "github.com/golang/mock/mockgen" 8 | _ "github.com/onsi/ginkgo/v2" 9 | _ "golang.org/x/tools/cmd/goimports" 10 | _ "k8s.io/code-generator" 11 | ) 12 | -------------------------------------------------------------------------------- /hack/verify-crds.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 8 | 9 | DIFFROOT="${SCRIPT_ROOT}/config/crd" 10 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/crds" 11 | _tmp="${SCRIPT_ROOT}/_tmp" 12 | 13 | cleanup() { 14 | rm -rf "${_tmp}" 15 | } 16 | trap "cleanup" EXIT SIGINT 17 | 18 | cleanup 19 | 20 | mkdir -p "${TMP_DIFFROOT}" 21 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" 22 | 23 | make manifests 24 | echo "diffing ${DIFFROOT} against freshly generated CRDs" 25 | ret=0 26 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? 27 | cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" 28 | if [[ $ret -eq 0 ]]; then 29 | echo "${DIFFROOT} up to date." 30 | else 31 | echo "${DIFFROOT} is out of date. Please run 'make crds'" 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /hack/verify-import-aliases.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 8 | cd "${SCRIPT_ROOT}" 9 | ROOT_PATH=$(pwd) 10 | 11 | IMPORT_ALIASES_PATH="${ROOT_PATH}/hack/.import-aliases" 12 | INCLUDE_PATH="(${ROOT_PATH}/cmd|${ROOT_PATH}/test|${ROOT_PATH}/pkg)" 13 | EXCLUDE_PATH="(${ROOT_PATH}/pkg/.*/mocks)" 14 | 15 | 16 | ret=0 17 | # We can't directly install preferredimports by `go install` due to the go.mod issue: 18 | # go install k8s.io/kubernetes/cmd/preferredimports@v1.21.3: k8s.io/kubernetes@v1.21.3 19 | # The go.mod file for the module providing named packages contains one or 20 | # more replace directives. It must not contain directives that would cause 21 | # it to be interpreted differently than if it were the main module. 22 | go run "${ROOT_PATH}/hack/tools/preferredimports/preferredimports.go" -import-aliases "${IMPORT_ALIASES_PATH}" -include-path "${INCLUDE_PATH}" -exclude-path "${EXCLUDE_PATH}" "${ROOT_PATH}" || ret=$? 23 | if [[ $ret -ne 0 ]]; then 24 | echo "!!! Please see hack/.import-aliases for the preferred aliases for imports." >&2 25 | exit 1 26 | fi 27 | -------------------------------------------------------------------------------- /hack/verify-staticcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 8 | cd "${REPO_ROOT}" 9 | source "hack/util.sh" 10 | 11 | GOLANGCI_LINT_PKG="github.com/golangci/golangci-lint/cmd/golangci-lint" 12 | GOLANGCI_LINT_VER="v1.50.1" 13 | LINTER="golangci-lint" 14 | 15 | which ${LINTER} || util::install_tools ${GOLANGCI_LINT_PKG} ${GOLANGCI_LINT_VER} 16 | 17 | ${LINTER} --version 18 | 19 | if ${LINTER} run --timeout=10m; then 20 | echo 'Congratulations! All Go source files have passed staticcheck.' 21 | else 22 | echo # print one empty line, separate from warning messages. 23 | echo 'Please review the above warnings.' 24 | echo 'If the above warnings do not make sense, feel free to file an issue.' 25 | exit 1 26 | fi 27 | 28 | 29 | go install golang.org/x/tools/cmd/goimports@latest -------------------------------------------------------------------------------- /hack/verify-vendor.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 8 | 9 | DIFFROOT="${SCRIPT_ROOT}/vendor" 10 | # The vendor contains soft links, 11 | # which need to be in the same level as the vendor in order to avoid link failure 12 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp_vendor" 13 | _tmp="${SCRIPT_ROOT}/_tmp" 14 | 15 | cleanup() { 16 | rm -rf "${TMP_DIFFROOT}" 17 | rm -rf "${_tmp}" 18 | } 19 | trap "cleanup" EXIT SIGINT 20 | 21 | cleanup 22 | 23 | mkdir -p "${_tmp}" 24 | mkdir -p "${TMP_DIFFROOT}" 25 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" 26 | cp "${SCRIPT_ROOT}"/go.mod "$_tmp"/go.mod 27 | cp "${SCRIPT_ROOT}"/go.sum "$_tmp"/go.sum 28 | 29 | make -C "${SCRIPT_ROOT}" vendor 30 | echo "diffing ${DIFFROOT} against freshly generated files" 31 | 32 | govendor=0 33 | diff -Nqaupr "${DIFFROOT}" "${TMP_DIFFROOT}" || govendor=$? 34 | gomod=0 35 | diff -Naupr "${SCRIPT_ROOT}"/go.mod "${_tmp}"/go.mod || gomod=$? 36 | gosum=0 37 | diff -Naupr "${SCRIPT_ROOT}"/go.sum "${_tmp}"/go.sum || gosum=$? 38 | 39 | rm -rf "${DIFFROOT}" 40 | mv "${TMP_DIFFROOT}" "${DIFFROOT}" 41 | cp "${_tmp}"/go.mod "${SCRIPT_ROOT}"/go.mod 42 | cp "${_tmp}"/go.sum "${SCRIPT_ROOT}"/go.sum 43 | if [[ $govendor -eq 0 && $gomod -eq 0 && $gosum -eq 0 ]] 44 | then 45 | echo "${DIFFROOT} up to date." 46 | else 47 | echo "${DIFFROOT}, 'go.mod' or 'go.sum' is out of date. Please run 'make vendor'" 48 | exit 1 49 | fi 50 | -------------------------------------------------------------------------------- /internal/controller/noderegistryconfigs_controller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 controller 18 | 19 | import ( 20 | "bytes" 21 | "context" 22 | "encoding/json" 23 | "net/url" 24 | "os" 25 | "path/filepath" 26 | "reflect" 27 | 28 | configregistryv1alpha1 "github.com/copilot-io/runtime-copilot/api/v1alpha1" 29 | 30 | "github.com/BurntSushi/toml" 31 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 | "k8s.io/apimachinery/pkg/runtime" 33 | "k8s.io/klog/v2" 34 | ctrl "sigs.k8s.io/controller-runtime" 35 | "sigs.k8s.io/controller-runtime/pkg/client" 36 | "sigs.k8s.io/controller-runtime/pkg/log" 37 | ) 38 | 39 | // NodeRegistryConfigsReconciler reconciles a NodeRegistryConfigs object. 40 | type NodeRegistryConfigsReconciler struct { 41 | client.Client 42 | Scheme *runtime.Scheme 43 | // HostRootDir is the runtime config registry host root dir 44 | HostRootDir string 45 | } 46 | 47 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=noderegistryconfigs,verbs=get;list;watch;create;update;patch;delete 48 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=noderegistryconfigs/status,verbs=get;update;patch 49 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=noderegistryconfigs/finalizers,verbs=update 50 | // +kubebuilder:printcolumn:name="NAME",type=string,JSONPath=`.metadata.namme` 51 | // +kubebuilder:printcolumn:name="STATE",type=string,JSONPath=`.status.state` 52 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 53 | 54 | // Reconcile is part of the main kubernetes reconciliation loop which aims to 55 | // move the current state of the cluster closer to the desired state. 56 | // TODO(user): Modify the Reconcile function to compare the state specified by 57 | // the NodeRegistryConfigs object against the actual cluster state, and then 58 | // perform operations to make the cluster state reflect the state specified by 59 | // the user. 60 | // 61 | // For more details, check Reconcile and its Result here: 62 | // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile 63 | func (r *NodeRegistryConfigsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 64 | _ = log.FromContext(ctx) 65 | nodeName := os.Getenv("NODE_NAME") 66 | if nodeName == "" { 67 | return ctrl.Result{}, nil 68 | } 69 | klog.Infof("reconcile node registry config for node %s", req.String()) 70 | // step1. get the NodeRegistryConfigs object 71 | var nodeRegistryConfigs configregistryv1alpha1.NodeRegistryConfigs 72 | if err := r.Get(ctx, req.NamespacedName, &nodeRegistryConfigs); err != nil { 73 | return ctrl.Result{}, client.IgnoreNotFound(err) 74 | } 75 | if nodeRegistryConfigs.Spec.NodeName != nodeName { 76 | return ctrl.Result{}, nil 77 | } 78 | if nodeRegistryConfigs.Status.RetryNum == nodeRegistryConfigs.Spec.RetryNum { 79 | klog.Warning("node registry config retry num is: %d, please check the config,", nodeRegistryConfigs.Spec.RetryNum) 80 | return ctrl.Result{}, nil 81 | } 82 | // step2. compare last nodeRegistryConfigs and current nodeRegistryConfigs, find the delete server 83 | if v, ok := nodeRegistryConfigs.ObjectMeta.Annotations["config.registry.runtime.copilot.io/last-applied-configuration"]; ok { 84 | var old configregistryv1alpha1.NodeRegistryConfigs 85 | if err := json.Unmarshal([]byte(v), &old); err != nil { 86 | return ctrl.Result{}, err 87 | } 88 | deleteNodeRegistryHostConfigs := r.diffDifferent(old, nodeRegistryConfigs) 89 | // step4. delete this node registry config for this server 90 | if err := r.deleteRegistryByHost(deleteNodeRegistryHostConfigs); err != nil { 91 | nodeRegistryConfigs.Status.State = configregistryv1alpha1.StatusStateFailed 92 | nodeRegistryConfigs.Status.RetryNum++ 93 | if err := r.Status().Update(ctx, &nodeRegistryConfigs); err != nil { 94 | return ctrl.Result{}, err 95 | } 96 | return ctrl.Result{}, err 97 | } 98 | } 99 | // step3. get current node for this server registry config, compare need update server 100 | if err := r.createOrUpdateRegistry(&nodeRegistryConfigs); err != nil { 101 | nodeRegistryConfigs.Status.State = configregistryv1alpha1.StatusStateFailed 102 | nodeRegistryConfigs.Status.RetryNum++ 103 | if err := r.Status().Update(ctx, &nodeRegistryConfigs); err != nil { 104 | return ctrl.Result{}, err 105 | } 106 | return ctrl.Result{}, err 107 | } 108 | // step5. create or update this node registry config for this server 109 | nodeRegistryConfigs.Status.State = configregistryv1alpha1.StatusStateSuccess 110 | if err := r.Status().Update(ctx, &nodeRegistryConfigs); err != nil { 111 | nodeRegistryConfigs.Status.State = configregistryv1alpha1.StatusStateFailed 112 | nodeRegistryConfigs.Status.RetryNum++ 113 | if err := r.Status().Update(ctx, &nodeRegistryConfigs); err != nil { 114 | return ctrl.Result{}, err 115 | } 116 | return ctrl.Result{}, err 117 | } 118 | return ctrl.Result{}, nil 119 | } 120 | 121 | func (r *NodeRegistryConfigsReconciler) diffDifferent(oldCR, newCR configregistryv1alpha1.NodeRegistryConfigs) []configregistryv1alpha1.NodeRegistryHostConfig { 122 | oldHostConfigs, newHostConfigs := oldCR.Spec.HostConfigs, newCR.Spec.HostConfigs 123 | oldHostConfigsMap, newHostConfigsMap := make(map[string]configregistryv1alpha1.NodeRegistryHostConfig), make(map[string]configregistryv1alpha1.NodeRegistryHostConfig) 124 | for i, v := range oldHostConfigs { 125 | oldHostConfigsMap[v.Server] = oldHostConfigs[i] 126 | } 127 | for i, v := range newHostConfigs { 128 | newHostConfigsMap[v.Server] = newHostConfigs[i] 129 | } 130 | for k := range newHostConfigsMap { 131 | delete(oldHostConfigsMap, k) 132 | } 133 | if len(oldHostConfigsMap) == 0 { 134 | return nil 135 | } 136 | 137 | deleteNodeRegistryHostConfigs := make([]configregistryv1alpha1.NodeRegistryHostConfig, 0) 138 | for k, v := range oldHostConfigsMap { 139 | deleteNodeRegistryHostConfigs = append(deleteNodeRegistryHostConfigs, v) 140 | klog.Infof("delete node registry config for server %s", k) 141 | } 142 | return deleteNodeRegistryHostConfigs 143 | } 144 | 145 | func (r *NodeRegistryConfigsReconciler) deleteRegistryByHost(deleteHosts []configregistryv1alpha1.NodeRegistryHostConfig) error { 146 | if len(deleteHosts) == 0 { 147 | return nil 148 | } 149 | for _, host := range deleteHosts { 150 | parse, _ := url.Parse(host.Server) 151 | dir := filepath.Join(r.HostRootDir, parse.Host) 152 | _, err := os.Stat(dir) 153 | if err != nil { 154 | if os.IsNotExist(err) { 155 | continue 156 | } 157 | klog.Errorf("%s stat error: %+v", dir, err) 158 | return err 159 | } 160 | os.RemoveAll(dir) 161 | } 162 | return nil 163 | } 164 | 165 | func (r *NodeRegistryConfigsReconciler) createOrUpdateRegistry(nodeRegistryConfigs *configregistryv1alpha1.NodeRegistryConfigs) error { 166 | if len(nodeRegistryConfigs.Spec.HostConfigs) == 0 { 167 | return nil 168 | } 169 | if nodeRegistryConfigs.Status.Conditions == nil { 170 | nodeRegistryConfigs.Status.Conditions = make([]metav1.Condition, 0) 171 | } 172 | if _, err := os.Stat(r.HostRootDir); err != nil { 173 | if os.IsNotExist(err) { 174 | if err = os.MkdirAll(r.HostRootDir, 0o755); err != nil { 175 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 176 | Type: string(configregistryv1alpha1.ConditionTypeReadDataError), 177 | Status: metav1.ConditionFalse, 178 | LastTransitionTime: metav1.Now(), 179 | Reason: string(configregistryv1alpha1.ConditionTypeReadDataError), 180 | Message: err.Error(), 181 | }) 182 | return err 183 | } 184 | } else { 185 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 186 | Type: string(configregistryv1alpha1.ConditionTypeReadDataError), 187 | Status: metav1.ConditionFalse, 188 | LastTransitionTime: metav1.Now(), 189 | Reason: string(configregistryv1alpha1.ConditionTypeReadDataError), 190 | Message: err.Error(), 191 | }) 192 | } 193 | return err 194 | } 195 | for _, host := range nodeRegistryConfigs.Spec.HostConfigs { 196 | parse, _ := url.Parse(host.Server) 197 | hostsDir := filepath.Join(r.HostRootDir, parse.Host) 198 | if _, err := os.Stat(hostsDir); err != nil { 199 | if os.IsNotExist(err) { 200 | if err = os.MkdirAll(hostsDir, 0o755); err != nil { 201 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 202 | Type: string(configregistryv1alpha1.ConditionTypeReadDataError), 203 | Status: metav1.ConditionFalse, 204 | LastTransitionTime: metav1.Now(), 205 | Reason: string(configregistryv1alpha1.ConditionTypeReadDataError), 206 | Message: err.Error(), 207 | }) 208 | return err 209 | } 210 | } else { 211 | return err 212 | } 213 | } 214 | b, err := os.ReadFile(filepath.Join(hostsDir, "hosts.toml")) 215 | if err != nil && !os.IsNotExist(err) { 216 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 217 | Type: string(configregistryv1alpha1.ConditionTypeReadDataError), 218 | Status: metav1.ConditionFalse, 219 | LastTransitionTime: metav1.Now(), 220 | Reason: string(configregistryv1alpha1.ConditionTypeReadDataError), 221 | Message: err.Error(), 222 | }) 223 | return err 224 | } 225 | hostFileConfigs := convertNodeRegistryHostConfigToHostFileConfigs(host) 226 | if os.IsNotExist(err) { 227 | // create 228 | file, err := os.Create(filepath.Join(hostsDir, "hosts.toml")) 229 | if err != nil { 230 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 231 | Type: string(configregistryv1alpha1.ConditionTypeWriteDataError), 232 | Status: metav1.ConditionFalse, 233 | LastTransitionTime: metav1.Now(), 234 | Reason: string(configregistryv1alpha1.ConditionTypeWriteDataError), 235 | Message: err.Error(), 236 | }) 237 | return err 238 | } 239 | if err := toml.NewEncoder(file).Encode(hostFileConfigs); err != nil { 240 | klog.Errorf("encode toml error: %+v", err) 241 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 242 | Type: string(configregistryv1alpha1.ConditionTypeWriteDataError), 243 | Status: metav1.ConditionFalse, 244 | LastTransitionTime: metav1.Now(), 245 | Reason: string(configregistryv1alpha1.ConditionTypeWriteDataError), 246 | Message: err.Error(), 247 | }) 248 | return err 249 | } 250 | } else { 251 | // update 252 | var cfg Config 253 | if err := toml.Unmarshal(b, &cfg); err != nil { 254 | klog.Errorf("unmarshal toml error: %+v", err) 255 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 256 | Type: string(configregistryv1alpha1.ConditionTypeReadDataError), 257 | Status: metav1.ConditionFalse, 258 | LastTransitionTime: metav1.Now(), 259 | Reason: string(configregistryv1alpha1.ConditionTypeReadDataError), 260 | Message: err.Error(), 261 | }) 262 | return err 263 | } 264 | if cfg.Server == host.Server && reflect.DeepEqual(cfg.Host, hostFileConfigs.Host) { 265 | continue 266 | } 267 | cfg.Server = host.Server 268 | cfg.Host = hostFileConfigs.Host 269 | var buf bytes.Buffer 270 | if err := toml.NewEncoder(&buf).Encode(cfg); err != nil { 271 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 272 | Type: string(configregistryv1alpha1.ConditionTypeWriteDataError), 273 | Status: metav1.ConditionFalse, 274 | LastTransitionTime: metav1.Now(), 275 | Reason: string(configregistryv1alpha1.ConditionTypeWriteDataError), 276 | Message: err.Error(), 277 | }) 278 | return err 279 | } 280 | if err := os.WriteFile(filepath.Join(hostsDir, "hosts.toml"), buf.Bytes(), 0o644); err != nil { 281 | klog.Errorf("encode toml error: %+v", err) 282 | nodeRegistryConfigs.Status.Conditions = append(nodeRegistryConfigs.Status.Conditions, metav1.Condition{ 283 | Type: string(configregistryv1alpha1.ConditionTypeWriteDataError), 284 | Status: metav1.ConditionFalse, 285 | LastTransitionTime: metav1.Now(), 286 | Reason: string(configregistryv1alpha1.ConditionTypeWriteDataError), 287 | Message: err.Error(), 288 | }) 289 | return err 290 | } 291 | } 292 | } 293 | return nil 294 | } 295 | 296 | func convertNodeRegistryHostConfigToHostFileConfigs(host configregistryv1alpha1.NodeRegistryHostConfig) Config { 297 | capabilities := make([]string, 0) 298 | for _, v := range host.Capabilities { 299 | capabilities = append(capabilities, string(v)) 300 | } 301 | var header map[string]interface{} 302 | if len(host.Header) != 0 { 303 | header = make(map[string]interface{}) 304 | for k, v := range host.Header { 305 | header[k] = v 306 | } 307 | } 308 | hostFileConfigs := Config{ 309 | Server: host.Server, 310 | Host: &map[string]HostConfig{ 311 | host.Server: { 312 | Capabilities: capabilities, 313 | SkipVerify: host.SkipVerify, 314 | OverridePath: host.OverridePath, 315 | Header: header, 316 | }, 317 | }, 318 | } 319 | return hostFileConfigs 320 | } 321 | 322 | type Config struct { 323 | *HostConfig 324 | Server string `toml:"server"` 325 | Host *map[string]HostConfig `toml:"host,omitempty"` 326 | } 327 | 328 | type HostConfig struct { 329 | // Capabilities determine what operations a host is 330 | // capable of performing. Allowed values 331 | // - pull 332 | // - resolve 333 | // - push 334 | Capabilities []string `toml:"capabilities"` 335 | 336 | // CACert are the public key certificates for TLS 337 | // Accepted types 338 | // - string - Single file with certificate(s) 339 | // - []string - Multiple files with certificates 340 | CACert interface{} `toml:"ca"` 341 | 342 | // Client keypair(s) for TLS with client authentication 343 | // Accepted types 344 | // - string - Single file with public and private keys 345 | // - []string - Multiple files with public and private keys 346 | // - [][2]string - Multiple keypairs with public and private keys in separate files 347 | Client interface{} `toml:"client"` 348 | 349 | // SkipVerify skips verification of the server's certificate chain 350 | // and host name. This should only be used for testing or in 351 | // combination with other methods of verifying connections. 352 | SkipVerify *bool `toml:"skip_verify"` 353 | 354 | // Header are additional header files to send to the server 355 | Header map[string]interface{} `toml:"header"` 356 | 357 | // OverridePath indicates the API root endpoint is defined in the URL 358 | // path rather than by the API specification. 359 | // This may be used with non-compliant OCI registries to override the 360 | // API root endpoint. 361 | OverridePath bool `toml:"override_path"` 362 | } 363 | 364 | // SetupWithManager sets up the controller with the Manager. 365 | func (r *NodeRegistryConfigsReconciler) SetupWithManager(mgr ctrl.Manager) error { 366 | return ctrl.NewControllerManagedBy(mgr). 367 | For(&configregistryv1alpha1.NodeRegistryConfigs{}). 368 | Complete(r) 369 | } 370 | -------------------------------------------------------------------------------- /internal/controller/registryconfigs_controller.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023. 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 controller 18 | 19 | import ( 20 | "context" 21 | "encoding/json" 22 | "fmt" 23 | "strings" 24 | "time" 25 | 26 | configregistryv1alpha1 "github.com/copilot-io/runtime-copilot/api/v1alpha1" 27 | "github.com/copilot-io/runtime-copilot/internal/utils" 28 | 29 | v1 "k8s.io/api/core/v1" 30 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 | "k8s.io/apimachinery/pkg/runtime" 32 | "k8s.io/apimachinery/pkg/types" 33 | ctrl "sigs.k8s.io/controller-runtime" 34 | "sigs.k8s.io/controller-runtime/pkg/client" 35 | "sigs.k8s.io/controller-runtime/pkg/log" 36 | ) 37 | 38 | // RegistryConfigsReconciler reconciles a RegistryConfigs object. 39 | type RegistryConfigsReconciler struct { 40 | client.Client 41 | Scheme *runtime.Scheme 42 | } 43 | 44 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=registryconfigs,verbs=get;list;watch;create;update;patch;delete 45 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=registryconfigs/status,verbs=get;update;patch 46 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=registryconfigs/finalizers,verbs=update 47 | //+kubebuilder:rbac:groups=config.registry.runtime.copilot.io,resources=noderegistryconfigs,verbs=get;list;watch 48 | //+kubebuilder:rbac:groups=,resources=nodes,verbs=get;list;watch 49 | // +kubebuilder:printcolumn:name="NAME",type=string,JSONPath=`.metadata.namme` 50 | // +kubebuilder:printcolumn:name="STATE",type=string,JSONPath=`.status.state` 51 | // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 52 | 53 | // Reconcile is part of the main kubernetes reconciliation loop which aims to 54 | // move the current state of the cluster closer to the desired state. 55 | // TODO(user): Modify the Reconcile function to compare the state specified by 56 | // the RegistryConfigs object against the actual cluster state, and then 57 | // perform operations to make the cluster state reflect the state specified by 58 | // the user. 59 | // 60 | // For more details, check Reconcile and its Result here: 61 | // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile 62 | func (r *RegistryConfigsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 63 | logger := log.FromContext(ctx) 64 | 65 | logger.Info("Reconciling RegistryConfigs ", "NamespacedName", req.NamespacedName) 66 | // step1. get the RegistryConfigs object 67 | // TODO(lrf), current object may be is NodereRistryConfigs, current we don't to handle it 68 | var registryConfigs configregistryv1alpha1.RegistryConfigs 69 | if err := r.Get(ctx, req.NamespacedName, ®istryConfigs); err != nil { 70 | return ctrl.Result{}, client.IgnoreNotFound(err) 71 | } 72 | // step2. get the node list 73 | var nodeList v1.NodeList 74 | if err := r.List(ctx, &nodeList); err != nil { 75 | return ctrl.Result{}, err 76 | } 77 | // step3. get the nodeRegistryConfigs list 78 | var existNodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList 79 | listOption := client.MatchingLabels{ 80 | "config.registry.runtime.copilot.io/registryconfigs": registryConfigs.Name, 81 | } 82 | for k, v := range registryConfigs.Spec.Selector.MatchLabels { 83 | listOption[k] = v 84 | } 85 | if err := r.List(ctx, &existNodeRegistryConfigsList, listOption); err != nil { 86 | return ctrl.Result{}, err 87 | } 88 | nodeExistCr := make(map[string]configregistryv1alpha1.NodeRegistryConfigs) 89 | for index, item := range existNodeRegistryConfigsList.Items { 90 | nodeExistCr[item.Spec.NodeName] = existNodeRegistryConfigsList.Items[index] 91 | } 92 | // step4. generate the NodeRegistryConfigs 93 | nodeRegistryConfigsList := r.generateNodeRegistryConfigs(ctx, registryConfigs, nodeList) 94 | // step5. create or update the NodeRegistryConfigs 95 | for _, nodeRegistryConfigs := range nodeRegistryConfigsList.Items { 96 | if err := r.applyNodeRegistryConfigs(ctx, nodeRegistryConfigs, nodeExistCr); err != nil { 97 | return ctrl.Result{}, err 98 | } 99 | } 100 | // step6. update the RegistryConfigs 101 | if err := r.syncRegistryConfigsStatus(ctx, registryConfigs, nodeList); err != nil { 102 | return ctrl.Result{}, err 103 | } 104 | if registryConfigs.Status.State == configregistryv1alpha1.StatusStateSuccess { 105 | return ctrl.Result{}, nil 106 | } 107 | return ctrl.Result{RequeueAfter: time.Second * 30}, nil 108 | } 109 | 110 | func (r *RegistryConfigsReconciler) generateNodeRegistryConfigs(ctx context.Context, registryConfigs configregistryv1alpha1.RegistryConfigs, nodeList v1.NodeList) configregistryv1alpha1.NodeRegistryConfigsList { 111 | var nodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList 112 | for _, node := range nodeList.Items { 113 | if registryConfigs.Spec.Template.Spec.RetryNum == 0 { 114 | registryConfigs.Spec.Template.Spec.RetryNum = configregistryv1alpha1.MaxRetryNum 115 | } 116 | nodeRegistryConfigs := configregistryv1alpha1.NodeRegistryConfigs{ 117 | ObjectMeta: ctrl.ObjectMeta{ 118 | Name: fmt.Sprintf("%s-%s", registryConfigs.Name, utils.RandUUID()), 119 | Namespace: registryConfigs.Namespace, 120 | Labels: map[string]string{ 121 | "config.registry.runtime.copilot.io/registryconfigs": registryConfigs.Name, 122 | }, 123 | OwnerReferences: []metav1.OwnerReference{ 124 | { 125 | APIVersion: registryConfigs.APIVersion, 126 | Kind: registryConfigs.Kind, 127 | Name: registryConfigs.Name, 128 | UID: registryConfigs.UID, 129 | }, 130 | }, 131 | }, 132 | Spec: configregistryv1alpha1.NodeRegistryConfigsSpec{ 133 | NodeName: node.Name, 134 | Type: r.convertRuntimeType(node.Status.NodeInfo.ContainerRuntimeVersion), 135 | HostConfigs: registryConfigs.Spec.Template.Spec.HostConfigs, 136 | RetryNum: registryConfigs.Spec.Template.Spec.RetryNum, 137 | }, 138 | } 139 | 140 | for k, v := range registryConfigs.Spec.Selector.MatchLabels { 141 | nodeRegistryConfigs.ObjectMeta.Labels[k] = v 142 | } 143 | nodeRegistryConfigsList.Items = append(nodeRegistryConfigsList.Items, nodeRegistryConfigs) 144 | } 145 | return nodeRegistryConfigsList 146 | } 147 | 148 | func (r *RegistryConfigsReconciler) applyNodeRegistryConfigs(ctx context.Context, nodeRegistryConfigs configregistryv1alpha1.NodeRegistryConfigs, nodeExistCr map[string]configregistryv1alpha1.NodeRegistryConfigs) error { 149 | var nodeRegistryConfigsOld configregistryv1alpha1.NodeRegistryConfigs 150 | var ok bool 151 | if nodeRegistryConfigsOld, ok = nodeExistCr[nodeRegistryConfigs.Spec.NodeName]; !ok { 152 | return r.Create(ctx, &nodeRegistryConfigs) 153 | } 154 | lastAppliedConfiguration := configregistryv1alpha1.NodeRegistryConfigs{ 155 | TypeMeta: nodeRegistryConfigsOld.TypeMeta, 156 | ObjectMeta: metav1.ObjectMeta{ 157 | Name: nodeRegistryConfigsOld.Name, 158 | Namespace: nodeRegistryConfigsOld.Namespace, 159 | Labels: nodeRegistryConfigsOld.Labels, 160 | OwnerReferences: nodeRegistryConfigsOld.OwnerReferences, 161 | }, 162 | Spec: nodeRegistryConfigsOld.Spec, 163 | } 164 | bytes, _ := json.Marshal(lastAppliedConfiguration) 165 | if nodeRegistryConfigsOld.ObjectMeta.Annotations == nil { 166 | nodeRegistryConfigsOld.ObjectMeta.Annotations = make(map[string]string) 167 | } 168 | nodeRegistryConfigsOld.ObjectMeta.Annotations["config.registry.runtime.copilot.io/last-applied-configuration"] = string(bytes) 169 | nodeRegistryConfigsOld.Spec = nodeRegistryConfigs.Spec 170 | return r.Patch(ctx, &nodeRegistryConfigsOld, client.Merge, &client.PatchOptions{FieldManager: string(types.JSONPatchType)}) 171 | } 172 | 173 | func (r *RegistryConfigsReconciler) syncRegistryConfigsStatus(ctx context.Context, registryConfigs configregistryv1alpha1.RegistryConfigs, nodeList v1.NodeList) error { 174 | var nodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList 175 | listOption := client.MatchingLabels{ 176 | "config.registry.runtime.copilot.io/registryconfigs": registryConfigs.Name, 177 | } 178 | for k, v := range registryConfigs.Spec.Selector.MatchLabels { 179 | listOption[k] = v 180 | } 181 | if err := r.List(ctx, &nodeRegistryConfigsList, listOption); err != nil { 182 | return err 183 | } 184 | 185 | registryConfigs.Status.State = configregistryv1alpha1.StatusStateRunning 186 | registryConfigs.Status.TotalNodes = r.countTotalNode(ctx, nodeList) 187 | registryConfigs.Status.SuccessNodes = r.countSuccessNode(ctx, nodeList, nodeRegistryConfigsList) 188 | registryConfigs.Status.FailedNodes = r.countFailedNode(ctx, nodeList, nodeRegistryConfigsList) 189 | registryConfigs.Status.RunningNodes = r.countRunningNode(ctx, nodeList, nodeRegistryConfigsList) 190 | 191 | if len(registryConfigs.Status.FailedNodes) > 0 { 192 | registryConfigs.Status.State = configregistryv1alpha1.StatusStateFailed 193 | } 194 | if r.equalSuccessAndTotal(registryConfigs.Status.TotalNodes, registryConfigs.Status.SuccessNodes) { 195 | registryConfigs.Status.State = configregistryv1alpha1.StatusStateSuccess 196 | } 197 | return r.Status().Update(ctx, ®istryConfigs) 198 | } 199 | 200 | func (r *RegistryConfigsReconciler) convertRuntimeType(containerRuntimeVersion string) configregistryv1alpha1.RuntimeType { 201 | if strings.Contains(containerRuntimeVersion, "docker") { 202 | return configregistryv1alpha1.RuntimeTypeDocker 203 | } 204 | if strings.Contains(containerRuntimeVersion, "containerd") { 205 | return configregistryv1alpha1.RuntimeTypeContainerd 206 | } 207 | if strings.Contains(containerRuntimeVersion, "crio") { 208 | return configregistryv1alpha1.RuntimeTypeCrio 209 | } 210 | return configregistryv1alpha1.RuntimeTypeUnknown 211 | } 212 | 213 | func (r *RegistryConfigsReconciler) countTotalNode(ctx context.Context, nodeList v1.NodeList) []configregistryv1alpha1.RuntimeNum { 214 | runtimeNumsMap := make(map[configregistryv1alpha1.RuntimeType]int) 215 | for _, node := range nodeList.Items { 216 | runtimeType := r.convertRuntimeType(node.Status.NodeInfo.ContainerRuntimeVersion) 217 | if _, ok := runtimeNumsMap[runtimeType]; !ok { 218 | runtimeNumsMap[runtimeType] = 1 219 | } else { 220 | runtimeNumsMap[runtimeType]++ 221 | } 222 | } 223 | runtimeNums := make([]configregistryv1alpha1.RuntimeNum, 0) 224 | for k, v := range runtimeNumsMap { 225 | runtimeNums = append(runtimeNums, configregistryv1alpha1.RuntimeNum{ 226 | RuntimeType: k, 227 | Num: v, 228 | }) 229 | } 230 | return runtimeNums 231 | } 232 | 233 | func (r *RegistryConfigsReconciler) countSuccessNode(ctx context.Context, nodeList v1.NodeList, nodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList) []configregistryv1alpha1.RuntimeNum { 234 | runtimeTypeMap := make(map[string]configregistryv1alpha1.RuntimeType) 235 | for _, node := range nodeList.Items { 236 | runtimeType := r.convertRuntimeType(node.Status.NodeInfo.ContainerRuntimeVersion) 237 | if _, ok := runtimeTypeMap[node.Name]; !ok { 238 | runtimeTypeMap[node.Name] = runtimeType 239 | } 240 | } 241 | runtimeNumsMap := make(map[configregistryv1alpha1.RuntimeType]int) 242 | for _, item := range nodeRegistryConfigsList.Items { 243 | if item.Status.State != configregistryv1alpha1.StatusStateSuccess { 244 | continue 245 | } 246 | runtimeType := runtimeTypeMap[item.Spec.NodeName] 247 | if _, ok := runtimeNumsMap[runtimeType]; !ok { 248 | runtimeNumsMap[runtimeType] = 1 249 | } else { 250 | runtimeNumsMap[runtimeType]++ 251 | } 252 | } 253 | runtimeNums := make([]configregistryv1alpha1.RuntimeNum, 0) 254 | for k, v := range runtimeNumsMap { 255 | runtimeNums = append(runtimeNums, configregistryv1alpha1.RuntimeNum{ 256 | RuntimeType: k, 257 | Num: v, 258 | }) 259 | } 260 | return runtimeNums 261 | } 262 | 263 | func (r *RegistryConfigsReconciler) countFailedNode(ctx context.Context, nodeList v1.NodeList, nodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList) []configregistryv1alpha1.RuntimeNum { 264 | runtimeTypeMap := make(map[string]configregistryv1alpha1.RuntimeType) 265 | for _, node := range nodeList.Items { 266 | runtimeType := r.convertRuntimeType(node.Status.NodeInfo.ContainerRuntimeVersion) 267 | if _, ok := runtimeTypeMap[node.Name]; !ok { 268 | runtimeTypeMap[node.Name] = runtimeType 269 | } 270 | } 271 | runtimeNumsMap := make(map[configregistryv1alpha1.RuntimeType]int) 272 | for _, item := range nodeRegistryConfigsList.Items { 273 | if item.Status.State != configregistryv1alpha1.StatusStateFailed { 274 | continue 275 | } 276 | runtimeType := runtimeTypeMap[item.Spec.NodeName] 277 | if _, ok := runtimeNumsMap[runtimeType]; !ok { 278 | runtimeNumsMap[runtimeType] = 1 279 | } else { 280 | runtimeNumsMap[runtimeType]++ 281 | } 282 | } 283 | runtimeNums := make([]configregistryv1alpha1.RuntimeNum, 0) 284 | for k, v := range runtimeNumsMap { 285 | runtimeNums = append(runtimeNums, configregistryv1alpha1.RuntimeNum{ 286 | RuntimeType: k, 287 | Num: v, 288 | }) 289 | } 290 | return runtimeNums 291 | } 292 | 293 | func (r *RegistryConfigsReconciler) countRunningNode(ctx context.Context, nodeList v1.NodeList, nodeRegistryConfigsList configregistryv1alpha1.NodeRegistryConfigsList) []configregistryv1alpha1.RuntimeNum { 294 | runtimeTypeMap := make(map[string]configregistryv1alpha1.RuntimeType) 295 | for _, node := range nodeList.Items { 296 | runtimeType := r.convertRuntimeType(node.Status.NodeInfo.ContainerRuntimeVersion) 297 | if _, ok := runtimeTypeMap[node.Name]; !ok { 298 | runtimeTypeMap[node.Name] = runtimeType 299 | } 300 | } 301 | runtimeNumsMap := make(map[configregistryv1alpha1.RuntimeType]int) 302 | for _, item := range nodeRegistryConfigsList.Items { 303 | if item.Status.State != configregistryv1alpha1.StatusStateRunning { 304 | continue 305 | } 306 | runtimeType := runtimeTypeMap[item.Spec.NodeName] 307 | if _, ok := runtimeNumsMap[runtimeType]; !ok { 308 | runtimeNumsMap[runtimeType] = 1 309 | } else { 310 | runtimeNumsMap[runtimeType]++ 311 | } 312 | } 313 | runtimeNums := make([]configregistryv1alpha1.RuntimeNum, 0) 314 | for k, v := range runtimeNumsMap { 315 | runtimeNums = append(runtimeNums, configregistryv1alpha1.RuntimeNum{ 316 | RuntimeType: k, 317 | Num: v, 318 | }) 319 | } 320 | return runtimeNums 321 | } 322 | 323 | func (r *RegistryConfigsReconciler) equalSuccessAndTotal(total, success []configregistryv1alpha1.RuntimeNum) bool { 324 | if len(total) != len(success) { 325 | return false 326 | } 327 | totalMap, successMap := make(map[configregistryv1alpha1.RuntimeType]int), make(map[configregistryv1alpha1.RuntimeType]int) 328 | for _, item := range total { 329 | totalMap[item.RuntimeType] = item.Num 330 | } 331 | for _, item := range success { 332 | successMap[item.RuntimeType] = item.Num 333 | } 334 | for k, v := range totalMap { 335 | if successMap[k] != v { 336 | return false 337 | } 338 | } 339 | return true 340 | } 341 | 342 | // SetupWithManager sets up the controller with the Manager. 343 | func (r *RegistryConfigsReconciler) SetupWithManager(mgr ctrl.Manager) error { 344 | return ctrl.NewControllerManagedBy(mgr). 345 | For(&configregistryv1alpha1.RegistryConfigs{}). 346 | Complete(r) 347 | } 348 | -------------------------------------------------------------------------------- /internal/utils/rand.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | func init() { 9 | rand.Seed(time.Now().UnixNano()) 10 | } 11 | 12 | const ( 13 | length = 5 14 | chars = "abcdefghijklmnopqrstuvwxyz0123456789" 15 | ) 16 | 17 | func RandUUID() string { 18 | result := make([]byte, length) 19 | for i := 0; i < length; i++ { 20 | index := rand.Intn(len(chars)) 21 | result[i] = chars[index] 22 | } 23 | return string(result) 24 | } 25 | --------------------------------------------------------------------------------